Package org.wso2.carbon.user.core.common

Source Code of org.wso2.carbon.user.core.common.DefaultRealmService

/*
*  Copyright (c) 2005-2008, 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.common;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

import javax.sql.DataSource;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;

import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.framework.BundleContext;
import org.wso2.carbon.user.api.RealmConfiguration;
import org.wso2.carbon.user.api.TenantMgtConfiguration;
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.builder.ClaimBuilder;
import org.wso2.carbon.user.core.config.RealmConfigXMLProcessor;
import org.wso2.carbon.user.core.config.TenantMgtXMLProcessor;
import org.wso2.carbon.user.core.config.multitenancy.MultiTenantRealmConfigBuilder;
import org.wso2.carbon.user.core.ldap.LDAPConnectionContext;
import org.wso2.carbon.user.core.ldap.LDAPConstants;
import org.wso2.carbon.user.core.profile.builder.ProfileConfigurationBuilder;
import org.wso2.carbon.user.core.service.RealmService;
import org.wso2.carbon.user.core.tenant.TenantManager;
import org.wso2.carbon.user.core.util.DatabaseUtil;
import org.wso2.carbon.utils.CarbonUtils;
import org.wso2.carbon.utils.dbcreator.DatabaseCreator;
import org.wso2.carbon.utils.multitenancy.MultitenantConstants;

public class DefaultRealmService implements RealmService {
    private Map<Integer, UserRealm> userRealmMap = new HashMap<Integer, UserRealm>();
    private BundleContext bc;
    private RealmConfiguration bootstrapRealmConfig;
    private TenantMgtConfiguration tenantMgtConfiguration;
    private DataSource dataSource;
    private LDAPConnectionContext ldapConnectionSource = null;
    private OMElement parentElement;
    private TenantManager tenantManager;
    private UserRealm bootstrapRealm;
    private MultiTenantRealmConfigBuilder multiTenantBuilder = null;
    private static final String TENANT_MGT_XML = "tenant-mgt.xml";
    private static final Log log = LogFactory.getLog(DefaultRealmService.class);

    private static final String DB_CHECK_SQL = "select * from UM_USER";

    //map to store and pass the connections to database and ldap which are created in this class.
    private Map<String, Object> properties = new Hashtable<String, Object>();

    public DefaultRealmService(BundleContext bc, RealmConfiguration realmConfig) throws Exception {
        if (realmConfig != null) {
            this.bootstrapRealmConfig = realmConfig;
        } else {
            this.bootstrapRealmConfig = buildBootStrapRealmConfig();
        }
        this.tenantMgtConfiguration = buildTenantMgtConfig(bc);
        this.dataSource = DatabaseUtil.getRealmDataSource(bootstrapRealmConfig);
        initializeDatabase(dataSource);
        properties.put(UserCoreConstants.DATA_SOURCE, dataSource);

        /* Here we check whether LDAP user store is enabled, in user-mgt.xml.
        LDAP constant-ConnectionURL is present in UserStoreProperties, only when
        LDAP user store is used.*/

        if (bootstrapRealmConfig.getUserStoreProperty(LDAPConstants.CONNECTION_URL) != null) {
            /*if LDAP is being used as the user-store, we create connection to LDAP server here
            and pass it to both tenant manager and user store manager.*/
            ldapConnectionSource = new LDAPConnectionContext(bootstrapRealmConfig);
            properties.put(UserCoreConstants.LDAP_CONNECTION_SOURCE, ldapConnectionSource);
        }

        //this.tenantManager = this.initializeTenantManger(this.getTenantConfigurationElement(bc));
        this.tenantManager = this.initializeTenantManger(this.tenantMgtConfiguration);
        this.tenantManager.setBundleContext(bc);
        //initialize existing partitions if applicable with the particular tenant manager.
        this.tenantManager.initializeExistingPartitions();
        // initializing the bootstrapRealm
        this.bc = bc;
        bootstrapRealm = initializeRealm(bootstrapRealmConfig, 0);
        Dictionary<String, String> dictionary = new Hashtable<String, String>();
        dictionary.put(UserCoreConstants.REALM_GENRE, UserCoreConstants.DELEGATING_REALM);
        if (bc != null) {
            // note that in a case of we don't run this in an OSGI envrionment
            // like checkin-client,
            // we need to avoid the registration of the service
            bc.registerService(UserRealm.class.getName(), bootstrapRealm, dictionary);
        }

    }

    public DefaultRealmService(BundleContext bc) throws Exception {
        this(bc, null);
    }

    /**
     * Non OSGI constructor
     */
    public DefaultRealmService(RealmConfiguration realmConfig, TenantManager tenantManager)
            throws Exception {
        this.bootstrapRealmConfig = realmConfig;
        this.dataSource = DatabaseUtil.getRealmDataSource(bootstrapRealmConfig);
        properties.put(UserCoreConstants.DATA_SOURCE, dataSource);
        //creating ldap connection if aaplicable, as described in other constructor.
        if (bootstrapRealmConfig.getUserStoreProperty(LDAPConstants.CONNECTION_URL) != null) {
            ldapConnectionSource = new LDAPConnectionContext(bootstrapRealmConfig);
            properties.put(UserCoreConstants.LDAP_CONNECTION_SOURCE, ldapConnectionSource);
        }
        this.tenantManager = tenantManager;
        bootstrapRealm = initializeRealm(bootstrapRealmConfig, 0);
    }

    private RealmConfiguration buildBootStrapRealmConfig() throws UserStoreException {
        this.parentElement = getConfigurationElement();
        OMElement realmElement = parentElement.getFirstChildWithName(new QName(
                UserCoreConstants.RealmConfig.LOCAL_NAME_REALM));
        RealmConfigXMLProcessor rmProcessor = new RealmConfigXMLProcessor();
        rmProcessor.setSecretResolver(parentElement);
        return rmProcessor.buildRealmConfiguration(realmElement);
    }

    private TenantMgtConfiguration buildTenantMgtConfig(BundleContext bc)
            throws UserStoreException {
        TenantMgtXMLProcessor tenantMgtXMLProcessor = new TenantMgtXMLProcessor();
        tenantMgtXMLProcessor.setBundleContext(bc);
        return tenantMgtXMLProcessor.buildTenantMgtConfigFromFile();
    }

    public org.wso2.carbon.user.api.UserRealm getTenantUserRealm(int tenantId)
            throws org.wso2.carbon.user.api.UserStoreException {
        if (tenantId == MultitenantConstants.SUPER_TENANT_ID) {
            return bootstrapRealm;
        }

        org.wso2.carbon.user.api.UserRealm userRealm = getCachedUserRealm(tenantId);
        if (userRealm != null) {
            return userRealm;
        }
        try {
          if (tenantManager.getTenant(tenantId) != null) {
              RealmConfiguration tenantRealmConfig = (RealmConfiguration) tenantManager.getTenant(
                          tenantId).getRealmConfig();
                  userRealm = initializeRealm(tenantRealmConfig, tenantId);
                  synchronized (this) {
                      userRealmMap.put(Integer.valueOf(tenantId), (UserRealm) userRealm);
                  }
          }
         
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new org.wso2.carbon.user.api.UserStoreException(e.getMessage(), e);
        }
        return userRealm;
    }

    public UserRealm getCachedUserRealm(int tenantId) throws UserStoreException {
        return userRealmMap.get(Integer.valueOf(tenantId));
    }

    public UserRealm getUserRealm(RealmConfiguration tenantRealmConfig) throws UserStoreException {
        UserRealm userRealm = null;
        int tenantId = tenantRealmConfig.getTenantId();
        userRealm = userRealmMap.get(Integer.valueOf(tenantId));
        if (userRealm == null && tenantId == 0) {
            userRealm = bootstrapRealm;
        }

        if (tenantId != 0) {
            MultiTenantRealmConfigBuilder realmConfigBuilder = getMultiTenantRealmConfigBuilder();
            if (realmConfigBuilder != null) {
                tenantRealmConfig = realmConfigBuilder.getRealmConfigForTenantToCreateRealm(
                        bootstrapRealmConfig, tenantRealmConfig, tenantId);
            }
        }

        if (userRealm == null) {
            synchronized (this) {
                userRealm = initializeRealm(tenantRealmConfig, tenantId);
                userRealmMap.put(Integer.valueOf(tenantId), userRealm);
            }
        } else {
            long existingRealmPersistedTime = -1L;
            long newRealmConfigPersistedTime = -1L;
            if (userRealm.getRealmConfiguration().getPersistedTimestamp() != null) {
                existingRealmPersistedTime = userRealm.getRealmConfiguration()
                        .getPersistedTimestamp().getTime();
            }
            if (tenantRealmConfig.getPersistedTimestamp() != null) {
                newRealmConfigPersistedTime = tenantRealmConfig.getPersistedTimestamp().getTime();
            }

            if (existingRealmPersistedTime != newRealmConfigPersistedTime) {
                // this is an update
                userRealm = initializeRealm(tenantRealmConfig, tenantId);
                synchronized (this) {
                    userRealmMap.put(Integer.valueOf(tenantId), userRealm);
                }
            }
        }
        return userRealm;
    }

    @SuppressWarnings("unchecked")
    public UserRealm initializeRealm(RealmConfiguration realmConfig, int tenantId)
            throws UserStoreException {
        ClaimBuilder.setBundleContext(bc);
        ProfileConfigurationBuilder.setBundleContext(bc);
        UserRealm userRealm = null;
        try {
            Class clazz = Class.forName(realmConfig.getRealmClassName());
            userRealm = (UserRealm) clazz.newInstance();
            userRealm.init(realmConfig, properties, tenantId);
        } catch (Exception e) {
            String msg = "Cannot initialize the realm.";
            log.error(msg, e);
            throw new UserStoreException(msg, e);
        }
        return userRealm;
    }

    // TODO : Move this into RealmConfigXMLProcessor

    private OMElement getConfigurationElement() throws UserStoreException {
        try {
            String userMgt = CarbonUtils.getUserMgtXMLPath();
            InputStream inStream = null;
            if (userMgt != null) {
                File userMgtXml = new File(userMgt);
                if (!userMgtXml.exists()) {
                    String msg = "Instance of a WSO2 User Manager has not been created. user-mgt.xml is not found.";
                    throw new FileNotFoundException(msg);
                }
                inStream = new FileInputStream(userMgtXml);
            } else {
                inStream = this.getClass().getClassLoader()
                        .getResourceAsStream("repository/conf/user-mgt.xml");
                if (inStream == null) {
                    String msg = "Instance of a WSO2 User Manager has not been created. user-mgt.xml is not found. Please set the carbon.home";
                    throw new FileNotFoundException(msg);
                }
            }

            StAXOMBuilder builder = new StAXOMBuilder(inStream);
            return builder.getDocumentElement();
        } catch (FileNotFoundException e) {
            log.error(e.getMessage(), e);
            throw new UserStoreException(e.getMessage(), e);
        } catch (XMLStreamException e) {
            log.error(e.getMessage(), e);
            throw new UserStoreException(e.getMessage(), e);
        }
    }

    private void initializeDatabase(DataSource ds) throws Exception {
        String value = System.getProperty("setup");
        if (value != null) {
            DatabaseCreator databaseCreator = new DatabaseCreator(ds);
            try {
                if (!databaseCreator.isDatabaseStructureCreated(DB_CHECK_SQL)) {
                    databaseCreator.createRegistryDatabase();
                } else {
                    log.info("Database already exists. Not creating a new database.");
                }
            } catch (Exception e) {
                String msg = "Error in creating the database";
                throw new Exception(msg, e);
            }
        }
    }

    @SuppressWarnings("unchecked")
    private TenantManager initializeTenantManger(TenantMgtConfiguration tenantMgtConfiguration)
            throws Exception {
        TenantManager tenantManager = null;
        // read the tenant manager from tenant-mgt.xml
        //String className = configElement.getAttribute(new QName("class")).getAttributeValue();
        String className = tenantMgtConfiguration.getTenantManagerClass();
        Class clazz = Class.forName(className);

        Constructor constructor = clazz.getConstructor(OMElement.class, Map.class);
        /*put the tenantMgtConfiguration and realm configuration inside the property map that is
        passed to tenant manager constructor. These are mainly used by LDAPTenantManager*/
        properties.put(UserCoreConstants.TENANT_MGT_CONFIGURATION, tenantMgtConfiguration);
        properties.put(UserCoreConstants.REALM_CONFIGURATION, bootstrapRealmConfig);

        //tenant config OMElement passed to the constructor is not used anymore. Hence passing a null.
        Object newObject = constructor.newInstance(null, properties);
        tenantManager = (TenantManager) newObject;

        return tenantManager;
    }

    public RealmConfiguration getBootstrapRealmConfiguration() {
        return bootstrapRealmConfig;
    }

    public UserRealm getBootstrapRealm() throws UserStoreException {
        return bootstrapRealm;
    }

    public void setTenantManager(org.wso2.carbon.user.api.TenantManager tenantManager)
            throws org.wso2.carbon.user.api.UserStoreException {
        setTenantManager((TenantManager) tenantManager);
    }

    public TenantManager getTenantManager() {
        return this.tenantManager;
    }

    public void setTenantManager(TenantManager tenantManager) {
        this.tenantManager = tenantManager;
    }

    public TenantMgtConfiguration getTenantMgtConfiguration() {
        return tenantMgtConfiguration;
    }

    public MultiTenantRealmConfigBuilder getMultiTenantRealmConfigBuilder()
            throws UserStoreException {
        try {
            if (multiTenantBuilder == null) {
                String clazzName = bootstrapRealmConfig
                        .getRealmProperty("MultiTenantRealmConfigBuilder");
                if (clazzName != null) {
                    Class clazz = Class.forName(clazzName);
                    MultiTenantRealmConfigBuilder multiConfigBuilder = (MultiTenantRealmConfigBuilder) clazz
                            .newInstance();
                    return multiConfigBuilder;
                }
                return null;
            } else {
                return multiTenantBuilder;
            }
        } catch (ClassNotFoundException e) {
            errorEncountered(e);
        } catch (InstantiationException e) {
            errorEncountered(e);
        } catch (IllegalAccessException e) {
            errorEncountered(e);
        }
        return null;
    }

    private void errorEncountered(Exception e) throws UserStoreException {
        String msg = "Exception while creating multi tenant builder " + e.getMessage();
        log.error(msg, e);
        throw new UserStoreException(msg, e);
    }

    /*This has been moved to TenantMgtXMLProcessor, and not used anymore.*/
    private OMElement getTenantConfigurationElement(BundleContext bundleContext) throws Exception {
        InputStream inStream = null;
        File claimConfigXml = new File(CarbonUtils.getCarbonConfigDirPath(), TENANT_MGT_XML);
        if (claimConfigXml.exists()) {
            inStream = new FileInputStream(claimConfigXml);
        }

        String warningMessage = "";
        if (inStream == null) {
            URL url;
            if (bundleContext != null) {
                if ((url = bundleContext.getBundle().getResource(TENANT_MGT_XML)) != null) {
                    inStream = url.openStream();
                } else {
                    warningMessage = "Bundle context could not find resource "
                                     + TENANT_MGT_XML
                                     + " or user does not have sufficient permission to access the resource.";
                }
            } else {
                if ((url = this.getClass().getClassLoader().getResource(TENANT_MGT_XML)) != null) {
                    inStream = url.openStream();
                } else {
                    warningMessage = "ClaimBuilder could not find resource "
                                     + TENANT_MGT_XML
                                     + " or user does not have sufficient permission to access the resource.";
                }
            }
        }

        if (inStream == null) {
            String message = "Tenant configuration not found. Cause - " + warningMessage;
            if (log.isDebugEnabled()) {
                log.debug(message);
            }
            throw new FileNotFoundException(message);
        }

        StAXOMBuilder builder = new StAXOMBuilder(inStream);
        OMElement documentElement = builder.getDocumentElement();

        return documentElement;
    }
}
TOP

Related Classes of org.wso2.carbon.user.core.common.DefaultRealmService

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.