| | |
| | | */ |
| | | package org.opends.admin.ads; |
| | | |
| | | import static org.forgerock.opendj.ldap.ModificationType.*; |
| | | import static org.forgerock.opendj.ldap.SearchScope.*; |
| | | import static org.forgerock.opendj.ldap.requests.Requests.*; |
| | | import static org.forgerock.util.Utils.*; |
| | | import static org.opends.messages.QuickSetupMessages.*; |
| | | import static org.opends.server.schema.SchemaConstants.*; |
| | | |
| | | import java.io.File; |
| | | import java.io.IOException; |
| | | import java.util.Collection; |
| | | import java.util.HashMap; |
| | | import java.util.HashSet; |
| | | import java.util.LinkedHashSet; |
| | |
| | | import java.util.SortedSet; |
| | | import java.util.TreeSet; |
| | | |
| | | import javax.naming.CompositeName; |
| | | import javax.naming.InvalidNameException; |
| | | import javax.naming.NameAlreadyBoundException; |
| | | import javax.naming.NameNotFoundException; |
| | | import javax.naming.NamingEnumeration; |
| | | import javax.naming.NamingException; |
| | | import javax.naming.NoPermissionException; |
| | | import javax.naming.NotContextException; |
| | | import javax.naming.directory.Attribute; |
| | | import javax.naming.directory.Attributes; |
| | | import javax.naming.directory.BasicAttribute; |
| | | import javax.naming.directory.BasicAttributes; |
| | | import javax.naming.directory.DirContext; |
| | | import javax.naming.directory.SearchControls; |
| | | import javax.naming.directory.SearchResult; |
| | | import javax.naming.ldap.Control; |
| | | import javax.naming.ldap.InitialLdapContext; |
| | | import javax.naming.ldap.LdapContext; |
| | | import javax.naming.ldap.LdapName; |
| | | import javax.naming.ldap.Rdn; |
| | | |
| | | import org.forgerock.i18n.LocalizableMessage; |
| | | import org.forgerock.i18n.slf4j.LocalizedLogger; |
| | | import org.forgerock.opendj.ldap.Attribute; |
| | | import org.forgerock.opendj.ldap.AuthorizationException; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.Connection; |
| | | import org.forgerock.opendj.ldap.DN; |
| | | import org.forgerock.opendj.ldap.EntryNotFoundException; |
| | | import org.forgerock.opendj.ldap.LdapException; |
| | | import org.forgerock.opendj.ldap.LinkedAttribute; |
| | | import org.forgerock.opendj.ldap.Modification; |
| | | import org.forgerock.opendj.ldap.ModificationType; |
| | | import org.forgerock.opendj.ldap.RDN; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.forgerock.opendj.ldap.requests.AddRequest; |
| | | import org.forgerock.opendj.ldap.requests.ModifyRequest; |
| | | import org.forgerock.opendj.ldap.requests.SearchRequest; |
| | | import org.forgerock.opendj.ldap.responses.Result; |
| | | import org.forgerock.opendj.ldap.responses.SearchResultEntry; |
| | | import org.forgerock.opendj.ldap.schema.AttributeType; |
| | | import org.forgerock.opendj.ldif.ConnectionEntryReader; |
| | | import org.opends.admin.ads.ADSContextException.ErrorType; |
| | | import org.opends.admin.ads.util.ConnectionWrapper; |
| | | import org.opends.quicksetup.Constants; |
| | | import org.opends.server.schema.SchemaConstants; |
| | | import org.opends.server.types.HostPort; |
| | | |
| | | /** Class used to update and read the contents of the Administration Data. */ |
| | |
| | | } |
| | | |
| | | /** |
| | | * Returns the DirContext used to retrieve information by this ADSContext. |
| | | * |
| | | * @return the DirContext used to retrieve information by this ADSContext. |
| | | */ |
| | | public InitialLdapContext getDirContext() |
| | | { |
| | | return connectionWrapper.getLdapContext(); |
| | | } |
| | | |
| | | /** |
| | | * Returns the connection used to retrieve information by this ADSContext. |
| | | * |
| | | * @return the connection |
| | |
| | | */ |
| | | public void registerServer(Map<ServerProperty, Object> serverProperties) throws ADSContextException |
| | | { |
| | | LdapName dn = makeDNFromServerProperties(serverProperties); |
| | | BasicAttributes attrs = makeAttrsFromServerProperties(serverProperties, true); |
| | | String dn = makeDNFromServerProperties(serverProperties); |
| | | |
| | | AddRequest request = newAddRequest(dn); |
| | | for (ServerProperty prop : serverProperties.keySet()) |
| | | { |
| | | Attribute attribute = makeAttrFromServerProperty(prop, serverProperties.get(prop)); |
| | | if (attribute != null) |
| | | { |
| | | request.addAttribute(attribute); |
| | | } |
| | | } |
| | | // TODO: use another structural objectclass |
| | | request.addAttribute("objectclass", "top", "ds-cfg-branch", "extensibleobject"); |
| | | try |
| | | { |
| | | // This check is required because by default the server container entry |
| | | // does not exist. |
| | | if (!isExistingEntry(nameFromDN(getServerContainerDN()))) |
| | | if (!isExistingEntry(getServerContainerDN())) |
| | | { |
| | | createContainerEntry(getServerContainerDN()); |
| | | } |
| | | connectionWrapper.getLdapContext().createSubcontext(dn, attrs).close(); |
| | | throwIfNotSuccess(connectionWrapper.getConnection().add(request)); |
| | | if (serverProperties.containsKey(ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE)) |
| | | { |
| | | registerInstanceKeyCertificate(serverProperties, dn); |
| | |
| | | { |
| | | throw ace; |
| | | } |
| | | catch (NameAlreadyBoundException x) |
| | | catch (LdapException x) |
| | | { |
| | | if (x.getResult().getResultCode().equals(ResultCode.ENTRY_ALREADY_EXISTS)) |
| | | { |
| | | throw new ADSContextException(ErrorType.ALREADY_REGISTERED); |
| | | } |
| | | catch (Exception x) |
| | | { |
| | | throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); |
| | | } |
| | | } |
| | |
| | | private void updateServer(Map<ServerProperty, Object> serverProperties, String newServerId) |
| | | throws ADSContextException |
| | | { |
| | | LdapName dn = makeDNFromServerProperties(serverProperties); |
| | | String dn = makeDNFromServerProperties(serverProperties); |
| | | |
| | | try |
| | | { |
| | |
| | | { |
| | | Map<ServerProperty, Object> newServerProps = new HashMap<>(serverProperties); |
| | | newServerProps.put(ServerProperty.ID, newServerId); |
| | | LdapName newDn = makeDNFromServerProperties(newServerProps); |
| | | connectionWrapper.getLdapContext().rename(dn, newDn); |
| | | String newDn = makeDNFromServerProperties(newServerProps); |
| | | throwIfNotSuccess(connectionWrapper.getConnection().modifyDN(dn, newDn)); |
| | | dn = newDn; |
| | | serverProperties.put(ServerProperty.ID, newServerId); |
| | | } |
| | | BasicAttributes attrs = makeAttrsFromServerProperties(serverProperties, false); |
| | | connectionWrapper.getLdapContext().modifyAttributes(dn, DirContext.REPLACE_ATTRIBUTE, attrs); |
| | | |
| | | ModifyRequest request = newModifyRequest(dn); |
| | | for (ServerProperty prop : serverProperties.keySet()) |
| | | { |
| | | Attribute attr = makeAttrFromServerProperty(prop, serverProperties.get(prop)); |
| | | if (attr != null) |
| | | { |
| | | request.addModification(new Modification(REPLACE, attr)); |
| | | } |
| | | } |
| | | throwIfNotSuccess(connectionWrapper.getConnection().modify(request)); |
| | | |
| | | if (serverProperties.containsKey(ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE)) |
| | | { |
| | | registerInstanceKeyCertificate(serverProperties, dn); |
| | |
| | | { |
| | | throw ace; |
| | | } |
| | | catch (NameNotFoundException x) |
| | | catch (EntryNotFoundException x) |
| | | { |
| | | throw new ADSContextException(ErrorType.NOT_YET_REGISTERED); |
| | | } |
| | |
| | | */ |
| | | public void unregisterServer(Map<ServerProperty, Object> serverProperties) throws ADSContextException |
| | | { |
| | | LdapName dn = makeDNFromServerProperties(serverProperties); |
| | | String dn = makeDNFromServerProperties(serverProperties); |
| | | Connection conn = connectionWrapper.getConnection(); |
| | | try |
| | | { |
| | | // Unregister the server from the server groups. |
| | |
| | | } |
| | | } |
| | | |
| | | connectionWrapper.getLdapContext().destroySubcontext(dn); |
| | | throwIfNotSuccess(conn.delete(dn)); |
| | | } |
| | | catch (NameNotFoundException x) |
| | | catch (EntryNotFoundException x) |
| | | { |
| | | throw new ADSContextException(ErrorType.NOT_YET_REGISTERED); |
| | | } |
| | | catch (NamingException x) |
| | | catch (LdapException x) |
| | | { |
| | | throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); |
| | | } |
| | | |
| | | // Unregister the server in server groups |
| | | NamingEnumeration<SearchResult> ne = null; |
| | | try |
| | | { |
| | | SearchControls sc = new SearchControls(); |
| | | |
| | | String serverID = getServerID(serverProperties); |
| | | if (serverID != null) |
| | | { |
| | | // Unregister the server in server groups |
| | | String memberAttrName = ServerGroupProperty.MEMBERS.getAttributeName(); |
| | | String filter = "(" + memberAttrName + "=cn=" + serverID + ")"; |
| | | sc.setSearchScope(SearchControls.ONELEVEL_SCOPE); |
| | | ne = connectionWrapper.getLdapContext().search(getServerGroupContainerDN(), filter, sc); |
| | | while (ne.hasMore()) |
| | | SearchRequest request = newSearchRequest(getServerGroupContainerDN(), SINGLE_LEVEL, filter); |
| | | try (ConnectionEntryReader entryReader = conn.search(request);) |
| | | { |
| | | SearchResult sr = ne.next(); |
| | | String groupDn = sr.getNameInNamespace(); |
| | | BasicAttribute newAttr = new BasicAttribute(memberAttrName); |
| | | NamingEnumeration<? extends Attribute> attrs = sr.getAttributes().getAll(); |
| | | try |
| | | while (entryReader.hasNext()) |
| | | { |
| | | while (attrs.hasMore()) |
| | | SearchResultEntry sr = entryReader.readEntry(); |
| | | DN groupDn = sr.getName(); |
| | | Attribute newAttr = new LinkedAttribute(memberAttrName); |
| | | for (Attribute attr : sr.getAllAttributes()) |
| | | { |
| | | Attribute attr = attrs.next(); |
| | | String attrID = attr.getID(); |
| | | |
| | | if (attrID.equalsIgnoreCase(memberAttrName)) |
| | | AttributeType attrType = attr.getAttributeDescription().getAttributeType(); |
| | | if (attrType.hasName(memberAttrName)) |
| | | { |
| | | NamingEnumeration<?> ae = attr.getAll(); |
| | | try |
| | | for (ByteString value : attr) |
| | | { |
| | | while (ae.hasMore()) |
| | | { |
| | | String value = (String) ae.next(); |
| | | if (!value.equalsIgnoreCase("cn=" + serverID)) |
| | | if (!value.toString().equalsIgnoreCase("cn=" + serverID)) |
| | | { |
| | | newAttr.add(value); |
| | | } |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | handleCloseNamingEnumeration(ae); |
| | | } |
| | | ModificationType modType = newAttr.size() > 0 ? REPLACE : DELETE; |
| | | ModifyRequest modRequest = newModifyRequest(groupDn) |
| | | .addModification(new Modification(modType, newAttr)); |
| | | throwIfNotSuccess(conn.modify(modRequest)); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | handleCloseNamingEnumeration(attrs); |
| | | } |
| | | BasicAttributes newAttrs = new BasicAttributes(); |
| | | newAttrs.put(newAttr); |
| | | if (newAttr.size() > 0) |
| | | { |
| | | connectionWrapper.getLdapContext().modifyAttributes(groupDn, DirContext.REPLACE_ATTRIBUTE, newAttrs); |
| | | } |
| | | else |
| | | { |
| | | connectionWrapper.getLdapContext().modifyAttributes(groupDn, DirContext.REMOVE_ATTRIBUTE, newAttrs); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | catch (NameNotFoundException x) |
| | | catch (EntryNotFoundException x) |
| | | { |
| | | throw new ADSContextException(ErrorType.BROKEN_INSTALL); |
| | | } |
| | | catch (NoPermissionException x) |
| | | catch (AuthorizationException x) |
| | | { |
| | | throw new ADSContextException(ErrorType.ACCESS_PERMISSION); |
| | | } |
| | | catch (NamingException x) |
| | | catch (IOException x) |
| | | { |
| | | throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); |
| | | } |
| | | finally |
| | | { |
| | | handleCloseNamingEnumeration(ne); |
| | | } |
| | | } |
| | | |
| | |
| | | */ |
| | | private boolean isAdministratorAlreadyRegistered(String uid) throws ADSContextException |
| | | { |
| | | return isExistingEntry(makeDNFromAdministratorProperties(uid)); |
| | | return isExistingEntry(getAdministratorDN(uid)); |
| | | } |
| | | |
| | | /** |
| | |
| | | */ |
| | | private Set<String> getServerGroupMemberList(String serverGroupId) throws ADSContextException |
| | | { |
| | | LdapName dn = nameFromDN("cn=" + Rdn.escapeValue(serverGroupId) + "," + getServerGroupContainerDN()); |
| | | String dn = "cn=" + Rdn.escapeValue(serverGroupId) + "," + getServerGroupContainerDN(); |
| | | |
| | | Set<String> result = new HashSet<>(); |
| | | NamingEnumeration<SearchResult> srs = null; |
| | | NamingEnumeration<? extends Attribute> ne = null; |
| | | try |
| | | SearchRequest request = newSearchRequest(dn, BASE_OBJECT, "(objectclass=*)"); |
| | | try (ConnectionEntryReader entryReader = getConnection().getConnection().search(request)) |
| | | { |
| | | SearchControls sc = new SearchControls(); |
| | | sc.setSearchScope(SearchControls.OBJECT_SCOPE); |
| | | srs = getDirContext().search(dn, "(objectclass=*)", sc); |
| | | |
| | | if (!srs.hasMore()) |
| | | Set<String> result = new HashSet<>(); |
| | | if (!entryReader.hasNext()) |
| | | { |
| | | return result; |
| | | } |
| | | Attributes attrs = srs.next().getAttributes(); |
| | | ne = attrs.getAll(); |
| | | while (ne.hasMore()) |
| | | for (Attribute attr : entryReader.readEntry().getAllAttributes()) |
| | | { |
| | | Attribute attr = ne.next(); |
| | | String attrID = attr.getID(); |
| | | |
| | | if (!attrID.toLowerCase().equals(ServerGroupProperty.MEMBERS.getAttributeName().toLowerCase())) |
| | | AttributeType attrType = attr.getAttributeDescription().getAttributeType(); |
| | | if (attrType.hasName(ServerGroupProperty.MEMBERS.getAttributeName())) |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | // We have the members list |
| | | NamingEnumeration<?> ae = attr.getAll(); |
| | | try |
| | | { |
| | | while (ae.hasMore()) |
| | | { |
| | | result.add((String) ae.next()); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | handleCloseNamingEnumeration(ae); |
| | | } |
| | | toStrings(result, attr); |
| | | break; |
| | | } |
| | | } |
| | | catch (NameNotFoundException x) |
| | | { |
| | | result = new HashSet<>(); |
| | | return result; |
| | | } |
| | | catch (NoPermissionException x) |
| | | catch (EntryNotFoundException x) |
| | | { |
| | | return new HashSet<>(); |
| | | } |
| | | catch (AuthorizationException x) |
| | | { |
| | | throw new ADSContextException(ErrorType.ACCESS_PERMISSION); |
| | | } |
| | | catch (NamingException x) |
| | | catch (IOException x) |
| | | { |
| | | throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); |
| | | } |
| | | finally |
| | | { |
| | | handleCloseNamingEnumeration(srs); |
| | | handleCloseNamingEnumeration(ne); |
| | | } |
| | | return result; |
| | | |
| | | private void toStrings(Set<String> result, Attribute attr) |
| | | { |
| | | for (ByteString value : attr) |
| | | { |
| | | result.add(value.toString()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | public Set<Map<ServerProperty, Object>> readServerRegistry() throws ADSContextException |
| | | { |
| | | Set<Map<ServerProperty, Object>> result = new HashSet<>(); |
| | | NamingEnumeration<SearchResult> ne = null; |
| | | try |
| | | { |
| | | SearchControls sc = new SearchControls(); |
| | | |
| | | sc.setSearchScope(SearchControls.ONELEVEL_SCOPE); |
| | | ne = connectionWrapper.getLdapContext().search(getServerContainerDN(), "(objectclass=*)", sc); |
| | | while (ne.hasMore()) |
| | | SearchRequest request = newSearchRequest(getServerContainerDN(), SINGLE_LEVEL, "(objectclass=*)"); |
| | | try (ConnectionEntryReader entryReader = connectionWrapper.getConnection().search(request)) |
| | | { |
| | | SearchResult sr = ne.next(); |
| | | Map<ServerProperty, Object> properties = makePropertiesFromServerAttrs(sr.getAttributes()); |
| | | while (entryReader.hasNext()) |
| | | { |
| | | SearchResultEntry sr = entryReader.readEntry(); |
| | | Map<ServerProperty, Object> properties = makePropertiesFromServerAttrs(sr); |
| | | Object keyId = properties.get(ServerProperty.INSTANCE_KEY_ID); |
| | | if (keyId != null) |
| | | { |
| | | NamingEnumeration<SearchResult> ne2 = null; |
| | | try |
| | | SearchRequest request2 = newSearchRequest( |
| | | getInstanceKeysContainerDN(), SINGLE_LEVEL, "(ds-cfg-key-id=" + keyId + ")", |
| | | "ds-cfg-public-key-certificate;binary"); |
| | | try (ConnectionEntryReader entryReader2 = connectionWrapper.getConnection().search(request2)) |
| | | { |
| | | SearchControls sc1 = new SearchControls(); |
| | | sc1.setSearchScope(SearchControls.ONELEVEL_SCOPE); |
| | | final String attrIDs[] = { "ds-cfg-public-key-certificate;binary" }; |
| | | sc1.setReturningAttributes(attrIDs); |
| | | |
| | | ne2 = connectionWrapper.getLdapContext().search( |
| | | getInstanceKeysContainerDN(), "(ds-cfg-key-id=" + keyId + ")", sc); |
| | | boolean found = false; |
| | | while (ne2.hasMore()) |
| | | while (entryReader2.hasNext()) |
| | | { |
| | | SearchResult certEntry = ne2.next(); |
| | | Attribute certAttr = certEntry.getAttributes().get(attrIDs[0]); |
| | | properties.put(ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE, certAttr.get()); |
| | | SearchResultEntry certEntry = entryReader2.readEntry(); |
| | | Attribute certAttr = certEntry.getAttribute("ds-cfg-public-key-certificate;binary"); |
| | | properties.put(ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE, certAttr.firstValue().toByteArray()); |
| | | found = true; |
| | | } |
| | | if (!found) |
| | |
| | | logger.warn(LocalizableMessage.raw("Could not find public key for " + properties)); |
| | | } |
| | | } |
| | | catch (NameNotFoundException x) |
| | | catch (EntryNotFoundException x) |
| | | { |
| | | logger.warn(LocalizableMessage.raw("Could not find public key for " + properties)); |
| | | } |
| | | finally |
| | | { |
| | | handleCloseNamingEnumeration(ne2); |
| | | } |
| | | } |
| | | result.add(properties); |
| | | } |
| | | return result; |
| | | } |
| | | catch (NameNotFoundException x) |
| | | catch (EntryNotFoundException x) |
| | | { |
| | | throw new ADSContextException(ErrorType.BROKEN_INSTALL); |
| | | } |
| | | catch (NoPermissionException x) |
| | | catch (AuthorizationException x) |
| | | { |
| | | throw new ADSContextException(ErrorType.ACCESS_PERMISSION); |
| | | } |
| | | catch (NamingException x) |
| | | catch (IOException x) |
| | | { |
| | | throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); |
| | | } |
| | | finally |
| | | { |
| | | handleCloseNamingEnumeration(ne); |
| | | } |
| | | |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | |
| | | */ |
| | | private void createServerGroup(Map<ServerGroupProperty, Object> serverGroupProperties) throws ADSContextException |
| | | { |
| | | LdapName dn = makeDNFromServerGroupProperties(serverGroupProperties); |
| | | BasicAttributes attrs = makeAttrsFromServerGroupProperties(serverGroupProperties); |
| | | // Add the objectclass attribute value |
| | | Attribute oc = new BasicAttribute("objectclass"); |
| | | oc.add("top"); |
| | | oc.add("groupOfUniqueNames"); |
| | | attrs.put(oc); |
| | | String dn = makeDNFromServerGroupProperties(serverGroupProperties); |
| | | AddRequest request = newAddRequest(dn) |
| | | .addAttribute("objectclass", "top", "groupOfUniqueNames"); |
| | | for (ServerGroupProperty prop : serverGroupProperties.keySet()) |
| | | { |
| | | request.addAttribute(makeAttrFromServerGroupProperty(prop, serverGroupProperties.get(prop))); |
| | | } |
| | | |
| | | try |
| | | { |
| | | DirContext ctx = connectionWrapper.getLdapContext().createSubcontext(dn, attrs); |
| | | ctx.close(); |
| | | throwIfNotSuccess(connectionWrapper.getConnection().add(request)); |
| | | } |
| | | catch (NameAlreadyBoundException x) |
| | | catch (LdapException x) |
| | | { |
| | | if (x.getResult().getResultCode().equals(ResultCode.ENTRY_ALREADY_EXISTS)) |
| | | { |
| | | throw new ADSContextException(ErrorType.ALREADY_REGISTERED); |
| | | } |
| | | catch (NamingException x) |
| | | { |
| | | throw new ADSContextException(ErrorType.BROKEN_INSTALL, x); |
| | | } |
| | | } |
| | |
| | | private void updateServerGroup(String groupID, Map<ServerGroupProperty, Object> serverGroupProperties) |
| | | throws ADSContextException |
| | | { |
| | | LdapName dn = nameFromDN("cn=" + Rdn.escapeValue(groupID) + "," + getServerGroupContainerDN()); |
| | | String dn = "cn=" + Rdn.escapeValue(groupID) + "," + getServerGroupContainerDN(); |
| | | try |
| | | { |
| | | // Entry renaming ? |
| | |
| | | if (!newGroupId.equals(groupID)) |
| | | { |
| | | // Rename to entry |
| | | LdapName newDN = nameFromDN("cn=" + Rdn.escapeValue(newGroupId) + "," + getServerGroupContainerDN()); |
| | | connectionWrapper.getLdapContext().rename(dn, newDN); |
| | | String newDN = ("cn=" + Rdn.escapeValue(newGroupId) + "," + getServerGroupContainerDN()); |
| | | throwIfNotSuccess(connectionWrapper.getConnection().modifyDN(dn, newDN)); |
| | | dn = newDN; |
| | | } |
| | | |
| | |
| | | return; |
| | | } |
| | | |
| | | BasicAttributes attrs = makeAttrsFromServerGroupProperties(serverGroupProperties); |
| | | // attribute modification |
| | | connectionWrapper.getLdapContext().modifyAttributes(dn, DirContext.REPLACE_ATTRIBUTE, attrs); |
| | | // Transform 'properties' into 'attributes' |
| | | ModifyRequest request = newModifyRequest(dn); |
| | | for (ServerGroupProperty prop : serverGroupProperties.keySet()) |
| | | { |
| | | request.addModification(new Modification( |
| | | REPLACE, makeAttrFromServerGroupProperty(prop, serverGroupProperties.get(prop)))); |
| | | } |
| | | catch (NameNotFoundException x) |
| | | throwIfNotSuccess(connectionWrapper.getConnection().modify(request)); |
| | | } |
| | | catch (EntryNotFoundException x) |
| | | { |
| | | throw new ADSContextException(ErrorType.NOT_YET_REGISTERED); |
| | | } |
| | | catch (NameAlreadyBoundException x) |
| | | catch (LdapException x) |
| | | { |
| | | if (x.getResult().getResultCode().equals(ResultCode.ENTRY_ALREADY_EXISTS)) |
| | | { |
| | | throw new ADSContextException(ErrorType.ALREADY_REGISTERED); |
| | | } |
| | | catch (NamingException x) |
| | | { |
| | | throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); |
| | | } |
| | | } |
| | |
| | | */ |
| | | private Set<Map<ServerGroupProperty, Object>> readServerGroupRegistry() throws ADSContextException |
| | | { |
| | | SearchRequest request = newSearchRequest(getServerGroupContainerDN(), SINGLE_LEVEL, "(objectclass=*)"); |
| | | try (ConnectionEntryReader entryReader = connectionWrapper.getConnection().search(request)) |
| | | { |
| | | Set<Map<ServerGroupProperty, Object>> result = new HashSet<>(); |
| | | NamingEnumeration<SearchResult> ne = null; |
| | | try |
| | | while (entryReader.hasNext()) |
| | | { |
| | | SearchControls sc = new SearchControls(); |
| | | sc.setSearchScope(SearchControls.ONELEVEL_SCOPE); |
| | | ne = connectionWrapper.getLdapContext().search(getServerGroupContainerDN(), "(objectclass=*)", sc); |
| | | while (ne.hasMore()) |
| | | { |
| | | SearchResult sr = ne.next(); |
| | | result.add(makePropertiesFromServerGroupAttrs(sr.getAttributes())); |
| | | SearchResultEntry sr = entryReader.readEntry(); |
| | | result.add(makePropertiesFromServerGroupAttrs(sr)); |
| | | } |
| | | return result; |
| | | } |
| | | catch (NameNotFoundException x) |
| | | catch (EntryNotFoundException x) |
| | | { |
| | | throw new ADSContextException(ErrorType.BROKEN_INSTALL); |
| | | } |
| | | catch (NoPermissionException x) |
| | | catch (AuthorizationException x) |
| | | { |
| | | throw new ADSContextException(ErrorType.ACCESS_PERMISSION); |
| | | } |
| | | catch (NamingException x) |
| | | catch (IOException x) |
| | | { |
| | | throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); |
| | | } |
| | | finally |
| | | { |
| | | handleCloseNamingEnumeration(ne); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | |
| | | public Set<Map<AdministratorProperty, Object>> readAdministratorRegistry() throws ADSContextException |
| | | { |
| | | Set<Map<AdministratorProperty, Object>> result = new HashSet<>(); |
| | | NamingEnumeration<SearchResult> ne = null; |
| | | try |
| | | SearchRequest request = newSearchRequest( |
| | | getAdministratorContainerDN(), SINGLE_LEVEL, "(objectclass=*)", |
| | | "cn", "userpassword", "ds-privilege-name", "description"); |
| | | try (ConnectionEntryReader entryReader = connectionWrapper.getConnection().search(request)) |
| | | { |
| | | SearchControls sc = new SearchControls(); |
| | | sc.setSearchScope(SearchControls.ONELEVEL_SCOPE); |
| | | String[] attList = { "cn", "userpassword", "ds-privilege-name", "description" }; |
| | | sc.setReturningAttributes(attList); |
| | | ne = connectionWrapper.getLdapContext().search(getAdministratorContainerDN(), "(objectclass=*)", sc); |
| | | while (ne.hasMore()) |
| | | while (entryReader.hasNext()) |
| | | { |
| | | SearchResult sr = ne.next(); |
| | | result.add(makePropertiesFromAdministratorAttrs(getRdn(sr.getName()), sr.getAttributes())); |
| | | SearchResultEntry sr = entryReader.readEntry(); |
| | | result.add(makePropertiesFromAdministratorAttrs(sr.getName().rdn(), sr.getAllAttributes())); |
| | | } |
| | | } |
| | | catch (NameNotFoundException x) |
| | | catch (EntryNotFoundException x) |
| | | { |
| | | throw new ADSContextException(ErrorType.BROKEN_INSTALL); |
| | | } |
| | | catch (NoPermissionException x) |
| | | catch (AuthorizationException x) |
| | | { |
| | | throw new ADSContextException(ErrorType.ACCESS_PERMISSION); |
| | | } |
| | | catch (NamingException x) |
| | | catch (IOException x) |
| | | { |
| | | throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); |
| | | } |
| | | finally |
| | | { |
| | | handleCloseNamingEnumeration(ne); |
| | | } |
| | | |
| | | return result; |
| | | } |
| | |
| | | private void createAdminDataContainers() throws ADSContextException |
| | | { |
| | | // Create the DIT below the administration suffix |
| | | if (!isExistingEntry(nameFromDN(getAdministrationSuffixDN()))) |
| | | if (!isExistingEntry(getAdministrationSuffixDN())) |
| | | { |
| | | createTopContainerEntry(); |
| | | } |
| | | if (!isExistingEntry(nameFromDN(getAdministratorContainerDN()))) |
| | | if (!isExistingEntry(getAdministratorContainerDN())) |
| | | { |
| | | createAdministratorContainerEntry(); |
| | | } |
| | | if (!isExistingEntry(nameFromDN(getServerContainerDN()))) |
| | | if (!isExistingEntry(getServerContainerDN())) |
| | | { |
| | | createContainerEntry(getServerContainerDN()); |
| | | } |
| | | if (!isExistingEntry(nameFromDN(getServerGroupContainerDN()))) |
| | | if (!isExistingEntry(getServerGroupContainerDN())) |
| | | { |
| | | createContainerEntry(getServerGroupContainerDN()); |
| | | } |
| | | |
| | | // Add the default "all-servers" group |
| | | if (!isExistingEntry(nameFromDN(getAllServerGroupDN()))) |
| | | if (!isExistingEntry((getAllServerGroupDN()))) |
| | | { |
| | | Map<ServerGroupProperty, Object> allServersGroupsMap = new HashMap<>(); |
| | | allServersGroupsMap.put(ServerGroupProperty.UID, ALL_SERVERGROUP_NAME); |
| | |
| | | } |
| | | |
| | | // Create the CryptoManager instance key DIT below the administration suffix |
| | | if (!isExistingEntry(nameFromDN(getInstanceKeysContainerDN()))) |
| | | if (!isExistingEntry(getInstanceKeysContainerDN())) |
| | | { |
| | | createContainerEntry(getInstanceKeysContainerDN()); |
| | | } |
| | | |
| | | // Create the CryptoManager secret key DIT below the administration suffix |
| | | if (!isExistingEntry(nameFromDN(getSecretKeysContainerDN()))) |
| | | if (!isExistingEntry(getSecretKeysContainerDN())) |
| | | { |
| | | createContainerEntry(getSecretKeysContainerDN()); |
| | | } |
| | |
| | | { |
| | | if (dn != null) |
| | | { |
| | | LdapName ldapName = nameFromDN(dn); |
| | | if (isExistingEntry(ldapName)) |
| | | if (isExistingEntry(dn)) |
| | | { |
| | | tmpContext.destroySubcontext(dn); |
| | | } |
| | |
| | | boolean hasAdminData = true; |
| | | for (int i = 0; i < dns.length && hasAdminData; i++) |
| | | { |
| | | hasAdminData = isExistingEntry(nameFromDN(dns[i])); |
| | | hasAdminData = isExistingEntry(dns[i]); |
| | | } |
| | | return hasAdminData; |
| | | } |
| | |
| | | */ |
| | | public void createAdministrator(Map<AdministratorProperty, Object> adminProperties) throws ADSContextException |
| | | { |
| | | LdapName dnCentralAdmin = makeDNFromAdministratorProperties(adminProperties); |
| | | BasicAttributes attrs = makeAttrsFromAdministratorProperties(adminProperties, true, null); |
| | | AddRequest request = newAddRequest(getAdministratorDN(getAdministratorUID(adminProperties))); |
| | | addAttrsFromAdministratorProperties(request, adminProperties, true); |
| | | |
| | | try |
| | | { |
| | | DirContext ctx = connectionWrapper.getLdapContext().createSubcontext(dnCentralAdmin, attrs); |
| | | ctx.close(); |
| | | throwIfNotSuccess(connectionWrapper.getConnection().add(request)); |
| | | } |
| | | catch (NameAlreadyBoundException x) |
| | | { |
| | | throw new ADSContextException(ErrorType.ALREADY_REGISTERED); |
| | | } |
| | | catch (NoPermissionException x) |
| | | catch (AuthorizationException x) |
| | | { |
| | | throw new ADSContextException(ErrorType.ACCESS_PERMISSION); |
| | | } |
| | | catch (NamingException x) |
| | | catch (LdapException x) |
| | | { |
| | | if (x.getResult().getResultCode().equals(ResultCode.ENTRY_ALREADY_EXISTS)) |
| | | { |
| | | throw new ADSContextException(ErrorType.ALREADY_REGISTERED); |
| | | } |
| | | throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); |
| | | } |
| | | } |
| | |
| | | */ |
| | | public void deleteAdministrator(Map<AdministratorProperty, Object> adminProperties) throws ADSContextException |
| | | { |
| | | LdapName dnCentralAdmin = makeDNFromAdministratorProperties(adminProperties); |
| | | |
| | | String dnCentralAdmin = getAdministratorDN(getAdministratorUID(adminProperties)); |
| | | try |
| | | { |
| | | connectionWrapper.getLdapContext().destroySubcontext(dnCentralAdmin); |
| | | throwIfNotSuccess(connectionWrapper.getConnection().delete(dnCentralAdmin)); |
| | | } |
| | | catch (NameNotFoundException | NotContextException x) |
| | | catch (EntryNotFoundException x) |
| | | { |
| | | throw new ADSContextException(ErrorType.NOT_YET_REGISTERED); |
| | | } |
| | | catch (NoPermissionException x) |
| | | catch (AuthorizationException x) |
| | | { |
| | | throw new ADSContextException(ErrorType.ACCESS_PERMISSION); |
| | | } |
| | | catch (NamingException x) |
| | | catch (LdapException x) |
| | | { |
| | | throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); |
| | | } |
| | |
| | | * @throws ADSContextException |
| | | * if something goes wrong. |
| | | */ |
| | | private static LdapName makeDNFromHostnameAndPath(String hostname, String ipath) throws ADSContextException |
| | | private static String makeDNFromHostnameAndPath(String hostname, String ipath) throws ADSContextException |
| | | { |
| | | return nameFromDN("cn=" + Rdn.escapeValue(hostname + "@" + ipath) + "," + getServerContainerDN()); |
| | | return "cn=" + Rdn.escapeValue(hostname + "@" + ipath) + "," + getServerContainerDN(); |
| | | } |
| | | |
| | | /** |
| | |
| | | * @throws ADSContextException |
| | | * if something goes wrong. |
| | | */ |
| | | private static LdapName makeDNFromServerUniqueId(String serverUniqueId) throws ADSContextException |
| | | private static String makeDNFromServerUniqueId(String serverUniqueId) throws ADSContextException |
| | | { |
| | | return nameFromDN("cn=" + Rdn.escapeValue(serverUniqueId) + "," + getServerContainerDN()); |
| | | return "cn=" + Rdn.escapeValue(serverUniqueId) + "," + getServerContainerDN(); |
| | | } |
| | | |
| | | /** |
| | |
| | | * @throws ADSContextException |
| | | * if something goes wrong. |
| | | */ |
| | | private static LdapName makeDNFromServerGroupProperties(Map<ServerGroupProperty, Object> serverGroupProperties) |
| | | private static String makeDNFromServerGroupProperties(Map<ServerGroupProperty, Object> serverGroupProperties) |
| | | throws ADSContextException |
| | | { |
| | | String serverGroupId = (String) serverGroupProperties.get(ServerGroupProperty.UID); |
| | |
| | | { |
| | | throw new ADSContextException(ErrorType.MISSING_NAME); |
| | | } |
| | | return nameFromDN("cn=" + Rdn.escapeValue(serverGroupId) + "," + getServerGroupContainerDN()); |
| | | return "cn=" + Rdn.escapeValue(serverGroupId) + "," + getServerGroupContainerDN(); |
| | | } |
| | | |
| | | /** |
| | |
| | | * @throws ADSContextException |
| | | * if something goes wrong. |
| | | */ |
| | | private static LdapName makeDNFromServerProperties(Map<ServerProperty, Object> serverProperties) |
| | | private static String makeDNFromServerProperties(Map<ServerProperty, Object> serverProperties) |
| | | throws ADSContextException |
| | | { |
| | | String serverID = getServerID(serverProperties); |
| | |
| | | } |
| | | |
| | | /** |
| | | * This method returns the DN of the entry that corresponds to the given |
| | | * administrator properties. |
| | | * |
| | | * @param adminProperties |
| | | * the administrator properties. |
| | | * @return the DN of the entry that corresponds to the given administrator |
| | | * properties. |
| | | * @throws ADSContextException |
| | | * if something goes wrong. |
| | | */ |
| | | private static LdapName makeDNFromAdministratorProperties(Map<AdministratorProperty, Object> adminProperties) |
| | | throws ADSContextException |
| | | { |
| | | return makeDNFromAdministratorProperties(getAdministratorUID(adminProperties)); |
| | | } |
| | | |
| | | /** |
| | | * This method returns the DN of the entry that corresponds to the given |
| | | * administrator properties. |
| | | * |
| | | * @param adminUid |
| | | * the administrator uid. |
| | | * @return the DN of the entry that corresponds to the given administrator |
| | | * properties. |
| | | * @throws ADSContextException |
| | | * if something goes wrong. |
| | | */ |
| | | private static LdapName makeDNFromAdministratorProperties(String adminUid) throws ADSContextException |
| | | { |
| | | return nameFromDN(getAdministratorDN(adminUid)); |
| | | } |
| | | |
| | | /** |
| | | * Returns the attributes for some administrator properties. |
| | | * Enrich the provided add request with the attributes for some administrator properties. |
| | | * |
| | | * @param adminProperties |
| | | * the administrator properties. |
| | | * @param passwordRequired |
| | | * Indicates if the properties should include the password. |
| | | * @param currentPrivileges |
| | | * The current privilege list or null. |
| | | * @return the attributes for the given administrator properties. |
| | | * @throws ADSContextException |
| | | * if something goes wrong. |
| | | */ |
| | | private static BasicAttributes makeAttrsFromAdministratorProperties( |
| | | Map<AdministratorProperty, Object> adminProperties, boolean passwordRequired, |
| | | NamingEnumeration<?> currentPrivileges) throws ADSContextException |
| | | private static void addAttrsFromAdministratorProperties(AddRequest request, |
| | | Map<AdministratorProperty, Object> adminProperties, boolean passwordRequired) throws ADSContextException |
| | | { |
| | | BasicAttributes attrs = new BasicAttributes(); |
| | | Attribute oc = new BasicAttribute("objectclass"); |
| | | if (passwordRequired) |
| | | { |
| | | attrs.put("userPassword", getAdministratorPassword(adminProperties)); |
| | | request.addAttribute("userPassword", getAdministratorPassword(adminProperties)); |
| | | } |
| | | oc.add("top"); |
| | | oc.add("person"); |
| | | attrs.put(oc); |
| | | attrs.put("sn", GLOBAL_ADMIN_UID); |
| | | request.addAttribute("objectclass", "top", "person"); |
| | | request.addAttribute("sn", GLOBAL_ADMIN_UID); |
| | | if (adminProperties.containsKey(AdministratorProperty.DESCRIPTION)) |
| | | { |
| | | attrs.put("description", adminProperties.get(AdministratorProperty.DESCRIPTION)); |
| | | request.addAttribute("description", adminProperties.get(AdministratorProperty.DESCRIPTION)); |
| | | } |
| | | Attribute privilegeAtt; |
| | | if (adminProperties.containsKey(AdministratorProperty.PRIVILEGE)) |
| | | { |
| | | // We assume that privilege strings provided in |
| | | // AdministratorProperty.PRIVILEGE |
| | | // are valid privileges represented as a LinkedList of string. |
| | | privilegeAtt = new BasicAttribute("ds-privilege-name"); |
| | | if (currentPrivileges != null) |
| | | { |
| | | while (currentPrivileges.hasMoreElements()) |
| | | { |
| | | privilegeAtt.add(currentPrivileges.nextElement().toString()); |
| | | } |
| | | } |
| | | |
| | | LinkedList<?> privileges = (LinkedList<?>) adminProperties.get(AdministratorProperty.PRIVILEGE); |
| | | for (Object o : privileges) |
| | | { |
| | | String p = o.toString(); |
| | | if (p.startsWith("-")) |
| | | { |
| | | privilegeAtt.remove(p.substring(1)); |
| | | request.removeAttribute("ds-privilege-name", p.substring(1)); |
| | | } |
| | | else |
| | | { |
| | | privilegeAtt.add(p); |
| | | request.addAttribute("ds-privilege-name", p); |
| | | } |
| | | } |
| | | } |
| | | else |
| | | { |
| | | privilegeAtt = addRootPrivileges(); |
| | | request.addAttribute(addRootPrivileges()); |
| | | } |
| | | attrs.put(privilegeAtt); |
| | | |
| | | // Add the RootDNs Password policy so the password do not expire. |
| | | attrs.put("ds-pwp-password-policy-dn", "cn=Root Password Policy,cn=Password Policies,cn=config"); |
| | | |
| | | return attrs; |
| | | request.addAttribute("ds-pwp-password-policy-dn", "cn=Root Password Policy,cn=Password Policies,cn=config"); |
| | | } |
| | | |
| | | /** |
| | |
| | | */ |
| | | private static Attribute addRootPrivileges() |
| | | { |
| | | Attribute privilege = new BasicAttribute("ds-privilege-name"); |
| | | Attribute privilege = new LinkedAttribute("ds-privilege-name"); |
| | | privilege.add("bypass-acl"); |
| | | privilege.add("modify-acl"); |
| | | privilege.add("config-read"); |
| | |
| | | } |
| | | |
| | | /** |
| | | * Returns the attributes for some server properties. |
| | | * |
| | | * @param serverProperties |
| | | * the server properties. |
| | | * @param addObjectClass |
| | | * Indicates if the object class has to be added. |
| | | * @return the attributes for the given server properties. |
| | | */ |
| | | private static BasicAttributes makeAttrsFromServerProperties(Map<ServerProperty, Object> serverProperties, |
| | | boolean addObjectClass) |
| | | { |
| | | BasicAttributes result = new BasicAttributes(); |
| | | |
| | | // Transform 'properties' into 'attributes' |
| | | for (ServerProperty prop : serverProperties.keySet()) |
| | | { |
| | | Attribute attr = makeAttrFromServerProperty(prop, serverProperties.get(prop)); |
| | | if (attr != null) |
| | | { |
| | | result.put(attr); |
| | | } |
| | | } |
| | | if (addObjectClass) |
| | | { |
| | | // Add the objectclass attribute value |
| | | // TODO: use another structural objectclass |
| | | Attribute oc = new BasicAttribute("objectclass"); |
| | | oc.add("top"); |
| | | oc.add("ds-cfg-branch"); |
| | | oc.add("extensibleobject"); |
| | | result.put(oc); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * Returns the attribute for a given server property. |
| | | * |
| | | * @param property |
| | |
| | | */ |
| | | private static Attribute makeAttrFromServerProperty(ServerProperty property, Object value) |
| | | { |
| | | Attribute result; |
| | | |
| | | switch (property) |
| | | { |
| | | case INSTANCE_PUBLIC_KEY_CERTIFICATE: |
| | | result = null; // used in separate instance key entry |
| | | break; |
| | | // used in separate instance key entry |
| | | return null; |
| | | case GROUPS: |
| | | result = new BasicAttribute(ServerProperty.GROUPS.getAttributeName()); |
| | | for (Object o : ((Set<?>) value)) |
| | | { |
| | | result.add(o); |
| | | } |
| | | break; |
| | | return new LinkedAttribute(ServerProperty.GROUPS.getAttributeName(), ((Collection<?>) value)); |
| | | default: |
| | | result = new BasicAttribute(property.getAttributeName(), value); |
| | | return new LinkedAttribute(property.getAttributeName(), value); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * Returns the attributes for some server group properties. |
| | | * |
| | | * @param serverGroupProperties |
| | | * the server group properties. |
| | | * @return the attributes for the given server group properties. |
| | | */ |
| | | private static BasicAttributes makeAttrsFromServerGroupProperties( |
| | | Map<ServerGroupProperty, Object> serverGroupProperties) |
| | | { |
| | | BasicAttributes result = new BasicAttributes(); |
| | | |
| | | // Transform 'properties' into 'attributes' |
| | | for (ServerGroupProperty prop : serverGroupProperties.keySet()) |
| | | { |
| | | Attribute attr = makeAttrFromServerGroupProperty(prop, serverGroupProperties.get(prop)); |
| | | if (attr != null) |
| | | { |
| | | result.put(attr); |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | |
| | | switch (property) |
| | | { |
| | | case MEMBERS: |
| | | Attribute result = new BasicAttribute(ServerGroupProperty.MEMBERS.getAttributeName()); |
| | | for (Object o : ((Set<?>) value)) |
| | | { |
| | | result.add(o); |
| | | } |
| | | return result; |
| | | return new LinkedAttribute(ServerGroupProperty.MEMBERS.getAttributeName(), (Collection<?>) value); |
| | | default: |
| | | return new BasicAttribute(property.getAttributeName(), value); |
| | | return new LinkedAttribute(property.getAttributeName(), value); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Returns the properties of a server group for some LDAP attributes. |
| | | * |
| | | * @param attrs |
| | | * the LDAP attributes. |
| | | * @param entry |
| | | * the LDAP entry. |
| | | * @return the properties of a server group for some LDAP attributes. |
| | | * @throws ADSContextException |
| | | * if something goes wrong. |
| | | */ |
| | | private Map<ServerGroupProperty, Object> makePropertiesFromServerGroupAttrs(Attributes attrs) |
| | | private Map<ServerGroupProperty, Object> makePropertiesFromServerGroupAttrs(SearchResultEntry entry) |
| | | throws ADSContextException |
| | | { |
| | | Map<ServerGroupProperty, Object> result = new HashMap<>(); |
| | | try |
| | | { |
| | | for (ServerGroupProperty prop : ServerGroupProperty.values()) |
| | | { |
| | | Attribute attr = attrs.get(prop.getAttributeName()); |
| | | Attribute attr = entry.getAttribute(prop.getAttributeName()); |
| | | if (attr == null) |
| | | { |
| | | continue; |
| | |
| | | if (attr.size() >= 1 && MULTIVALUED_SERVER_GROUP_PROPERTIES.contains(prop)) |
| | | { |
| | | Set<String> set = new HashSet<>(); |
| | | NamingEnumeration<?> ae = attr.getAll(); |
| | | try |
| | | { |
| | | while (ae.hasMore()) |
| | | { |
| | | set.add((String) ae.next()); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | ae.close(); |
| | | } |
| | | toStrings(set, attr); |
| | | value = set; |
| | | } |
| | | else |
| | | { |
| | | value = attr.get(0); |
| | | value = attr.firstValueAsString(); |
| | | } |
| | | |
| | | result.put(prop, value); |
| | | } |
| | | } |
| | | catch (NamingException x) |
| | | { |
| | | throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * Returns the properties of a server for some LDAP attributes. |
| | | * |
| | | * @param attrs |
| | | * the LDAP attributes. |
| | | * @param entry |
| | | * the entry. |
| | | * @return the properties of a server for some LDAP attributes. |
| | | * @throws ADSContextException |
| | | * if something goes wrong. |
| | | */ |
| | | private Map<ServerProperty, Object> makePropertiesFromServerAttrs(Attributes attrs) throws ADSContextException |
| | | private Map<ServerProperty, Object> makePropertiesFromServerAttrs(SearchResultEntry entry) throws ADSContextException |
| | | { |
| | | Map<ServerProperty, Object> result = new HashMap<>(); |
| | | try |
| | | for (Attribute attr : entry.getAllAttributes()) |
| | | { |
| | | NamingEnumeration<? extends Attribute> ne = attrs.getAll(); |
| | | while (ne.hasMore()) |
| | | { |
| | | Attribute attr = ne.next(); |
| | | String attrID = attr.getID(); |
| | | AttributeType attrType = attr.getAttributeDescription().getAttributeType(); |
| | | Object value; |
| | | |
| | | if (attrID.endsWith(";binary")) |
| | | { |
| | | attrID = attrID.substring(0, attrID.lastIndexOf(";binary")); |
| | | } |
| | | |
| | | ServerProperty prop = null; |
| | | ServerProperty[] props = ServerProperty.values(); |
| | | for (int i = 0; i < props.length && prop == null; i++) |
| | | { |
| | | String v = props[i].getAttributeName(); |
| | | if (attrID.equalsIgnoreCase(v)) |
| | | if (attrType.hasName(v)) |
| | | { |
| | | prop = props[i]; |
| | | } |
| | |
| | | if (attr.size() >= 1 && MULTIVALUED_SERVER_PROPERTIES.contains(prop)) |
| | | { |
| | | Set<String> set = new HashSet<>(); |
| | | NamingEnumeration<?> ae = attr.getAll(); |
| | | try |
| | | { |
| | | while (ae.hasMore()) |
| | | { |
| | | set.add((String) ae.next()); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | ae.close(); |
| | | } |
| | | toStrings(set, attr); |
| | | value = set; |
| | | } |
| | | else |
| | | { |
| | | value = attr.get(0); |
| | | value = attr.firstValueAsString(); |
| | | } |
| | | |
| | | result.put(prop, value); |
| | | } |
| | | } |
| | | } |
| | | catch (NamingException x) |
| | | { |
| | | throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | |
| | | * @throws ADSContextException |
| | | * if something goes wrong. |
| | | */ |
| | | private Map<AdministratorProperty, Object> makePropertiesFromAdministratorAttrs(String rdn, Attributes attrs) |
| | | throws ADSContextException |
| | | private Map<AdministratorProperty, Object> makePropertiesFromAdministratorAttrs(RDN rdn, Iterable<Attribute> attrs) |
| | | { |
| | | Map<AdministratorProperty, Object> result = new HashMap<>(); |
| | | String dn = nameFromDN(rdn) + "," + getAdministratorContainerDN(); |
| | | result.put(AdministratorProperty.ADMINISTRATOR_DN, dn); |
| | | NamingEnumeration<? extends Attribute> ne = null; |
| | | try |
| | | result.put(AdministratorProperty.ADMINISTRATOR_DN, rdn + "," + getAdministratorContainerDN()); |
| | | for (Attribute attr : attrs) |
| | | { |
| | | ne = attrs.getAll(); |
| | | while (ne.hasMore()) |
| | | { |
| | | Attribute attr = ne.next(); |
| | | String attrID = attr.getID(); |
| | | Object value; |
| | | AttributeType attrName = attr.getAttributeDescription().getAttributeType(); |
| | | |
| | | if ("cn".equalsIgnoreCase(attrID)) |
| | | if (attrName.hasName("cn")) |
| | | { |
| | | value = attr.get(0); |
| | | result.put(AdministratorProperty.UID, value); |
| | | result.put(AdministratorProperty.UID, attr.firstValueAsString()); |
| | | } |
| | | else if ("userpassword".equalsIgnoreCase(attrID)) |
| | | else if (attrName.hasName("userpassword")) |
| | | { |
| | | value = new String((byte[]) attr.get()); |
| | | result.put(AdministratorProperty.PASSWORD, value); |
| | | result.put(AdministratorProperty.PASSWORD, new String(attr.firstValue().toByteArray())); |
| | | } |
| | | else if ("description".equalsIgnoreCase(attrID)) |
| | | else if (attrName.hasName("description")) |
| | | { |
| | | value = attr.get(0); |
| | | result.put(AdministratorProperty.DESCRIPTION, value); |
| | | result.put(AdministratorProperty.DESCRIPTION, attr.firstValueAsString()); |
| | | } |
| | | else if ("ds-privilege-name".equalsIgnoreCase(attrID)) |
| | | else if (attrName.hasName("ds-privilege-name")) |
| | | { |
| | | LinkedHashSet<String> privileges = new LinkedHashSet<>(); |
| | | NamingEnumeration<?> attValueList = attr.getAll(); |
| | | while (attValueList.hasMoreElements()) |
| | | { |
| | | privileges.add(attValueList.next().toString()); |
| | | } |
| | | toStrings(privileges, attr); |
| | | result.put(AdministratorProperty.PRIVILEGE, privileges); |
| | | } |
| | | } |
| | | } |
| | | catch (NamingException x) |
| | | { |
| | | throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); |
| | | } |
| | | finally |
| | | { |
| | | handleCloseNamingEnumeration(ne); |
| | | } |
| | | |
| | | return result; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | // LDAP utilities |
| | | /** |
| | | * Returns the LdapName object for the given dn. |
| | | * |
| | | * @param dn |
| | | * the DN. |
| | | * @return the LdapName object for the given dn. |
| | | * @throws ADSContextException |
| | | * if a valid LdapName could not be retrieved for the given dn. |
| | | */ |
| | | private static LdapName nameFromDN(String dn) throws ADSContextException |
| | | { |
| | | try |
| | | { |
| | | return new LdapName(dn); |
| | | } |
| | | catch (InvalidNameException x) |
| | | { |
| | | logger.error(LocalizableMessage.raw("Error parsing dn " + dn, x)); |
| | | throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Returns the String rdn for the given search result name. |
| | | * |
| | | * @param rdnName |
| | | * the search result name. |
| | | * @return the String rdn for the given search result name. |
| | | * @throws ADSContextException |
| | | * if a valid String rdn could not be retrieved for the given result |
| | | * name. |
| | | */ |
| | | private static String getRdn(String rdnName) throws ADSContextException |
| | | { |
| | | // Transform the JNDI name into a RDN string |
| | | try |
| | | { |
| | | return new CompositeName(rdnName).get(0); |
| | | } |
| | | catch (InvalidNameException x) |
| | | { |
| | | logger.error(LocalizableMessage.raw("Error parsing rdn " + rdnName, x)); |
| | | throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Tells whether an entry with the provided DN exists. |
| | |
| | | * @throws ADSContextException |
| | | * if an error occurred while checking if the entry exists or not. |
| | | */ |
| | | private boolean isExistingEntry(LdapName dn) throws ADSContextException |
| | | private boolean isExistingEntry(String dn) throws ADSContextException |
| | | { |
| | | try |
| | | SearchRequest request = newSearchRequest(dn, BASE_OBJECT, "(objectclass=*)", NO_ATTRIBUTES); |
| | | try (ConnectionEntryReader entryReader = getConnection().getConnection().search(request)) |
| | | { |
| | | SearchControls sc = new SearchControls(); |
| | | sc.setSearchScope(SearchControls.OBJECT_SCOPE); |
| | | sc.setReturningAttributes(new String[] { SchemaConstants.NO_ATTRIBUTES }); |
| | | NamingEnumeration<SearchResult> sr = getDirContext().search(dn, "(objectclass=*)", sc); |
| | | try |
| | | while (entryReader.hasNext()) |
| | | { |
| | | while (sr.hasMore()) |
| | | { |
| | | sr.next(); |
| | | entryReader.readEntry(); |
| | | return true; |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | sr.close(); |
| | | } |
| | | return false; |
| | | } |
| | | catch (NameNotFoundException x) |
| | | catch (EntryNotFoundException x) |
| | | { |
| | | return false; |
| | | } |
| | | catch (NoPermissionException x) |
| | | catch (AuthorizationException x) |
| | | { |
| | | throw new ADSContextException(ErrorType.ACCESS_PERMISSION); |
| | | } |
| | | catch (javax.naming.NamingException x) |
| | | catch (IOException x) |
| | | { |
| | | throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); |
| | | } |
| | |
| | | */ |
| | | private void createContainerEntry(String dn) throws ADSContextException |
| | | { |
| | | Attribute oc = new BasicAttribute("objectclass"); |
| | | oc.add("top"); |
| | | oc.add("ds-cfg-branch"); |
| | | BasicAttributes attrs = new BasicAttributes(); |
| | | attrs.put(oc); |
| | | createEntry(dn, attrs); |
| | | createEntry(newAddRequest(dn).addAttribute("objectclass", "top", "ds-cfg-branch")); |
| | | } |
| | | |
| | | /** |
| | |
| | | */ |
| | | private void createAdministratorContainerEntry() throws ADSContextException |
| | | { |
| | | Attribute oc = new BasicAttribute("objectclass"); |
| | | oc.add("groupofurls"); |
| | | BasicAttributes attrs = new BasicAttributes(); |
| | | attrs.put(oc); |
| | | attrs.put("memberURL", "ldap:///" + getAdministratorContainerDN() + "??one?(objectclass=*)"); |
| | | attrs.put("description", "Group of identities which have full access."); |
| | | createEntry(getAdministratorContainerDN(), attrs); |
| | | AddRequest request = newAddRequest(getAdministratorContainerDN()) |
| | | .addAttribute("objectclass", "groupofurls") |
| | | .addAttribute("memberURL", "ldap:///" + getAdministratorContainerDN() + "??one?(objectclass=*)") |
| | | .addAttribute("description", "Group of identities which have full access."); |
| | | createEntry(request); |
| | | } |
| | | |
| | | /** |
| | |
| | | */ |
| | | private void createTopContainerEntry() throws ADSContextException |
| | | { |
| | | Attribute oc = new BasicAttribute("objectclass"); |
| | | oc.add("top"); |
| | | oc.add("ds-cfg-branch"); |
| | | BasicAttributes attrs = new BasicAttributes(); |
| | | attrs.put(oc); |
| | | createEntry(getAdministrationSuffixDN(), attrs); |
| | | AddRequest request = newAddRequest(getAdministrationSuffixDN()) |
| | | .addAttribute("objectclass", "top", "ds-cfg-branch"); |
| | | createEntry(request); |
| | | } |
| | | |
| | | /** |
| | | * Creates an entry with the provided dn and attributes. |
| | | * Creates an entry with the provided add request. |
| | | * |
| | | * @param dn |
| | | * the dn of the entry. |
| | | * @param attrs |
| | | * the attributes of the entry. |
| | | * @param addRequest |
| | | * the add request. |
| | | * @throws ADSContextException |
| | | * if the entry could not be created. |
| | | */ |
| | | private void createEntry(String dn, Attributes attrs) throws ADSContextException |
| | | private void createEntry(AddRequest request) throws ADSContextException |
| | | { |
| | | try |
| | | { |
| | | DirContext ctx = getDirContext().createSubcontext(nameFromDN(dn), attrs); |
| | | ctx.close(); |
| | | throwIfNotSuccess(getConnection().getConnection().add(request)); |
| | | } |
| | | catch (NamingException x) |
| | | catch (LdapException e) |
| | | { |
| | | throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); |
| | | throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, e); |
| | | } |
| | | } |
| | | |
| | | private void throwIfNotSuccess(Result result) throws LdapException |
| | | { |
| | | ResultCode rc = result.getResultCode(); |
| | | if (rc.isExceptional()) |
| | | { |
| | | throw LdapException.newLdapException(result); |
| | | } |
| | | } |
| | | |
| | |
| | | * @throws ADSContextException |
| | | * In case there is a problem registering the instance public key certificate ID |
| | | */ |
| | | private void registerInstanceKeyCertificate(Map<ServerProperty, Object> serverProperties, LdapName serverEntryDn) |
| | | private void registerInstanceKeyCertificate(Map<ServerProperty, Object> serverProperties, String serverEntryDn) |
| | | throws ADSContextException |
| | | { |
| | | ADSContextHelper helper = new ADSContextHelper(); |
| | |
| | | */ |
| | | public Map<String, byte[]> getTrustedCertificates() throws ADSContextException |
| | | { |
| | | final Map<String, byte[]> certificateMap = new HashMap<>(); |
| | | final String baseDNStr = getInstanceKeysContainerDN(); |
| | | try |
| | | { |
| | | final String baseDN = getInstanceKeysContainerDN(); |
| | | ADSContextHelper helper = new ADSContextHelper(); |
| | | final LdapName baseDN = new LdapName(baseDNStr); |
| | | final String FILTER_OC_INSTANCE_KEY = "(objectclass=" + helper.getOcCryptoInstanceKey() + ")"; |
| | | final String FILTER_NOT_COMPROMISED = "(!(" + helper.getAttrCryptoKeyCompromisedTime() + "=*))"; |
| | | final String searchFilter = "(&" + FILTER_OC_INSTANCE_KEY + FILTER_NOT_COMPROMISED + ")"; |
| | | 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 = |
| | | connectionWrapper.getLdapContext().search(baseDN, searchFilter, searchControls); |
| | | try |
| | | |
| | | String instanceKeyId = ADSContext.ServerProperty.INSTANCE_KEY_ID.getAttributeName(); |
| | | String instanceKeyCertificate = |
| | | ADSContext.ServerProperty.INSTANCE_PUBLIC_KEY_CERTIFICATE.getAttributeName() + ";binary"; |
| | | SearchRequest request = |
| | | newSearchRequest(baseDN, SINGLE_LEVEL, searchFilter, instanceKeyId, instanceKeyCertificate); |
| | | |
| | | final Map<String, byte[]> certificateMap = new HashMap<>(); |
| | | try (ConnectionEntryReader entryReader = connectionWrapper.getConnection().search(request)) |
| | | { |
| | | while (keyEntries.hasMore()) |
| | | while (entryReader.hasNext()) |
| | | { |
| | | final SearchResult entry = keyEntries.next(); |
| | | final Attributes attrs = entry.getAttributes(); |
| | | final Attribute keyIDAttr = attrs.get(attrIDs[0]); |
| | | final Attribute keyCertAttr = attrs.get(attrIDs[1]); |
| | | final SearchResultEntry entry = entryReader.readEntry(); |
| | | final Attribute keyIDAttr = entry.getAttribute(instanceKeyId); |
| | | final Attribute keyCertAttr = entry.getAttribute(instanceKeyCertificate); |
| | | if (null == keyIDAttr || null == keyCertAttr) |
| | | { |
| | | continue;// schema viol. |
| | | } |
| | | certificateMap.put((String) keyIDAttr.get(), (byte[]) keyCertAttr.get()); |
| | | certificateMap.put(keyIDAttr.firstValueAsString(), keyCertAttr.firstValue().toByteArray()); |
| | | } |
| | | return certificateMap; |
| | | } |
| | | finally |
| | | { |
| | | try |
| | | { |
| | | keyEntries.close(); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | logger.warn(LocalizableMessage.raw("Unexpected error closing enumeration on ADS key pairs", ex)); |
| | | } |
| | | } |
| | | } |
| | | catch (NamingException x) |
| | | catch (IOException x) |
| | | { |
| | | throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, x); |
| | | } |
| | | return certificateMap; |
| | | } |
| | | |
| | | /** |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | private void handleCloseNamingEnumeration(NamingEnumeration<?> ne) throws ADSContextException |
| | | { |
| | | if (ne != null) |
| | | { |
| | | try |
| | | { |
| | | ne.close(); |
| | | } |
| | | catch (NamingException ex) |
| | | { |
| | | throw new ADSContextException(ErrorType.ERROR_UNEXPECTED, ex); |
| | | } |
| | | } |
| | | } |
| | | } |