/* * Copyright 2002-2011 the original author or authors. * * Licensed 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.springframework.flex.security3; import java.beans.PropertyDescriptor; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.servlet.Filter; import org.springframework.beans.BeanWrapper; import org.springframework.beans.BeansException; import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.PropertyAccessorFactory; import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.support.ManagedList; import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.flex.core.ExceptionTranslator; import org.springframework.security.web.FilterChainProxy; import org.springframework.security.web.authentication.RememberMeServices; import org.springframework.security.web.authentication.logout.LogoutHandler; import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy; import org.springframework.util.ClassUtils; import org.springframework.util.CollectionUtils; import flex.messaging.FlexSession; /** * Infrastructure class for setting up the necessary integration points with Spring Security. * * <p>Given existing Spring Security configuration for implementations of {@link SessionAuthenticationStrategy}, {@link RememberMeServices}, * will configure the {@link SpringSecurityLoginCommand} and {@link FilterChainProxy} to work with those services as necessary. An existing * <code>SessionAuthentiactionStrategy</code> will be wrapped with a {@link FlexSessionAwareSessionAuthenticationStrategy} in order to ensure * proper handling of the {@link FlexSession}. * * <p>This class will be configured automatically through use of the XML namespace tags. * * @author Jeremy Grelle */ public class SecurityConfigurationPostProcessor implements MergedBeanDefinitionPostProcessor, InitializingBean, ApplicationContextAware { private SessionAuthenticationStrategy sessionAuthenticationStrategy; private RememberMeServices rememberMeServices; private FilterChainProxy filterChainProxy; private ApplicationContext context; @SuppressWarnings({ "rawtypes", "unchecked" }) public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName) { if (SpringSecurityLoginCommand.class.isAssignableFrom(beanType)) { MutablePropertyValues pv = beanDefinition.getPropertyValues(); boolean rememberMeServicesConfigured = (pv.getPropertyValue("rememberMeServices") != null); if (this.sessionAuthenticationStrategy != null && pv.getPropertyValue("sessionAuthenticationStrategy") == null) { pv.add("sessionAuthenticationStrategy", this.sessionAuthenticationStrategy); } if (this.rememberMeServices != null && !rememberMeServicesConfigured) { pv.add("rememberMeServices", this.rememberMeServices); } if (pv.getPropertyValue("logoutHandlers") == null) { ManagedList handlers = new ManagedList(); SecurityContextLogoutHandler contextHandler = new SecurityContextLogoutHandler(); boolean invalidateHttpSession = (Boolean) beanDefinition.getAttribute("invalidateHttpSession"); contextHandler.setInvalidateHttpSession(invalidateHttpSession); handlers.add(contextHandler); if (this.rememberMeServices != null && !rememberMeServicesConfigured && ClassUtils.isAssignableValue(LogoutHandler.class, this.rememberMeServices)) { handlers.add(this.rememberMeServices); } pv.add("logoutHandlers", handlers); } } } public void afterPropertiesSet() throws Exception { if (this.sessionAuthenticationStrategy != null) { this.sessionAuthenticationStrategy = new FlexSessionAwareSessionAuthenticationStrategy(this.sessionAuthenticationStrategy); Set<Filter> allFilters = new HashSet<Filter>(BeanFactoryUtils.beansOfTypeIncludingAncestors(context, Filter.class, false, false).values()); if (this.filterChainProxy != null) { allFilters.addAll(new FilterChainAccessor(this.filterChainProxy).getFilters()); } for (Filter filter : allFilters) { BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(filter); for (PropertyDescriptor pd : bw.getPropertyDescriptors()) { if (ClassUtils.isAssignableValue(pd.getPropertyType(), this.sessionAuthenticationStrategy) && bw.isWritableProperty(pd.getName())) { bw.setPropertyValue(pd.getName(), this.sessionAuthenticationStrategy); } } } } Map<String, ExceptionTranslator> exceptionTranslators = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ExceptionTranslator.class); if (!CollectionUtils.isEmpty(exceptionTranslators)) { Map<String, FlexAuthenticationEntryPoint> entryPoints = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, FlexAuthenticationEntryPoint.class); for (FlexAuthenticationEntryPoint entryPoint: entryPoints.values()) { if (CollectionUtils.isEmpty(entryPoint.getExceptionTranslators())) { entryPoint.setExceptionTranslators(new HashSet<ExceptionTranslator>(exceptionTranslators.values())); } } } } public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } public void setApplicationContext(ApplicationContext context) throws BeansException { this.context = context; } public void setFilterChainProxy(FilterChainProxy filterChainProxy) { this.filterChainProxy = filterChainProxy; } public void setRememberMeServices(RememberMeServices rememberMeServices) { this.rememberMeServices = rememberMeServices; } public void setSessionAuthenticationStrategy( SessionAuthenticationStrategy sessionAuthenticationStrategy) { this.sessionAuthenticationStrategy = sessionAuthenticationStrategy; } private static final class FilterChainAccessor { private final Set<Filter> filters; public FilterChainAccessor(FilterChainProxy proxy) { this.filters = new LinkedHashSet<Filter>(); for (List<Filter> filters : proxy.getFilterChainMap().values()) { this.filters.addAll(filters); } } public Set<Filter> getFilters() { return this.filters; } } }