org.cesecore.configuration.GlobalConfigurationSessionBean.java Source code

Java tutorial

Introduction

Here is the source code for org.cesecore.configuration.GlobalConfigurationSessionBean.java

Source

/*************************************************************************
 *                                                                       *
 *  CESeCore: CE Security Core                                           *
 *                                                                       *
 *  This software is free software; you can redistribute it and/or       *
 *  modify it under the terms of the GNU Lesser General Public           *
 *  License as published by the Free Software Foundation; either         *
 *  version 2.1 of the License, or any later version.                    *
 *                                                                       *
 *  See terms of license at gnu.org.                                     *
 *                                                                       *
 *************************************************************************/

package org.cesecore.configuration;

import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.ejb.EJB;
import javax.ejb.SessionContext;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.cesecore.audit.enums.EventStatus;
import org.cesecore.audit.enums.EventTypes;
import org.cesecore.audit.enums.ModuleTypes;
import org.cesecore.audit.enums.ServiceTypes;
import org.cesecore.audit.log.SecurityEventsLoggerSessionLocal;
import org.cesecore.authentication.tokens.AuthenticationToken;
import org.cesecore.authorization.AuthorizationDeniedException;
import org.cesecore.authorization.control.AccessControlSessionLocal;
import org.cesecore.authorization.control.StandardRules;
import org.cesecore.certificates.certificate.certextensions.AvailableCustomCertificateExtensionsConfiguration;
import org.cesecore.config.AvailableExtendedKeyUsagesConfiguration;
import org.cesecore.config.CesecoreConfiguration;
import org.cesecore.internal.InternalResources;
import org.cesecore.internal.UpgradeableDataHashMap;
import org.cesecore.jndi.JndiConstants;

/**
 * This bean handled global configurations.
 * 
 * @version $Id$
 */
@Stateless(mappedName = JndiConstants.APP_JNDI_PREFIX + "GlobalConfigurationSessionRemote")
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class GlobalConfigurationSessionBean
        implements GlobalConfigurationSessionLocal, GlobalConfigurationSessionRemote {

    private static final Logger log = Logger.getLogger(GlobalConfigurationSessionBean.class);

    /** Internal localization of logs and errors */
    private static final InternalResources intres = InternalResources.getInstance();

    @PersistenceContext(unitName = CesecoreConfiguration.PERSISTENCE_UNIT)
    private EntityManager entityManager;

    @EJB
    private SecurityEventsLoggerSessionLocal auditSession;
    @EJB
    private AccessControlSessionLocal accessSession;

    // Myself needs to be looked up in postConstruct
    @Resource
    private SessionContext sessionContext;
    private GlobalConfigurationSessionLocal globalConfigSession;

    /** Default create for SessionBean without any creation Arguments. */
    @PostConstruct
    public void postConstruct() {
        // We lookup the reference to our-self in PostConstruct, since we cannot inject this.
        // We can not inject ourself, JBoss will not start then therefore we use this to get a reference to this session bean
        // to call saveConfiguration from getCachedCOnfiguration we want to do it on the real bean in order to get
        // the transaction setting (REQUIRED) which created a new transaction in order to create default config
        globalConfigSession = sessionContext.getBusinessObject(GlobalConfigurationSessionLocal.class);
    }

    @TransactionAttribute(TransactionAttributeType.SUPPORTS)
    @Override
    public Properties getAllProperties(AuthenticationToken admin, String configID)
            throws AuthorizationDeniedException {
        if (StringUtils.equals(AvailableExtendedKeyUsagesConfiguration.CONFIGURATION_ID, configID)
                && !accessSession.isAuthorized(admin, StandardRules.EKUCONFIGURATION_EDIT.resource())) {
            String msg = intres.getLocalizedMessage("authorization.notuathorizedtoresource",
                    StandardRules.EKUCONFIGURATION_EDIT.resource(), null);
            Map<String, Object> details = new LinkedHashMap<String, Object>();
            details.put("msg", msg);
            auditSession.log(EventTypes.ACCESS_CONTROL, EventStatus.FAILURE, ModuleTypes.CA, ServiceTypes.CORE,
                    admin.toString(), null, null, null, details);
            throw new AuthorizationDeniedException(msg);
        } else if (StringUtils.equals(AvailableCustomCertificateExtensionsConfiguration.CONFIGURATION_ID, configID)
                && !accessSession.isAuthorized(admin,
                        StandardRules.CUSTOMCERTEXTENSIONCONFIGURATION_EDIT.resource())) {
            String msg = intres.getLocalizedMessage("authorization.notuathorizedtoresource",
                    StandardRules.CUSTOMCERTEXTENSIONCONFIGURATION_EDIT.resource(), null);
            Map<String, Object> details = new LinkedHashMap<String, Object>();
            details.put("msg", msg);
            auditSession.log(EventTypes.ACCESS_CONTROL, EventStatus.FAILURE, ModuleTypes.CA, ServiceTypes.CORE,
                    admin.toString(), null, null, null, details);
            throw new AuthorizationDeniedException(msg);
        } else if (!accessSession.isAuthorized(admin, StandardRules.SYSTEMCONFIGURATION_EDIT.resource())) {
            String msg = intres.getLocalizedMessage("authorization.notuathorizedtoresource",
                    StandardRules.SYSTEMCONFIGURATION_EDIT.resource(), null);
            Map<String, Object> details = new LinkedHashMap<String, Object>();
            details.put("msg", msg);
            auditSession.log(EventTypes.ACCESS_CONTROL, EventStatus.FAILURE, ModuleTypes.CA, ServiceTypes.CORE,
                    admin.toString(), null, null, null, details);
            throw new AuthorizationDeniedException(msg);
        }

        return GlobalConfigurationCacheHolder.INSTANCE.getAllProperties(configID);
    }

    @TransactionAttribute(TransactionAttributeType.SUPPORTS)
    @Override
    public Set<String> getIds() {
        return GlobalConfigurationCacheHolder.INSTANCE.getIds();
    }

    @TransactionAttribute(TransactionAttributeType.SUPPORTS)
    @Override
    public ConfigurationBase getCachedConfiguration(String configID) {
        ConfigurationBase result;
        try {
            if (log.isTraceEnabled()) {
                log.trace(">loadConfiguration()");
            }
            // Only do the actual SQL query if we might update the configuration
            // due to cache time anyhow
            if (!GlobalConfigurationCacheHolder.INSTANCE.needsUpdate(configID)) {
                result = GlobalConfigurationCacheHolder.INSTANCE.getConfiguration(configID);
            } else {
                if (log.isDebugEnabled()) {
                    log.debug("Reading Configuration: " + configID);
                }
                GlobalConfigurationData gcdata = findByConfigurationId(configID);
                if (gcdata != null) {
                    result = GlobalConfigurationCacheHolder.INSTANCE.getConfiguration(gcdata.getData(), configID);
                    GlobalConfigurationCacheHolder.INSTANCE.updateConfiguration(result, configID);
                } else {
                    if (log.isDebugEnabled()) {
                        log.debug("No default GlobalConfiguration exists. Trying to create a new one.");
                    }
                    result = GlobalConfigurationCacheHolder.INSTANCE.getNewConfiguration(configID);
                    // Call self bean as external here in order to create a transaction if no transaction exists (this method only has SUPPORTS to be as fast as possible)
                    globalConfigSession.saveConfigurationNoLog(result);
                }
            }
            return result;
        } finally {
            if (log.isTraceEnabled()) {
                log.trace("<loadGlobalConfiguration()");
            }
        }
    }

    @Override
    public void saveConfiguration(final AuthenticationToken admin, final ConfigurationBase conf)
            throws AuthorizationDeniedException {
        if (log.isTraceEnabled()) {
            log.trace(">saveConfiguration()");
        }
        String configID = conf.getConfigurationId();
        checkAuthorization(admin, configID);

        final GlobalConfigurationData gcdata = findByConfigurationId(configID);
        if (gcdata != null) {
            // Save object and create a diff over what has changed
            @SuppressWarnings("unchecked")
            final Map<Object, Object> orgmap = (Map<Object, Object>) GlobalConfigurationCacheHolder.INSTANCE
                    .getConfiguration(gcdata.getData(), configID).saveData();
            gcdata.setConfiguration(conf);
            GlobalConfigurationCacheHolder.INSTANCE.updateConfiguration(conf, configID);
            @SuppressWarnings("unchecked")
            final Map<Object, Object> newmap = (Map<Object, Object>) conf.saveData();
            // Get the diff of what changed
            final Map<Object, Object> diff = UpgradeableDataHashMap.diffMaps(orgmap, newmap);
            // Make security audit log record
            final String msg = intres.getLocalizedMessage("globalconfig.savedconf", gcdata.getConfigurationId());
            final Map<String, Object> details = new LinkedHashMap<String, Object>();
            details.put("msg", msg);
            for (Map.Entry<Object, Object> entry : diff.entrySet()) {
                details.put(entry.getKey().toString(), entry.getValue().toString());
            }
            auditSession.log(EventTypes.SYSTEMCONF_EDIT, EventStatus.SUCCESS, ModuleTypes.GLOBALCONF,
                    ServiceTypes.CORE, admin.toString(), null, null, null, details);
        } else {
            // Global configuration doesn't yet exist.
            try {
                saveConfigurationNoLog(conf);
                final String msg = intres.getLocalizedMessage("globalconfig.createdconf", configID);
                final Map<String, Object> details = new LinkedHashMap<String, Object>();
                details.put("msg", msg);
                auditSession.log(EventTypes.SYSTEMCONF_CREATE, EventStatus.SUCCESS, ModuleTypes.GLOBALCONF,
                        ServiceTypes.CORE, admin.toString(), null, null, null, details);
            } catch (Exception e) {
                final String msg = intres.getLocalizedMessage("globalconfig.errorcreateconf");
                log.info(msg, e);
                final Map<String, Object> details = new LinkedHashMap<String, Object>();
                details.put("msg", msg);
                details.put("error", e.getMessage());
                auditSession.log(EventTypes.SYSTEMCONF_CREATE, EventStatus.FAILURE, ModuleTypes.GLOBALCONF,
                        ServiceTypes.CORE, admin.toString(), null, null, null, details);
            }
        }
        if (log.isTraceEnabled()) {
            log.trace("<saveGlobalConfiguration()");
        }
    }

    private void checkAuthorization(final AuthenticationToken admin, final String configID)
            throws AuthorizationDeniedException {
        if (StringUtils.equals(AvailableExtendedKeyUsagesConfiguration.CONFIGURATION_ID, configID)) {
            if (!this.accessSession.isAuthorized(admin, StandardRules.EKUCONFIGURATION_EDIT.resource())) {
                throw new AuthorizationDeniedException("Authorization was denied to user " + admin + " to resource "
                        + StandardRules.EKUCONFIGURATION_EDIT.resource() + ". Could not save configuration.");
            }
        } else if (StringUtils.equals(AvailableCustomCertificateExtensionsConfiguration.CONFIGURATION_ID,
                configID)) {
            if (!this.accessSession.isAuthorized(admin,
                    StandardRules.CUSTOMCERTEXTENSIONCONFIGURATION_EDIT.resource())) {
                throw new AuthorizationDeniedException("Authorization was denied to user " + admin + " to resource "
                        + StandardRules.CUSTOMCERTEXTENSIONCONFIGURATION_EDIT.resource()
                        + ". Could not save configuration.");
            }
        } else if (!this.accessSession.isAuthorized(admin, StandardRules.SYSTEMCONFIGURATION_EDIT.resource())) {
            throw new AuthorizationDeniedException("Authorization was denied to user " + admin + " to resource "
                    + StandardRules.SYSTEMCONFIGURATION_EDIT.resource() + ". Could not save configuration.");
        }
    }

    @Override
    public void saveConfigurationNoLog(ConfigurationBase conf) {
        String configID = conf.getConfigurationId();
        GlobalConfigurationData gcd = new GlobalConfigurationData(configID, conf);
        entityManager.persist(gcd);
        GlobalConfigurationCacheHolder.INSTANCE.updateConfiguration(conf, configID);
    }

    @Override
    public void flushConfigurationCache(final String configID) {
        if (log.isTraceEnabled()) {
            log.trace(">flushConfigurationCache()");
        }

        GlobalConfigurationCacheHolder.INSTANCE.clearCache(configID);
        getCachedConfiguration(configID);

        if (log.isTraceEnabled()) {
            log.trace("<flushConfigurationCache()");
        }
    }

    /** @return the found entity instance or null if the entity does not exist */
    @Override
    @TransactionAttribute(TransactionAttributeType.SUPPORTS)
    public GlobalConfigurationData findByConfigurationId(String configurationId) {
        return entityManager.find(GlobalConfigurationData.class, configurationId);
    }

    private static enum GlobalConfigurationCacheHolder {
        INSTANCE;

        private final Map<String, ConfigurationCache> caches = new ConcurrentHashMap<String, ConfigurationCache>();

        private GlobalConfigurationCacheHolder() {
            ServiceLoader<? extends ConfigurationCache> serviceLoader = ServiceLoader
                    .load(ConfigurationCache.class);
            // Extract all the caches from the plugin list
            for (ConfigurationCache cache : serviceLoader) {
                if (caches.containsKey(cache.getConfigId())) {
                    throw new IllegalStateException("Two caches loaded with the same config ID: "
                            + cache.getConfigId() + ". This is an invalid state.");
                } else {
                    caches.put(cache.getConfigId(), cache);
                }
            }
        }

        /** @return all registered configuration IDs. */
        public Set<String> getIds() {
            return new HashSet<String>(caches.keySet());
        }

        public void updateConfiguration(final ConfigurationBase conf, final String configId) {
            caches.get(configId).updateConfiguration(conf);
        }

        public void clearCache(final String configId) {
            caches.get(configId).clearCache();
        }

        public boolean needsUpdate(final String configId) {
            if (caches.get(configId) == null) {
                return true;
            }
            return caches.get(configId).needsUpdate();
        }

        public ConfigurationBase getConfiguration(final String configId) {
            ConfigurationCache cache = caches.get(configId);
            if (cache == null) {
                return null;
            } else {
                return cache.getConfiguration();
            }
        }

        @SuppressWarnings("rawtypes")
        public ConfigurationBase getConfiguration(final HashMap data, final String configId) {
            ConfigurationCache cache = caches.get(configId);
            if (cache == null) {
                return null;
            } else {
                return cache.getConfiguration(data);
            }
        }

        public ConfigurationBase getNewConfiguration(final String configId) {
            ConfigurationCache cache = caches.get(configId);
            if (cache == null) {
                return null;
            } else {
                return cache.getNewConfiguration();
            }
        }

        public Properties getAllProperties(final String configId) {
            ConfigurationCache cache = caches.get(configId);
            if (cache == null) {
                return null;
            } else {
                return caches.get(configId).getAllProperties();
            }
        }

    }
}