diff --git a/core-tiger/src/test/java/org/springframework/security/config/AnnotationDrivenBeanDefinitionParserTests.java b/core-tiger/src/test/java/org/springframework/security/config/AnnotationDrivenBeanDefinitionParserTests.java new file mode 100644 index 0000000000..9d3b6651a5 --- /dev/null +++ b/core-tiger/src/test/java/org/springframework/security/config/AnnotationDrivenBeanDefinitionParserTests.java @@ -0,0 +1,70 @@ +package org.springframework.security.config; + +import static org.junit.Assert.fail; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.security.AccessDeniedException; +import org.springframework.security.AuthenticationCredentialsNotFoundException; +import org.springframework.security.GrantedAuthority; +import org.springframework.security.GrantedAuthorityImpl; +import org.springframework.security.annotation.BusinessService; +import org.springframework.security.context.SecurityContextHolder; +import org.springframework.security.providers.UsernamePasswordAuthenticationToken; + +/** + * @author Ben Alex + * @version $Id: InterceptMethodsBeanDefinitionDecoratorTests.java 2217 2007-10-27 00:45:30Z luke_t $ + */ +public class AnnotationDrivenBeanDefinitionParserTests { + private ClassPathXmlApplicationContext appContext; + + private BusinessService target; + + @Before + public void loadContext() { + appContext = new ClassPathXmlApplicationContext("org/springframework/security/config/annotated-method-security.xml"); + target = (BusinessService) appContext.getBean("target"); + } + + @After + public void closeAppContext() { + if (appContext != null) { + appContext.close(); + } + SecurityContextHolder.clearContext(); + } + + @Test + public void targetShouldPreventProtectedMethodInvocationWithNoContext() { + try { + target.someUserMethod1(); + fail("Expected AuthenticationCredentialsNotFoundException"); + } catch (AuthenticationCredentialsNotFoundException expected) { + } + } + + @Test + public void targetShouldAllowProtectedMethodInvocationWithCorrectRole() { + UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password", + new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_USER")}); + SecurityContextHolder.getContext().setAuthentication(token); + + target.someUserMethod1(); + } + + @Test + public void targetShouldPreventProtectedMethodInvocationWithIncorrectRole() { + UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password", + new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_SOMEOTHERROLE")}); + SecurityContextHolder.getContext().setAuthentication(token); + + try { + target.someAdminMethod(); + fail("Expected AccessDeniedException"); + } catch (AccessDeniedException expected) { + } + } +} diff --git a/core/src/main/java/org/springframework/security/config/AnnotationDrivenBeanDefinitionParser.java b/core/src/main/java/org/springframework/security/config/AnnotationDrivenBeanDefinitionParser.java index 6cbf33cc5b..bf512cf34f 100644 --- a/core/src/main/java/org/springframework/security/config/AnnotationDrivenBeanDefinitionParser.java +++ b/core/src/main/java/org/springframework/security/config/AnnotationDrivenBeanDefinitionParser.java @@ -12,18 +12,21 @@ import org.springframework.security.intercept.method.aopalliance.MethodSecurityI import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; +import org.springframework.util.StringUtils; + import org.w3c.dom.Element; /** * Processes the top-level "annotation-driven" element. - * + * * @author Ben Alex * @version $Id$ */ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser { public static final String SECURITY_ANNOTATION_ATTRIBUTES_CLASS = "org.springframework.security.annotation.SecurityAnnotationAttributes"; - + private static final String ATT_ACCESS_MGR = "access-decision-manager"; + public BeanDefinition parse(Element element, ParserContext parserContext) { // Reflectively obtain the Annotation-based ObjectDefinitionSource. // Reflection is used to avoid a compile-time dependency on SECURITY_ANNOTATION_ATTRIBUTES_CLASS, as this parser is in the Java 4 project whereas the dependency is in the Tiger project. @@ -34,26 +37,38 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser { } catch (Exception ex) { ReflectionUtils.handleReflectionException(ex); } - + RootBeanDefinition securityAnnotations = new RootBeanDefinition(clazz); parserContext.getRegistry().registerBeanDefinition(BeanIds.SECURITY_ANNOTATION_ATTRIBUTES, securityAnnotations); RootBeanDefinition methodDefinitionAttributes = new RootBeanDefinition(MethodDefinitionAttributes.class); methodDefinitionAttributes.getPropertyValues().addPropertyValue("attributes", new RuntimeBeanReference(BeanIds.SECURITY_ANNOTATION_ATTRIBUTES)); parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_DEFINITION_ATTRIBUTES, methodDefinitionAttributes); - - MethodSecurityInterceptorUtils.registerPostProcessorIfNecessary(parserContext.getRegistry()); - + RootBeanDefinition interceptor = new RootBeanDefinition(MethodSecurityInterceptor.class); + + String accessManagerId = element.getAttribute(ATT_ACCESS_MGR); + + if (!StringUtils.hasText(accessManagerId)) { + ConfigUtils.registerDefaultAccessManagerIfNecessary(parserContext); + accessManagerId = BeanIds.ACCESS_MANAGER; + } + + interceptor.getPropertyValues().addPropertyValue("accessDecisionManager", + new RuntimeBeanReference(accessManagerId)); + + interceptor.getPropertyValues().addPropertyValue("authenticationManager", + new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER)); + interceptor.getPropertyValues().addPropertyValue("objectDefinitionSource", new RuntimeBeanReference(BeanIds.METHOD_DEFINITION_ATTRIBUTES)); parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_SECURITY_INTERCEPTOR, interceptor); - + RootBeanDefinition advisor = new RootBeanDefinition(MethodDefinitionSourceAdvisor.class); advisor.getConstructorArgumentValues().addGenericArgumentValue(interceptor); parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_DEFINITION_SOURCE_ADVISOR, advisor); - + AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element); - + return null; } } diff --git a/core/src/main/java/org/springframework/security/config/ConfigUtils.java b/core/src/main/java/org/springframework/security/config/ConfigUtils.java index 73d15eb1b7..f614078266 100644 --- a/core/src/main/java/org/springframework/security/config/ConfigUtils.java +++ b/core/src/main/java/org/springframework/security/config/ConfigUtils.java @@ -3,18 +3,18 @@ package org.springframework.security.config; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.ManagedList; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.security.AccessDecisionManager; import org.springframework.security.AuthenticationManager; import org.springframework.security.providers.ProviderManager; import org.springframework.security.userdetails.UserDetailsService; import org.springframework.security.vote.AffirmativeBased; import org.springframework.security.vote.AuthenticatedVoter; import org.springframework.security.vote.RoleVoter; -import org.springframework.util.Assert; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import java.util.Arrays; import java.util.Map; @@ -27,23 +27,17 @@ import java.util.Map; * @version $Id$ */ public abstract class ConfigUtils { - static void registerAccessManagerIfNecessary(ConfigurableListableBeanFactory bf) { - if (bf.getBeanNamesForType(AccessDecisionManager.class).length > 0) { - return; - } + private static final Log logger = LogFactory.getLog(ConfigUtils.class); - Assert.isInstanceOf(BeanDefinitionRegistry.class, bf, "Auto-registration of default AccessManager will " + - "only work with a BeanFactory which implements BeanDefinitionRegistry"); + static void registerDefaultAccessManagerIfNecessary(ParserContext parserContext) { - BeanDefinitionRegistry registry = (BeanDefinitionRegistry)bf; - - if (!registry.containsBeanDefinition(BeanIds.ACCESS_MANAGER)) { + if (!parserContext.getRegistry().containsBeanDefinition(BeanIds.ACCESS_MANAGER)) { BeanDefinitionBuilder accessMgrBuilder = BeanDefinitionBuilder.rootBeanDefinition(AffirmativeBased.class); accessMgrBuilder.addPropertyValue("decisionVoters", Arrays.asList(new Object[] {new RoleVoter(), new AuthenticatedVoter()})); BeanDefinition accessMgr = accessMgrBuilder.getBeanDefinition(); - registry.registerBeanDefinition(BeanIds.ACCESS_MANAGER, accessMgr); + parserContext.getRegistry().registerBeanDefinition(BeanIds.ACCESS_MANAGER, accessMgr); } } @@ -66,32 +60,6 @@ public abstract class ConfigUtils { } - /** - * Supplies the BeanDefinition for an instance of AbstractSecurityInterceptor with the default - * AccessDecisionManager and AuthenticationManager. - * - * @param beanFactory - * @param securityInterceptor - */ - static void configureSecurityInterceptor(ConfigurableListableBeanFactory beanFactory, - BeanDefinition securityInterceptor) { - - ConfigUtils.registerAccessManagerIfNecessary(beanFactory); - - Map accessManagers = beanFactory.getBeansOfType(AccessDecisionManager.class); - - if (accessManagers.size() > 1) { - throw new IllegalArgumentException("More than one AccessDecisionManager registered. Please specify one " + - " using the TODO attribute."); - } - - AccessDecisionManager accessMgr = (AccessDecisionManager) accessManagers.values().toArray()[0]; - - securityInterceptor.getPropertyValues().addPropertyValue("accessDecisionManager", accessMgr); - securityInterceptor.getPropertyValues().addPropertyValue("authenticationManager", - getAuthenticationManager(beanFactory)); - } - static UserDetailsService getUserDetailsService(ConfigurableListableBeanFactory bf) { Map services = bf.getBeansOfType(UserDetailsService.class); diff --git a/core/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java b/core/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java index 44affc679f..f0851ca964 100644 --- a/core/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java +++ b/core/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java @@ -73,6 +73,8 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { static final String ATT_SERVLET_API_PROVISION = "servlet-api-provision"; static final String DEF_SERVLET_API_PROVISION = "true"; + static final String ATT_ACCESS_MGR = "access-decision-manager"; + public BeanDefinition parse(Element element, ParserContext parserContext) { RootBeanDefinition filterChainProxy = new RootBeanDefinition(FilterChainProxy.class); RootBeanDefinition httpScif = new RootBeanDefinition(HttpSessionContextIntegrationFilter.class); @@ -139,6 +141,19 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { filterSecurityInterceptorBuilder.addPropertyValue("objectDefinitionSource", interceptorFilterInvDefSource); + // Set up the access manager and authentication mananger references for http + String accessManagerId = element.getAttribute(ATT_ACCESS_MGR); + + if (!StringUtils.hasText(accessManagerId)) { + ConfigUtils.registerDefaultAccessManagerIfNecessary(parserContext); + accessManagerId = BeanIds.ACCESS_MANAGER; + } + + filterSecurityInterceptorBuilder.addPropertyValue("accessDecisionManager", + new RuntimeBeanReference(accessManagerId)); + filterSecurityInterceptorBuilder.addPropertyValue("authenticationManager", + ConfigUtils.registerProviderManagerIfNecessary(parserContext)); + parseInterceptUrls(DomUtils.getChildElementsByTagName(element, "intercept-url"), filterChainMap, interceptorFilterInvDefSource, channelFilterInvDefSource, parserContext); diff --git a/core/src/main/java/org/springframework/security/config/HttpSecurityConfigPostProcessor.java b/core/src/main/java/org/springframework/security/config/HttpSecurityConfigPostProcessor.java index cb65883e30..e89a06ccd8 100644 --- a/core/src/main/java/org/springframework/security/config/HttpSecurityConfigPostProcessor.java +++ b/core/src/main/java/org/springframework/security/config/HttpSecurityConfigPostProcessor.java @@ -38,12 +38,6 @@ public class HttpSecurityConfigPostProcessor implements BeanFactoryPostProcessor private Log logger = LogFactory.getLog(getClass()); public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { - ConfigUtils.registerAccessManagerIfNecessary(beanFactory); - BeanDefinition securityInterceptor = - beanFactory.getBeanDefinition(BeanIds.FILTER_SECURITY_INTERCEPTOR); - - ConfigUtils.configureSecurityInterceptor(beanFactory, securityInterceptor); - injectUserDetailsServiceIntoRememberMeServices(beanFactory); injectAuthenticationEntryPointIntoExceptionTranslationFilter(beanFactory); @@ -55,8 +49,7 @@ public class HttpSecurityConfigPostProcessor implements BeanFactoryPostProcessor private void injectUserDetailsServiceIntoRememberMeServices(ConfigurableListableBeanFactory beanFactory) { try { - BeanDefinition rememberMeServices = - beanFactory.getBeanDefinition(BeanIds.REMEMBER_ME_SERVICES); + BeanDefinition rememberMeServices = beanFactory.getBeanDefinition(BeanIds.REMEMBER_ME_SERVICES); rememberMeServices.getPropertyValues().addPropertyValue("userDetailsService", ConfigUtils.getUserDetailsService(beanFactory)); } catch (NoSuchBeanDefinitionException e) { diff --git a/core/src/main/java/org/springframework/security/config/InterceptMethodsBeanDefinitionDecorator.java b/core/src/main/java/org/springframework/security/config/InterceptMethodsBeanDefinitionDecorator.java index c85a3b6c99..ff3d1246cd 100644 --- a/core/src/main/java/org/springframework/security/config/InterceptMethodsBeanDefinitionDecorator.java +++ b/core/src/main/java/org/springframework/security/config/InterceptMethodsBeanDefinitionDecorator.java @@ -5,6 +5,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.aop.config.AbstractInterceptorDrivenBeanDefinitionDecorator; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.BeanDefinitionDecorator; import org.springframework.beans.factory.xml.ParserContext; @@ -13,6 +14,8 @@ import org.springframework.security.ConfigAttributeEditor; import org.springframework.security.intercept.method.MethodDefinitionMap; import org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor; import org.springframework.util.xml.DomUtils; +import org.springframework.util.StringUtils; + import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -22,33 +25,48 @@ import java.util.List; /** * @author Luke Taylor * @author Ben Alex - * + * * @version $Id$ */ public class InterceptMethodsBeanDefinitionDecorator implements BeanDefinitionDecorator { private BeanDefinitionDecorator delegate = new InternalInterceptMethodsBeanDefinitionDecorator(); public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) { - MethodSecurityInterceptorUtils.registerPostProcessorIfNecessary(parserContext.getRegistry()); + ConfigUtils.registerProviderManagerIfNecessary(parserContext); + ConfigUtils.registerDefaultAccessManagerIfNecessary(parserContext); return delegate.decorate(node, definition, parserContext); } } /** - * This is the real class which does the work. We need acccess to the ParserContext in order to register the - * post processor, + * This is the real class which does the work. We need acccess to the ParserContext in order to do bean + * registration. */ class InternalInterceptMethodsBeanDefinitionDecorator extends AbstractInterceptorDrivenBeanDefinitionDecorator { static final String ATT_CLASS = "class"; static final String ATT_METHOD = "method"; static final String ATT_ACCESS = "access"; - private Log logger = LogFactory.getLog(getClass()); + private static final String ATT_ACCESS_MGR = "access-decision-manager"; + + private Log logger = LogFactory.getLog(getClass()); protected BeanDefinition createInterceptorDefinition(Node node) { Element interceptMethodsElt = (Element)node; RootBeanDefinition interceptor = new RootBeanDefinition(MethodSecurityInterceptor.class); + String accessManagerId = interceptMethodsElt.getAttribute(ATT_ACCESS_MGR); + + if (!StringUtils.hasText(accessManagerId)) { + accessManagerId = BeanIds.ACCESS_MANAGER; + } + + interceptor.getPropertyValues().addPropertyValue("accessDecisionManager", + new RuntimeBeanReference(accessManagerId)); + + interceptor.getPropertyValues().addPropertyValue("authenticationManager", + new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER)); + Element beanNode = (Element)interceptMethodsElt.getParentNode(); // Get the class from the parent bean... String targetClassName = beanNode.getAttribute(ATT_CLASS); @@ -57,7 +75,8 @@ class InternalInterceptMethodsBeanDefinitionDecorator extends AbstractIntercepto try { targetClass = Thread.currentThread().getContextClassLoader().loadClass(targetClassName); } catch (ClassNotFoundException e) { - throw new IllegalArgumentException("Couldn't load class " + targetClassName, e); + logger.error("Couldn't load class " + targetClassName); + throw new SecurityConfigurationException("Couldn't load class " + targetClassName); } // Parse the included methods @@ -70,10 +89,10 @@ class InternalInterceptMethodsBeanDefinitionDecorator extends AbstractIntercepto String accessConfig = protectmethodElt.getAttribute(ATT_ACCESS); attributeEditor.setAsText(accessConfig); -// TODO: We want to use just the method names, but MethodDefinitionMap won't work that way. +// TODO: We want to use just the method names, but MethodDefinitionMap won't work that way. // methodMap.addSecureMethod(targetClass, protectmethodElt.getAttribute("method"), // (ConfigAttributeDefinition) attributeEditor.getValue()); - methodMap.addSecureMethod(protectmethodElt.getAttribute(ATT_METHOD), + methodMap.addSecureMethod(protectmethodElt.getAttribute(ATT_METHOD), (ConfigAttributeDefinition) attributeEditor.getValue()); } diff --git a/core/src/main/java/org/springframework/security/config/MethodSecurityInterceptorUtils.java b/core/src/main/java/org/springframework/security/config/MethodSecurityInterceptorUtils.java deleted file mode 100644 index ccb4e881cc..0000000000 --- a/core/src/main/java/org/springframework/security/config/MethodSecurityInterceptorUtils.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.springframework.security.config; - -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.BeanFactoryPostProcessor; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.RootBeanDefinition; -import org.springframework.core.Ordered; -import org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor; - -/** - * Provides convenience methods supporting method security configuration. - * - * @author Ben Alex - * @author Luke Taylor - * - */ -abstract class MethodSecurityInterceptorUtils { - - private static class MethodSecurityConfigPostProcessor implements BeanFactoryPostProcessor, Ordered { - - public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { - String[] interceptors = beanFactory.getBeanNamesForType(MethodSecurityInterceptor.class); - - for (int i=0; i < interceptors.length; i++) { - BeanDefinition interceptor = beanFactory.getBeanDefinition(interceptors[i]); - ConfigUtils.configureSecurityInterceptor(beanFactory, interceptor); - } - } - - public int getOrder() { - return HIGHEST_PRECEDENCE; - } - - } - - /** - * Causes a BeanFactoryPostProcessor to be registered that will ensure all MethodSecurityInterceptor - * instances are properly configured with an AccessDecisionManager etc. - * - * @param registry to register the BeanPostProcessorWith - */ - public static void registerPostProcessorIfNecessary(BeanDefinitionRegistry registry) { - if (registry.containsBeanDefinition(BeanIds.INTERCEPT_METHODS_BEAN_FACTORY_POST_PROCESSOR)) { - return; - } - - registry.registerBeanDefinition(BeanIds.INTERCEPT_METHODS_BEAN_FACTORY_POST_PROCESSOR, - new RootBeanDefinition(MethodSecurityInterceptorUtils.MethodSecurityConfigPostProcessor.class)); - } - -} diff --git a/core/src/test/java/org/springframework/security/config/InterceptMethodsBeanDefinitionDecoratorTests.java b/core/src/test/java/org/springframework/security/config/InterceptMethodsBeanDefinitionDecoratorTests.java index ba2308ddee..1c905e8955 100644 --- a/core/src/test/java/org/springframework/security/config/InterceptMethodsBeanDefinitionDecoratorTests.java +++ b/core/src/test/java/org/springframework/security/config/InterceptMethodsBeanDefinitionDecoratorTests.java @@ -16,29 +16,21 @@ import org.junit.*; * @version $Id$ */ public class InterceptMethodsBeanDefinitionDecoratorTests { - private static ClassPathXmlApplicationContext appContext; + private ClassPathXmlApplicationContext appContext; private TestBusinessBean target; - @BeforeClass - public static void loadContext() { - appContext = new ClassPathXmlApplicationContext("org/springframework/security/config/method-security.xml"); - } - - @AfterClass - public static void closeAppContext() { - if (appContext != null) { - appContext.close(); - } - } - @Before - public void setUp() { + public void loadContext() { + appContext = new ClassPathXmlApplicationContext("org/springframework/security/config/method-security.xml"); target = (TestBusinessBean) appContext.getBean("target"); } @After - public void clearSecurityContext() { + public void closeAppContext() { + if (appContext != null) { + appContext.close(); + } SecurityContextHolder.clearContext(); } diff --git a/samples/contacts/src/main/resources/applicationContext-common-authorization.xml b/samples/contacts/src/main/resources/applicationContext-common-authorization.xml index e4f8cb218f..605f308703 100644 --- a/samples/contacts/src/main/resources/applicationContext-common-authorization.xml +++ b/samples/contacts/src/main/resources/applicationContext-common-authorization.xml @@ -185,7 +185,7 @@ to the Contact presented as a method argument. --> - + diff --git a/samples/contacts/src/main/resources/applicationContext-common-business.xml b/samples/contacts/src/main/resources/applicationContext-common-business.xml index 082f1ff93c..ad1e6ee18f 100644 --- a/samples/contacts/src/main/resources/applicationContext-common-business.xml +++ b/samples/contacts/src/main/resources/applicationContext-common-business.xml @@ -1,5 +1,4 @@ - - + @@ -55,12 +58,12 @@ - - - - - - + + + + + + diff --git a/samples/contacts/src/main/webapp/WEB-INF/applicationContext-acegi-security.xml b/samples/contacts/src/main/webapp/WEB-INF/applicationContext-acegi-security.xml index b71d58c7a7..007fea6e9d 100644 --- a/samples/contacts/src/main/webapp/WEB-INF/applicationContext-acegi-security.xml +++ b/samples/contacts/src/main/webapp/WEB-INF/applicationContext-acegi-security.xml @@ -1,6 +1,4 @@ - - - + - - + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - Contacts Realm + - foobar - anonymousUser,ROLE_ANONYMOUS + + - foobar + - - + @@ -96,15 +65,15 @@ - springRocks + - springRocks + - + @@ -115,38 +84,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - @@ -169,18 +106,6 @@ false - - false - - - - - - - - @@ -199,14 +124,44 @@ +--> + + + + + + + + + + + + + + + + + + + + + - - - /j_spring_security_switch_user - /j_spring_security_exit_user - /spring-security-sample-contacts-filter/secure/index.htm - + + + - +