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 }