Search in sources :

Example 1 with NodeDescription

use of org.alfresco.repo.security.sync.NodeDescription in project alfresco-repository by Alfresco.

the class LDAPUserRegistry method getGroups.

/*
     * (non-Javadoc)
     * @see org.alfresco.repo.security.sync.UserRegistry#getGroups(java.util.Date)
     */
public Collection<NodeDescription> getGroups(Date modifiedSince) {
    // Work out whether the user and group trees are disjoint. This may allow us to optimize reverse DN
    // resolution.
    final LdapName groupDistinguishedNamePrefix;
    try {
        groupDistinguishedNamePrefix = fixedLdapName(this.groupSearchBase.toLowerCase());
    } catch (InvalidNameException e) {
        Object[] params = { this.groupSearchBase.toLowerCase(), e.getLocalizedMessage() };
        throw new AlfrescoRuntimeException("synchronization.err.ldap.search.base.invalid", params, e);
    }
    final LdapName userDistinguishedNamePrefix;
    try {
        userDistinguishedNamePrefix = fixedLdapName(this.userSearchBase.toLowerCase());
    } catch (InvalidNameException e) {
        Object[] params = { this.userSearchBase.toLowerCase(), e.getLocalizedMessage() };
        throw new AlfrescoRuntimeException("synchronization.err.ldap.search.base.invalid", params, e);
    }
    final boolean disjoint = !groupDistinguishedNamePrefix.startsWith(userDistinguishedNamePrefix) && !userDistinguishedNamePrefix.startsWith(groupDistinguishedNamePrefix);
    // Choose / generate the query
    String query;
    if (modifiedSince == null) {
        query = this.groupQuery;
    } else {
        query = MessageFormat.format(this.groupDifferentialQuery, this.timestampFormat.format(modifiedSince));
    }
    // Run the query and process the results
    final Map<String, NodeDescription> lookup = new TreeMap<String, NodeDescription>();
    processQuery(new AbstractSearchCallback() {

        // We get a whole new context to avoid interference with cookies from paged results
        private DirContext ctx = LDAPUserRegistry.this.ldapInitialContextFactory.getDefaultIntialDirContext();

        protected void doProcess(SearchResult result) throws NamingException, ParseException {
            Attributes attributes = result.getAttributes();
            Attribute gidAttribute = attributes.get(LDAPUserRegistry.this.groupIdAttributeName);
            if (gidAttribute == null) {
                if (LDAPUserRegistry.this.errorOnMissingGID) {
                    Object[] params = { result.getNameInNamespace(), LDAPUserRegistry.this.groupIdAttributeName };
                    throw new AlfrescoRuntimeException("synchronization.err.ldap.get.group.id.missing", params);
                } else {
                    LDAPUserRegistry.logger.warn("Missing GID on " + attributes);
                    return;
                }
            }
            String groupShortName = gidAttribute.get(0).toString();
            String gid = "GROUP_" + groupShortName;
            NodeDescription group = lookup.get(gid);
            if (group == null) {
                // Apply the mapped properties to the node description
                group = mapToNode(LDAPUserRegistry.this.groupAttributeMapping, LDAPUserRegistry.this.groupAttributeDefaults, result);
                // Make sure the "GROUP_" prefix is applied
                group.getProperties().put(ContentModel.PROP_AUTHORITY_NAME, gid);
                lookup.put(gid, group);
            } else if (LDAPUserRegistry.this.errorOnDuplicateGID) {
                throw new AlfrescoRuntimeException("Duplicate group id found for " + gid);
            } else {
                LDAPUserRegistry.logger.warn("Duplicate gid found for " + gid + " -> merging definitions");
            }
            Set<String> childAssocs = group.getChildAssociations();
            // Get the repeating (and possibly range restricted) member attribute
            Attribute memAttribute = getRangeRestrictedAttribute(attributes, LDAPUserRegistry.this.memberAttributeName);
            int nextStart = LDAPUserRegistry.this.attributeBatchSize;
            if (LDAPUserRegistry.logger.isDebugEnabled()) {
                LDAPUserRegistry.logger.debug("Processing group: " + gid + ", from source: " + group.getSourceId());
            }
            // Loop until we get to the end of the range
            while (memAttribute != null) {
                for (int i = 0; i < memAttribute.size(); i++) {
                    String attribute = (String) memAttribute.get(i);
                    if (attribute != null && attribute.length() > 0) {
                        try {
                            // Attempt to parse the member attribute as a DN. If this fails we have a fallback
                            // in the catch block
                            LdapName distinguishedNameForComparison = fixedLdapName(attribute.toLowerCase());
                            Attribute nameAttribute;
                            // and group DNs without a secondary lookup
                            if (disjoint) {
                                LdapName distinguishedName = fixedLdapName(attribute);
                                Attributes nameAttributes = distinguishedName.getRdn(distinguishedName.size() - 1).toAttributes();
                                // Recognize user DNs
                                if (distinguishedNameForComparison.startsWith(userDistinguishedNamePrefix) && (nameAttribute = nameAttributes.get(LDAPUserRegistry.this.userIdAttributeName)) != null) {
                                    if (LDAPUserRegistry.logger.isDebugEnabled()) {
                                        LDAPUserRegistry.logger.debug("User DN recognized: " + nameAttribute.get());
                                    }
                                    childAssocs.add((String) nameAttribute.get());
                                    continue;
                                }
                                // Recognize group DNs
                                if (distinguishedNameForComparison.startsWith(groupDistinguishedNamePrefix) && (nameAttribute = nameAttributes.get(LDAPUserRegistry.this.groupIdAttributeName)) != null) {
                                    if (LDAPUserRegistry.logger.isDebugEnabled()) {
                                        LDAPUserRegistry.logger.debug("Group DN recognized: " + "GROUP_" + nameAttribute.get());
                                    }
                                    childAssocs.add("GROUP_" + nameAttribute.get());
                                    continue;
                                }
                            }
                            // If we can't determine the name and type from the DN alone, try a directory lookup
                            if (distinguishedNameForComparison.startsWith(userDistinguishedNamePrefix) || distinguishedNameForComparison.startsWith(groupDistinguishedNamePrefix)) {
                                try {
                                    Attributes childAttributes = this.ctx.getAttributes(jndiName(attribute), new String[] { "objectclass", LDAPUserRegistry.this.groupIdAttributeName, LDAPUserRegistry.this.userIdAttributeName });
                                    Attribute objectClass = childAttributes.get("objectclass");
                                    if (hasAttributeValue(objectClass, LDAPUserRegistry.this.personType)) {
                                        nameAttribute = childAttributes.get(LDAPUserRegistry.this.userIdAttributeName);
                                        if (nameAttribute == null) {
                                            if (LDAPUserRegistry.this.errorOnMissingUID) {
                                                throw new AlfrescoRuntimeException("User missing user id attribute DN =" + attribute + "  att = " + LDAPUserRegistry.this.userIdAttributeName);
                                            } else {
                                                LDAPUserRegistry.logger.warn("User missing user id attribute DN =" + attribute + "  att = " + LDAPUserRegistry.this.userIdAttributeName);
                                                continue;
                                            }
                                        }
                                        if (LDAPUserRegistry.logger.isDebugEnabled()) {
                                            LDAPUserRegistry.logger.debug("User DN recognized by directory lookup: " + nameAttribute.get());
                                        }
                                        childAssocs.add((String) nameAttribute.get());
                                        continue;
                                    } else if (hasAttributeValue(objectClass, LDAPUserRegistry.this.groupType)) {
                                        nameAttribute = childAttributes.get(LDAPUserRegistry.this.groupIdAttributeName);
                                        if (nameAttribute == null) {
                                            if (LDAPUserRegistry.this.errorOnMissingGID) {
                                                Object[] params = { result.getNameInNamespace(), LDAPUserRegistry.this.groupIdAttributeName };
                                                throw new AlfrescoRuntimeException("synchronization.err.ldap.get.group.id.missing", params);
                                            } else {
                                                LDAPUserRegistry.logger.warn("Missing GID on " + childAttributes);
                                                continue;
                                            }
                                        }
                                        if (LDAPUserRegistry.logger.isDebugEnabled()) {
                                            LDAPUserRegistry.logger.debug("Group DN recognized by directory lookup: " + "GROUP_" + nameAttribute.get());
                                        }
                                        childAssocs.add("GROUP_" + nameAttribute.get());
                                        continue;
                                    }
                                } catch (ServiceUnavailableException | CommunicationException e) {
                                    // MNT-21614: Check & fail if communication breaks due to ServiceUnavailableException or CommunicationException
                                    if (e.getMessage() != null) {
                                        Object[] params = { e.getLocalizedMessage() };
                                        throw new AlfrescoRuntimeException("synchronization.err.ldap.search", params, e);
                                    }
                                    continue;
                                } catch (NamingException e) {
                                    // MNT-17966
                                    if (e.getMessage() != null && e.getMessage().startsWith(NAMING_TIMEOUT_EXCEPTION_MESSAGE)) {
                                        Object[] params = { e.getLocalizedMessage() };
                                        throw new AlfrescoRuntimeException("synchronization.err.ldap.search", params, e);
                                    }
                                    // Unresolvable name
                                    if (LDAPUserRegistry.this.errorOnMissingMembers) {
                                        Object[] params = { groupShortName, attribute, e.getLocalizedMessage() };
                                        throw new AlfrescoRuntimeException("synchronization.err.ldap.group.member.missing.exception", params, e);
                                    }
                                    LDAPUserRegistry.logger.warn("Failed to resolve member of group '" + groupShortName + "' with distinguished name: " + attribute, e);
                                    continue;
                                }
                            }
                            if (LDAPUserRegistry.this.errorOnMissingMembers) {
                                Object[] params = { groupShortName, attribute };
                                throw new AlfrescoRuntimeException("synchronization.err.ldap.group.member.missing", params);
                            }
                            LDAPUserRegistry.logger.warn("Failed to resolve member of group '" + groupShortName + "' with distinguished name: " + attribute);
                        } catch (InvalidNameException e) {
                            // posixGroup (FDS) that directly lists user names
                            if (LDAPUserRegistry.logger.isDebugEnabled()) {
                                LDAPUserRegistry.logger.debug("Member DN recognized as posixGroup: " + attribute);
                            }
                            childAssocs.add(attribute);
                        }
                    }
                }
                // fetch the next batch
                if (nextStart > 0 && !LDAPUserRegistry.PATTERN_RANGE_END.matcher(memAttribute.getID().toLowerCase()).find()) {
                    Attributes childAttributes = this.ctx.getAttributes(jndiName(result.getNameInNamespace()), new String[] { LDAPUserRegistry.this.memberAttributeName + ";range=" + nextStart + '-' + (nextStart + LDAPUserRegistry.this.attributeBatchSize - 1) });
                    memAttribute = getRangeRestrictedAttribute(childAttributes, LDAPUserRegistry.this.memberAttributeName);
                    nextStart += LDAPUserRegistry.this.attributeBatchSize;
                } else {
                    memAttribute = null;
                }
            }
        }

        public void close() throws NamingException {
            this.ctx.close();
        }
    }, this.groupSearchBase, query, this.groupKeys.getFirst());
    if (LDAPUserRegistry.logger.isDebugEnabled()) {
        LDAPUserRegistry.logger.debug("Found " + lookup.size());
    }
    return lookup.values();
}
Also used : Set(java.util.Set) TreeSet(java.util.TreeSet) HashSet(java.util.HashSet) Attribute(javax.naming.directory.Attribute) Attributes(javax.naming.directory.Attributes) SearchResult(javax.naming.directory.SearchResult) InitialDirContext(javax.naming.directory.InitialDirContext) DirContext(javax.naming.directory.DirContext) TreeMap(java.util.TreeMap) LdapName(javax.naming.ldap.LdapName) NodeDescription(org.alfresco.repo.security.sync.NodeDescription) InvalidNameException(javax.naming.InvalidNameException) AlfrescoRuntimeException(org.alfresco.error.AlfrescoRuntimeException) NamingException(javax.naming.NamingException) ParseException(java.text.ParseException)

Example 2 with NodeDescription

use of org.alfresco.repo.security.sync.NodeDescription in project alfresco-repository by Alfresco.

the class LDAPUserRegistry method mapToNode.

private NodeDescription mapToNode(Map<String, String> attributeMapping, Map<String, String> attributeDefaults, SearchResult result) throws NamingException {
    NodeDescription nodeDescription = new NodeDescription(result.getNameInNamespace());
    Attributes ldapAttributes = result.getAttributes();
    // Parse the timestamp
    Attribute modifyTimestamp = ldapAttributes.get(this.modifyTimestampAttributeName);
    if (modifyTimestamp != null) {
        try {
            nodeDescription.setLastModified(this.timestampFormat.parse(modifyTimestamp.get().toString()));
        } catch (ParseException e) {
            throw new AlfrescoRuntimeException("Failed to parse timestamp.", e);
        }
    }
    // Apply the mapped attributes
    PropertyMap properties = nodeDescription.getProperties();
    for (String key : attributeMapping.keySet()) {
        QName keyQName = QName.createQName(key, this.namespaceService);
        // cater for null
        String attributeName = attributeMapping.get(key);
        if (attributeName != null) {
            Attribute attribute = ldapAttributes.get(attributeName);
            String defaultAttribute = attributeDefaults.get(key);
            if (attribute != null) {
                String value = (String) attribute.get(0);
                if (value != null) {
                    properties.put(keyQName, value);
                }
            } else if (defaultAttribute != null) {
                properties.put(keyQName, defaultAttribute);
            } else {
                // Make sure that a 2nd sync, updates deleted ldap attributes(MNT-14026)
                properties.put(keyQName, null);
            }
        } else {
            String defaultValue = attributeDefaults.get(key);
            if (defaultValue != null) {
                properties.put(keyQName, defaultValue);
            }
        }
    }
    return nodeDescription;
}
Also used : NodeDescription(org.alfresco.repo.security.sync.NodeDescription) PropertyMap(org.alfresco.util.PropertyMap) Attribute(javax.naming.directory.Attribute) QName(org.alfresco.service.namespace.QName) Attributes(javax.naming.directory.Attributes) AlfrescoRuntimeException(org.alfresco.error.AlfrescoRuntimeException) ParseException(java.text.ParseException)

Aggregations

ParseException (java.text.ParseException)2 Attribute (javax.naming.directory.Attribute)2 Attributes (javax.naming.directory.Attributes)2 AlfrescoRuntimeException (org.alfresco.error.AlfrescoRuntimeException)2 NodeDescription (org.alfresco.repo.security.sync.NodeDescription)2 HashSet (java.util.HashSet)1 Set (java.util.Set)1 TreeMap (java.util.TreeMap)1 TreeSet (java.util.TreeSet)1 InvalidNameException (javax.naming.InvalidNameException)1 NamingException (javax.naming.NamingException)1 DirContext (javax.naming.directory.DirContext)1 InitialDirContext (javax.naming.directory.InitialDirContext)1 SearchResult (javax.naming.directory.SearchResult)1 LdapName (javax.naming.ldap.LdapName)1 QName (org.alfresco.service.namespace.QName)1 PropertyMap (org.alfresco.util.PropertyMap)1