org.jsecurity.spring.SpringIniWebConfiguration.java Source code

Java tutorial

Introduction

Here is the source code for org.jsecurity.spring.SpringIniWebConfiguration.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF 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.jsecurity.spring;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jsecurity.JSecurityException;
import org.jsecurity.mgt.RealmSecurityManager;
import org.jsecurity.mgt.SecurityManager;
import org.jsecurity.realm.Realm;
import org.jsecurity.web.config.IniWebConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextException;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.ServletContext;
import java.util.Collection;
import java.util.Map;

/**
 * <p>JSecurity configuration that relies on Spring to define and initialize the JSecurity SecurityManager
 * instance (and all of its dependencies) and makes it available to the JSecurityFilter by performing a Spring bean
 * lookup.  The URL/filter definitions are still .ini based and loaded according to the behavior of the parent class
 * {@link org.jsecurity.web.config.IniWebConfiguration}</p>
 * <p/>
 * That is, this class is offers a hybrid means of configuring JSecurity in Spring apps deployed in a web container:
 * Spring XML config for the SecurityManager and its dependencies (realms, etc), and .ini format for configuring
 * the filters and the url chains in web.xml, which many people like to maintain separation of concerns:
 * the web/filter/url config stays in web.xml, whereas the SecurityManager config (really a business-tier concern)
 * stays in Spring .xml files.
 * <p/>
 * The behavior used to acquire the JSecurity <code>SecurityManager</code> is as follows:
 * <ol>
 * <li>If a 'securityManagerBeanName' init-param is set, retrieve that sec manager from Spring.</li>
 * <li>If not, look for beans of type {@link SecurityManager} - if there is one instance, use that.
 * If more than one exist, use the one named "securityManager".  If none of them are named "securityManager"
 * throw an exception that says you have to set the init-param to specify the bean name.</li>
 * <li>if no beans of type {@link SecurityManager}, look for any beans of type {@link Realm}.
 * If some are found, create a default security manager by calling
 * {@link org.jsecurity.web.config.IniWebConfiguration#createSecurityManager(java.util.Map) super.createSecurityManager(Map)}
 * and set the Realms on that SecurityManager instance.</li>
 * <li>If none of the above, throw an exception that explains the options.</li>
 * <ol>
 * </p>
 *
 * @author Jeremy Haile
 * @see IniWebConfiguration
 * @since 0.9
 */
public class SpringIniWebConfiguration extends IniWebConfiguration {

    //TODO - complete JavaDoc

    public static final String SECURITY_MANAGER_BEAN_NAME_PARAM_NAME = "securityManagerBeanName";
    public static final String DEFAULT_SECURITY_MANAGER_BEAN_ID = "securityManager";

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

    protected String securityManagerBeanName;

    public String getSecurityManagerBeanName() {
        return securityManagerBeanName;
    }

    public void setSecurityManagerBeanName(String securityManagerBeanName) {
        this.securityManagerBeanName = securityManagerBeanName;
    }

    public SpringIniWebConfiguration() {
    }

    @Override
    public void init() throws JSecurityException {
        String beanName = getFilterConfig().getInitParameter(SECURITY_MANAGER_BEAN_NAME_PARAM_NAME);
        if (beanName != null) {
            setSecurityManagerBeanName(beanName);
        }

        super.init();
    }

    @Override
    protected SecurityManager createDefaultSecurityManager() {
        return createSecurityManager(null);
    }

    @Override
    protected SecurityManager createSecurityManager(Map<String, Map<String, String>> sections) {
        ServletContext servletContext = getFilterConfig().getServletContext();
        ApplicationContext appCtx = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
        return getOrCreateSecurityManager(appCtx, sections);
    }

    protected SecurityManager getOrCreateSecurityManager(ApplicationContext appCtx,
            Map<String, Map<String, String>> sections) {
        String beanName = getSecurityManagerBeanName();

        SecurityManager securityManager = null;
        if (beanName != null) {
            securityManager = (SecurityManager) appCtx.getBean(beanName, SecurityManager.class);
        }

        if (securityManager == null) {
            securityManager = getSecurityManagerByType(appCtx);
        }

        if (securityManager == null) {
            securityManager = createDefaultSecurityManagerFromRealms(appCtx, sections);
        }

        if (securityManager == null) {
            String msg = "Unable to locate a " + SecurityManager.class.getName() + " instance in the "
                    + "Spring WebApplicationContext.  You can 1) simply just define the securityManager as a bean ("
                    + "it will be automatically located based on type) or "
                    + "2) explicitly specifify which bean is retrieved by setting this filter's "
                    + "'securityManagerBeanName' init-param or 3) define one or more " + Realm.class.getName()
                    + " instances and a default SecurityManager using those realms will be created automatically.";
            throw new ApplicationContextException(msg);
        }
        return securityManager;
    }

    @SuppressWarnings("unchecked")
    protected SecurityManager createDefaultSecurityManagerFromRealms(ApplicationContext appCtx,
            Map<String, Map<String, String>> sections) {
        SecurityManager securityManager = null;

        Map<String, Realm> realmMap = appCtx.getBeansOfType(Realm.class);
        if (realmMap == null || realmMap.isEmpty()) {
            return null;
        }

        Collection<Realm> realms = realmMap.values();
        if (realms == null || realms.isEmpty()) {
            return null;
        }

        if (!realms.isEmpty()) {

            // Create security manager according to superclass and set realms on it from Spring.
            securityManager = super.createSecurityManager(sections);

            if (securityManager instanceof RealmSecurityManager) {
                RealmSecurityManager realmSM = (RealmSecurityManager) securityManager;
                realmSM.setRealms(realms);
            } else {
                log.warn("Attempted to set realms declared in Spring on SecurityManager, but was not of "
                        + "type RealmSecurityManager - instead was of type: "
                        + securityManager.getClass().getName());
            }
        }

        return securityManager;
    }

    @SuppressWarnings("unchecked")
    protected SecurityManager getSecurityManagerByType(ApplicationContext appCtx) {

        SecurityManager securityManager = null;

        Map<String, SecurityManager> securityManagers = appCtx.getBeansOfType(SecurityManager.class);
        if (securityManagers == null || securityManagers.isEmpty()) {
            return null;
        }

        if (securityManagers.size() > 1) {

            // If more than one are declared, see if one is named "securityManager"
            securityManager = securityManagers.get(DEFAULT_SECURITY_MANAGER_BEAN_ID);

            if (securityManager == null) {
                String msg = "There is more than one bean of type " + SecurityManager.class.getName()
                        + " available in the "
                        + "Spring WebApplicationContext.  Please specify which bean should be used by "
                        + "setting this filter's 'securityManagerBeanName' init-param or by naming one of the "
                        + "security managers '" + DEFAULT_SECURITY_MANAGER_BEAN_ID + "'.";
                throw new ApplicationContextException(msg);
            }

        } else if (securityManagers.size() == 1) {

            securityManager = securityManagers.values().iterator().next();
        }

        return securityManager;
    }

}