001 /*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License"). You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at
010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 * Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 * Copyright 2007-2008 Sun Microsystems, Inc.
026 */
027
028 package org.opends.admin.ads;
029
030 import java.util.Map;
031 import java.util.SortedSet;
032 import java.util.TreeSet;
033
034 import javax.naming.NameNotFoundException;
035 import javax.naming.NamingEnumeration;
036 import javax.naming.NamingException;
037 import javax.naming.directory.Attribute;
038 import javax.naming.directory.BasicAttribute;
039 import javax.naming.directory.BasicAttributes;
040 import javax.naming.directory.SearchResult;
041 import javax.naming.ldap.InitialLdapContext;
042 import javax.naming.ldap.LdapName;
043 import javax.naming.ldap.Rdn;
044
045 import org.opends.admin.ads.ADSContext.ServerProperty;
046 import org.opends.server.admin.ManagedObjectNotFoundException;
047 import org.opends.server.admin.client.ManagementContext;
048 import org.opends.server.admin.client.ldap.JNDIDirContextAdaptor;
049 import org.opends.server.admin.client.ldap.LDAPManagementContext;
050 import org.opends.server.admin.std.client.*;
051 import org.opends.server.admin.std.meta.BackendCfgDefn;
052 import org.opends.server.admin.std.meta.LDIFBackendCfgDefn;
053 import org.opends.server.config.ConfigConstants;
054 import org.opends.server.crypto.CryptoManagerImpl;
055 import org.opends.server.types.CryptoManagerException;
056 import org.opends.server.types.DN;
057
058 /**
059 * This is the only class in the org.opends.admin.ads package that uses the
060 * classes from OpenDS.jar (in particular the administration client framework
061 * API). Before calling this class OpenDS.jar must be
062 * loaded. The goal is basically to centralize in one single place the
063 * dependencies of this package on OpenDS.jar. This is done in order the
064 * QuickSetup code to be able to use some of the functionalities provided
065 * by the ADSContext classes before OpenDS.jar is downloaded.
066 */
067 public class ADSContextHelper
068 {
069 /**
070 * Default constructor.
071 */
072 public ADSContextHelper()
073 {
074 }
075 /**
076 * Removes the administration suffix.
077 * @param ctx the DirContext to be used.
078 * @param backendName the name of the backend where the administration
079 * suffix is stored.
080 * @throws ADSContextException if the administration suffix could not be
081 * removed.
082 */
083 public void removeAdministrationSuffix(InitialLdapContext ctx,
084 String backendName) throws ADSContextException
085 {
086 try
087 {
088 ManagementContext mCtx = LDAPManagementContext.createFromContext(
089 JNDIDirContextAdaptor.adapt(ctx));
090 RootCfgClient root = mCtx.getRootConfiguration();
091 BackendCfgClient backend = null;
092 try
093 {
094 backend = root.getBackend(backendName);
095 }
096 catch (ManagedObjectNotFoundException monfe)
097 {
098 // It does not exist.
099 }
100 if (backend != null)
101 {
102 SortedSet<DN> suffixes = backend.getBaseDN();
103 if (suffixes != null)
104 {
105 if (suffixes.remove(
106 DN.decode(ADSContext.getAdministrationSuffixDN())))
107 {
108 if (suffixes.size() > 0)
109 {
110 backend.setBaseDN(suffixes);
111 backend.commit();
112 }
113 else
114 {
115 root.removeBackend(backendName);
116 }
117 }
118 }
119 }
120 }
121 catch (Throwable t)
122 {
123 throw new ADSContextException(
124 ADSContextException.ErrorType.ERROR_UNEXPECTED, t);
125 }
126 }
127
128 /**
129 * Creates the Administration Suffix.
130 * @param ctx the DirContext to be used.
131 * @param backendName the name of the backend where the administration
132 * suffix is stored.
133 * @throws ADSContextException if the administration suffix could not be
134 * created.
135 */
136 public void createAdministrationSuffix(InitialLdapContext ctx,
137 String backendName)
138 throws ADSContextException
139 {
140 try
141 {
142 ManagementContext mCtx = LDAPManagementContext.createFromContext(
143 JNDIDirContextAdaptor.adapt(ctx));
144 RootCfgClient root = mCtx.getRootConfiguration();
145 LDIFBackendCfgClient backend = null;
146 try
147 {
148 backend = (LDIFBackendCfgClient)root.getBackend(backendName);
149 }
150 catch (ManagedObjectNotFoundException e)
151 {
152 }
153 catch (ClassCastException cce)
154 {
155 throw new ADSContextException(
156 ADSContextException.ErrorType.UNEXPECTED_ADS_BACKEND_TYPE, cce);
157 }
158
159 if (backend == null)
160 {
161 LDIFBackendCfgDefn provider = LDIFBackendCfgDefn.getInstance();
162 backend = root.createBackend(provider, backendName, null);
163 backend.setEnabled(true);
164 backend.setLDIFFile(ADSContext.getAdminLDIFFile());
165 backend.setBackendId(backendName);
166 backend.setWritabilityMode(BackendCfgDefn.WritabilityMode.ENABLED);
167 backend.setIsPrivateBackend(true);
168 }
169 SortedSet<DN> suffixes = backend.getBaseDN();
170 if (suffixes == null)
171 {
172 suffixes = new TreeSet<DN>();
173 }
174 DN newDN = DN.decode(ADSContext.getAdministrationSuffixDN());
175 if (!suffixes.contains(newDN))
176 {
177 suffixes.add(newDN);
178 backend.setBaseDN(suffixes);
179 backend.commit();
180 }
181 }
182 catch (Throwable t)
183 {
184 throw new ADSContextException(
185 ADSContextException.ErrorType.ERROR_UNEXPECTED, t);
186 }
187 }
188
189 /**
190 Register instance key-pair public-key certificate provided in
191 serverProperties: generate a key-id attribute if one is not provided (as
192 expected); add an instance key public-key certificate entry for the key
193 certificate; and associate the certificate entry with the server entry via
194 the key ID attribute.
195 @param ctx the InitialLdapContext on the server we want to update.
196 @param serverProperties Properties of the server being registered to which
197 the instance key entry belongs.
198 @param serverEntryDn The server's ADS entry DN.
199 @throws ADSContextException In case some JNDI operation fails or there is a
200 problem getting the instance public key certificate ID.
201 */
202 public void registerInstanceKeyCertificate(
203 InitialLdapContext ctx, Map<ServerProperty, Object> serverProperties,
204 LdapName serverEntryDn)
205 throws ADSContextException {
206 assert serverProperties.containsKey(
207 ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE);
208 if (! serverProperties.containsKey(
209 ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE)) {
210 return;
211 }
212
213 /* the key ID might be supplied in serverProperties (although, I am unaware
214 of any such case). */
215 String keyID = (String)serverProperties.get(ServerProperty.INSTANCE_KEY_ID);
216
217 /* these attributes are used both to search for an existing certificate
218 entry and, if one does not exist, add a new certificate entry */
219 final BasicAttributes keyAttrs = new BasicAttributes();
220 final Attribute oc = new BasicAttribute("objectclass");
221 oc.add("top"); oc.add("ds-cfg-instance-key");
222 keyAttrs.put(oc);
223 if (null != keyID) {
224 keyAttrs.put(new BasicAttribute(
225 ServerProperty.INSTANCE_KEY_ID.getAttributeName(), keyID));
226 }
227 keyAttrs.put(new BasicAttribute(
228 ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE.getAttributeName()
229 + ";binary",
230 serverProperties.get(
231 ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE)));
232
233 /* search for public-key certificate entry in ADS DIT */
234 final String attrIDs[] = { "ds-cfg-key-id" };
235 try
236 {
237 final NamingEnumeration<SearchResult> results = ctx.search(
238 ADSContext.getInstanceKeysContainerDN(), keyAttrs, attrIDs);
239 if (results.hasMore()) {
240 final Attribute keyIdAttr =
241 results.next().getAttributes().get(attrIDs[0]);
242 if (null != keyIdAttr) {
243 /* attribute ds-cfg-key-id is the entry is a MUST in the schema */
244 keyID = (String)keyIdAttr.get();
245 }
246 }
247 /* TODO: It is possible (but unexpected) that the caller specifies a
248 ds-cfg-key-id value for which there is a certificate entry in ADS, but
249 the certificate value does not match that supplied by the caller. The
250 above search would not return the entry, but the below attempt to add
251 an new entry with the supplied ds-cfg-key-id will fail (throw a
252 NameAlreadyBoundException) */
253 else {
254 /* create key ID, if it was not supplied in serverProperties */
255 if (null == keyID) {
256 keyID = CryptoManagerImpl.getInstanceKeyID(
257 (byte[])serverProperties.get(
258 ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE));
259 keyAttrs.put(new BasicAttribute(
260 ServerProperty.INSTANCE_KEY_ID.getAttributeName(), keyID));
261 }
262
263 /* add public-key certificate entry */
264 final LdapName keyDn = new LdapName((new StringBuilder())
265 .append(ServerProperty.INSTANCE_KEY_ID.getAttributeName())
266 .append("=").append(Rdn.escapeValue(keyID)).append(",")
267 .append(ADSContext.getInstanceKeysContainerDN()).toString());
268 ctx.createSubcontext(keyDn, keyAttrs).close();
269 }
270
271 /* associate server entry with certificate entry via key ID attribute */
272 ctx.modifyAttributes(serverEntryDn,
273 InitialLdapContext.REPLACE_ATTRIBUTE,
274 (new BasicAttributes(
275 ServerProperty.INSTANCE_KEY_ID.getAttributeName(), keyID)));
276 }
277 catch (NamingException ne)
278 {
279 throw new ADSContextException(
280 ADSContextException.ErrorType.ERROR_UNEXPECTED, ne);
281 }
282 catch (CryptoManagerException cme)
283 {
284 throw new ADSContextException(
285 ADSContextException.ErrorType.ERROR_UNEXPECTED, cme);
286 }
287 }
288
289
290 /**
291 Unregister instance key-pair public-key certificate provided in
292 serverProperties.
293 @param ctx the connection to the server.
294 @param serverProperties Properties of the server being unregistered to which
295 the instance key entry belongs.
296 @param serverEntryDn The server's ADS entry DN.
297 @throws ADSContextException In case some JNDI operation fails.
298 */
299 public void unregisterInstanceKeyCertificate(
300 InitialLdapContext ctx, Map<ServerProperty, Object> serverProperties,
301 LdapName serverEntryDn)
302 throws ADSContextException {
303 assert serverProperties.containsKey(
304 ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE);
305 if (! serverProperties.containsKey(
306 ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE)) {
307 return;
308 }
309
310 /* these attributes are used both to search for an existing certificate
311 entry and, if one does not exist, add a new certificate entry */
312 final BasicAttributes keyAttrs = new BasicAttributes();
313 final Attribute oc = new BasicAttribute("objectclass");
314 oc.add("top"); oc.add("ds-cfg-instance-key");
315 keyAttrs.put(oc);
316 keyAttrs.put(new BasicAttribute(
317 ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE.getAttributeName()
318 + ";binary",
319 serverProperties.get(
320 ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE)));
321
322 /* search for public-key certificate entry in ADS DIT */
323 final String attrIDs[] = { "ds-cfg-key-id" };
324 try
325 {
326 final NamingEnumeration<SearchResult> results = ctx.search(
327 ADSContext.getInstanceKeysContainerDN(), keyAttrs, attrIDs);
328 if (results.hasMore()) {
329 SearchResult res = results.next();
330 ctx.destroySubcontext(res.getNameInNamespace());
331 }
332 }
333 catch (NameNotFoundException nnfe)
334 {
335 }
336 catch (NamingException ne)
337 {
338 throw new ADSContextException(
339 ADSContextException.ErrorType.ERROR_UNEXPECTED, ne);
340 }
341 }
342
343 /**
344 * Returns the crypto instance key objectclass name as defined in
345 * ConfigConstants.
346 * @return the crypto instance key objectclass name as defined in
347 * ConfigConstants.
348 */
349 public String getOcCryptoInstanceKey()
350 {
351 return ConfigConstants.OC_CRYPTO_INSTANCE_KEY;
352 }
353
354 /**
355 * Returns the crypto key compromised time attribute name as defined in
356 * ConfigConstants.
357 * @return the crypto key compromised time attribute name as defined in
358 * ConfigConstants.
359 */
360 public String getAttrCryptoKeyCompromisedTime()
361 {
362 return ConfigConstants.ATTR_CRYPTO_KEY_COMPROMISED_TIME;
363 }
364 }