| /* |
| * 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.apache.ki.spring; |
| |
| import java.util.Collection; |
| import java.util.Map; |
| import javax.servlet.ServletContext; |
| |
| import org.springframework.context.ApplicationContext; |
| import org.springframework.context.ApplicationContextException; |
| import org.springframework.web.context.support.WebApplicationContextUtils; |
| |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| |
| import org.apache.ki.KiException; |
| import org.apache.ki.mgt.RealmSecurityManager; |
| import org.apache.ki.mgt.SecurityManager; |
| import org.apache.ki.realm.Realm; |
| import org.apache.ki.web.config.IniWebConfiguration; |
| |
| |
| /** |
| * <p>Apache Ki configuration that relies on Spring to define and initialize the Apache Ki SecurityManager |
| * instance (and all of its dependencies) and makes it available to the Apache KiFilter 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.apache.ki.web.config.IniWebConfiguration}</p> |
| * <p/> |
| * That is, this class is offers a hybrid means of configuring Apache Ki 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 Apache Ki <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.apache.ki.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 KiException { |
| 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, org.apache.ki.mgt.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; |
| } |
| |
| } |