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

org.connid.bundles.ldap.modify.LdapUpdate 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.modify;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.ModificationItem;
import org.connid.bundles.ldap.LdapConnection;
import org.connid.bundles.ldap.commons.GroupHelper;
import org.connid.bundles.ldap.commons.GroupHelper.GroupMembership;
import org.connid.bundles.ldap.commons.GroupHelper.Modification;
import org.connid.bundles.ldap.commons.LdapConstants;
import org.connid.bundles.ldap.commons.LdapModifyOperation;
import static org.connid.bundles.ldap.commons.LdapUtil.checkedListByFilter;
import static org.connid.bundles.ldap.commons.LdapUtil.quietCreateLdapName;
import org.connid.bundles.ldap.commons.StatusManagement;
import org.connid.bundles.ldap.schema.GuardedPasswordAttribute;
import org.connid.bundles.ldap.schema.GuardedPasswordAttribute.Accessor;
import org.connid.bundles.ldap.search.LdapSearches;
import static org.identityconnectors.common.CollectionUtil.isEmpty;
import static org.identityconnectors.common.CollectionUtil.newSet;
import static org.identityconnectors.common.CollectionUtil.nullAsEmpty;
import org.identityconnectors.common.Pair;
import org.identityconnectors.framework.common.exceptions.ConnectorException;
import org.identityconnectors.framework.common.objects.Attribute;
import org.identityconnectors.framework.common.objects.AttributeUtil;
import org.identityconnectors.framework.common.objects.Name;
import org.identityconnectors.framework.common.objects.ObjectClass;
import org.identityconnectors.framework.common.objects.OperationalAttributes;
import org.identityconnectors.framework.common.objects.Uid;

public class LdapUpdate extends LdapModifyOperation {

    private final ObjectClass oclass;

    private Uid uid;

    public LdapUpdate(
            final LdapConnection conn,
            final ObjectClass oclass,
            final Uid uid) {

        super(conn);
        this.oclass = oclass;
        this.uid = uid;
    }

    public Uid update(final Set attrs) {
        String entryDN = LdapSearches.findEntryDN(conn, oclass, uid);
        PosixGroupMember posixMember = new PosixGroupMember(entryDN);

        // Extract the Name attribute if any, to be used to rename the entry later.
        Set updateAttrs = attrs;

        Name newName = (Name) AttributeUtil.find(Name.NAME, attrs);

        // serach for status attribute
        final Attribute status = AttributeUtil.find(OperationalAttributes.ENABLE_NAME, attrs);

        String newEntryDN = null;

        if (newName != null) {
            updateAttrs = newSet(attrs);
            updateAttrs.remove(newName);
            newEntryDN = conn.getSchemaMapping().getEntryDN(oclass, newName);
        }

        final List ldapGroups = getStringListValue(updateAttrs, LdapConstants.LDAP_GROUPS_NAME);

        final List posixGroups = getStringListValue(updateAttrs, LdapConstants.POSIX_GROUPS_NAME);

        final Pair attrToModify = getAttributesToModify(updateAttrs);

        final Attributes ldapAttrs = attrToModify.first;

        // If we are removing all POSIX ref attributes, check they are not used
        // in POSIX groups. Note it is OK to update the POSIX ref attribute instead of
        // removing them -- we will update the groups to refer to the new attributes.
        final Set newPosixRefAttrs = getAttributeValues(
                GroupHelper.getPosixRefAttribute(),
                quietCreateLdapName(newEntryDN != null ? newEntryDN : entryDN),
                ldapAttrs);

        if (newPosixRefAttrs != null && newPosixRefAttrs.isEmpty()) {
            checkRemovedPosixRefAttrs(posixMember.getPosixRefAttributes(),
                    posixMember.getPosixGroupMemberships());
        }

        if (status != null && status.getValue() != null && !status.getValue().isEmpty()) {
            StatusManagement.getInstance(
                    conn.getConfiguration().getStatusManagementClass()).
                    setStatus((Boolean) status.getValue().get(0),
                    ldapAttrs,
                    posixGroups,
                    ldapGroups);
        }

        // Update the attributes.
        modifyAttributes(entryDN, attrToModify, DirContext.REPLACE_ATTRIBUTE);

        // Rename the entry if needed.
        String oldEntryDN = null;

        if (newName != null) {
            if (newPosixRefAttrs != null && conn.getConfiguration().
                    isMaintainPosixGroupMembership() || posixGroups != null) {
                posixMember.getPosixRefAttributes();
            }
            oldEntryDN = entryDN;
            entryDN = conn.getSchemaMapping().rename(oclass, oldEntryDN, newName);
        }

        // Update the LDAP groups.
        final Modification ldapGroupMod = new Modification();

        if (oldEntryDN != null && conn.getConfiguration().isMaintainLdapGroupMembership()) {
            Set members = groupHelper.getLdapGroupMemberships(oldEntryDN);
            ldapGroupMod.removeAll(members);
            for (GroupMembership member : members) {
                ldapGroupMod.add(new GroupMembership(entryDN, member.getGroupDN()));
            }
        }

        if (ldapGroups != null) {
            Set members = groupHelper.getLdapGroupMemberships(entryDN);
            ldapGroupMod.removeAll(members);
            ldapGroupMod.clearAdded(); // Since we will be replacing with the new groups.
            for (String ldapGroup : ldapGroups) {
                ldapGroupMod.add(new GroupMembership(entryDN, ldapGroup));
            }
        }

        groupHelper.modifyLdapGroupMemberships(ldapGroupMod);

        // Update the POSIX groups.
        final Modification posixGroupMod = new Modification();

        if (newPosixRefAttrs != null && conn.getConfiguration().isMaintainPosixGroupMembership()) {
            Set removedPosixRefAttrs = new HashSet(posixMember.getPosixRefAttributes());
            removedPosixRefAttrs.removeAll(newPosixRefAttrs);
            Set members = posixMember.getPosixGroupMembershipsByAttrs(removedPosixRefAttrs);
            posixGroupMod.removeAll(members);
            if (!members.isEmpty()) {
                String firstPosixRefAttr = getFirstPosixRefAttr(entryDN, newPosixRefAttrs);
                for (GroupMembership member : members) {
                    posixGroupMod.add(new GroupMembership(firstPosixRefAttr, member.getGroupDN()));
                }
            }
        }

        if (posixGroups != null) {
            Set members = posixMember.getPosixGroupMemberships();
            posixGroupMod.removeAll(members);
            posixGroupMod.clearAdded(); // Since we will be replacing with the new groups.
            if (!posixGroups.isEmpty()) {
                String firstPosixRefAttr = getFirstPosixRefAttr(entryDN, newPosixRefAttrs);
                for (String posixGroup : posixGroups) {
                    posixGroupMod.add(new GroupMembership(firstPosixRefAttr, posixGroup));
                }
            }
        }

        groupHelper.modifyPosixGroupMemberships(posixGroupMod);

        return conn.getSchemaMapping().createUid(oclass, entryDN);
    }

    public Uid addAttributeValues(final Set attrs) {
        String entryDN = LdapSearches.findEntryDN(conn, oclass, uid);
        PosixGroupMember posixMember = new PosixGroupMember(entryDN);

        Pair attrsToModify = getAttributesToModify(attrs);
        modifyAttributes(entryDN, attrsToModify, DirContext.ADD_ATTRIBUTE);

        List ldapGroups = getStringListValue(attrs, LdapConstants.LDAP_GROUPS_NAME);
        if (!isEmpty(ldapGroups)) {
            groupHelper.addLdapGroupMemberships(entryDN, ldapGroups);
        }

        List posixGroups = getStringListValue(attrs, LdapConstants.POSIX_GROUPS_NAME);
        if (!isEmpty(posixGroups)) {
            Set posixRefAttrs = posixMember.getPosixRefAttributes();
            String posixRefAttr = getFirstPosixRefAttr(entryDN, posixRefAttrs);
            groupHelper.addPosixGroupMemberships(posixRefAttr, posixGroups);
        }

        return uid;
    }

    public Uid removeAttributeValues(final Set attrs) {
        String entryDN = LdapSearches.findEntryDN(conn, oclass, uid);
        PosixGroupMember posixMember = new PosixGroupMember(entryDN);

        Pair attrsToModify = getAttributesToModify(attrs);
        Attributes ldapAttrs = attrsToModify.first;

        Set removedPosixRefAttrs = getAttributeValues(GroupHelper.getPosixRefAttribute(), null, ldapAttrs);
        if (!isEmpty(removedPosixRefAttrs)) {
            checkRemovedPosixRefAttrs(removedPosixRefAttrs, posixMember.getPosixGroupMemberships());
        }

        modifyAttributes(entryDN, attrsToModify, DirContext.REMOVE_ATTRIBUTE);

        List ldapGroups = getStringListValue(attrs, LdapConstants.LDAP_GROUPS_NAME);
        if (!isEmpty(ldapGroups)) {
            groupHelper.removeLdapGroupMemberships(entryDN, ldapGroups);
        }

        List posixGroups = getStringListValue(attrs, LdapConstants.POSIX_GROUPS_NAME);
        if (!isEmpty(posixGroups)) {
            Set members = posixMember.getPosixGroupMembershipsByGroups(posixGroups);
            groupHelper.removePosixGroupMemberships(members);
        }

        return uid;
    }

    private void checkRemovedPosixRefAttrs(
            final Set removedPosixRefAttrs,
            final Set memberships) {

        for (GroupMembership membership : memberships) {
            if (removedPosixRefAttrs.contains(membership.getMemberRef())) {
                throw new ConnectorException(
                        conn.format("cannotRemoveBecausePosixMember", GroupHelper.getPosixRefAttribute()));
            }
        }
    }

    private Pair getAttributesToModify(final Set attrs) {
        BasicAttributes ldapAttrs = new BasicAttributes();
        GuardedPasswordAttribute pwdAttr = null;
        for (Attribute attr : attrs) {
            javax.naming.directory.Attribute ldapAttr = null;
            if (attr.is(Uid.NAME)) {
                throw new IllegalArgumentException("Unable to modify an object's uid");
            } else if (attr.is(Name.NAME)) {
                // Such a change would have been handled in update() above.
                throw new IllegalArgumentException("Unable to modify an object's name");
            } else if (LdapConstants.isLdapGroups(attr.getName())) {
                // Handled elsewhere.
            } else if (LdapConstants.isPosixGroups(attr.getName())) {
                // Handled elsewhere.
            } else if (attr.is(OperationalAttributes.PASSWORD_NAME)) {
                pwdAttr = conn.getSchemaMapping().encodePassword(oclass, attr);
            } else {
                ldapAttr = conn.getSchemaMapping().encodeAttribute(oclass, attr);
            }
            if (ldapAttr != null) {
                javax.naming.directory.Attribute existingAttr = ldapAttrs.get(ldapAttr.getID());
                if (existingAttr != null) {
                    try {
                        NamingEnumeration all = ldapAttr.getAll();
                        while (all.hasMoreElements()) {
                            existingAttr.add(all.nextElement());
                        }
                    } catch (NamingException e) {
                        throw new ConnectorException(e);
                    }
                } else {
                    ldapAttrs.put(ldapAttr);
                }
            }
        }
        return new Pair(ldapAttrs, pwdAttr);
    }

    private void modifyAttributes(final String entryDN, Pair attrs,
            final int ldapModifyOp) {

        final List modItems = new ArrayList(attrs.first.size());
        NamingEnumeration attrEnum = attrs.first.getAll();
        while (attrEnum.hasMoreElements()) {
            modItems.add(new ModificationItem(ldapModifyOp, attrEnum.nextElement()));
        }

        if (attrs.second != null) {
            attrs.second.access(new Accessor() {

                @Override
                public void access(javax.naming.directory.Attribute passwordAttr) {
                    // Do not add the password to the result Attributes because it is a guarded value.
                    hashPassword(passwordAttr, entryDN);
                    modItems.add(new ModificationItem(ldapModifyOp, passwordAttr));
                    modifyAttributes(entryDN, modItems);
                }
            });
        } else {
            modifyAttributes(entryDN, modItems);
        }
    }

    private void modifyAttributes(final String entryDN, final List modItems) {
        try {
            conn.getInitialContext().modifyAttributes(entryDN, modItems.toArray(new ModificationItem[modItems.size()]));
        } catch (NamingException e) {
            throw new ConnectorException(e);
        }
    }

    private List getStringListValue(final Set attrs, final String attrName) {
        Attribute attr = AttributeUtil.find(attrName, attrs);
        return attr == null ? null : checkedListByFilter(nullAsEmpty(attr.getValue()), String.class);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy