opends/src/ads/org/opends/admin/ads/ADSContext.java
@@ -173,7 +173,7 @@ * belongs to an instance key entry, separate from the server entry and * named by the ds-cfg-key-id attribute from the server entry. */ INSTANCE_KEY_CERT("ds-cfg-public-key-certificate"/*;binary*/, INSTANCE_PUBLIC_KEY_CERTIFICATE("ds-cfg-public-key-certificate"/*;binary*/, ADSPropertySyntax.CERTIFICATE_BINARY); private String attrName; @@ -418,7 +418,8 @@ try { dirContext.createSubcontext(dn, attrs).close(); if (serverProperties.containsKey(ServerProperty.INSTANCE_KEY_CERT)) if (serverProperties.containsKey( ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE)) { registerInstanceKeyCertificate(serverProperties, dn); } @@ -462,7 +463,8 @@ BasicAttributes attrs = makeAttrsFromServerProperties(serverProperties); dirContext.modifyAttributes(dn, InitialLdapContext.REPLACE_ATTRIBUTE, attrs); if (serverProperties.containsKey(ServerProperty.INSTANCE_KEY_CERT)) if (serverProperties.containsKey( ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE)) { registerInstanceKeyCertificate(serverProperties, dn); } @@ -481,7 +483,8 @@ /** * Method called to unregister a server in the ADS. Note that the server's * instance key-pair public-key certificate entry (created in registerServer) * instance key-pair public-key certificate entry (created in * <tt>registerServer()</tt>) * is left untouched. * @param serverProperties the properties of the server. * @throws ADSContextException if the server could not be unregistered. @@ -1400,7 +1403,7 @@ switch(property) { case INSTANCE_KEY_CERT: case INSTANCE_PUBLIC_KEY_CERTIFICATE: result = null; // used in separate instance key entry break; case GROUPS: @@ -2017,8 +2020,8 @@ */ /** * Returns the parent entry of the server key entries in ADS. * @return the parent entry of the server key entries in ADS. Returns the parent entry of the server key entries in ADS. @return the parent entry of the server key entries in ADS. */ private static String getInstanceKeysContainerDN() { @@ -2041,8 +2044,10 @@ Map<ServerProperty, Object> serverProperties, LdapName serverEntryDn) throws NamingException { assert serverProperties.containsKey(ServerProperty.INSTANCE_KEY_CERT); if (! serverProperties.containsKey(ServerProperty.INSTANCE_KEY_CERT)) { assert serverProperties.containsKey( ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE); if (! serverProperties.containsKey( ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE)) { return; } @@ -2061,8 +2066,10 @@ ServerProperty.INSTANCE_KEY_ID.getAttributeName(), keyID)); } keyAttrs.put(new BasicAttribute( ServerProperty.INSTANCE_KEY_CERT.getAttributeName() + ";binary", serverProperties.get(ServerProperty.INSTANCE_KEY_CERT))); ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE.getAttributeName() + ";binary", serverProperties.get( ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE))); /* search for public-key certificate entry in ADS DIT */ final String attrIDs[] = { "ds-cfg-key-id" }; @@ -2076,6 +2083,12 @@ keyID = (String)keyIdAttr.get(); } } /* TODO: It is possible (but unexpected) that the caller specifies a ds-cfg-key-id value for which there is a certificate entry in ADS, but the certificate value does not match that supplied by the caller. The above search would not return the entry, but the below attempt to add an new entry with the supplied ds-cfg-key-id will fail (throw a NameAlreadyBoundException) */ else { /* create key ID, if it was not supplied in serverProperties */ if (null == keyID) { @@ -2098,4 +2111,46 @@ (new BasicAttributes( ServerProperty.INSTANCE_KEY_ID.getAttributeName(), keyID))); } /** Return the set of valid (i.e., not tagged as compromised) instance key-pair public-key certificate entries in ADS. @return The set of valid (i.e., not tagged as compromised) instance key-pair public-key certificate entries in ADS represented as a Map from ds-cfg-key-id value to ds-cfg-public-key-certificate;binary value Note that the collection might be empty. @throws ADSContextException in case of problems with the entry search. */ public Map<String,byte[]> getTrustedCertificates() throws ADSContextException { Map<String, byte[]> keyEntryMap = new HashMap<String, byte[]>(); try { final LdapName baseDN = new LdapName(getInstanceKeysContainerDN()); final String searchFilter = "(&(objectclass=ds-cfg-instance-key)(!(ds-cfg-key-compromised-time=*)))"; final SearchControls searchControls = new SearchControls(); searchControls.setSearchScope(SearchControls.ONELEVEL_SCOPE); final String attrIDs[]= { ADSContext.ServerProperty.INSTANCE_KEY_ID.getAttributeName(), ADSContext.ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE .getAttributeName() + ";binary"}; searchControls.setReturningAttributes(attrIDs); NamingEnumeration<SearchResult> keyEntries = dirContext.search(baseDN, searchFilter, searchControls); while (keyEntries.hasMore()) { final SearchResult entry = keyEntries.next(); final Attributes attrs = entry.getAttributes(); final Attribute keyIDAttr = attrs.get(attrIDs[0]); final Attribute keyCertAttr = attrs.get(attrIDs[1]); if (null == keyIDAttr || null == keyCertAttr) continue; // schema viol. keyEntryMap.put((String)keyIDAttr.get(), (byte[])keyCertAttr.get()); } } catch (NamingException x) { throw new ADSContextException( ADSContextException.ErrorType.ERROR_UNEXPECTED, x); } return keyEntryMap; } } opends/src/ads/org/opends/admin/ads/ServerDescriptor.java
@@ -37,13 +37,11 @@ import javax.naming.NameNotFoundException; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.BasicAttribute; import javax.naming.directory.BasicAttributes; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import javax.naming.NameAlreadyBoundException; import javax.naming.directory.*; import javax.naming.ldap.InitialLdapContext; import javax.naming.ldap.LdapName; import javax.naming.ldap.Rdn; import org.opends.admin.ads.util.ConnectionUtils; @@ -338,6 +336,7 @@ } catch (Throwable t) { /* ignore */ } } return host + ":" + port; @@ -481,7 +480,7 @@ } } adsProperties.put(ADSContext.ServerProperty.ID, getHostPort(true)); adsProperties.put(ADSContext.ServerProperty.INSTANCE_KEY_CERT, adsProperties.put(ADSContext.ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE, getInstancePublicKeyCertificate()); } @@ -717,6 +716,7 @@ } catch (NameNotFoundException nse) { /* ignore */ } desc.serverProperties.put(ServerProperty.IS_REPLICATION_ENABLED, replicationEnabled ? Boolean.TRUE : Boolean.FALSE); @@ -769,6 +769,7 @@ } catch (NameNotFoundException nse) { /* ignore */ } ctls = new SearchControls(); @@ -815,23 +816,22 @@ } catch (NameNotFoundException nse) { /* ignore */ } } /** * Updates the instance key public-key certificate value of this context from * the local truststore of the instance bound by this context. Any current * value of the certificate is overwritten. The intent of this method is to * retrieve the instance-key public-key certificate when this context is bound * to an instance, and cache it for later use in registering the instance into * ADS. * * @param desc The map to update with the instance key-pair public-key * certificate. * @param ctx The bound server instance. * * @throws NamingException if unable to retrieve certificate from bound * instance. Updates the instance key public-key certificate value of this context from the local truststore of the instance bound by this context. Any current value of the certificate is overwritten. The intent of this method is to retrieve the instance-key public-key certificate when this context is bound to an instance, and cache it for later use in registering the instance into ADS. @param desc The map to update with the instance key-pair public-key certificate. @param ctx The bound server instance. @throws NamingException if unable to retrieve certificate from bound instance. */ private static void updatePublicKeyCertificate(ServerDescriptor desc, InitialLdapContext ctx) throws NamingException @@ -845,12 +845,12 @@ it (which induces the CryptoManager to create the public-key certificate attribute), then repeat the search. */ try { final SearchControls sc = new SearchControls(); sc.setSearchScope(SearchControls.OBJECT_SCOPE); final SearchControls searchControls = new SearchControls(); searchControls.setSearchScope(SearchControls.OBJECT_SCOPE); final String attrIDs[] = { "ds-cfg-public-key-certificate;binary" }; sc.setReturningAttributes(attrIDs); final SearchResult certEntry = ctx.search(dn, "(objectclass=ds-cfg-instance-key)", sc).next(); searchControls.setReturningAttributes(attrIDs); final SearchResult certEntry = ctx.search(dn, "(objectclass=ds-cfg-instance-key)", searchControls).next(); final Attribute certAttr = certEntry.getAttributes().get(attrIDs[0]); if (null != certAttr) { /* attribute ds-cfg-public-key-certificate is a MUST in the schema */ @@ -864,7 +864,7 @@ if (0 == i) { /* Poke CryptoManager to initialize truststore. Note the special attribute in the request. */ final BasicAttributes attrs = new BasicAttributes(); final Attributes attrs = new BasicAttributes(); final Attribute oc = new BasicAttribute("objectclass"); oc.add("top"); oc.add("ds-cfg-self-signed-cert-request"); @@ -878,6 +878,53 @@ } } /** Seeds the bound instance's local ads-truststore with a set of instance key-pair public key certificates. The result is the instance will trust any instance posessing the private key corresponding to one of the public-key certificates. This trust is necessary at least to initialize replication, which uses the trusted certificate entries in the ads-truststore for server authentication. @param ctx The bound instance. @param keyEntryMap The set of valid (i.e., not tagged as compromised) instance key-pair public-key certificate entries in ADS represented as a map from keyID to public-key certificate (binary). @throws NamingException in case an error occurs while updating the instance's ads-truststore via LDAP. */ public static void seedAdsTrustStore( InitialLdapContext ctx, Map<String, byte[]> keyEntryMap) throws NamingException { /* TODO: this DN is declared in some core constants file. Create a constants file for the installer and import it into the core. */ final String truststoreDnStr = "cn=ads-truststore"; final Attribute oc = new BasicAttribute("objectclass"); oc.add("top"); oc.add("ds-cfg-instance-key"); for (Map.Entry<String, byte[]> keyEntry : keyEntryMap.entrySet()){ final BasicAttributes keyAttrs = new BasicAttributes(); keyAttrs.put(oc); final Attribute rdnAttr = new BasicAttribute( ADSContext.ServerProperty.INSTANCE_KEY_ID.getAttributeName(), keyEntry.getKey()); keyAttrs.put(rdnAttr); keyAttrs.put(new BasicAttribute( ADSContext.ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE. getAttributeName() + ";binary", keyEntry.getValue())); final LdapName keyDn = new LdapName((new StringBuilder(rdnAttr.getID())) .append("=").append(Rdn.escapeValue(rdnAttr.get())).append(",") .append(truststoreDnStr).toString()); try { ctx.createSubcontext(keyDn, keyAttrs).close(); } catch(NameAlreadyBoundException x){ ctx.destroySubcontext(keyDn); ctx.createSubcontext(keyDn, keyAttrs).close(); } } } /** * Returns the number of entries in a given backend using the provided @@ -915,7 +962,7 @@ } catch (Exception ex) { /* ignore */ } return nEntries; @@ -972,6 +1019,7 @@ areDnsEqual = name1.equals(name2); } catch (Exception ex) { /* ignore */ } return areDnsEqual; } opends/src/ads/org/opends/admin/ads/SuffixDescriptor.java
@@ -114,7 +114,7 @@ buf.append(getDN()); for (ReplicaDescriptor replica : getReplicas()) { buf.append("-"+replica.getServer().getId()); buf.append("-").append(replica.getServer().getId()); } return buf.toString(); opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java
@@ -1867,9 +1867,9 @@ protected void updateADS() throws ApplicationException { DataReplicationOptions repl = getUserData().getReplicationOptions(); boolean remoteServer = boolean isRemoteServer = repl.getType() == DataReplicationOptions.Type.IN_EXISTING_TOPOLOGY; AuthenticationData auth = (remoteServer) ? repl.getAuthenticationData() AuthenticationData auth = (isRemoteServer) ? repl.getAuthenticationData() : null; InitialLdapContext remoteCtx = null; // Bound to remote ADS host (if any). InitialLdapContext localCtx = null; // Bound to local server. @@ -1879,7 +1879,7 @@ ADSContextException to ApplicationException and clean up JNDI contexts.*/ try { if (remoteServer) if (isRemoteServer) { /* In case the user specified an existing topology... */ String ldapUrl = getLdapUrl(auth); @@ -1921,7 +1921,7 @@ /* Act on local server depending on if using remote or local ADS */ notifyListeners(getFormattedWithPoints(INFO_PROGRESS_CREATING_ADS.get())); localCtx = createLocalContext(); if (remoteServer) if (isRemoteServer) { /* Create an empty ADS suffix on the local server. */ ADSContext localAdsContext = new ADSContext(localCtx); @@ -1938,14 +1938,16 @@ /* Register new server in ADS. */ ServerDescriptor server = ServerDescriptor.createStandalone(localCtx); server.updateAdsPropertiesWithServerProperties(); if (0 != adsContext.registerOrUpdateServer(server.getAdsProperties())) { if (0 == adsContext.registerOrUpdateServer(server.getAdsProperties())) { if (isRemoteServer) registeredNewServerOnRemote = true; } else { LOG.log(Level.WARNING, "Server was already registered. Updating " + "server registration."); } else if (remoteServer) if (isRemoteServer) { registeredNewServerOnRemote = true; ServerDescriptor.seedAdsTrustStore(localCtx, adsContext.getTrustedCertificates()); } notifyListeners(getFormattedDone()); notifyListeners(getLineBreak()); @@ -1960,7 +1962,7 @@ INFO_PROGRESS_CREATING_ADMINISTRATOR.get())); adsContext.createAdministrator(getAdministratorProperties( getUserData())); if (remoteServer && !createdRemoteAds) createdAdministrator = true; if (isRemoteServer && !createdRemoteAds) createdAdministrator = true; notifyListeners(getFormattedDone()); notifyListeners(getLineBreak()); checkAbort(); @@ -1982,7 +1984,7 @@ } catch (NoPermissionException ne) { if (remoteServer) if (isRemoteServer) { throw new ApplicationException( ReturnCode.CONFIGURATION_ERROR, @@ -2001,7 +2003,7 @@ } catch (NamingException ne) { if (remoteServer) if (isRemoteServer) { throw new ApplicationException( ReturnCode.CONFIGURATION_ERROR, @@ -2019,7 +2021,7 @@ { throw new ApplicationException( ReturnCode.CONFIGURATION_ERROR, ((remoteServer) ((isRemoteServer) ? INFO_REMOTE_ADS_EXCEPTION.get( getHostDisplay(auth), ace.getReason()) : INFO_ADS_EXCEPTION.get(ace.toString())), ace);