Package org.wso2.carbon.user.core.ldap

Source Code of org.wso2.carbon.user.core.ldap.ApacheDSUserStoreManager

/*
*  Copyright (c) 2005-2010, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
*  WSO2 Inc. licenses this file to you under the Apache License,
*  Version 2.0 (the "License"); you may not use this file except
*  in compliance with the License.
*  You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.wso2.carbon.user.core.ldap;

import org.apache.axiom.om.util.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.CarbonConstants;
import org.wso2.carbon.user.api.RealmConfiguration;
import org.wso2.carbon.user.core.Permission;
import org.wso2.carbon.user.core.UserCoreConstants;
import org.wso2.carbon.user.core.UserRealm;
import org.wso2.carbon.user.core.UserStoreException;
import org.wso2.carbon.user.core.claim.ClaimManager;
import org.wso2.carbon.user.core.claim.ClaimMapping;
import org.wso2.carbon.user.core.profile.ProfileConfigurationManager;
import org.wso2.carbon.user.core.tenant.Tenant;
import org.wso2.carbon.user.core.util.JNDIUtil;

import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
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.InvalidAttributeValueException;
import javax.naming.directory.NoSuchAttributeException;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

/**
* This class is responsible for manipulating ApacheDS data. This class provides
* facility to add/delete/modify/view user info in a directory server. The LDAPUserStoreManager
* only operates under read only mode. i.e. using LDAPUserStoreManager user is not allowed to
* do any modifications to data in directory server. But with ApacheDSUserStoreManager user
* can do modifications to directory server.
*/
public class ApacheDSUserStoreManager extends LDAPUserStoreManager {

    private static Log logger = LogFactory.getLog(ApacheDSUserStoreManager.class);
    public static final String PASSWORD_HASH_METHOD = "passwordHashMethod";
    public static final String PASSWORD_HASH_METHOD_SHA = "SHA";
    public static final String PASSWORD_HASH_METHOD_MD5 = "MD5";
    public static final String ATTR_NAME_CN = "cn";
    public static final String ATTR_NAME_SN = "sn";

    private static final String KRB5_PRINCIPAL_NAME_ATTRIBUTE = "krb5PrincipalName";
    private static final String KRB5_KEY_VERSION_NUMBER_ATTRIBUTE = "krb5KeyVersionNumber";

    private static Log log = LogFactory.getLog(ApacheDSUserStoreManager.class);

    private static final String EMPTY_ATTRIBUTE_STRING = "";

    private static String READ_LDAP_USER_GROUPS = null;
    private static String WRITE_LDAP_USER_GROUPS = null;
    private static String READ_ONLY = null;
    private static String USER_SEARCH_BASE = null;
    private static String GROUP_SEARCH_BASE = null;
    /*following is by default true since embedded-ldap allows it. If connected to an external ldap
    * where empty roles not allowed, then following property should be set accordingly
    * in user-mgt.xml*/
    private static boolean EMPTY_ROLES_ALLOWED = true;

    protected boolean kdcEnabled = false;

    public ApacheDSUserStoreManager(RealmConfiguration realmConfig,
                                    Map<String, Object> properties,
                                    ClaimManager claimManager,
                                    ProfileConfigurationManager profileManager,
                                    UserRealm realm,
                                    Integer tenantId) throws UserStoreException {

        super(realmConfig, properties, claimManager, profileManager, realm, tenantId);
        setKdcEnabled(realmConfig);
        //checkRequiredUserStoreConfiguration();
    }

    public ApacheDSUserStoreManager(RealmConfiguration realmConfig,
                                    ClaimManager claimManager,
                                    ProfileConfigurationManager profileManager)
            throws UserStoreException {
        super(realmConfig, claimManager, profileManager);
        setKdcEnabled(realmConfig);
        //checkRequiredUserStoreConfiguration();
    }

    protected void setKdcEnabled(RealmConfiguration realmConfig) {

        String stringKdcEnabled = realmConfig.getUserStoreProperty(
                UserCoreConstants.RealmConfig.PROPERTY_KDC_ENABLED);

        if (stringKdcEnabled != null) {
            this.kdcEnabled = Boolean.parseBoolean(stringKdcEnabled);
        }
    }

    public boolean isKdcEnabled() {
        return kdcEnabled;
    }

    public boolean isReadOnly() {
        return false;
    }

    private String getRealmName() {

        // First check whether realm name is defined in the configuration
        String defaultRealmName = this.realmConfig
                .getUserStoreProperty(UserCoreConstants.RealmConfig.DEFAULT_REALM_NAME);

        if (defaultRealmName != null) {
            return defaultRealmName;
        }

        // If not build the realm name from the search base.
        // Here the realm name will be a concatenation of dc components in the search base.
        String searchBase = this.realmConfig.getUserStoreProperty(LDAPConstants.USER_SEARCH_BASE);

        String[] domainComponents = searchBase.split("dc=");

        StringBuilder builder = new StringBuilder();

        int i = 0;
        for (String dc : domainComponents) {
            if (!dc.contains("=")) {
                String trimmedDc = dc.trim();
                if (trimmedDc.endsWith(",")) {
                    builder.append(trimmedDc.replace(',', '.'));
                } else {
                    builder.append(trimmedDc);
                }
            }
        }

        return builder.toString().toUpperCase(Locale.ENGLISH);
    }

    public void addUser(String userName, Object credential, String[] roleList,
                        Map<String, String> claims, String profileName) throws UserStoreException {
        this.addUser(userName, credential, roleList, claims, profileName, false);
    }

    public void addUser(String userName, Object credential, String[] roleList,
                        Map<String, String> claims, String profileName,
                        boolean requirePasswordChange) throws UserStoreException {

        if (!checkUserNameValid(userName)) {
            throw new UserStoreException(
                    "User name not valid. User name must be a non null string with following format, " +
                    realmConfig.getUserStoreProperty(UserCoreConstants.RealmConfig.PROPERTY_USER_NAME_JAVA_REG_EX));

        }

        if (!checkUserPasswordValid(credential)) {
            throw new UserStoreException(
                    "Credential not valid. Credential must be a non null string with following format, " +
                    realmConfig.getUserStoreProperty(UserCoreConstants.RealmConfig.PROPERTY_JAVA_REG_EX));

        }

        DirContext mainDirContext = this.connectionSource.getContext();
        DirContext dirContext = null;
        String searchBase = realmConfig.getUserStoreProperty(LDAPConstants.USER_SEARCH_BASE);
        try {

            dirContext = (DirContext) mainDirContext.lookup(searchBase);
            //above this the search base or base directory for this storage. we assume users
            // are stored under ou=users folder here

            BasicAttributes basicAttributes = new BasicAttributes(true);
            //read the object class for saving user entries in LDAP.
            String userObjectClass = realmConfig.getUserStoreProperty(
                    LDAPConstants.USER_ENTRY_OBJECT_CLASS);
            // set the objectClass type for schema
            BasicAttribute objectClass = new BasicAttribute(LDAPConstants.OBJECT_CLASS_NAME);
            objectClass.add(userObjectClass);

            //If KDC is enabled we have to set KDC specific object classes also
            if (isKdcEnabled()) {
                // Add Kerberos specific object classes
                objectClass.add("krb5principal");
                objectClass.add("krb5kdcentry");
                objectClass.add("subschema");
            }

            basicAttributes.put(objectClass);

            BasicAttribute uid = new BasicAttribute("uid");
            uid.add(userName);
            basicAttributes.put(uid);

            if (isKdcEnabled()) {
                String principal = userName + "@" + this.getRealmName();

                BasicAttribute principalAttribute = new BasicAttribute(KRB5_PRINCIPAL_NAME_ATTRIBUTE);
                principalAttribute.add(principal);
                basicAttributes.put(principalAttribute);

                BasicAttribute versionNumberAttribute = new BasicAttribute(KRB5_KEY_VERSION_NUMBER_ATTRIBUTE);
                versionNumberAttribute.add("0");
                basicAttributes.put(versionNumberAttribute);
            }

            BasicAttribute userPassword = new BasicAttribute("userPassword");
            userPassword.add(getPasswordToStore((String) credential,
                                                this.realmConfig.getUserStoreProperty(
                                                        PASSWORD_HASH_METHOD)));
            basicAttributes.put(userPassword);

            BasicAttribute claim;

            /*we keep boolean values to know whether compulsory attributes 'sn' and 'cn' are set
            during setting claims.*/
            boolean isSNExists = false;
            boolean isCNExists = false;

            for (Map.Entry<String, String> entry : claims.entrySet()) {
                /*LDAP does not allow for empty values. If an attribute has a value it’s stored
                 with the entry, otherwise it is not. Hence needs to check for empty values before
                 storing the attribute.*/
                if (EMPTY_ATTRIBUTE_STRING.equals(entry.getValue())) {
                    continue;
                }
                //needs to get attribute name from claim mapping
                String claimURI = entry.getKey();
                ClaimMapping claimMapping = null;
                claimMapping = (ClaimMapping) claimManager.getClaimMapping(claimURI);

                String attributeName = null;
                if (claimMapping != null) {
                    attributeName = claimMapping.getMappedAttribute();
                    if (ATTR_NAME_CN.equals(attributeName)) {
                        isCNExists = true;
                    } else if (ATTR_NAME_SN.equals(attributeName)) {
                        isSNExists = true;
                    }
                } else {
                    attributeName = claimURI;
                }
                claim = new BasicAttribute(attributeName);
                claim.add(claims.get(entry.getKey()));
                basicAttributes.put(claim);
            }
            //following attribute is not added to attributes. May be it could be removed.
            BasicAttribute isChangePassword = new BasicAttribute("requirePasswordChange");
            isChangePassword.add(requirePasswordChange);

            // If required attributes cn, sn are not set during claim mapping, set them as user names

            if (!isCNExists) {
                BasicAttribute cn = new BasicAttribute("cn");
                cn.add(userName);
                basicAttributes.put(cn);
            }

            if (!isSNExists) {
                BasicAttribute sn = new BasicAttribute("sn");
                sn.add(userName);
                basicAttributes.put(sn);
            }

            dirContext.bind("uid=" + userName, null, basicAttributes);

            if ((roleList != null) || (roleList.length != 0)) {
                //add user to role according to the group configuration in user-mgt.xml
                for (String role : roleList) {
                    if (("true".equals(READ_LDAP_USER_GROUPS)) &&
                        ("true".equals(WRITE_LDAP_USER_GROUPS))) {
                        if (!isInternalRole(role)) {
                            this.updateRoleListOfUser(userName, new String[]{}, new String[]{role});
                        } else if (isInternalRole(role)) {
                            this.hybridRoleManager.addHybridRole(role, new String[]{userName});
                        }
                    }
                    if (("false".equals(READ_LDAP_USER_GROUPS)) &&
                        ("false".equals(WRITE_LDAP_USER_GROUPS))
                        || (("true".equals(READ_LDAP_USER_GROUPS)) &&
                            ("false".equals(WRITE_LDAP_USER_GROUPS)))) {
                        this.hybridRoleManager.addHybridRole(role, new String[]{userName});
                    }
                }
            }

        } catch (NamingException e) {
            String errorMessage = "Can not access the directory context or" +
                                  "user already exists in the system";
            logger.error(errorMessage, e);
            throw new UserStoreException(errorMessage, e);
        } catch (org.wso2.carbon.user.api.UserStoreException e) {
            String errorMessage = "Error in obtaining claim mapping.";
            logger.error(errorMessage, e);
            throw new UserStoreException(errorMessage, e);
        } finally {
            JNDIUtil.closeContext(dirContext);
            JNDIUtil.closeContext(mainDirContext);
        }
    }

    private String getPasswordToStore(String password, String passwordHashMethod)
            throws UserStoreException {

        if (isKdcEnabled()) {
            // If KDC is enabled we will always use plain text passwords.
            // Cause - KDC cannot operate with hashed passwords.

            return password;
        }

        String passwordToStore = password;

        if (passwordHashMethod != null) {
            try {
                MessageDigest messageDigest = MessageDigest.getInstance(passwordHashMethod);
                byte[] digestValue = messageDigest.digest(password.getBytes());
                passwordToStore = "{" + passwordHashMethod + "}" + Base64.encode(digestValue);
            } catch (NoSuchAlgorithmException e) {
                throw new UserStoreException("Invalid hashMethod", e);
            }
        }
        return passwordToStore;
    }

    public void deleteUser(String userName) throws UserStoreException {

        if (realmConfig.getAdminUserName().equals(userName)) {
            throw new UserStoreException("Cannot delete admin user");
        }

        if (CarbonConstants.REGISTRY_ANONNYMOUS_USERNAME.equals(userName)) {
            throw new UserStoreException("Cannot delete anonymous user");
        }

        if (("false".equals(READ_LDAP_USER_GROUPS)) && ("false".equals(WRITE_LDAP_USER_GROUPS))
            || (("true".equals(READ_LDAP_USER_GROUPS)) &&
                ("false".equals(WRITE_LDAP_USER_GROUPS)))) {
            if (this.hybridRoleManager != null) {
                this.hybridRoleManager.deleteUser(userName);
            }
        }
        //delete user from LDAP group if read-write enabled.
        String userNameAttribute = realmConfig.getUserStoreProperty(
                LDAPConstants.USER_NAME_ATTRIBUTE_NAME);
        String searchFilter = realmConfig.getUserStoreProperty(LDAPConstants.USER_NAME_FILTER);
        searchFilter = searchFilter.replace("?", userName);
        String[] returningUserAttributes = new String[]{userNameAttribute};

        DirContext mainDirContext = this.connectionSource.getContext();

        NamingEnumeration<SearchResult> userResults = searchInUserBase(
                searchFilter, returningUserAttributes, SearchControls.SUBTREE_SCOPE, mainDirContext);
        NamingEnumeration<SearchResult> groupResults = null;

        DirContext subDirContext = null;
        try {
            SearchResult userResult = null;
            String userDN = null;
            // here we assume only one user
            // TODO: what to do if there are more than one user
            while (userResults.hasMore()) {
                userResult = userResults.next();
                userDN = userResult.getName();
            }

            if (("true".equals(READ_LDAP_USER_GROUPS)) &&
                ("true".equals(WRITE_LDAP_USER_GROUPS))) {
                String[] rolesOfUser = getRoleListOfUser(userName);

                if (rolesOfUser.length != 0) {
                    String roleNameSearchFilter = realmConfig.getUserStoreProperty(
                            LDAPConstants.ROLE_NAME_FILTER);
                    String[] returningGroupAttributes = new String[]{
                            realmConfig.getUserStoreProperty(LDAPConstants.MEMBERSHIP_ATTRIBUTE)};
                    for (String role : rolesOfUser) {
                        if (!isInternalRole(role)) {
                            String groupSearchFilter = roleNameSearchFilter.replace("?", role);
                            groupResults = searchInGroupBase(
                                    groupSearchFilter, returningGroupAttributes,
                                    SearchControls.SUBTREE_SCOPE, mainDirContext);
                            SearchResult groupResult = null;
                            while (groupResults.hasMore()) {
                                groupResult = groupResults.next();
                            }
                            if ((isOnlyUserInRole(userDN, groupResult)) && (!EMPTY_ROLES_ALLOWED)) {
                                String errorMessage = "User: " + userName + " is the only user " +
                                                      "in " + role + "." + "There should be at " +
                                                      "least one user" + " in the role. Hence can" +
                                                      " not delete the user.";
                                logger.error(errorMessage);
                                throw new UserStoreException(errorMessage);
                            }

                        }
                    }
                    for (String role : rolesOfUser) {
                        //no need to update entries related to internal roles when deleting user.
                        if (!isInternalRole(role)) {
                            updateRoleListOfUser(userName, new String[]{role}, new String[]{});
                        } else if (isInternalRole(role)) {
                            hybridRoleManager.deleteUser(userName);
                        }
                    }
                }
            }
            //delete user entry
            if (userResult.getAttributes().get(userNameAttribute).get().equals(userName)) {
                subDirContext = (DirContext) mainDirContext.lookup(USER_SEARCH_BASE);
                subDirContext.destroySubcontext(userDN);
            }
            this.userRealm.getAuthorizationManager().clearUserAuthorization(userName);
        } catch (NamingException e) {
            String errorMessage = "Error occurred while deleting the user. ";
            logger.error(errorMessage, e);
            throw new UserStoreException(errorMessage, e);
        } finally {
            JNDIUtil.closeNamingEnumeration(groupResults);
            JNDIUtil.closeNamingEnumeration(userResults);

            JNDIUtil.closeContext(subDirContext);
            JNDIUtil.closeContext(mainDirContext);
        }
    }

    public void updateCredential(String userName, Object newCredential, Object oldCredential)
            throws UserStoreException {
        DirContext dirContext = this.connectionSource.getContext();
        DirContext subDirContext = null;
        //first search the existing user entry.
        String searchBase = realmConfig.getUserStoreProperty(LDAPConstants.USER_SEARCH_BASE);
        String searchFilter = realmConfig.getUserStoreProperty(LDAPConstants.USER_NAME_FILTER);
        searchFilter = searchFilter.replace("?", userName);

        SearchControls searchControls = new SearchControls();
        searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
        searchControls.setReturningAttributes(new String[]{"userPassword"});

        NamingEnumeration<SearchResult> namingEnumeration = null;
        NamingEnumeration passwords = null;

        try {
            namingEnumeration = dirContext.search(
                    searchBase, searchFilter, searchControls);
            // here we assume only one user
            // TODO: what to do if there are more than one user
            SearchResult searchResult = null;
            while (namingEnumeration.hasMore()) {
                searchResult = namingEnumeration.next();
                Attributes attributes = searchResult.getAttributes();
                Attribute userPassword = attributes.get("userPassword");

                String passwordHashMethod = null;
                // when admin changes other user passwords he do not have to provide
                // the old password.
                if (oldCredential != null) {
                    // here it is only possible to have one password, if there are more
                    // every one should match with the given old password
                    passwords = userPassword.getAll();
                    if (passwords.hasMore()) {
                        byte[] byteArray = (byte[]) passwords.next();
                        String password = new String(byteArray);

                        if (password.startsWith("{")) {
                            passwordHashMethod = password.substring(password.indexOf("{") +
                                                                    1, password.indexOf("}"));
                        }

                        if (!password.equals(getPasswordToStore((String) oldCredential,
                                                                passwordHashMethod))) {
                            throw new UserStoreException("Old password does not match");
                        }
                    }
                }

                String dnName = searchResult.getName();
                subDirContext = (DirContext) dirContext.lookup(searchBase);

                Attribute passwordAttribute = new BasicAttribute("userPassword");
                passwordAttribute.add(getPasswordToStore((String) newCredential,
                                                         passwordHashMethod));
                BasicAttributes basicAttributes = new BasicAttributes(true);
                basicAttributes.put(passwordAttribute);
                subDirContext.modifyAttributes(dnName, DirContext.REPLACE_ATTRIBUTE,
                                               basicAttributes);
            }
            //we check whether both carbon admin entry and ldap connection entry are the same
            if (searchResult.getNameInNamespace().equals(realmConfig.getUserStoreProperty(
                    LDAPConstants.CONNECTION_NAME))) {
                this.connectionSource.updateCredential((String) newCredential);
            }

        } catch (NamingException e) {
            throw new UserStoreException("Can not access the directory service", e);
        } finally {
            JNDIUtil.closeNamingEnumeration(passwords);
            JNDIUtil.closeNamingEnumeration(namingEnumeration);

            JNDIUtil.closeContext(subDirContext);
            JNDIUtil.closeContext(dirContext);
        }
    }

    public Map<String, String> getProperties(Tenant tenant) throws UserStoreException {
        Map<String, String> existingProperties = this.realmConfig.getUserStoreProperties();
        String tenantSufix = getTenantSuffix(tenant.getDomain());
        String propertyName = null;
        Map<String, String> newProperties = new HashMap<String, String>();
        for (Map.Entry<String, String> iter : existingProperties.entrySet()) {
            propertyName = iter.getKey();
            if (propertyName.equals(LDAPConstants.USER_SEARCH_BASE)) {
                newProperties.put(propertyName, tenantSufix);
            } else {
                newProperties.put(propertyName, iter.getValue());
            }
        }
        return newProperties;
    }

    private String getTenantSuffix(String domain) {
        // here we use a simple algorithum by splitting the domain with .
        String[] domainParts = domain.split("\\.");
        StringBuffer suffixName = new StringBuffer();
        for (String domainPart : domainParts) {
            suffixName.append(",dc=").append(domainPart);
        }
        return suffixName.toString().replaceFirst(",", "");
    }

    /**
     * This method overwrites the method in LDAPUserStoreManager. This implements the functionality
     * of updating user's profile information in LDAP user store.
     *
     * @param userName
     * @param claims
     * @param profileName
     * @throws UserStoreException
     */
    public void setUserClaimValues(String userName, Map<String, String> claims, String profileName)
            throws UserStoreException {

        //get the LDAP Directory context
        DirContext dirContext = this.connectionSource.getContext();
        DirContext subDirContext = null;
        //search the relevant user entry by user name
        String userSearchBase = realmConfig.getUserStoreProperty(LDAPConstants.USER_SEARCH_BASE);
        String userSearchFilter = realmConfig.getUserStoreProperty(LDAPConstants.USER_NAME_FILTER);
        userSearchFilter = userSearchFilter.replace("?", userName);

        SearchControls searchControls = new SearchControls();
        searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
        searchControls.setReturningAttributes(null);

        NamingEnumeration<SearchResult> returnedResultList = null;
        String returnedUserEntry = null;

        try {

            returnedResultList = dirContext.search(userSearchBase, userSearchFilter,
                                                   searchControls);
            //assume only one user is returned from the search
            //TODO:what if more than one user is returned
            returnedUserEntry = returnedResultList.next().getName();

        } catch (NamingException e) {

            throw new UserStoreException("Results could not be retrieved from the directory " +
                                         "context", e);
        } finally {
            JNDIUtil.closeNamingEnumeration(returnedResultList);
        }


        if (profileName == null) {

            profileName = UserCoreConstants.DEFAULT_PROFILE;
        }

        if (claims.get(UserCoreConstants.PROFILE_CONFIGURATION) == null) {

            claims.put(UserCoreConstants.PROFILE_CONFIGURATION, UserCoreConstants.
                    DEFAULT_PROFILE_CONFIGURATION);
        }
        try {
            Attributes updatedAttributes = new BasicAttributes(true);
            for (Map.Entry<String, String> claimEntry : claims.entrySet()) {
                String claimURI = claimEntry.getKey();
                //if there is no attribute for profile configuration in LDAP, skip updating it.
                if (claimURI.equals(UserCoreConstants.PROFILE_CONFIGURATION)) {
                    continue;
                }
                //get the claimMapping related to this claimURI
                ClaimMapping claimMapping = (ClaimMapping) claimManager.getClaimMapping(claimURI);
                String attributeName = null;

                if (claimMapping != null) {
                    attributeName = claimMapping.getMappedAttribute();
                } else {
                    attributeName = claimURI;
                }
                Attribute currentUpdatedAttribute = new BasicAttribute(attributeName);
                /*if updated attribute value is null, remove its values.*/
                if (EMPTY_ATTRIBUTE_STRING.equals(claimEntry.getValue())) {
                    currentUpdatedAttribute.clear();
                } else {
                    currentUpdatedAttribute.add(claimEntry.getValue());
                }
                updatedAttributes.put(currentUpdatedAttribute);
            }
            //update the attributes in the relevant entry of the directory store

            subDirContext = (DirContext) dirContext.lookup(userSearchBase);
            subDirContext.modifyAttributes(returnedUserEntry, DirContext.REPLACE_ATTRIBUTE, updatedAttributes);

        } catch (InvalidAttributeValueException e) {
            String errorMessage = "One or more attribute values provided are incompatible. " +
                                  "Please check and try again.";
            logger.error(errorMessage, e);
            throw new UserStoreException(errorMessage, e);

        } catch (NoSuchAttributeException e) {
            String errorMessage = "One or more attributes you are trying to add/update are not " +
                                  "supported by underlying LDAP.";
            logger.error(errorMessage, e);
            throw new UserStoreException(errorMessage, e);

        } catch (NamingException e) {
            String errorMessage = "Profile information could not be updated in ApacheDS " +
                                  "LDAP user store";
            logger.error(errorMessage, e);
            throw new UserStoreException(errorMessage, e);

        } catch (org.wso2.carbon.user.api.UserStoreException e) {
            String errorMessage = "Error in obtaining claim mapping.";
            logger.error(errorMessage, e);
            throw new UserStoreException(errorMessage, e);
        } finally {
            JNDIUtil.closeContext(subDirContext);
            JNDIUtil.closeContext(dirContext);
        }

    }

    /**
     * Add roles by writing groups to LDAP.
     *
     * @param roleName
     * @param userList
     * @param permissions
     * @throws UserStoreException
     */
    @Override
    public void addRole(String roleName, String[] userList, Permission[] permissions)
            throws UserStoreException {
        //internal roles are managed in UM_DB or code.
        if ((isInternalRole(roleName)) || (("false".equals(READ_LDAP_USER_GROUPS)) &&
                                           ("false".equals(WRITE_LDAP_USER_GROUPS)))) {
            hybridRoleManager.addHybridRole(roleName, userList);
            return;
        }
        //check group read-write settings and execute super method as appropriate.
        if (("true".equals(READ_LDAP_USER_GROUPS)) && ("false".equals(WRITE_LDAP_USER_GROUPS))) {
            super.addRole(roleName, userList, permissions);
            return;
        }
        if (("true".equals(READ_LDAP_USER_GROUPS)) && ("true".equals(WRITE_LDAP_USER_GROUPS))) {
            //check whether role name is valid.
            if (!roleNameValid(roleName)) {
                String roleNameRegEx = realmConfig.getUserStoreProperty(
                        UserCoreConstants.RealmConfig.PROPERTY_ROLE_NAME_JAVA_REG_EX);
                String errorMsg = "Role name not valid. Role name must be a non null string " +
                                  "with following format, " + roleNameRegEx;

                logger.error(errorMsg);
                throw new UserStoreException(errorMsg);
            }
            if (isExistingRole(roleName)) {
                String errorMessage = "Can not add the role. Role name: " + roleName +
                                      " already exists.";
                logger.error(errorMessage);
                throw new UserStoreException(errorMessage);
            } else {
                /*there should be at least one member for an LDAP group if EMPTY_ROLES_ALLOWED is false.*/
                if (((userList == null) || (userList.length == 0)) && (!EMPTY_ROLES_ALLOWED)) {
                    String errorMessage = "Can not create empty role. There should be at least " +
                                          "one user for the role.";
                    logger.error(errorMessage);
                    throw new UserStoreException(errorMessage);

                } else if (((userList == null) && (EMPTY_ROLES_ALLOWED)) ||
                           ((userList.length > 0) && (!EMPTY_ROLES_ALLOWED)) ||
                           (EMPTY_ROLES_ALLOWED)) {
                    //if (userList.length > 0) {
                    DirContext mainDirContext = this.connectionSource.getContext();
                    DirContext groupContext = null;
                    NamingEnumeration<SearchResult> results = null;

                    try {
                        //create the attribute set for group entry
                        Attributes groupAttributes = new BasicAttributes(true);

                        //create group entry's object class attribute
                        Attribute objectClassAttribute = new BasicAttribute(
                                LDAPConstants.OBJECT_CLASS_NAME);
                        objectClassAttribute.add(realmConfig.getUserStoreProperty(
                                LDAPConstants.GROUP_ENTRY_OBJECT_CLASS));
                        groupAttributes.put(objectClassAttribute);

                        //create cn attribute
                        String groupNameAttributeName = realmConfig.getUserStoreProperties().get(
                                LDAPConstants.ROLE_NAME_ATTRIBUTE_NAME);
                        Attribute cnAttribute = new BasicAttribute(groupNameAttributeName);
                        cnAttribute.add(roleName);
                        groupAttributes.put(cnAttribute);
                        //following check is for if EMPTY_ROLES_ALLOWED made this code executed.
                        if ((userList != null) && (userList.length > 0)) {
                            String memberAttributeName = realmConfig.getUserStoreProperty(
                                    LDAPConstants.MEMBERSHIP_ATTRIBUTE);
                            Attribute memberAttribute = new BasicAttribute(memberAttributeName);
                            for (String userName : userList) {
                                //search the user in user search base
                                String searchFilter = realmConfig.getUserStoreProperty(
                                        LDAPConstants.USER_NAME_FILTER);
                                searchFilter = searchFilter.replace("?", userName);
                                results =
                                        searchInUserBase(searchFilter, new String[]{},
                                                         SearchControls.SUBTREE_SCOPE, mainDirContext);
                                //we assume only one user with the given user name under user search base.
                                SearchResult userResult = null;
                                if (results.hasMore()) {
                                    userResult = results.next();
                                } else {
                                    String errorMsg = "There is no user with the user name: " +
                                                      userName + " to be added to this role.";
                                    logger.error(errorMsg);
                                    throw new UserStoreException(errorMsg);
                                }
                                //get his DN
                                String userEntryDN = userResult.getNameInNamespace();
                                //put it as member-attribute value
                                memberAttribute.add(userEntryDN);
                            }
                            groupAttributes.put(memberAttribute);
                        }

                        groupContext = (DirContext) mainDirContext.lookup(GROUP_SEARCH_BASE);
                        groupContext.bind(groupNameAttributeName + "=" + roleName, null,
                                          groupAttributes);
                        //if permissions are assigned to role, add permission.
                        if (permissions != null) {
                            for (Permission permission : permissions) {
                                String resourceId = permission.getResourceId();
                                String action = permission.getAction();
                                userRealm.getAuthorizationManager().authorizeRole(
                                        roleName, resourceId, action);
                            }
                        }

                    } catch (NamingException e) {
                        String errorMsg = "Role: " + roleName + "could not be added.";
                        logger.error(errorMsg, e);
                        throw new UserStoreException(errorMsg, e);

                    } catch (Exception e) {
                        String errorMsg = "Role: " + roleName + "could not be added.";
                        logger.error(errorMsg, e);
                        throw new UserStoreException(errorMsg, e);
                    } finally {
                        JNDIUtil.closeNamingEnumeration(results);
                        JNDIUtil.closeContext(groupContext);
                        JNDIUtil.closeContext(mainDirContext);
                    }

                }

            }

        }
    }

    /**
     * Update role list of user by writting to LDAP.
     *
     * @param userName
     * @param deletedRoles
     * @param newRoles
     * @throws UserStoreException
     */
    @Override
    public void updateRoleListOfUser(String userName, String[] deletedRoles, String[] newRoles)
            throws UserStoreException {

        if (("false".equals(READ_LDAP_USER_GROUPS)) && ("false".equals(WRITE_LDAP_USER_GROUPS)) ||
            (("true".equals(READ_LDAP_USER_GROUPS)) && ("false".equals(WRITE_LDAP_USER_GROUPS)))) {
            hybridRoleManager.updateHybridRoleListOfUser(userName, deletedRoles, newRoles);
        }
        if (("true".equals(READ_LDAP_USER_GROUPS)) && ("true".equals(WRITE_LDAP_USER_GROUPS))) {
            //check whether everyone role is trying to be deleted,
            if (deletedRoles != null) {
                Arrays.sort(deletedRoles);
                if (Arrays.binarySearch(deletedRoles, realmConfig.getEveryOneRoleName()) > -1) {
                    log.error("An attempt to remove " + userName + " user from Everyone role ");
                    throw new UserStoreException("Everyone role is not updatable");
                }
            }
            // check whether admin role is trying to be deleted from admin user.
            if (deletedRoles != null) {
                Arrays.sort(deletedRoles);
                if (realmConfig.getAdminUserName().equals(userName)
                    && Arrays.binarySearch(deletedRoles, realmConfig.getAdminRoleName()) > -1) {
                    log.error("An attempt to remove Admin user from Admin role ");
                    throw new UserStoreException("Cannot remove Admin user from Admin role");
                }
            }
            //get the DN of the user entry
            String userNameDN = this.getNameInSpaceForUserName(userName);
            String membershipAttribute = realmConfig.getUserStoreProperty(
                    LDAPConstants.MEMBERSHIP_ATTRIBUTE);

            /*check deleted roles and delete member entries from relevant groups.*/
            String errorMessage = null;
            String searchFilter = realmConfig.getUserStoreProperty(LDAPConstants.ROLE_NAME_FILTER);
            String roleSearchFilter = null;

            DirContext mainDirContext = this.connectionSource.getContext();

            try {
                if (deletedRoles.length != 0) {
                    //perform validation for empty role occurrences before updating in LDAP
                    for (String deletedRole : deletedRoles) {
                        roleSearchFilter = searchFilter.replace("?", deletedRole);
                        String[] returningAttributes = new String[]{membershipAttribute};

                        NamingEnumeration<SearchResult> groupResults = searchInGroupBase(
                                roleSearchFilter, returningAttributes, SearchControls.SUBTREE_SCOPE,
                                mainDirContext);
                        SearchResult resultedGroup = null;
                        if (groupResults.hasMore()) {
                            resultedGroup = groupResults.next();
                        }
                        if ((isOnlyUserInRole(userNameDN, resultedGroup)) &&
                            (!EMPTY_ROLES_ALLOWED)) {
                            errorMessage = userName + " is the only user in the role: "
                                           + deletedRole + ". Hence can not delete user from role.";
                            logger.error(errorMessage);
                            throw new UserStoreException(errorMessage);
                        }

                        JNDIUtil.closeNamingEnumeration(groupResults);
                    }
                    //if empty role violation does not happen, continue updating the LDAP.
                    for (String deletedRole : deletedRoles) {
                        if (isExistingRole(deletedRole)) {
                            roleSearchFilter = searchFilter.replace("?", deletedRole);
                            String[] returningAttributes = new String[]{membershipAttribute};

                            NamingEnumeration<SearchResult> groupResults = searchInGroupBase(
                                    roleSearchFilter, returningAttributes,
                                    SearchControls.SUBTREE_SCOPE, mainDirContext);
                            SearchResult resultedGroup = null;
                            String groupDN = null;
                            if (groupResults.hasMore()) {
                                resultedGroup = groupResults.next();
                                groupDN = resultedGroup.getName();
                            }
                            this.modifyUserInRole(userNameDN, groupDN, DirContext.REMOVE_ATTRIBUTE);

                            JNDIUtil.closeNamingEnumeration(groupResults);

                        } else {
                            errorMessage = "The role: " + deletedRole + " does not exist.";
                            logger.error(errorMessage);
                            throw new UserStoreException(errorMessage);
                        }
                    }
                }
                if (newRoles.length != 0) {
                    for (String newRole : newRoles) {
                        if (isExistingRole(newRole)) {
                            roleSearchFilter = searchFilter.replace("?", newRole);
                            String[] returningAttributes = new String[]{membershipAttribute};

                            NamingEnumeration<SearchResult> groupResults = searchInGroupBase(
                                    roleSearchFilter, returningAttributes,
                                    SearchControls.SUBTREE_SCOPE, mainDirContext);
                            SearchResult resultedGroup = null;
                            //assume only one group with given group name
                            String groupDN = null;
                            if (groupResults.hasMore()) {
                                resultedGroup = groupResults.next();
                                groupDN = resultedGroup.getName();
                            }
                            if (!isUserInRole(userNameDN, resultedGroup)) {
                                modifyUserInRole(userNameDN, groupDN, DirContext.ADD_ATTRIBUTE);
                            } else {
                                errorMessage = "User: " + userName +
                                               " already belongs to role: " + groupDN;
                                logger.error(errorMessage);
                                throw new UserStoreException(errorMessage);
                            }

                            JNDIUtil.closeNamingEnumeration(groupResults);

                        } else {
                            errorMessage = "The role: " + newRole + " does not exist.";
                            logger.error(errorMessage);
                            throw new UserStoreException(errorMessage);
                        }
                    }
                }

            } catch (NamingException e) {
                errorMessage = "Error occurred while modifying the role list of user: " + userName;
                logger.error(errorMessage);
                throw new UserStoreException(errorMessage);
            } finally {
                JNDIUtil.closeContext(mainDirContext);
            }
        }

    }

    /**
     * Update the set of users belong to a LDAP role.
     *
     * @param roleName
     * @param deletedUsers
     * @param newUsers
     */
    @Override
    public void updateUserListOfRole(String roleName, String[] deletedUsers, String[] newUsers)
            throws UserStoreException {
        if (("false".equals(READ_LDAP_USER_GROUPS)) && ("false".equals(WRITE_LDAP_USER_GROUPS)) ||
            (("true".equals(READ_LDAP_USER_GROUPS)) && ("false".equals(WRITE_LDAP_USER_GROUPS)))) {
            hybridRoleManager.updateUserListOfHybridRole(roleName, deletedUsers, newUsers);
        }
        if (("true".equals(READ_LDAP_USER_GROUPS)) && ("true".equals(WRITE_LDAP_USER_GROUPS))) {
            if (realmConfig.getEveryOneRoleName().equals(roleName)) {
                throw new UserStoreException("Everyone role is not updatable");
            }

            if (deletedUsers != null) {
                Arrays.sort(deletedUsers);
                if (realmConfig.getAdminRoleName().equals(roleName)
                    && Arrays.binarySearch(deletedUsers, realmConfig.getAdminUserName()) > -1) {
                    log.error("An attempt to remove Admin user from Admin role ");
                    throw new UserStoreException("Cannot remove Admin user from Admin role");
                }
            }
            String errorMessage = null;
            NamingEnumeration<SearchResult> groupSearchResults = null;

            if (isExistingRole(roleName)) {

                DirContext mainDirContext = this.connectionSource.getContext();

                try {
                    String searchFilter = realmConfig.getUserStoreProperty(
                            LDAPConstants.ROLE_NAME_FILTER);
                    searchFilter = searchFilter.replace("?", roleName);
                    String membershipAttributeName = realmConfig.getUserStoreProperty(
                            LDAPConstants.MEMBERSHIP_ATTRIBUTE);
                    String[] returningAttributes = new String[]{membershipAttributeName};

                    groupSearchResults = searchInGroupBase(
                            searchFilter, returningAttributes, SearchControls.SUBTREE_SCOPE, mainDirContext);
                    SearchResult resultedGroup = null;
                    String groupName = null;
                    while (groupSearchResults.hasMoreElements()) {
                        resultedGroup = groupSearchResults.next();
                        groupName = resultedGroup.getName();
                    }
                    //check whether update operations are going to violate non empty role
                    // restriction specified in user-mgt.xml by
                    //checking whether all users are trying to be deleted before updating LDAP.
                    Attribute returnedMemberAttribute = resultedGroup.getAttributes().get(
                            membershipAttributeName);
                    if ((!EMPTY_ROLES_ALLOWED) && (((newUsers.length - deletedUsers.length) +
                                                    returnedMemberAttribute.size()) == 0)) {
                        errorMessage = "There should be at least one member in the role. " +
                                       "Hence can not delete all the members.";
                        logger.error(errorMessage);
                        throw new UserStoreException(errorMessage);

                    } else {
                        if (newUsers.length != 0) {
                            for (String newUser : newUsers) {
                                String userNameDN = getNameInSpaceForUserName(newUser);
                                if (!isUserInRole(userNameDN, resultedGroup)) {
                                    modifyUserInRole(userNameDN, groupName, DirContext.ADD_ATTRIBUTE);
                                } else {
                                    errorMessage = "User: " + newUser +
                                                   " already belongs to role: " + roleName;
                                    logger.error(errorMessage);
                                    throw new UserStoreException(errorMessage);
                                }
                            }
                        }

                        if (deletedUsers != null && deletedUsers.length != 0) {
                            for (String deletedUser : deletedUsers) {
                                String userNameDN = getNameInSpaceForUserName(deletedUser);
                                modifyUserInRole(userNameDN, groupName, DirContext.REMOVE_ATTRIBUTE);
                            }
                        }
                    }
                } catch (NamingException e) {

                    errorMessage = "Error occurred while modifying the user list of role: " +
                                   roleName;
                    logger.error(errorMessage);
                    throw new UserStoreException(errorMessage);
                } finally {
                    JNDIUtil.closeNamingEnumeration(groupSearchResults);
                    JNDIUtil.closeContext(mainDirContext);
                }
            } else {
                errorMessage = "The role: " + roleName + " does not exist.";
                logger.error(errorMessage);
                throw new UserStoreException(errorMessage);
            }


        }


    }

    /**
     * @param roleName
     * @return
     * @throws UserStoreException
     */
    @Override
    public boolean isExistingRole(String roleName) throws UserStoreException {
        boolean isExistingRole = false;
        //internal roles are managed in UM_DB or code.
        if ((isInternalRole(roleName)) || (("false".equals(READ_LDAP_USER_GROUPS)) &&
                                           ("false".equals(WRITE_LDAP_USER_GROUPS)))) {
            return hybridRoleManager.isExistingRole(roleName);
        }
        //check group read-write settings and execute super method as appropriate.
        if (("true".equals(READ_LDAP_USER_GROUPS)) && ("false".equals(WRITE_LDAP_USER_GROUPS)) ||
            (("true".equals(READ_LDAP_USER_GROUPS)) && ("true".equals(WRITE_LDAP_USER_GROUPS)))) {
            return super.isExistingRole(roleName);
        }
        return isExistingRole;
    }

    /**
     * Either delete or add user from/to group.
     *
     * @param userNameDN : distinguish name of user entry.
     * @param groupRDN   : relative distinguish name of group entry
     * @param modifyType : modify attribute type in DirCOntext.
     * @throws UserStoreException
     */
    protected void modifyUserInRole(String userNameDN, String groupRDN, int modifyType)
            throws UserStoreException {
        DirContext mainDirContext = null;
        DirContext groupContext = null;
        try {
            mainDirContext = this.connectionSource.getContext();
            groupContext = (DirContext) mainDirContext.lookup(GROUP_SEARCH_BASE);
            String memberAttributeName = realmConfig.getUserStoreProperty(
                    LDAPConstants.MEMBERSHIP_ATTRIBUTE);
            Attributes modifyingAttributes = new BasicAttributes(true);
            Attribute memberAttribute = new BasicAttribute(memberAttributeName);
            memberAttribute.add(userNameDN);
            modifyingAttributes.put(memberAttribute);
            groupContext.modifyAttributes(groupRDN, modifyType, modifyingAttributes);
            if (log.isDebugEnabled()) {
                logger.debug("Member attribute value: " + userNameDN + " was successfully " +
                             "modified in LDAP group: " + groupRDN);
            }
        } catch (NamingException e) {
            String errorMessage = "Error occurred while modifying user entry: " + userNameDN +
                                  " in LDAP role: " + groupRDN;
            logger.error(errorMessage, e);
            throw new UserStoreException(errorMessage, e);
        } finally {
            JNDIUtil.closeContext(groupContext);
            JNDIUtil.closeContext(mainDirContext);
        }
    }

    /**
     * Check whether user is in the group by searching through its member attributes.
     *
     * @param userDN
     * @param groupEntry
     * @return
     * @throws UserStoreException
     */
    protected boolean isUserInRole(String userDN, SearchResult groupEntry)
            throws UserStoreException {
        boolean isUserInRole = false;
        try {
            Attributes groupAttributes = groupEntry.getAttributes();
            if (groupAttributes != null) {
                //get group's returned attributes
                NamingEnumeration attributes = groupAttributes.getAll();
                //loop through attributes
                while (attributes.hasMoreElements()) {
                    Attribute memberAttribute = (Attribute) attributes.next();
                    String memberAttributeName = realmConfig.getUserStoreProperty(
                            LDAPConstants.MEMBERSHIP_ATTRIBUTE);
                    if ((memberAttributeName).equals(memberAttribute.getID())) {
                        //loop through attribute values
                        for (int i = 0; i < memberAttribute.size(); i++) {
                            if (userDN.equals(memberAttribute.get(i))) {
                                return true;
                            }
                        }
                    }

                }

                attributes.close();
            }
        } catch (NamingException e) {
            String errorMessage = "Error occurred while looping through attributes set of group: " +
                                  groupEntry.getNameInNamespace();
            logger.error(errorMessage, e);
            throw new UserStoreException(errorMessage, e);
        }
        return isUserInRole;
    }

    /**
     * Check whether this is the last/only user in this group.
     *
     * @param userDN
     * @param groupEntry
     * @return
     */
    protected boolean isOnlyUserInRole(String userDN, SearchResult groupEntry) throws
                                                                               UserStoreException {
        boolean isOnlyUserInRole = false;
        try {
            Attributes groupAttributes = groupEntry.getAttributes();
            if (groupAttributes != null) {
                NamingEnumeration attributes = groupAttributes.getAll();
                while (attributes.hasMoreElements()) {
                    Attribute memberAttribute = (Attribute) attributes.next();
                    String memberAttributeName = realmConfig.getUserStoreProperty(
                            LDAPConstants.MEMBERSHIP_ATTRIBUTE);
                    String attributeID = memberAttribute.getID();
                    if ((memberAttributeName).equals(attributeID)) {
                        if ((memberAttribute.size() == 1) && (userDN.equals(
                                memberAttribute.get()))) {
                            return true;
                        }
                    }

                }

                attributes.close();

            }
        } catch (NamingException e) {
            String errorMessage = "Error occurred while looping through attributes set of group: " +
                                  groupEntry.getNameInNamespace();
            logger.error(errorMessage, e);
            throw new UserStoreException(errorMessage, e);
        }
        return isOnlyUserInRole;
    }

    @Override
    public void updateRoleName(String roleName, String newRoleName) throws UserStoreException {
        if (("false".equals(READ_LDAP_USER_GROUPS)) && ("false".equals(WRITE_LDAP_USER_GROUPS)) ||
            (("true".equals(READ_LDAP_USER_GROUPS)) && ("false".equals(WRITE_LDAP_USER_GROUPS)))) {
            hybridRoleManager.updateHybridRoleName(roleName, newRoleName);
        }
        if (("true".equals(READ_LDAP_USER_GROUPS)) && ("true".equals(WRITE_LDAP_USER_GROUPS))) {
            //admin role and everyone role are not editable.
            if (realmConfig.getAdminRoleName().equals(roleName)) {
                throw new UserStoreException("Cannot rename admin role");
            }
            if (realmConfig.getEveryOneRoleName().equals(roleName)) {
                throw new UserStoreException("Cannot rename everyone role");
            }
            if (isExistingRole(newRoleName)) {
                throw new UserStoreException(
                        "Duplicate role name in the system. Please pick another name");
            } else if (!isExistingRole(newRoleName)) {
                DirContext mainContext = this.connectionSource.getContext();
                DirContext groupContext = null;
                NamingEnumeration<SearchResult> groupSearchResults = null;

                try {
                    String groupSearchFilter = realmConfig.getUserStoreProperty(
                            LDAPConstants.ROLE_NAME_FILTER);
                    groupSearchFilter = groupSearchFilter.replace("?", roleName);
                    String roleNameAttributeName = realmConfig.getUserStoreProperty(
                            LDAPConstants.ROLE_NAME_ATTRIBUTE_NAME);
                    String[] returningAttributes = {roleNameAttributeName};

                    //DirContext mainDirContext = this.connectionSource.getContext();

                    groupSearchResults = searchInGroupBase(
                            groupSearchFilter, returningAttributes, SearchControls.SUBTREE_SCOPE, mainContext);
                    SearchResult resultedGroup = null;
                    while (groupSearchResults.hasMoreElements()) {
                        resultedGroup = groupSearchResults.next();
                    }

                    if (resultedGroup == null) {
                        throw new UserStoreException("Could not find user role " + roleName + " in LDAP server.");
                    }

                    String groupNameRDN = resultedGroup.getName();
                    String newGroupNameRDN = roleNameAttributeName + "=" + newRoleName;

                    groupContext = (DirContext) mainContext.lookup(GROUP_SEARCH_BASE);
                    groupContext.rename(groupNameRDN, newGroupNameRDN);
                    this.userRealm.getAuthorizationManager().resetPermissionOnUpdateRole(roleName,
                                                                                         newRoleName);
                } catch (NamingException e) {
                    String errorMessage = "Error occurred while modifying the name of role: " +
                                          roleName;
                    logger.error(errorMessage, e);
                    throw new UserStoreException(errorMessage, e);
                } finally {
                    JNDIUtil.closeNamingEnumeration(groupSearchResults);
                    JNDIUtil.closeContext(groupContext);
                    JNDIUtil.closeContext(mainContext);
                }
            }
        }

    }

    /**
     * Delete LDAP group corresponding to the role.
     *
     * @param roleName The role to delete.
     * @throws UserStoreException In case if an error occurred while deleting a role.
     */
    @Override
    public void deleteRole(String roleName) throws UserStoreException {
        if (("false".equals(READ_LDAP_USER_GROUPS)) && ("false".equals(WRITE_LDAP_USER_GROUPS)) ||
            (("true".equals(READ_LDAP_USER_GROUPS)) && ("false".equals(WRITE_LDAP_USER_GROUPS)))) {
            hybridRoleManager.deleteHybridRole(roleName);
        }
        if (("true".equals(READ_LDAP_USER_GROUPS)) && ("true".equals(WRITE_LDAP_USER_GROUPS))) {
            //admin role and everyone role are not editable.
            if (realmConfig.getAdminRoleName().equals(roleName)) {
                throw new UserStoreException("Cannot delete admin role.");
            }
            if (realmConfig.getEveryOneRoleName().equals(roleName)) {
                throw new UserStoreException("Cannot delete everyone role.");
            }
            if (isExistingRole(roleName)) {
                DirContext mainDirContext = null;
                DirContext groupContext = null;
                NamingEnumeration<SearchResult> groupSearchResults = null;

                try {
                    String groupSearchFilter = realmConfig.getUserStoreProperty(
                            LDAPConstants.ROLE_NAME_FILTER);
                    groupSearchFilter = groupSearchFilter.replace("?", roleName);
                    String[] returningAttributes = {realmConfig.getUserStoreProperty(
                            LDAPConstants.ROLE_NAME_ATTRIBUTE_NAME)};

                    mainDirContext = this.connectionSource.getContext();

                    groupSearchResults = searchInGroupBase(
                            groupSearchFilter, returningAttributes, SearchControls.SUBTREE_SCOPE, mainDirContext);
                    SearchResult resultedGroup = null;
                    while (groupSearchResults.hasMoreElements()) {
                        resultedGroup = groupSearchResults.next();
                    }

                    if (resultedGroup == null) {
                        throw new UserStoreException("Could not find specified group/role - " + roleName);
                    }

                    String groupName = resultedGroup.getName();

                    groupContext = (DirContext) mainDirContext.lookup(GROUP_SEARCH_BASE);
                    String groupNameAttributeValue = (String) resultedGroup.getAttributes().get(
                            realmConfig.getUserStoreProperty(
                                    LDAPConstants.ROLE_NAME_ATTRIBUTE_NAME)).get();
                    if (groupNameAttributeValue.equals(roleName)) {
                        groupContext.destroySubcontext(groupName);
                    }
                    this.userRealm.getAuthorizationManager().clearRoleAuthorization(roleName);

                } catch (NamingException e) {
                    String errorMessage = ("Error occurred while deleting the role: " + roleName);
                    logger.error(errorMessage, e);
                    throw new UserStoreException(errorMessage, e);
                } finally {
                    JNDIUtil.closeNamingEnumeration(groupSearchResults);
                    JNDIUtil.closeContext(groupContext);
                    JNDIUtil.closeContext(mainDirContext);
                }

            } else {
                String errorMessage = ("Role name: " + roleName + " does not exist in group base.");
                logger.error(errorMessage);
                throw new UserStoreException(errorMessage);
            }
        }
    }

    /**
     * Reused methods to search users with various filters
     *
     * @param searchFilter
     * @param returningAttributes
     * @param searchScope
     * @return
     */
    private NamingEnumeration<SearchResult> searchInUserBase(String searchFilter,
                                                             String[] returningAttributes,
                                                             int searchScope, DirContext rootContext)
            throws UserStoreException {
        String userBase = realmConfig.getUserStoreProperty(LDAPConstants.USER_SEARCH_BASE);
        SearchControls userSearchControl = new SearchControls();
        userSearchControl.setReturningAttributes(returningAttributes);
        userSearchControl.setSearchScope(searchScope);
        NamingEnumeration<SearchResult> userSearchResults = null;

        try {
            userSearchResults = rootContext.search(
                    userBase, searchFilter, userSearchControl);
        } catch (NamingException e) {
            String errorMessage = "Error occurred while searching in user base.";
            logger.error(errorMessage, e);
            throw new UserStoreException(errorMessage, e);
        }

        return userSearchResults;

    }

    /**
     * Reused method to search groups with various filters.
     *
     * @param searchFilter
     * @param returningAttributes
     * @param searchScope
     * @return
     */
    private NamingEnumeration<SearchResult> searchInGroupBase(String searchFilter,
                                                              String[] returningAttributes,
                                                              int searchScope, DirContext rootContext)
            throws UserStoreException {
        String userBase = realmConfig.getUserStoreProperty(LDAPConstants.GROUP_SEARCH_BASE);
        SearchControls userSearchControl = new SearchControls();
        userSearchControl.setReturningAttributes(returningAttributes);
        userSearchControl.setSearchScope(searchScope);
        NamingEnumeration<SearchResult> groupSearchResults = null;
        try {
            groupSearchResults = rootContext.search(
                    userBase, searchFilter, userSearchControl);
        } catch (NamingException e) {
            String errorMessage = "Error occurred while searching in group base.";
            logger.error(errorMessage, e);
            throw new UserStoreException(errorMessage, e);
        }

        return groupSearchResults;
    }

    /**
     * This is to read and validate the required user store configuration for this
     * user store manager to take decisions.
     *
     * @throws UserStoreException
     */
    protected void checkRequiredUserStoreConfiguration() throws UserStoreException {
        READ_ONLY = realmConfig.getUserStoreProperty(
                UserCoreConstants.RealmConfig.PROPERTY_READ_ONLY);
        if (READ_ONLY.equals("true")) {
            throw new UserStoreException("This user store manager meant to be read-write, " +
                                         "if you want to use user-store in read-only mode, " +
                                         "please use LDAPUserStoreManager.");
        }
        //checkGroupConfiguration
        READ_LDAP_USER_GROUPS = realmConfig.getUserStoreProperty(LDAPConstants.READ_EXTERNAL_ROLES);
        WRITE_LDAP_USER_GROUPS = realmConfig.getUserStoreProperty(
                LDAPConstants.WRITE_EXTERNAL_ROLES);
        USER_SEARCH_BASE = realmConfig.getUserStoreProperty(LDAPConstants.USER_SEARCH_BASE);
        GROUP_SEARCH_BASE = realmConfig.getUserStoreProperty(LDAPConstants.GROUP_SEARCH_BASE);

        if ((READ_LDAP_USER_GROUPS == null) || (WRITE_LDAP_USER_GROUPS == null)) {
            throw new UserStoreException("Please set the LDAP groups configuration properly.");
        }
        if ((READ_LDAP_USER_GROUPS.equals("false")) && (WRITE_LDAP_USER_GROUPS.equals("true"))) {
            throw new UserStoreException("Wrong combination for LDAP groups " +
                                         "read-write properties.");
        }
        if ("true".equals(realmConfig.getUserStoreProperty(LDAPConstants.EMPTY_ROLES_ALLOWED))) {

            EMPTY_ROLES_ALLOWED = true;
        }
        if ("false".equals(realmConfig.getUserStoreProperty(LDAPConstants.EMPTY_ROLES_ALLOWED))) {
            EMPTY_ROLES_ALLOWED = false;
        }
    }

    /**
     * This is to validate whether a particular role is an internal role of carbon.
     *
     * @param roleName
     * @return
     */
    private boolean isInternalRole(String roleName) {
        boolean isInternalRole = false;
        if ((roleName.equals(CarbonConstants.REGISTRY_ANONNYMOUS_ROLE_NAME)) ||
            (roleName.equals(realmConfig.getEveryOneRoleName()))) {
            return true;
        }
        return isInternalRole;
    }
}
TOP

Related Classes of org.wso2.carbon.user.core.ldap.ApacheDSUserStoreManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.