SEC-271: Fixed IllegalStateException being thrown by LogoutHandlerOrdereResolver and add an assert statement in the unit test

This commit is contained in:
Vishal Puri 2007-05-17 13:42:51 +00:00
parent a01bb3bbee
commit a934f82af4
4 changed files with 200 additions and 159 deletions

View File

@ -67,17 +67,21 @@ public class LogoutHandlerOrderResolver implements BeanFactoryPostProcessor {
for (int i = 0, n = names.length; i < n; i++) { for (int i = 0, n = names.length; i < n; i++) {
RootBeanDefinition definition = (RootBeanDefinition) beanFactory.getBeanDefinition(names[i]); RootBeanDefinition definition = (RootBeanDefinition) beanFactory.getBeanDefinition(names[i]);
if (Ordered.class.isAssignableFrom(definition.getBeanClass())) { if (definition.hasBeanClass()) {
definition.getPropertyValues().addPropertyValue("order", new Integer(getOrder(definition.getBeanClass()))); if (Ordered.class.isAssignableFrom(definition.getBeanClass())) {
} else { definition.getPropertyValues().addPropertyValue("order",
definition.getPropertyValues().addPropertyValue("order", new Integer(Integer.MAX_VALUE)); new Integer(getOrder(definition.getBeanClass())));
}
else {
definition.getPropertyValues().addPropertyValue("order", new Integer(Integer.MAX_VALUE));
}
} }
list.add(definition); list.add(definition);
} }
Collections.sort(list, new OrderComparator()); Collections.sort(list, new OrderComparator());
return list; return list;
} }
private int getOrder(Class clazz) { private int getOrder(Class clazz) {
if (clazz.getName().equals(TokenBasedRememberMeServices.class.getName())) { if (clazz.getName().equals(TokenBasedRememberMeServices.class.getName())) {
return 100; return 100;

View File

@ -3,19 +3,27 @@
*/ */
package org.acegisecurity.config; package org.acegisecurity.config;
import org.springframework.context.ApplicationContext; import java.util.Map;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.acegisecurity.ui.logout.LogoutHandler;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/** /**
* @author vpuri * @author vpuri
* *
*/ */
public class LogoutFilterBeanDefinitionParserTests extends TestCase { public class LogoutFilterBeanDefinitionParserTests extends TestCase {
public void testLogoutFilter(){ public void testLogoutFilter() {
ApplicationContext context = new ClassPathXmlApplicationContext("org/acegisecurity/config/logout-filter-with-handlers.xml"); ApplicationContext context = new ClassPathXmlApplicationContext(
"org/acegisecurity/config/logout-filter-with-handlers.xml");
ConfigurableListableBeanFactory bf = (ConfigurableListableBeanFactory) context.getAutowireCapableBeanFactory();
Map m = bf.getBeansOfType(LogoutHandler.class);
assertEquals(2, m.size());
} }
} }

View File

@ -14,11 +14,14 @@ http://www.springframework.org/schema/security http://www.springframework.org/sc
<!-- If LogoutFilter does not have setHandlers populated, introspect app ctx for LogoutHandlers, using Ordered (if present, otherwise assume Integer.MAX_VALUE) --> <!-- If LogoutFilter does not have setHandlers populated, introspect app ctx for LogoutHandlers, using Ordered (if present, otherwise assume Integer.MAX_VALUE) -->
<!-- The logoutUrl and redirectAfterLogout are both optional and default to that shown --> <!-- The logoutUrl and redirectAfterLogout are both optional and default to that shown -->
<security:logout-support id="logoutFilter" <security:logout-support id="logoutFilter"
redirectAfterLogoutUrl="/" logoutUrl="/logout"/> redirectAfterLogoutUrl="/" logoutUrl="/logout" />
<security:authentication-remember-me-services <security:authentication-remember-me-services
id="rememberMeServices" key="someValue" /> id="rememberMeServices" key="someValue" />
<bean id="SecurityContextLogoutHandler"
class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler" />
<security:principal-repository id="userDetailsService"> <security:principal-repository id="userDetailsService">
<security:user-definition username="vishal" <security:user-definition username="vishal"
password="nottellingya" enabled="true"> password="nottellingya" enabled="true">

View File

@ -1,148 +1,174 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans xmlns="http://www.springframework.org/schema/beans"
<!-- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- A simple "base bones" Acegi Security configuration. xmlns:security="http://www.springframework.org/schema/security"
- xmlns:util="http://www.springframework.org/schema/util"
- The sample includes the "popular" features that people tend to use. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
- Specifically, form authentication, remember-me, and anonymous processing. http://www.springframework.org/schema/util http://www.springframework.org/schema/beans/spring-util-2.0.xsd
- Other features aren't setup, as these can be added later by inserting http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd">
- the relevant XML fragments as specified in the Reference Guide.
- <!--
- To assist new users, the filters specified in the FilterChainProxy are - A simple "base bones" Acegi Security configuration.
- declared in the application context in the same order. Collaborators -
- required by those filters are placed at the end of the file. - The sample includes the "popular" features that people tend to use.
- - Specifically, form authentication, remember-me, and anonymous processing.
- $Id$ - Other features aren't setup, as these can be added later by inserting
--> - the relevant XML fragments as specified in the Reference Guide.
-
<beans> - To assist new users, the filters specified in the FilterChainProxy are
- declared in the application context in the same order. Collaborators
<bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy"> - required by those filters are placed at the end of the file.
<property name="filterInvocationDefinitionSource"> -
<value> - $Id$
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON -->
PATTERN_TYPE_APACHE_ANT
/**=httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
</value>
</property> <bean id="filterChainProxy"
</bean> class="org.acegisecurity.util.FilterChainProxy">
<property name="filterInvocationDefinitionSource">
<bean id="httpSessionContextIntegrationFilter" class="org.acegisecurity.context.HttpSessionContextIntegrationFilter"/> <value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
<bean id="logoutFilter" class="org.acegisecurity.ui.logout.LogoutFilter"> PATTERN_TYPE_APACHE_ANT
<constructor-arg value="/index.jsp"/> <!-- URL redirected to after logout --> /**=httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
<constructor-arg> </value>
<list> </property>
<ref bean="rememberMeServices"/> </bean>
<bean class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler"/>
</list> <!-- sessionCreation defaults to ifRequired(true) always(true) never(false) . -->
</constructor-arg> <security:session-context-integration
</bean> id="httpSessionContextIntegrationFilter" sessionCreation="ifRequired" />
<bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
<property name="authenticationManager" ref="authenticationManager"/> <!-- If LogoutFilter does not have setHandlers populated, introspect app ctx for LogoutHandlers, using Ordered (if present, otherwise assume Integer.MAX_VALUE) -->
<property name="authenticationFailureUrl" value="/acegilogin.jsp?login_error=1"/> <!-- The logoutUrl and redirectAfterLogout are both optional and default to that shown -->
<property name="defaultTargetUrl" value="/"/> <security:logout-support id="logoutFilter"
<property name="filterProcessesUrl" value="/j_acegi_security_check"/> redirectAfterLogoutUrl="/index.jsp" />
<property name="rememberMeServices" ref="rememberMeServices"/>
</bean> <security:authentication-remember-me-services
id="rememberMeServices" key="someValue" />
<bean id="securityContextHolderAwareRequestFilter" class="org.acegisecurity.wrapper.SecurityContextHolderAwareRequestFilter"/>
<bean id="rememberMeProcessingFilter" class="org.acegisecurity.ui.rememberme.RememberMeProcessingFilter"> <bean id="securityContextLogoutHandler"
<property name="authenticationManager" ref="authenticationManager"/> class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler" />
<property name="rememberMeServices" ref="rememberMeServices"/>
</bean> <!-- the URLs are all mandatory and have no defaults (well, except authenticationUrl) -->
<security:authentication-form id="authenticationProcessinFilter"
<bean id="anonymousProcessingFilter" class="org.acegisecurity.providers.anonymous.AnonymousProcessingFilter"> authenticationUrl="/j_acegi_security_check" defaultTargetUrl="/"
<property name="key" value="changeThis"/> errorFormUrl="/acegilogin.jsp?login_error=1" />
<property name="userAttribute" value="anonymousUser,ROLE_ANONYMOUS"/>
</bean> <!-- make it optional, if not supplied autodetect all auth-providers from app ctx, using Ordered to resolve their order -->
<security:authentication-mechanism id="authenticationManager" />
<bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter">
<property name="authenticationEntryPoint"> <!-- dao authentication provider "authenticationRepository" -->
<bean class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint"> <security:authentication-repository id="daoAuthenticationProvider" />
<property name="loginFormUrl" value="/acegilogin.jsp"/>
<property name="forceHttps" value="false"/> <bean id="securityContextHolderAwareRequestFilter"
</bean> class="org.acegisecurity.wrapper.SecurityContextHolderAwareRequestFilter" />
</property>
<property name="accessDeniedHandler"> <!-- makes the filter, but does little else, as it auto-detects everything -->
<bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl"> <security:authentication-remember-me-filter id="rememberMeFilter" />
<property name="errorPage" value="/accessDenied.jsp"/>
</bean> <bean id="anonymousProcessingFilter"
</property> class="org.acegisecurity.providers.anonymous.AnonymousProcessingFilter">
</bean> <property name="key" value="changeThis" />
<property name="userAttribute"
<bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor"> value="anonymousUser,ROLE_ANONYMOUS" />
<property name="authenticationManager" ref="authenticationManager"/> </bean>
<property name="accessDecisionManager">
<bean class="org.acegisecurity.vote.AffirmativeBased"> <!-- Basically accessDeniedUrl is optional, we if unspecified impl will auto-detect any AccessDeniedHandler in ctx and use it;
<property name="allowIfAllAbstainDecisions" value="false"/> alternately if there are > 1 such handlers, we can nominate the one to use via accessDeniedBeanRef; provide nested elements for
<property name="decisionVoters"> other props; i do not mind if you move the access denied stuff to a sub-element -->
<list> <security:exception-translation id="exceptionTranslationFilter">
<bean class="org.acegisecurity.vote.RoleVoter"/> <security:entry-point
<bean class="org.acegisecurity.vote.AuthenticatedVoter"/> entryPointBeanRef="authenticationEntryPoint" />
</list> </security:exception-translation>
</property>
</bean>
</property> <bean id="authenticationEntryPoint"
<property name="objectDefinitionSource"> class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
<value> <property name="loginFormUrl" value="/acegilogin.jsp" />
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON <property name="forceHttps" value="false" />
PATTERN_TYPE_APACHE_ANT </bean>
/secure/extreme/**=ROLE_SUPERVISOR
/secure/**=IS_AUTHENTICATED_REMEMBERED
/**=IS_AUTHENTICATED_ANONYMOUSLY <bean id="accessDeniedHandler"
</value> class="org.acegisecurity.ui.AccessDeniedHandlerImpl">
</property> <property name="errorPage" value="/accessDenied.jsp" />
</bean> </bean>
<bean id="rememberMeServices" class="org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices">
<property name="userDetailsService" ref="userDetailsService"/> <bean id="filterInvocationInterceptor"
<property name="key" value="changeThis"/> class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
</bean> <property name="authenticationManager"
ref="authenticationManager" />
<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager"> <property name="accessDecisionManager">
<property name="providers"> <bean class="org.acegisecurity.vote.AffirmativeBased">
<list> <property name="allowIfAllAbstainDecisions"
<ref local="daoAuthenticationProvider"/> value="false" />
<bean class="org.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider"> <property name="decisionVoters">
<property name="key" value="changeThis"/> <list>
</bean> <bean class="org.acegisecurity.vote.RoleVoter" />
<bean class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider"> <bean
<property name="key" value="changeThis"/> class="org.acegisecurity.vote.AuthenticatedVoter" />
</bean> </list>
</list> </property>
</property> </bean>
</bean> </property>
<property name="objectDefinitionSource">
<bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider"> <value>
<property name="userDetailsService" ref="userDetailsService"/> CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
<property name="userCache"> PATTERN_TYPE_APACHE_ANT
<bean class="org.acegisecurity.providers.dao.cache.EhCacheBasedUserCache"> /secure/extreme/**=ROLE_SUPERVISOR
<property name="cache"> /secure/**=IS_AUTHENTICATED_REMEMBERED
<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean"> /**=IS_AUTHENTICATED_ANONYMOUSLY
<property name="cacheManager"> </value>
<bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/> </property>
</property> </bean>
<property name="cacheName" value="userCache"/>
</bean>
</property> <!--<bean id="authenticationManager"
</bean> class="org.acegisecurity.providers.ProviderManager">
</property> <property name="providers">
</bean> <list>
<ref local="daoAuthenticationProvider" />
<!-- UserDetailsService is the most commonly frequently Acegi Security interface implemented by end users --> <bean
<bean id="userDetailsService" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl"> class="org.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider">
<property name="userProperties"> <property name="key" value="changeThis" />
<bean class="org.springframework.beans.factory.config.PropertiesFactoryBean"> </bean>
<property name="location" value="/WEB-INF/users.properties"/> <bean
</bean> class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider">
</property> <property name="key" value="changeThis" />
</bean> </bean>
</list>
<!-- This bean is optional; it isn't used by any other bean as it only listens and logs --> </property>
<bean id="loggerListener" class="org.acegisecurity.event.authentication.LoggerListener"/> </bean>-->
<bean id="userCache"
class="org.acegisecurity.providers.dao.cache.EhCacheBasedUserCache">
<property name="cache">
<bean
class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager">
<bean
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" />
</property>
<property name="cacheName" value="userCache" />
</bean>
</property>
</bean>
<!-- UserDetailsService is the most commonly frequently Acegi Security interface implemented by end users -->
<security:principal-repository id="userDetailsService">
<security:properties resource="/WEB-INF/users.properties" />
</security:principal-repository>
<!-- This bean is optional; it isn't used by any other bean as it only listens and logs -->
<bean id="loggerListener"
class="org.acegisecurity.event.authentication.LoggerListener" />
</beans> </beans>