All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.connid.bundles.ldap.commons.LdapModifyOperation Maven / Gradle / Ivy

The newest version!
/**
 * ====================
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved.
 * Copyright 2011-2013 Tirasa. All rights reserved.
 *
 * The contents of this file are subject to the terms of the Common Development
 * and Distribution License("CDDL") (the "License"). You may not use this file
 * except in compliance with the License.
 *
 * You can obtain a copy of the License at https://oss.oracle.com/licenses/CDDL
 * See the License for the specific language governing permissions and limitations
 * under the License.
 *
 * When distributing the Covered Code, include this CDDL Header Notice in each file
 * and include the License file at https://oss.oracle.com/licenses/CDDL.
 * If applicable, add the following below this CDDL Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 * ====================
 */
package org.connid.bundles.ldap.commons;

import static java.util.Collections.min;
import static org.connid.bundles.ldap.commons.LdapUtil.addStringAttrValues;
import static org.connid.bundles.ldap.commons.LdapUtil.quietCreateLdapName;
import static org.identityconnectors.common.CollectionUtil.isEmpty;
import static org.identityconnectors.common.StringUtil.isBlank;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;
import org.connid.bundles.ldap.LdapConnection;
import org.connid.bundles.ldap.commons.GroupHelper.GroupMembership;
import org.connid.bundles.ldap.search.LdapSearches;
import org.identityconnectors.common.Base64;
import org.identityconnectors.framework.common.exceptions.ConnectorException;

public abstract class LdapModifyOperation {

    protected final LdapConnection conn;

    protected final GroupHelper groupHelper;

    public LdapModifyOperation(LdapConnection conn) {
        this.conn = conn;
        groupHelper = new GroupHelper(conn);
    }

    protected final void hashPassword(final Attribute passwordAttr, final String entryDN) {
        String hashAlgorithm = conn.getConfiguration().getPasswordHashAlgorithm();
        if (isBlank(hashAlgorithm) || "NONE".equalsIgnoreCase(hashAlgorithm)) {
            return;
        }
        try {
            byte[] password = (byte[]) passwordAttr.get();
            if (password != null) {
                String newPassword = hashBytes(password, hashAlgorithm,
                        entryDN != null ? entryDN.hashCode() : 0);
                passwordAttr.clear();
                passwordAttr.add(newPassword);
            }
        } catch (NamingException e) {
            throw new ConnectorException(e);
        }
    }

    private String hashBytes(final byte[] plain, final String algorithm, final long randSeed) {
        String plainPassword = new String(plain);
        if (plainPassword != null && plainPassword.startsWith("{")) {
            String digest = plainPassword.substring(1, plainPassword.indexOf('}'));
            if (digest != null && algorithm.equalsIgnoreCase(digest)) {
                return plainPassword;
            }
        }
        
        MessageDigest digest = null;
        try {
            if (algorithm.equalsIgnoreCase("SSHA") || algorithm.equalsIgnoreCase("SHA")) {
                digest = MessageDigest.getInstance("SHA-1");
            } else if (algorithm.equalsIgnoreCase("SMD5") || algorithm.equalsIgnoreCase("MD5")) {
                digest = MessageDigest.getInstance("MD5");
            }
        } catch (NoSuchAlgorithmException e) {
            throw new ConnectorException("Could not find MessageDigest algorithm (" + algorithm + ") implementation");
        }
        if (digest == null) {
            throw new ConnectorException("Unsupported hash algorithm: " + algorithm);
        }

        byte[] salt = {};

        if (algorithm.equalsIgnoreCase("SSHA") || algorithm.equalsIgnoreCase("SMD5")) {
            Random rand = new Random();
            rand.setSeed(System.currentTimeMillis() + randSeed);
            // A RSA whitepaper 
            // suggested the salt length be the same as the output of the
            // hash function being used. The adapter uses the length of the input,
            // hoping that it is close enough an approximation.
            salt = new byte[8];
            rand.nextBytes(salt);
        }

        digest.reset();
        digest.update(plain);
        digest.update(salt);
        byte[] hash = digest.digest();

        byte[] hashPlusSalt = new byte[hash.length + salt.length];
        System.arraycopy(hash, 0, hashPlusSalt, 0, hash.length);
        System.arraycopy(salt, 0, hashPlusSalt, hash.length, salt.length);

        StringBuilder result = new StringBuilder(algorithm.length() + hashPlusSalt.length);
        result.append('{');
        result.append(algorithm);
        result.append('}');
        result.append(Base64.encode(hashPlusSalt));

        return result.toString();
    }

    protected static Set getAttributeValues(final String attrName, final LdapName entryDN,
            final Attributes attrs) {

        final Set result = new HashSet();
        if (entryDN != null && !entryDN.isEmpty()) {
            Rdn rdn = entryDN.getRdn(entryDN.size() - 1);
            addStringAttrValues(rdn.toAttributes(), attrName, result);
        }
        Attribute attr = attrs.get(attrName);
        if (attr != null) {
            try {
                NamingEnumeration attrEnum = attr.getAll();
                while (attrEnum.hasMoreElements()) {
                    result.add((String) attrEnum.nextElement());
                }
            } catch (NamingException e) {
                throw new ConnectorException(e);
            }
            return result;
        }
        // If we got here, the attribute was not in the Attributes instance. So if the
        // result is empty, that means the attribute is not present in either
        // the entry DN or the attribute set.
        return result.isEmpty() ? null : result;
    }

    protected final String getFirstPosixRefAttr(final String entryDN, final Set posixRefAttrs) {
        if (isEmpty(posixRefAttrs)) {
            throw new ConnectorException(conn.format("cannotAddToPosixGroup",
                    null, entryDN, GroupHelper.getPosixRefAttribute()));
        }
        return min(posixRefAttrs);
    }

    /**
     * Holds the POSIX ref attributes and the respective group memberships. Retrieves them lazily so that they are only
     * retrieved once, when they are needed.
     */
    public final class PosixGroupMember {

        private final String entryDN;

        private LdapEntry entry;

        private Set posixRefAttrs;

        private Set posixGroupMemberships;

        public PosixGroupMember(String entryDN) {
            this.entryDN = entryDN;
        }

        public Set getPosixGroupMemberships() {
            if (posixGroupMemberships == null) {
                posixGroupMemberships = groupHelper.getPosixGroupMemberships(
                        getPosixRefAttributes());
            }
            return posixGroupMemberships;
        }

        public Set getPosixGroupMembershipsByAttrs(final Set posixRefAttrs) {
            Set result = new HashSet();
            for (GroupMembership member : getPosixGroupMemberships()) {
                if (posixRefAttrs.contains(member.getMemberRef())) {
                    result.add(member);
                }
            }
            return result;
        }

        public Set getPosixGroupMembershipsByGroups(final List groupDNs) {
            Set groupNames = new HashSet();
            for (String groupDN : groupDNs) {
                groupNames.add(quietCreateLdapName(groupDN));
            }
            Set result = new HashSet();
            for (GroupMembership member : getPosixGroupMemberships()) {
                if (groupNames.contains(quietCreateLdapName(member.getGroupDN()))) {
                    result.add(member);
                }
            }
            return result;
        }

        public Set getPosixRefAttributes() {
            if (posixRefAttrs == null) {
                posixRefAttrs = getAttributeValues(GroupHelper.getPosixRefAttribute(), null,
                        getLdapEntry().getAttributes());
            }
            return posixRefAttrs;
        }

        private LdapEntry getLdapEntry() {
            if (entry == null) {
                entry = LdapSearches.getEntry(conn, quietCreateLdapName(entryDN), GroupHelper.getPosixRefAttribute());
            }
            return entry;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy