org.wso2.carbon.identity.user.registration.UserRegistrationService.java Source code

Java tutorial

Introduction

Here is the source code for org.wso2.carbon.identity.user.registration.UserRegistrationService.java

Source

/*
 * Copyright (c) 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.identity.user.registration;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xerces.impl.Constants;
import org.apache.xerces.util.SecurityManager;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.wso2.carbon.CarbonConstants;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.context.RegistryType;
import org.wso2.carbon.identity.base.IdentityConstants;
import org.wso2.carbon.identity.base.IdentityException;
import org.wso2.carbon.identity.core.IdentityClaimManager;
import org.wso2.carbon.identity.core.persistence.IdentityPersistenceManager;
import org.wso2.carbon.identity.core.util.IdentityTenantUtil;
import org.wso2.carbon.identity.core.util.IdentityUtil;
import org.wso2.carbon.identity.user.registration.dto.PasswordRegExDTO;
import org.wso2.carbon.identity.user.registration.dto.TenantRegistrationConfig;
import org.wso2.carbon.identity.user.registration.dto.UserDTO;
import org.wso2.carbon.identity.user.registration.dto.UserFieldDTO;
import org.wso2.carbon.registry.core.Registry;
import org.wso2.carbon.registry.core.Resource;
import org.wso2.carbon.registry.core.exceptions.RegistryException;
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.UserStoreManager;
import org.wso2.carbon.user.core.claim.Claim;
import org.wso2.carbon.user.core.util.UserCoreUtil;
import org.wso2.carbon.user.mgt.UserMgtConstants;
import org.wso2.carbon.utils.multitenancy.MultitenantUtils;
import org.wso2.carbon.identity.user.registration.util.CarbonEntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class UserRegistrationService {

    private static final Log log = LogFactory.getLog(UserRegistrationService.class);
    private static final String SECURITY_MANAGER_PROPERTY = Constants.XERCES_PROPERTY_PREFIX
            + Constants.SECURITY_MANAGER_PROPERTY;
    private static final int ENTITY_EXPANSION_LIMIT = 0;

    /**
     * This service method will return back all available password validation regular expressions
     * against the corresponding domain names.
     *
     * @return
     * @throws IdentityException
     */
    public PasswordRegExDTO[] getPasswordRegularExpressions() throws IdentityException {
        UserRealm realm = null;
        realm = IdentityTenantUtil.getRealm(null, null);
        List<PasswordRegExDTO> passwordRegExList = new ArrayList<PasswordRegExDTO>();
        PasswordRegExDTO passwordRegEx;

        try {

            UserStoreManager manager = realm.getUserStoreManager();
            String domainName;
            String regEx;

            while (manager != null) {
                domainName = manager.getRealmConfiguration()
                        .getUserStoreProperty(UserCoreConstants.RealmConfig.PROPERTY_DOMAIN_NAME);
                regEx = manager.getRealmConfiguration()
                        .getUserStoreProperty(UserCoreConstants.RealmConfig.PROPERTY_JS_REG_EX);
                if (regEx != null && regEx.length() > 0) {
                    passwordRegEx = new PasswordRegExDTO();
                    passwordRegEx.setDomainName(domainName);
                    passwordRegEx.setRegEx(regEx);
                    passwordRegExList.add(passwordRegEx);
                }
                manager = manager.getSecondaryUserStoreManager();
            }

        } catch (UserStoreException e) {
            log.error(e);
            throw new IdentityException("Error occured while loading password validation regular expressions.");
        }

        return passwordRegExList.toArray(new PasswordRegExDTO[passwordRegExList.size()]);
    }

    public UserFieldDTO[] readUserFieldsForUserRegistration(String dialect) throws IdentityException {
        IdentityClaimManager claimManager = null;
        Claim[] claims = null;
        List<UserFieldDTO> claimList = null;
        UserRealm realm = null;

        claimManager = IdentityClaimManager.getInstance();
        realm = IdentityTenantUtil.getRealm(null, null);
        claims = claimManager.getAllSupportedClaims(dialect, realm);

        if (claims == null || claims.length == 0) {
            return new UserFieldDTO[0];
        }

        claimList = new ArrayList<UserFieldDTO>();

        for (Claim claim : claims) {
            if (claim.getDisplayTag() != null
                    && !IdentityConstants.PPID_DISPLAY_VALUE.equals(claim.getDisplayTag())) {
                if (UserCoreConstants.ClaimTypeURIs.ACCOUNT_STATUS.equals(claim.getClaimUri())) {
                    continue;
                }
                if (!claim.isReadOnly()) {
                    claimList.add(getUserFieldDTO(claim.getClaimUri(), claim.getDisplayTag(), claim.isRequired(),
                            claim.getDisplayOrder(), claim.getRegEx()));
                }
            }
        }

        return claimList.toArray(new UserFieldDTO[claimList.size()]);
    }

    public void addUser(UserDTO user) throws Exception {
        UserFieldDTO[] userFieldDTOs = null;
        Map<String, String> userClaims = null;

        userFieldDTOs = user.getUserFields();
        userClaims = new HashMap<String, String>();

        if (userFieldDTOs != null) {
            for (UserFieldDTO userFieldDTO : userFieldDTOs) {
                userClaims.put(userFieldDTO.getClaimUri(), userFieldDTO.getFieldValue());
            }
        }

        UserRealm realm = null;
        String tenantAwareUserName = MultitenantUtils.getTenantAwareUsername(user.getUserName());
        String tenantName = MultitenantUtils.getTenantDomain(user.getUserName());
        realm = IdentityTenantUtil.getRealm(tenantName, null);
        Registry registry = IdentityTenantUtil.getRegistry(null, null);
        addUser(tenantAwareUserName, user.getPassword(), userClaims, null, realm);

        // OpenId Sign-Up if necessary.
        if (user.getOpenID() != null) {
            IdentityPersistenceManager persistentManager = IdentityPersistenceManager.getPersistanceManager();
            persistentManager.doOpenIdSignUp(registry, realm, user.getOpenID(), user.getUserName());
        }

    }

    public boolean isAddUserEnabled() throws Exception {

        UserRealm userRealm = IdentityTenantUtil.getRealm(null, null);
        if (userRealm != null) {
            UserStoreManager userStoreManager = userRealm.getUserStoreManager();
            if (userStoreManager != null) {
                return !userStoreManager.isReadOnly();
            }
        }

        return false;

    }

    public boolean isAddUserWithOpenIDEnabled() throws Exception {
        return false;
    }

    public boolean isAddUserWithInfoCardEnabled() throws Exception {
        return false;
    }

    private UserFieldDTO getUserFieldDTO(String claimUri, String displayName, boolean isRequired, int displayOrder,
            String regex) {
        UserFieldDTO fieldDTO = null;
        fieldDTO = new UserFieldDTO();
        fieldDTO.setClaimUri(claimUri);
        fieldDTO.setFieldName(displayName);
        fieldDTO.setRequired(isRequired);
        fieldDTO.setDisplayOrder(displayOrder);
        fieldDTO.setRegEx(regex);
        return fieldDTO;
    }

    private void addUser(String userName, String password, Map<String, String> claimList, String profileName,
            UserRealm realm) throws IdentityException {
        UserStoreManager admin = null;
        Permission permission = null;
        try {
            // get config from tenant registry
            TenantRegistrationConfig tenantConfig = getTenantSignUpConfig(
                    realm.getUserStoreManager().getTenantId());
            // set tenant config specific sign up domain
            if (tenantConfig != null && !"".equals(tenantConfig.getSignUpDomain())) {
                int index = userName.indexOf(UserCoreConstants.DOMAIN_SEPARATOR);
                if (index > 0) {
                    userName = tenantConfig.getSignUpDomain().toUpperCase() + UserCoreConstants.DOMAIN_SEPARATOR
                            + userName.substring(index + 1);
                } else {
                    userName = tenantConfig.getSignUpDomain().toUpperCase() + UserCoreConstants.DOMAIN_SEPARATOR
                            + userName;
                }
            }

            // add user to the relevant user store

            admin = realm.getUserStoreManager();
            if (!isUserNameWithAllowedDomainName(userName, realm)) {
                throw new IdentityException("Domain does not permit self registration");
            }
            // add user
            admin.addUser(userName, password, null, claimList, profileName);

            // after adding the user, assign specif roles
            List<String> roleNamesArr = getRoleName(userName, tenantConfig);
            if (claimList.get(SelfRegistrationConstants.SIGN_UP_ROLE_CLAIM_URI) != null) {
                // check is a user role is specified as a claim by the client, if so add it to the roles list
                if (tenantConfig != null) {
                    roleNamesArr
                            .add(tenantConfig.getSignUpDomain().toUpperCase() + UserCoreConstants.DOMAIN_SEPARATOR
                                    + claimList.get(SelfRegistrationConstants.SIGN_UP_ROLE_CLAIM_URI));
                } else {
                    roleNamesArr.add(UserCoreConstants.INTERNAL_DOMAIN + UserCoreConstants.DOMAIN_SEPARATOR
                            + claimList.get(SelfRegistrationConstants.SIGN_UP_ROLE_CLAIM_URI));
                }
            }
            String[] identityRoleNames = roleNamesArr.toArray(new String[roleNamesArr.size()]);

            for (int i = 0; i < identityRoleNames.length; i++) {
                // if this is the first time a user signs up, needs to create role
                doAddUser(i, admin, identityRoleNames, userName, permission);
            }

        } catch (UserStoreException e) {
            throw new IdentityException("Error occurred while adding user : " + userName + ". " + e.getMessage(),
                    e);
        }
    }

    private void doAddUser(int i, UserStoreManager admin, String[] identityRoleNames, String userName,
            Permission permission) throws IdentityException, UserStoreException {
        try {
            if (!admin.isExistingRole(identityRoleNames[i], false)) {
                permission = new Permission("/permission/admin/login", UserMgtConstants.EXECUTE_ACTION);
                admin.addRole(identityRoleNames[i], new String[] { userName }, new Permission[] { permission },
                        false);
            } else {
                // if role already exists, just add user to role
                admin.updateUserListOfRole(identityRoleNames[i], new String[] {}, new String[] { userName });
            }
        } catch (org.wso2.carbon.user.api.UserStoreException e) {
            // If something goes wrong here - then remove the already added user.
            admin.deleteUser(userName);
            throw new IdentityException("Error occurred while adding user : " + userName + ". " + e.getMessage(),
                    e);
        }
    }

    private boolean isUserNameWithAllowedDomainName(String userName, UserRealm realm) throws IdentityException {
        int index;
        index = userName.indexOf("/");

        // Check whether we have a secondary UserStoreManager setup.
        if (index > 0) {
            // Using the short-circuit. User name comes with the domain name.
            try {
                return !realm.getRealmConfiguration().isRestrictedDomainForSlefSignUp(userName.substring(0, index));
            } catch (UserStoreException e) {
                throw new IdentityException(e.getMessage(), e);
            }
        }

        return true;
    }

    private List<String> getRoleName(String userName, TenantRegistrationConfig tenantConfig) {
        // check for tenant config, if available return roles specified in tenant config
        if (tenantConfig != null) {
            List<String> roleNamesArr = new ArrayList<String>();
            Map<String, Boolean> roles = tenantConfig.getRoles();
            for (Map.Entry<String, Boolean> entry : roles.entrySet()) {
                String roleName;
                if (entry.getValue()) {
                    // external role
                    roleName = tenantConfig.getSignUpDomain().toUpperCase() + UserCoreConstants.DOMAIN_SEPARATOR
                            + entry.getKey();
                } else {
                    // internal role
                    roleName = UserCoreConstants.INTERNAL_DOMAIN + UserCoreConstants.DOMAIN_SEPARATOR
                            + entry.getKey();
                }
                roleNamesArr.add(roleName);
            }
            // return, don't need to worry about roles specified in identity.xml
            return roleNamesArr;
        }

        String roleName = IdentityUtil.getProperty(SelfRegistrationConstants.ROLE_NAME_PROPERTY);
        boolean externalRole = Boolean
                .parseBoolean(IdentityUtil.getProperty(SelfRegistrationConstants.ROLE_EXTERNAL_PROPERTY));

        String domainName = UserCoreConstants.INTERNAL_DOMAIN;
        if (externalRole) {
            domainName = UserCoreUtil.extractDomainFromName(userName);
        }

        if (roleName == null || roleName.trim().length() == 0) {
            roleName = IdentityConstants.IDENTITY_DEFAULT_ROLE;
        }

        if (domainName != null && domainName.trim().length() > 0) {
            roleName = domainName.toUpperCase() + CarbonConstants.DOMAIN_SEPARATOR + roleName;
        }

        return new ArrayList<String>(Arrays.asList(roleName));
    }

    private TenantRegistrationConfig getTenantSignUpConfig(int tenantId) throws IdentityException {
        TenantRegistrationConfig config;
        NodeList nodes;
        try {
            // start tenant flow to load tenant registry
            PrivilegedCarbonContext.startTenantFlow();
            PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(tenantId, true);
            PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain();
            Registry registry = (Registry) PrivilegedCarbonContext.getThreadLocalCarbonContext()
                    .getRegistry(RegistryType.SYSTEM_GOVERNANCE);
            if (registry.resourceExists(SelfRegistrationConstants.SIGN_UP_CONFIG_REG_PATH)) {
                Resource resource = registry.get(SelfRegistrationConstants.SIGN_UP_CONFIG_REG_PATH);
                // build config from tenant registry resource
                DocumentBuilder builder = getSecuredDocumentBuilder();
                String configXml = new String((byte[]) resource.getContent());
                InputSource configInputSource = new InputSource();
                configInputSource.setCharacterStream(new StringReader(configXml.trim()));
                Document doc = builder.parse(configInputSource);
                nodes = doc.getElementsByTagName(SelfRegistrationConstants.SELF_SIGN_UP_ELEMENT);
                if (nodes.getLength() > 0) {
                    config = new TenantRegistrationConfig();
                    config.setSignUpDomain(((Element) nodes.item(0))
                            .getElementsByTagName(SelfRegistrationConstants.SIGN_UP_DOMAIN_ELEMENT).item(0)
                            .getTextContent());
                    // there can be more than one <SignUpRole> elements, iterate through all elements
                    NodeList rolesEl = ((Element) nodes.item(0))
                            .getElementsByTagName(SelfRegistrationConstants.SIGN_UP_ROLE_ELEMENT);
                    for (int i = 0; i < rolesEl.getLength(); i++) {
                        Element tmpEl = (Element) rolesEl.item(i);
                        String tmpRole = tmpEl.getElementsByTagName(SelfRegistrationConstants.ROLE_NAME_ELEMENT)
                                .item(0).getTextContent();
                        boolean tmpIsExternal = Boolean.parseBoolean(
                                tmpEl.getElementsByTagName(SelfRegistrationConstants.IS_EXTERNAL_ELEMENT).item(0)
                                        .getTextContent());
                        config.getRoles().put(tmpRole, tmpIsExternal);
                    }
                    return config;
                } else {
                    return null;
                }
            }
        } catch (RegistryException e) {
            throw new IdentityException("Error retrieving sign up config from registry " + e.getMessage(), e);
        } catch (ParserConfigurationException e) {
            throw new IdentityException("Error parsing tenant sign up configuration " + e.getMessage(), e);
        } catch (SAXException e) {
            throw new IdentityException("Error parsing tenant sign up configuration " + e.getMessage(), e);
        } catch (IOException e) {
            throw new IdentityException("Error parsing tenant sign up configuration " + e.getMessage(), e);
        } finally {
            PrivilegedCarbonContext.endTenantFlow();
        }

        return null;
    }

    /**
     * * This method provides a secured document builder which will secure XXE attacks.
     *
     * @return DocumentBuilder
     * @throws ParserConfigurationException
     */
    private DocumentBuilder getSecuredDocumentBuilder() throws ParserConfigurationException {

        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        documentBuilderFactory.setNamespaceAware(true);
        documentBuilderFactory.setExpandEntityReferences(false);
        documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
        SecurityManager securityManager = new SecurityManager();
        securityManager.setEntityExpansionLimit(ENTITY_EXPANSION_LIMIT);
        documentBuilderFactory.setAttribute(SECURITY_MANAGER_PROPERTY, securityManager);
        DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
        documentBuilder.setEntityResolver(new CarbonEntityResolver());
        return documentBuilder;

    }
}