org.seedstack.seed.security.internal.SecurityPlugin.java Source code

Java tutorial

Introduction

Here is the source code for org.seedstack.seed.security.internal.SecurityPlugin.java

Source

/**
 * Copyright (c) 2013-2015 by The SeedStack authors. All rights reserved.
 *
 * This file is part of SeedStack, An enterprise-oriented full development stack.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
package org.seedstack.seed.security.internal;

import io.nuun.kernel.api.Plugin;
import io.nuun.kernel.api.plugin.InitState;
import io.nuun.kernel.api.plugin.context.InitContext;
import io.nuun.kernel.api.plugin.request.BindingRequest;
import io.nuun.kernel.api.plugin.request.ClasspathScanRequest;
import io.nuun.kernel.api.plugin.request.ClasspathScanRequestBuilder;
import io.nuun.kernel.core.AbstractPlugin;
import org.apache.commons.configuration.Configuration;
import org.seedstack.seed.core.api.SeedException;
import org.seedstack.seed.core.internal.application.ApplicationPlugin;
import org.seedstack.seed.core.utils.SeedReflectionUtils;
import org.seedstack.seed.el.internal.ELPlugin;
import org.seedstack.seed.security.api.*;
import org.seedstack.seed.security.internal.configure.SeedSecurityConfigurer;
import org.seedstack.seed.security.spi.SecurityErrorCodes;
import org.seedstack.seed.security.spi.SecurityScope;
import org.seedstack.seed.security.spi.data.DataObfuscationHandler;
import org.seedstack.seed.security.spi.data.DataSecurityHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * This plugin provides core security infrastructure, based on Apache Shiro
 * implementation.
 *
 * @author yves.dautremay@mpsa.com
 * @author adrien.lauer@mpsa.com
 */
public class SecurityPlugin extends AbstractPlugin {
    private static final Logger LOGGER = LoggerFactory.getLogger(SecurityPlugin.class);

    public static final String SECURITY_PREFIX = "org.seedstack.seed.security";

    private final Collection<SecurityProvider> securityProviders = new ArrayList<SecurityProvider>();
    private final Map<String, Class<? extends Scope>> scopeClasses = new HashMap<String, Class<? extends Scope>>();

    private Configuration securityConfiguration;
    private Map<Class<?>, Collection<Class<?>>> scannedClasses;
    private Collection<Class<? extends DataSecurityHandler<?>>> dataSecurityHandlers;
    private Collection<Class<? extends PrincipalCustomizer<?>>> principalCustomizerClasses;
    private boolean elDisabled;

    public SecurityPlugin() {
        for (SecurityProvider securityProvider : ServiceLoader.load(SecurityProvider.class,
                SeedReflectionUtils.findMostCompleteClassLoader(SecurityPlugin.class))) {
            securityProviders.add(securityProvider);
        }
    }

    @Override
    public String name() {
        return "seed-security-plugin";
    }

    @Override
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public InitState init(InitContext initContext) {
        for (Plugin plugin : initContext.pluginsRequired()) {
            if (plugin instanceof ApplicationPlugin) {
                securityConfiguration = ((ApplicationPlugin) plugin).getApplication().getConfiguration()
                        .subset(SECURITY_PREFIX);
            } else if (plugin instanceof ELPlugin) {
                elDisabled = ((ELPlugin) plugin).isDisabled();
            }
        }

        scannedClasses = initContext.scannedSubTypesByAncestorClass();
        principalCustomizerClasses = (Collection) scannedClasses.get(PrincipalCustomizer.class);
        dataSecurityHandlers = (Collection) scannedClasses.get(DataSecurityHandler.class);

        Collection<Class<? extends Scope>> scopeCandidateClasses = (Collection) scannedClasses.get(Scope.class);
        if (scopeCandidateClasses != null) {
            for (Class<?> scopeCandidateClass : scopeCandidateClasses) {
                if (Scope.class.isAssignableFrom(scopeCandidateClass)) {
                    SecurityScope securityScope = scopeCandidateClass.getAnnotation(SecurityScope.class);
                    String scopeName;

                    if (securityScope != null) {
                        scopeName = securityScope.value();
                    } else {
                        scopeName = scopeCandidateClass.getSimpleName();
                    }

                    try {
                        scopeCandidateClass.getConstructor(String.class);
                    } catch (NoSuchMethodException e) {
                        throw SeedException.wrap(e, SecurityErrorCodes.MISSING_ADEQUATE_SCOPE_CONSTRUCTOR)
                                .put("scopeName", scopeName);
                    }

                    if (scopeClasses.containsKey(scopeName)) {
                        throw SeedException.createNew(SecurityErrorCodes.DUPLICATE_SCOPE_NAME).put("scopeName",
                                scopeName);
                    }

                    scopeClasses.put(scopeName, (Class<? extends Scope>) scopeCandidateClass);
                }
            }
        }

        for (SecurityProvider securityProvider : securityProviders) {
            LOGGER.debug("Initializing security provider {}", securityProvider.getClass().getCanonicalName());
            securityProvider.init(initContext);
        }

        if (elDisabled) {
            LOGGER.warn("No Java EL support, data security is disabled");
        }

        return InitState.INITIALIZED;
    }

    @Override
    public void provideContainerContext(Object containerContext) {
        for (SecurityProvider securityProvider : securityProviders) {
            securityProvider.provideContainerContext(containerContext);
        }
    }

    @Override
    public Collection<Class<? extends Plugin>> requiredPlugins() {
        Collection<Class<? extends Plugin>> plugins = new ArrayList<Class<? extends Plugin>>();
        plugins.add(ApplicationPlugin.class);
        plugins.add(ELPlugin.class);
        return plugins;
    }

    @Override
    public Object nativeUnitModule() {
        return new SecurityModule(
                new SeedSecurityConfigurer(securityConfiguration, scannedClasses, principalCustomizerClasses),
                scopeClasses, dataSecurityHandlers, elDisabled, securityProviders);
    }

    @Override
    public Collection<ClasspathScanRequest> classpathScanRequests() {
        // Core plugin requests
        ClasspathScanRequestBuilder builder = classpathScanRequestBuilder().descendentTypeOf(Realm.class)
                .descendentTypeOf(RoleMapping.class).descendentTypeOf(RolePermissionResolver.class)
                .descendentTypeOf(Scope.class).descendentTypeOf(DataSecurityHandler.class)
                .descendentTypeOf(PrincipalCustomizer.class);

        // Additional plugins requests
        for (SecurityProvider securityProvider : securityProviders) {
            securityProvider.classpathScanRequests(builder);
        }

        return builder.build();
    }

    @Override
    public Collection<BindingRequest> bindingRequests() {
        return bindingRequestsBuilder().descendentTypeOf(DataObfuscationHandler.class).build();
    }
}