SEC-1126: separated out spring-security-config module containing namespace configuration classes and resources

This commit is contained in:
Luke Taylor
2009-03-23 04:23:48 +00:00
parent a45ba138f7
commit 2c985a1c36
92 changed files with 322 additions and 79 deletions

View File

@@ -0,0 +1,134 @@
package org.springframework.security.config;
import static org.junit.Assert.*;
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
import org.springframework.security.providers.ProviderManager;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import org.springframework.security.providers.AuthenticationProvider;
import org.springframework.security.providers.encoding.ShaPasswordEncoder;
import org.springframework.security.util.FieldUtils;
import org.springframework.context.support.AbstractXmlApplicationContext;
import org.junit.Test;
import org.junit.After;
import java.util.List;
/**
* Tests for {@link AuthenticationProviderBeanDefinitionParser}.
*
* @author Luke Taylor
* @version $Id$
*/
public class AuthenticationProviderBeanDefinitionParserTests {
private AbstractXmlApplicationContext appContext;
private UsernamePasswordAuthenticationToken bob = new UsernamePasswordAuthenticationToken("bob", "bobspassword");
@After
public void closeAppContext() {
if (appContext != null) {
appContext.close();
}
}
@Test
public void worksWithEmbeddedUserService() {
setContext(" <authentication-provider>" +
" <user-service>" +
" <user name='bob' password='bobspassword' authorities='ROLE_A' />" +
" </user-service>" +
" </authentication-provider>");
getProvider().authenticate(bob);
}
@Test
public void externalUserServiceRefWorks() throws Exception {
setContext(" <authentication-provider user-service-ref='myUserService' />" +
" <user-service id='myUserService'>" +
" <user name='bob' password='bobspassword' authorities='ROLE_A' />" +
" </user-service>");
getProvider().authenticate(bob);
}
@Test
public void providerWithMd5PasswordEncoderWorks() throws Exception {
setContext(" <authentication-provider>" +
" <password-encoder hash='md5'/>" +
" <user-service>" +
" <user name='bob' password='12b141f35d58b8b3a46eea65e6ac179e' authorities='ROLE_A' />" +
" </user-service>" +
" </authentication-provider>");
getProvider().authenticate(bob);
}
@Test
public void providerWithShaPasswordEncoderWorks() throws Exception {
setContext(" <authentication-provider>" +
" <password-encoder hash='{sha}'/>" +
" <user-service>" +
" <user name='bob' password='{SSHA}PpuEwfdj7M1rs0C2W4ssSM2XEN/Y6S5U' authorities='ROLE_A' />" +
" </user-service>" +
" </authentication-provider>");
getProvider().authenticate(bob);
}
@Test
public void providerWithSha256PasswordEncoderIsSupported() throws Exception {
setContext(" <authentication-provider>" +
" <password-encoder hash='sha-256'/>" +
" <user-service>" +
" <user name='bob' password='notused' authorities='ROLE_A' />" +
" </user-service>" +
" </authentication-provider>");
ShaPasswordEncoder encoder = (ShaPasswordEncoder) FieldUtils.getFieldValue(getProvider(), "passwordEncoder");
assertEquals("SHA-256", encoder.getAlgorithm());
}
@Test
public void passwordIsBase64EncodedWhenBase64IsEnabled() throws Exception {
setContext(" <authentication-provider>" +
" <password-encoder hash='md5' base64='true'/>" +
" <user-service>" +
" <user name='bob' password='ErFB811YuLOkbupl5qwXng==' authorities='ROLE_A' />" +
" </user-service>" +
" </authentication-provider>");
getProvider().authenticate(bob);
}
@Test
public void externalUserServicePasswordEncoderAndSaltSourceWork() throws Exception {
setContext(" <authentication-provider user-service-ref='customUserService'>" +
" <password-encoder ref='customPasswordEncoder'>" +
" <salt-source ref='saltSource'/>" +
" </password-encoder>" +
" </authentication-provider>" +
" <b:bean id='customPasswordEncoder' " +
"class='org.springframework.security.providers.encoding.Md5PasswordEncoder'/>" +
" <b:bean id='saltSource' " +
" class='org.springframework.security.providers.dao.salt.ReflectionSaltSource'>" +
" <b:property name='userPropertyToUse' value='username'/>" +
" </b:bean>" +
" <b:bean id='customUserService' " +
" class='org.springframework.security.userdetails.memory.InMemoryDaoImpl'>" +
" <b:property name='userMap' value='bob=f117f0862384e9497ff4f470e3522606,ROLE_A'/>" +
" </b:bean>");
getProvider().authenticate(bob);
}
private AuthenticationProvider getProvider() {
List<AuthenticationProvider> providers =
((ProviderManager)appContext.getBean(BeanIds.AUTHENTICATION_MANAGER)).getProviders();
return providers.get(0);
}
private void setContext(String context) {
appContext = new InMemoryXmlApplicationContext(context);
}
}

View File

@@ -0,0 +1,13 @@
package org.springframework.security.config;
public abstract class ConfigTestUtils {
public static final String AUTH_PROVIDER_XML =
" <authentication-provider>" +
" <user-service id='us'>" +
" <user name='bob' password='bobspassword' authorities='ROLE_A,ROLE_B' />" +
" <user name='bill' password='billspassword' authorities='ROLE_A,ROLE_B,AUTH_OTHER' />" +
" <user name='admin' password='password' authorities='ROLE_ADMIN,ROLE_USER' />" +
" <user name='user' password='password' authorities='ROLE_USER' />" +
" </user-service>" +
" </authentication-provider>";
}

View File

@@ -0,0 +1,43 @@
package org.springframework.security.config;
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.Test;
import org.springframework.context.support.AbstractXmlApplicationContext;
import org.springframework.security.afterinvocation.AfterInvocationProviderManager;
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
import org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor;
public class CustomAfterInvocationProviderBeanDefinitionDecoratorTests {
private AbstractXmlApplicationContext appContext;
@After
public void closeAppContext() {
if (appContext != null) {
appContext.close();
appContext = null;
}
}
@Test
public void customAfterInvocationProviderIsAddedToInterceptor() {
setContext(
"<global-method-security />" +
"<b:bean id='aip' class='org.springframework.security.config.MockAfterInvocationProvider'>" +
" <custom-after-invocation-provider />" +
"</b:bean>" +
ConfigTestUtils.AUTH_PROVIDER_XML
);
MethodSecurityInterceptor msi = (MethodSecurityInterceptor) appContext.getBean(GlobalMethodSecurityBeanDefinitionParser.SECURITY_INTERCEPTOR_ID);
AfterInvocationProviderManager apm = (AfterInvocationProviderManager) msi.getAfterInvocationManager();
assertNotNull(apm);
assertEquals(1, apm.getProviders().size());
assertTrue(apm.getProviders().get(0) instanceof MockAfterInvocationProvider);
}
private void setContext(String context) {
appContext = new InMemoryXmlApplicationContext(context);
}
}

View File

@@ -0,0 +1,44 @@
package org.springframework.security.config;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
import org.springframework.security.providers.ProviderManager;
public class CustomAuthenticationProviderBeanDefinitionDecoratorTests {
@Test
public void decoratedProviderParsesSuccessfully() {
InMemoryXmlApplicationContext ctx = new InMemoryXmlApplicationContext(
"<b:bean class='org.springframework.security.providers.dao.DaoAuthenticationProvider'>" +
" <custom-authentication-provider />" +
" <b:property name='userDetailsService' ref='us'/>" +
"</b:bean>" +
"<user-service id='us'>" +
" <user name='bob' password='bobspassword' authorities='ROLE_A,ROLE_B' />" +
"</user-service>"
);
ProviderManager authMgr = (ProviderManager) ctx.getBean(BeanIds.AUTHENTICATION_MANAGER);
assertEquals(1, authMgr.getProviders().size());
}
@Test
public void decoratedBeanAndRegisteredProviderAreTheSameObject() {
InMemoryXmlApplicationContext ctx = new InMemoryXmlApplicationContext(
"<b:bean id='myProvider' class='org.springframework.security.providers.dao.DaoAuthenticationProvider'>" +
" <custom-authentication-provider />" +
" <b:property name='userDetailsService' ref='us'/>" +
"</b:bean>" +
"<user-service id='us'>" +
" <user name='bob' password='bobspassword' authorities='ROLE_A,ROLE_B' />" +
"</user-service>"
);
ProviderManager authMgr = (ProviderManager) ctx.getBean(BeanIds.AUTHENTICATION_MANAGER);
assertEquals(1, authMgr.getProviders().size());
assertSame(ctx.getBean("myProvider"), authMgr.getProviders().get(0));
}
}

View File

@@ -0,0 +1,73 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* 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.security.config;
import javax.sql.DataSource;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.Assert;
/**
* Populates a database with test data for JDBC testing.
*
* @author Ben Alex
* @version $Id: DataSourcePopulator.java 2291 2007-12-03 02:56:52Z benalex $
*/
public class DataSourcePopulator implements InitializingBean {
//~ Instance fields ================================================================================================
JdbcTemplate template;
public void afterPropertiesSet() throws Exception {
Assert.notNull(template, "dataSource required");
template.execute("CREATE TABLE USERS(USERNAME VARCHAR_IGNORECASE(50) NOT NULL PRIMARY KEY,PASSWORD VARCHAR_IGNORECASE(50) NOT NULL,ENABLED BOOLEAN NOT NULL);");
template.execute("CREATE TABLE AUTHORITIES(USERNAME VARCHAR_IGNORECASE(50) NOT NULL,AUTHORITY VARCHAR_IGNORECASE(50) NOT NULL,CONSTRAINT FK_AUTHORITIES_USERS FOREIGN KEY(USERNAME) REFERENCES USERS(USERNAME));");
template.execute("CREATE UNIQUE INDEX IX_AUTH_USERNAME ON AUTHORITIES(USERNAME,AUTHORITY);");
/*
Passwords encoded using MD5, NOT in Base64 format, with null as salt
Encoded password for rod is "koala"
Encoded password for dianne is "emu"
Encoded password for scott is "wombat"
Encoded password for peter is "opal" (but user is disabled)
Encoded password for bill is "wombat"
Encoded password for bob is "wombat"
Encoded password for jane is "wombat"
*/
template.execute("INSERT INTO USERS VALUES('rod','koala',TRUE);");
template.execute("INSERT INTO USERS VALUES('dianne','65d15fe9156f9c4bbffd98085992a44e',TRUE);");
template.execute("INSERT INTO USERS VALUES('scott','2b58af6dddbd072ed27ffc86725d7d3a',TRUE);");
template.execute("INSERT INTO USERS VALUES('peter','22b5c9accc6e1ba628cedc63a72d57f8',FALSE);");
template.execute("INSERT INTO USERS VALUES('bill','2b58af6dddbd072ed27ffc86725d7d3a',TRUE);");
template.execute("INSERT INTO USERS VALUES('bob','2b58af6dddbd072ed27ffc86725d7d3a',TRUE);");
template.execute("INSERT INTO USERS VALUES('jane','2b58af6dddbd072ed27ffc86725d7d3a',TRUE);");
template.execute("INSERT INTO AUTHORITIES VALUES('rod','ROLE_USER');");
template.execute("INSERT INTO AUTHORITIES VALUES('rod','ROLE_SUPERVISOR');");
template.execute("INSERT INTO AUTHORITIES VALUES('dianne','ROLE_USER');");
template.execute("INSERT INTO AUTHORITIES VALUES('scott','ROLE_USER');");
template.execute("INSERT INTO AUTHORITIES VALUES('peter','ROLE_USER');");
template.execute("INSERT INTO AUTHORITIES VALUES('bill','ROLE_USER');");
template.execute("INSERT INTO AUTHORITIES VALUES('bob','ROLE_USER');");
template.execute("INSERT INTO AUTHORITIES VALUES('jane','ROLE_USER');");
}
public void setDataSource(DataSource dataSource) {
this.template = new JdbcTemplate(dataSource);
}
}

View File

@@ -0,0 +1,78 @@
package org.springframework.security.config;
import static org.junit.Assert.*;
import java.util.List;
import org.junit.After;
import org.junit.Test;
import org.springframework.context.support.AbstractXmlApplicationContext;
import org.springframework.mock.web.MockFilterChain;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.ConfigAttribute;
import org.springframework.security.SecurityConfig;
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
import org.springframework.security.intercept.web.DefaultFilterInvocationSecurityMetadataSource;
import org.springframework.security.intercept.web.FilterInvocation;
/**
*
* @author Luke Taylor
* @version $Id$
*/
public class FilterInvocationDefinitionSourceParserTests {
private AbstractXmlApplicationContext appContext;
@After
public void closeAppContext() {
if (appContext != null) {
appContext.close();
appContext = null;
}
}
private void setContext(String context) {
appContext = new InMemoryXmlApplicationContext(context);
}
@Test
public void parsingMinimalConfigurationIsSuccessful() {
setContext(
"<filter-invocation-definition-source id='fids'>" +
" <intercept-url pattern='/**' access='ROLE_A'/>" +
"</filter-invocation-definition-source>");
DefaultFilterInvocationSecurityMetadataSource fids = (DefaultFilterInvocationSecurityMetadataSource) appContext.getBean("fids");
List<? extends ConfigAttribute> cad = fids.getAttributes(createFilterInvocation("/anything", "GET"));
assertNotNull(cad);
assertTrue(cad.contains(new SecurityConfig("ROLE_A")));
}
@Test
public void parsingWithinFilterSecurityInterceptorIsSuccessful() {
setContext(
"<http auto-config='true'/>" +
"<b:bean id='fsi' class='org.springframework.security.intercept.web.FilterSecurityInterceptor' autowire='byType'>" +
" <b:property name='securityMetadataSource'>" +
" <filter-invocation-definition-source>" +
" <intercept-url pattern='/secure/extreme/**' access='ROLE_SUPERVISOR'/>" +
" <intercept-url pattern='/secure/**' access='ROLE_USER'/>" +
" <intercept-url pattern='/**' access='ROLE_USER'/>" +
" </filter-invocation-definition-source>" +
" </b:property>" +
"</b:bean>" + ConfigTestUtils.AUTH_PROVIDER_XML);
}
private FilterInvocation createFilterInvocation(String path, String method) {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setRequestURI(null);
request.setMethod(method);
request.setServletPath(path);
return new FilterInvocation(request, new MockHttpServletResponse(), new MockFilterChain());
}
}

View File

@@ -0,0 +1,255 @@
package org.springframework.security.config;
import static org.junit.Assert.*;
import static org.springframework.security.config.ConfigTestUtils.AUTH_PROVIDER_XML;
import java.util.ArrayList;
import java.util.List;
import org.junit.After;
import org.junit.Test;
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
import org.springframework.context.support.AbstractXmlApplicationContext;
import org.springframework.security.AccessDeniedException;
import org.springframework.security.AuthenticationCredentialsNotFoundException;
import org.springframework.security.afterinvocation.AfterInvocationProviderManager;
import org.springframework.security.annotation.BusinessService;
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
import org.springframework.security.context.SecurityContextHolder;
import org.springframework.security.expression.method.MethodExpressionAfterInvocationProvider;
import org.springframework.security.expression.method.MethodExpressionVoter;
import org.springframework.security.providers.TestingAuthenticationToken;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import org.springframework.security.userdetails.UserDetailsService;
import org.springframework.security.util.AuthorityUtils;
import org.springframework.security.util.FieldUtils;
import org.springframework.security.vote.AffirmativeBased;
/**
* @author Ben Alex
* @author Luke Taylor
* @version $Id$
*/
public class GlobalMethodSecurityBeanDefinitionParserTests {
private AbstractXmlApplicationContext appContext;
private BusinessService target;
public void loadContext() {
setContext(
"<b:bean id='target' class='org.springframework.security.annotation.BusinessServiceImpl'/>" +
"<global-method-security>" +
" <protect-pointcut expression='execution(* *.someUser*(..))' access='ROLE_USER'/>" +
" <protect-pointcut expression='execution(* *.someAdmin*(..))' access='ROLE_ADMIN'/>" +
"</global-method-security>" + ConfigTestUtils.AUTH_PROVIDER_XML
);
target = (BusinessService) appContext.getBean("target");
}
@After
public void closeAppContext() {
if (appContext != null) {
appContext.close();
appContext = null;
}
SecurityContextHolder.clearContext();
target = null;
}
@Test(expected=AuthenticationCredentialsNotFoundException.class)
public void targetShouldPreventProtectedMethodInvocationWithNoContext() {
loadContext();
target.someUserMethod1();
}
@Test
public void targetShouldAllowProtectedMethodInvocationWithCorrectRole() {
loadContext();
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("user", "password");
SecurityContextHolder.getContext().setAuthentication(token);
target.someUserMethod1();
}
@Test(expected=AccessDeniedException.class)
public void targetShouldPreventProtectedMethodInvocationWithIncorrectRole() {
loadContext();
TestingAuthenticationToken token = new TestingAuthenticationToken("Test", "Password", "ROLE_SOMEOTHERROLE");
token.setAuthenticated(true);
SecurityContextHolder.getContext().setAuthentication(token);
target.someAdminMethod();
}
@Test
public void doesntInterfereWithBeanPostProcessing() {
setContext(
"<b:bean id='myUserService' class='org.springframework.security.config.PostProcessedMockUserDetailsService'/>" +
"<global-method-security />" +
"<authentication-provider user-service-ref='myUserService'/>" +
"<b:bean id='beanPostProcessor' class='org.springframework.security.config.MockUserServiceBeanPostProcessor'/>"
);
PostProcessedMockUserDetailsService service = (PostProcessedMockUserDetailsService)appContext.getBean("myUserService");
assertEquals("Hello from the post processor!", service.getPostProcessorWasHere());
}
@Test(expected=AccessDeniedException.class)
public void worksWithAspectJAutoproxy() {
setContext(
"<global-method-security>" +
" <protect-pointcut expression='execution(* org.springframework.security.config.*Service.*(..))'" +
" access='ROLE_SOMETHING' />" +
"</global-method-security>" +
"<b:bean id='myUserService' class='org.springframework.security.config.PostProcessedMockUserDetailsService'/>" +
"<aop:aspectj-autoproxy />" +
"<authentication-provider user-service-ref='myUserService'/>"
);
UserDetailsService service = (UserDetailsService) appContext.getBean("myUserService");
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
AuthorityUtils.createAuthorityList("ROLE_SOMEOTHERROLE"));
SecurityContextHolder.getContext().setAuthentication(token);
service.loadUserByUsername("notused");
}
@Test
public void supportsMethodArgumentsInPointcut() {
setContext(
"<b:bean id='target' class='org.springframework.security.annotation.BusinessServiceImpl'/>" +
"<global-method-security>" +
" <protect-pointcut expression='execution(* org.springframework.security.annotation.BusinessService.someOther(String))' access='ROLE_ADMIN'/>" +
" <protect-pointcut expression='execution(* org.springframework.security.annotation.BusinessService.*(..))' access='ROLE_USER'/>" +
"</global-method-security>" + ConfigTestUtils.AUTH_PROVIDER_XML
);
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("user", "password"));
target = (BusinessService) appContext.getBean("target");
// someOther(int) should not be matched by someOther(String), but should require ROLE_USER
target.someOther(0);
try {
// String version should required admin role
target.someOther("somestring");
fail("Expected AccessDeniedException");
} catch (AccessDeniedException expected) {
}
}
@Test
public void supportsBooleanPointcutExpressions() {
setContext(
"<b:bean id='target' class='org.springframework.security.annotation.BusinessServiceImpl'/>" +
"<global-method-security>" +
" <protect-pointcut expression=" +
" 'execution(* org.springframework.security.annotation.BusinessService.*(..)) " +
" and not execution(* org.springframework.security.annotation.BusinessService.someOther(String)))' " +
" access='ROLE_USER'/>" +
"</global-method-security>" + ConfigTestUtils.AUTH_PROVIDER_XML
);
target = (BusinessService) appContext.getBean("target");
// String method should not be protected
target.someOther("somestring");
// All others should require ROLE_USER
try {
target.someOther(0);
fail("Expected AuthenticationCredentialsNotFoundException");
} catch (AuthenticationCredentialsNotFoundException expected) {
}
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("user", "password"));
target.someOther(0);
}
@Test(expected=BeanDefinitionParsingException.class)
public void duplicateElementCausesError() {
setContext(
"<global-method-security />" +
"<global-method-security />"
);
}
@Test(expected=AccessDeniedException.class)
public void worksWithoutTargetOrClass() {
setContext(
"<global-method-security secured-annotations='enabled'/>" +
"<b:bean id='businessService' class='org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean'>" +
" <b:property name='serviceUrl' value='http://localhost:8080/SomeService'/>" +
" <b:property name='serviceInterface' value='org.springframework.security.annotation.BusinessService'/>" +
"</b:bean>" + AUTH_PROVIDER_XML
);
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
AuthorityUtils.createAuthorityList("ROLE_SOMEOTHERROLE"));
SecurityContextHolder.getContext().setAuthentication(token);
target = (BusinessService) appContext.getBean("businessService");
target.someUserMethod1();
}
// Expression configuration tests
@SuppressWarnings("unchecked")
@Test
public void expressionVoterAndAfterInvocationProviderUseSameExpressionHandlerInstance() throws Exception {
setContext("<global-method-security expression-annotations='enabled'/>" + AUTH_PROVIDER_XML);
AffirmativeBased adm = (AffirmativeBased) appContext.getBean(GlobalMethodSecurityBeanDefinitionParser.ACCESS_MANAGER_ID);
List voters = (List) FieldUtils.getFieldValue(adm, "decisionVoters");
MethodExpressionVoter mev = (MethodExpressionVoter) voters.get(0);
AfterInvocationProviderManager pm = (AfterInvocationProviderManager) appContext.getBean(BeanIds.AFTER_INVOCATION_MANAGER);
MethodExpressionAfterInvocationProvider aip = (MethodExpressionAfterInvocationProvider) pm.getProviders().get(0);
assertTrue(FieldUtils.getFieldValue(mev, "expressionHandler") == FieldUtils.getFieldValue(aip, "expressionHandler"));
}
@Test(expected=AccessDeniedException.class)
public void accessIsDeniedForHasRoleExpression() {
setContext(
"<global-method-security expression-annotations='enabled'/>" +
"<b:bean id='target' class='org.springframework.security.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
AUTH_PROVIDER_XML);
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("bob","bobspassword"));
target = (BusinessService) appContext.getBean("target");
target.someAdminMethod();
}
@Test
public void preAndPostFilterAnnotationsWorkWithLists() {
setContext(
"<global-method-security expression-annotations='enabled'/>" +
"<b:bean id='target' class='org.springframework.security.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
AUTH_PROVIDER_XML);
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("bob","bobspassword"));
target = (BusinessService) appContext.getBean("target");
List<String> arg = new ArrayList<String>();
arg.add("joe");
arg.add("bob");
arg.add("sam");
List<?> result = target.methodReturningAList(arg);
// Expression is (filterObject == name or filterObject == 'sam'), so "joe" should be gone after pre-filter
// PostFilter should remove sam from the return object
assertEquals(1, result.size());
assertEquals("bob", result.get(0));
}
@Test
public void prePostFilterAnnotationWorksWithArrays() {
setContext(
"<global-method-security expression-annotations='enabled'/>" +
"<b:bean id='target' class='org.springframework.security.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
AUTH_PROVIDER_XML);
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("bob","bobspassword"));
target = (BusinessService) appContext.getBean("target");
Object[] arg = new String[] {"joe", "bob", "sam"};
Object[] result = target.methodReturningAnArray(arg);
assertEquals(1, result.length);
assertEquals("bob", result[0]);
}
private void setContext(String context) {
appContext = new InMemoryXmlApplicationContext(context);
}
}

View File

@@ -0,0 +1,788 @@
package org.springframework.security.config;
import static org.junit.Assert.*;
import static org.springframework.security.config.ConfigTestUtils.AUTH_PROVIDER_XML;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.List;
import javax.servlet.Filter;
import org.junit.After;
import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
import org.springframework.context.support.AbstractXmlApplicationContext;
import org.springframework.mock.web.MockFilterChain;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockHttpSession;
import org.springframework.security.AccessDeniedException;
import org.springframework.security.ConfigAttribute;
import org.springframework.security.MockAuthenticationEntryPoint;
import org.springframework.security.SecurityConfig;
import org.springframework.security.concurrent.ConcurrentLoginException;
import org.springframework.security.concurrent.ConcurrentSessionControllerImpl;
import org.springframework.security.concurrent.ConcurrentSessionFilter;
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
import org.springframework.security.context.HttpSessionSecurityContextRepository;
import org.springframework.security.context.SecurityContextHolder;
import org.springframework.security.context.SecurityContextPersistenceFilter;
import org.springframework.security.intercept.web.FilterInvocation;
import org.springframework.security.intercept.web.FilterInvocationSecurityMetadataSource;
import org.springframework.security.intercept.web.FilterSecurityInterceptor;
import org.springframework.security.providers.TestingAuthenticationToken;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import org.springframework.security.providers.anonymous.AnonymousProcessingFilter;
import org.springframework.security.securechannel.ChannelProcessingFilter;
import org.springframework.security.ui.AuthenticationFailureHandler;
import org.springframework.security.ui.AuthenticationSuccessHandler;
import org.springframework.security.ui.ExceptionTranslationFilter;
import org.springframework.security.ui.SessionFixationProtectionFilter;
import org.springframework.security.ui.WebAuthenticationDetails;
import org.springframework.security.ui.basicauth.BasicProcessingFilter;
import org.springframework.security.ui.logout.LogoutFilter;
import org.springframework.security.ui.logout.LogoutHandler;
import org.springframework.security.ui.preauth.x509.X509PreAuthenticatedProcessingFilter;
import org.springframework.security.ui.rememberme.PersistentTokenBasedRememberMeServices;
import org.springframework.security.ui.webapp.AuthenticationProcessingFilter;
import org.springframework.security.ui.webapp.DefaultLoginPageGeneratingFilter;
import org.springframework.security.util.FieldUtils;
import org.springframework.security.util.FilterChainProxy;
import org.springframework.security.util.MockFilter;
import org.springframework.security.util.PortMapperImpl;
import org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter;
import org.springframework.util.ReflectionUtils;
/**
* @author Luke Taylor
* @version $Id$
*/
public class HttpSecurityBeanDefinitionParserTests {
private static final int AUTO_CONFIG_FILTERS = 10;
private AbstractXmlApplicationContext appContext;
@After
public void closeAppContext() {
if (appContext != null) {
appContext.close();
appContext = null;
}
SecurityContextHolder.clearContext();
}
@Test
public void minimalConfigurationParses() {
setContext("<http><http-basic /></http>" + AUTH_PROVIDER_XML);
}
@Test
public void httpAutoConfigSetsUpCorrectFilterList() throws Exception {
setContext("<http auto-config='true' />" + AUTH_PROVIDER_XML);
List<Filter> filterList = getFilters("/anyurl");
checkAutoConfigFilters(filterList);
assertEquals(true, FieldUtils.getFieldValue(appContext.getBean("_filterChainProxy"), "stripQueryStringFromUrls"));
assertEquals(true, FieldUtils.getFieldValue(filterList.get(AUTO_CONFIG_FILTERS-1), "securityMetadataSource.stripQueryStringFromUrls"));
}
@Test(expected=BeanDefinitionParsingException.class)
public void duplicateElementCausesError() throws Exception {
setContext("<http auto-config='true' /><http auto-config='true' />" + AUTH_PROVIDER_XML);
}
private void checkAutoConfigFilters(List<Filter> filterList) throws Exception {
assertEquals("Expected " + AUTO_CONFIG_FILTERS + " filters in chain", AUTO_CONFIG_FILTERS, filterList.size());
Iterator<Filter> filters = filterList.iterator();
assertTrue(filters.next() instanceof SecurityContextPersistenceFilter);
assertTrue(filters.next() instanceof LogoutFilter);
Object authProcFilter = filters.next();
assertTrue(authProcFilter instanceof AuthenticationProcessingFilter);
// Check RememberMeServices has been set on AuthenticationProcessingFilter
//Object rms = FieldUtils.getFieldValue(authProcFilter, "rememberMeServices");
//assertNotNull(rms);
//assertTrue(rms instanceof RememberMeServices);
//assertFalse(rms instanceof NullRememberMeServices);
assertTrue(filters.next() instanceof DefaultLoginPageGeneratingFilter);
assertTrue(filters.next() instanceof BasicProcessingFilter);
assertTrue(filters.next() instanceof SecurityContextHolderAwareRequestFilter);
//assertTrue(filters.next() instanceof RememberMeProcessingFilter);
assertTrue(filters.next() instanceof AnonymousProcessingFilter);
assertTrue(filters.next() instanceof ExceptionTranslationFilter);
assertTrue(filters.next() instanceof SessionFixationProtectionFilter);
Object fsiObj = filters.next();
assertTrue(fsiObj instanceof FilterSecurityInterceptor);
FilterSecurityInterceptor fsi = (FilterSecurityInterceptor) fsiObj;
assertTrue(fsi.isObserveOncePerRequest());
}
@Test
public void filterListShouldBeEmptyForUnprotectedUrl() throws Exception {
setContext(
" <http auto-config='true'>" +
" <intercept-url pattern='/unprotected' filters='none' />" +
" </http>" + AUTH_PROVIDER_XML);
List<Filter> filters = getFilters("/unprotected");
assertTrue(filters.size() == 0);
}
@Test
public void regexPathsWorkCorrectly() throws Exception {
setContext(
" <http auto-config='true' path-type='regex'>" +
" <intercept-url pattern='\\A\\/[a-z]+' filters='none' />" +
" </http>" + AUTH_PROVIDER_XML);
assertEquals(0, getFilters("/imlowercase").size());
// This will be matched by the default pattern ".*"
List<Filter> allFilters = getFilters("/ImCaughtByTheUniversalMatchPattern");
checkAutoConfigFilters(allFilters);
assertEquals(false, FieldUtils.getFieldValue(appContext.getBean("_filterChainProxy"), "stripQueryStringFromUrls"));
assertEquals(false, FieldUtils.getFieldValue(allFilters.get(AUTO_CONFIG_FILTERS-1), "securityMetadataSource.stripQueryStringFromUrls"));
}
@Test
public void lowerCaseComparisonAttributeIsRespectedByFilterChainProxy() throws Exception {
setContext(
" <http auto-config='true' path-type='ant' lowercase-comparisons='false'>" +
" <intercept-url pattern='/Secure*' filters='none' />" +
" </http>" + AUTH_PROVIDER_XML);
assertEquals(0, getFilters("/Secure").size());
// These will be matched by the default pattern "/**"
checkAutoConfigFilters(getFilters("/secure"));
checkAutoConfigFilters(getFilters("/ImCaughtByTheUniversalMatchPattern"));
}
@Test
public void formLoginWithNoLoginPageAddsDefaultLoginPageFilter() throws Exception {
setContext(
"<http auto-config='true' path-type='ant' lowercase-comparisons='false'>" +
" <form-login />" +
"</http>" + AUTH_PROVIDER_XML);
// These will be matched by the default pattern "/**"
checkAutoConfigFilters(getFilters("/anything"));
}
@Test
public void formLoginAlwaysUseDefaultSetsCorrectProperty() throws Exception {
setContext(
"<http>" +
" <form-login default-target-url='/default' always-use-default-target='true' />" +
"</http>" + AUTH_PROVIDER_XML);
// These will be matched by the default pattern "/**"
AuthenticationProcessingFilter filter = (AuthenticationProcessingFilter) getFilters("/anything").get(1);
assertEquals("/default", FieldUtils.getFieldValue(filter, "successHandler.defaultTargetUrl"));
assertEquals(Boolean.TRUE, FieldUtils.getFieldValue(filter, "successHandler.alwaysUseDefaultTargetUrl"));
}
@Test(expected=BeanCreationException.class)
public void invalidLoginPageIsDetected() throws Exception {
setContext(
"<http>" +
" <form-login login-page='noLeadingSlash'/>" +
"</http>" + AUTH_PROVIDER_XML);
}
@Test(expected=BeanCreationException.class)
public void invalidDefaultTargetUrlIsDetected() throws Exception {
setContext(
"<http>" +
" <form-login default-target-url='noLeadingSlash'/>" +
"</http>" + AUTH_PROVIDER_XML);
}
@Test(expected=BeanCreationException.class)
public void invalidLogoutUrlIsDetected() throws Exception {
setContext(
"<http>" +
" <logout logout-url='noLeadingSlash'/>" +
" <form-login />" +
"</http>" + AUTH_PROVIDER_XML);
}
@Test(expected=BeanCreationException.class)
public void invalidLogoutSuccessUrlIsDetected() throws Exception {
setContext(
"<http>" +
" <logout logout-success-url='noLeadingSlash'/>" +
" <form-login />" +
"</http>" + AUTH_PROVIDER_XML);
}
@Test
public void lowerCaseComparisonIsRespectedBySecurityFilterInvocationDefinitionSource() throws Exception {
setContext(
" <http auto-config='true' path-type='ant' lowercase-comparisons='false'>" +
" <intercept-url pattern='/Secure*' access='ROLE_A,ROLE_B' />" +
" <intercept-url pattern='/**' access='ROLE_C' />" +
" </http>" + AUTH_PROVIDER_XML);
FilterSecurityInterceptor fis = (FilterSecurityInterceptor) appContext.getBean(BeanIds.FILTER_SECURITY_INTERCEPTOR);
FilterInvocationSecurityMetadataSource fids = fis.getSecurityMetadataSource();
List<? extends ConfigAttribute> attrDef = fids.getAttributes(createFilterinvocation("/Secure", null));
assertEquals(2, attrDef.size());
assertTrue(attrDef.contains(new SecurityConfig("ROLE_A")));
assertTrue(attrDef.contains(new SecurityConfig("ROLE_B")));
attrDef = fids.getAttributes(createFilterinvocation("/secure", null));
assertEquals(1, attrDef.size());
assertTrue(attrDef.contains(new SecurityConfig("ROLE_C")));
}
@Test
public void httpMethodMatchIsSupported() throws Exception {
setContext(
" <http auto-config='true'>" +
" <intercept-url pattern='/**' access='ROLE_C' />" +
" <intercept-url pattern='/secure*' method='DELETE' access='ROLE_SUPERVISOR' />" +
" <intercept-url pattern='/secure*' method='POST' access='ROLE_A,ROLE_B' />" +
" </http>" + AUTH_PROVIDER_XML);
FilterSecurityInterceptor fis = (FilterSecurityInterceptor) appContext.getBean(BeanIds.FILTER_SECURITY_INTERCEPTOR);
FilterInvocationSecurityMetadataSource fids = fis.getSecurityMetadataSource();
List<? extends ConfigAttribute> attrs = fids.getAttributes(createFilterinvocation("/secure", "POST"));
assertEquals(2, attrs.size());
assertTrue(attrs.contains(new SecurityConfig("ROLE_A")));
assertTrue(attrs.contains(new SecurityConfig("ROLE_B")));
}
@Test
public void oncePerRequestAttributeIsSupported() throws Exception {
setContext("<http once-per-request='false'><http-basic /></http>" + AUTH_PROVIDER_XML);
List<Filter> filters = getFilters("/someurl");
FilterSecurityInterceptor fsi = (FilterSecurityInterceptor) filters.get(filters.size() - 1);
assertFalse(fsi.isObserveOncePerRequest());
}
@Test
public void accessDeniedPageAttributeIsSupported() throws Exception {
setContext("<http access-denied-page='/access-denied'><http-basic /></http>" + AUTH_PROVIDER_XML);
List<Filter> filters = getFilters("/someurl");
ExceptionTranslationFilter etf = (ExceptionTranslationFilter) filters.get(filters.size() - 3);
assertEquals("/access-denied", FieldUtils.getFieldValue(etf, "accessDeniedHandler.errorPage"));
}
@Test(expected=BeanCreationException.class)
public void invalidAccessDeniedUrlIsDetected() throws Exception {
setContext("<http auto-config='true' access-denied-page='noLeadingSlash'/>" + AUTH_PROVIDER_XML);
}
@Test
public void interceptUrlWithRequiresChannelAddsChannelFilterToStack() throws Exception {
setContext(
" <http auto-config='true'>" +
" <intercept-url pattern='/**' requires-channel='https' />" +
" </http>" + AUTH_PROVIDER_XML);
List<Filter> filters = getFilters("/someurl");
assertEquals("Expected " + (AUTO_CONFIG_FILTERS + 1) +" filters in chain", AUTO_CONFIG_FILTERS + 1, filters.size());
assertTrue(filters.get(0) instanceof ChannelProcessingFilter);
}
@Test
public void portMappingsAreParsedCorrectly() throws Exception {
setContext(
" <http auto-config='true'>" +
" <port-mappings>" +
" <port-mapping http='9080' https='9443'/>" +
" </port-mappings>" +
" </http>" + AUTH_PROVIDER_XML);
PortMapperImpl pm = (PortMapperImpl) appContext.getBean(BeanIds.PORT_MAPPER);
assertEquals(1, pm.getTranslatedPortMappings().size());
assertEquals(Integer.valueOf(9080), pm.lookupHttpPort(9443));
assertEquals(Integer.valueOf(9443), pm.lookupHttpsPort(9080));
}
@Test
public void portMappingsWorkWithPlaceholders() throws Exception {
System.setProperty("http", "9080");
System.setProperty("https", "9443");
setContext(
" <b:bean id='configurer' class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>" +
" <http auto-config='true'>" +
" <port-mappings>" +
" <port-mapping http='${http}' https='${https}'/>" +
" </port-mappings>" +
" </http>" + AUTH_PROVIDER_XML);
PortMapperImpl pm = (PortMapperImpl) appContext.getBean(BeanIds.PORT_MAPPER);
assertEquals(1, pm.getTranslatedPortMappings().size());
assertEquals(Integer.valueOf(9080), pm.lookupHttpPort(9443));
assertEquals(Integer.valueOf(9443), pm.lookupHttpsPort(9080));
}
@Test
public void accessDeniedPageWorkWithPlaceholders() throws Exception {
System.setProperty("accessDenied", "/go-away");
setContext(
" <b:bean id='configurer' class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>" +
" <http auto-config='true' access-denied-page='${accessDenied}'/>" + AUTH_PROVIDER_XML);
ExceptionTranslationFilter filter = (ExceptionTranslationFilter) appContext.getBean(BeanIds.EXCEPTION_TRANSLATION_FILTER);
assertEquals("/go-away", FieldUtils.getFieldValue(filter, "accessDeniedHandler.errorPage"));
}
@Test
public void externalFiltersAreTreatedCorrectly() throws Exception {
// Decorated user-filters should be added to stack. The others should be ignored.
setContext(
"<http auto-config='true'/>" + AUTH_PROVIDER_XML +
"<b:bean id='userFilter' class='org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter'>" +
" <custom-filter after='LOGOUT_FILTER'/>" +
"</b:bean>" +
"<b:bean id='userFilter1' class='org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter'>" +
" <custom-filter before='SESSION_CONTEXT_INTEGRATION_FILTER'/>" +
"</b:bean>" +
"<b:bean id='userFilter2' class='org.springframework.security.util.MockFilter'>" +
" <custom-filter position='FIRST'/>" +
"</b:bean>" +
"<b:bean id='userFilter3' class='org.springframework.security.util.MockFilter'/>" +
"<b:bean id='userFilter4' class='org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter'/>"
);
List<Filter> filters = getFilters("/someurl");
assertEquals(AUTO_CONFIG_FILTERS + 3, filters.size());
assertTrue(filters.get(0) instanceof MockFilter);
assertTrue(filters.get(1) instanceof SecurityContextHolderAwareRequestFilter);
assertTrue(filters.get(4) instanceof SecurityContextHolderAwareRequestFilter);
}
@Test(expected=BeanCreationException.class)
public void twoFiltersWithSameOrderAreRejected() {
setContext(
"<http auto-config='true'/>" + AUTH_PROVIDER_XML +
"<b:bean id='userFilter' class='org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter'>" +
" <custom-filter position='LOGOUT_FILTER'/>" +
"</b:bean>");
}
@Test
public void rememberMeServiceWorksWithTokenRepoRef() {
setContext(
"<http auto-config='true'>" +
" <remember-me token-repository-ref='tokenRepo'/>" +
"</http>" +
"<b:bean id='tokenRepo' " +
"class='org.springframework.security.ui.rememberme.InMemoryTokenRepositoryImpl'/> " + AUTH_PROVIDER_XML);
Object rememberMeServices = appContext.getBean(BeanIds.REMEMBER_ME_SERVICES);
assertTrue(rememberMeServices instanceof PersistentTokenBasedRememberMeServices);
}
@Test
public void rememberMeServiceWorksWithDataSourceRef() {
setContext(
"<http auto-config='true'>" +
" <remember-me data-source-ref='ds'/>" +
"</http>" +
"<b:bean id='ds' class='org.springframework.security.TestDataSource'> " +
" <b:constructor-arg value='tokendb'/>" +
"</b:bean>" + AUTH_PROVIDER_XML);
Object rememberMeServices = appContext.getBean(BeanIds.REMEMBER_ME_SERVICES);
assertTrue(rememberMeServices instanceof PersistentTokenBasedRememberMeServices);
}
@Test
@SuppressWarnings("unchecked")
public void rememberMeServiceWorksWithExternalServicesImpl() throws Exception {
setContext(
"<http auto-config='true'>" +
" <remember-me key='ourkey' services-ref='rms'/>" +
"</http>" +
"<b:bean id='rms' class='org.springframework.security.ui.rememberme.TokenBasedRememberMeServices'> " +
" <b:property name='userDetailsService' ref='us'/>" +
" <b:property name='key' value='ourkey'/>" +
" <b:property name='tokenValiditySeconds' value='5000'/>" +
"</b:bean>" +
AUTH_PROVIDER_XML);
assertEquals(5000, FieldUtils.getFieldValue(appContext.getBean(BeanIds.REMEMBER_ME_SERVICES),
"tokenValiditySeconds"));
// SEC-909
List<LogoutHandler> logoutHandlers = (List<LogoutHandler>) FieldUtils.getFieldValue(appContext.getBean(BeanIds.LOGOUT_FILTER), "handlers");
assertEquals(2, logoutHandlers.size());
assertEquals(appContext.getBean(BeanIds.REMEMBER_ME_SERVICES), logoutHandlers.get(1));
}
@Test
public void rememberMeTokenValidityIsParsedCorrectly() throws Exception {
setContext(
"<http auto-config='true'>" +
" <remember-me key='ourkey' token-validity-seconds='10000' />" +
"</http>" + AUTH_PROVIDER_XML);
assertEquals(10000, FieldUtils.getFieldValue(appContext.getBean(BeanIds.REMEMBER_ME_SERVICES),
"tokenValiditySeconds"));
}
@Test
public void rememberMeTokenValidityAllowsNegativeValueForNonPersistentImplementation() throws Exception {
setContext(
"<http auto-config='true'>" +
" <remember-me key='ourkey' token-validity-seconds='-1' />" +
"</http>" + AUTH_PROVIDER_XML);
assertEquals(-1, FieldUtils.getFieldValue(appContext.getBean(BeanIds.REMEMBER_ME_SERVICES),
"tokenValiditySeconds"));
}
@Test(expected=BeanDefinitionParsingException.class)
public void rememberMeTokenValidityRejectsNegativeValueForPersistentImplementation() throws Exception {
setContext(
"<http auto-config='true'>" +
" <remember-me token-validity-seconds='-1' token-repository-ref='tokenRepo'/>" +
"</http>" +
"<b:bean id='tokenRepo' class='org.springframework.security.ui.rememberme.InMemoryTokenRepositoryImpl'/> " +
AUTH_PROVIDER_XML);
}
@Test
public void rememberMeServiceConfigurationParsesWithCustomUserService() {
setContext(
"<http auto-config='true'>" +
" <remember-me key='somekey' user-service-ref='userService'/>" +
"</http>" +
"<b:bean id='userService' class='org.springframework.security.userdetails.MockUserDetailsService'/> " +
AUTH_PROVIDER_XML);
// AbstractRememberMeServices rememberMeServices = (AbstractRememberMeServices) appContext.getBean(BeanIds.REMEMBER_ME_SERVICES);
}
@Test
public void x509SupportAddsFilterAtExpectedPosition() throws Exception {
setContext(
"<http auto-config='true'>" +
" <x509 />" +
"</http>" + AUTH_PROVIDER_XML);
List<Filter> filters = getFilters("/someurl");
assertTrue(filters.get(2) instanceof X509PreAuthenticatedProcessingFilter);
}
@Test
public void concurrentSessionSupportAddsFilterAndExpectedBeans() throws Exception {
setContext(
"<http auto-config='true'>" +
" <concurrent-session-control session-registry-alias='seshRegistry' expired-url='/expired'/>" +
"</http>" + AUTH_PROVIDER_XML);
List<Filter> filters = getFilters("/someurl");
assertTrue(filters.get(0) instanceof ConcurrentSessionFilter);
assertNotNull(appContext.getBean("seshRegistry"));
assertNotNull(appContext.getBean(BeanIds.CONCURRENT_SESSION_CONTROLLER));
}
@Test
public void externalSessionRegistryBeanIsConfiguredCorrectly() throws Exception {
setContext(
"<http auto-config='true'>" +
" <concurrent-session-control session-registry-ref='seshRegistry' />" +
"</http>" +
"<b:bean id='seshRegistry' class='org.springframework.security.concurrent.SessionRegistryImpl'/>" +
AUTH_PROVIDER_XML);
Object sessionRegistry = appContext.getBean("seshRegistry");
Object sessionRegistryFromFilter = FieldUtils.getFieldValue(
appContext.getBean(BeanIds.CONCURRENT_SESSION_FILTER),"sessionRegistry");
Object sessionRegistryFromController = FieldUtils.getFieldValue(
appContext.getBean(BeanIds.CONCURRENT_SESSION_CONTROLLER),"sessionRegistry");
Object sessionRegistryFromFixationFilter = FieldUtils.getFieldValue(
appContext.getBean(BeanIds.SESSION_FIXATION_PROTECTION_FILTER),"sessionRegistry");
assertSame(sessionRegistry, sessionRegistryFromFilter);
assertSame(sessionRegistry, sessionRegistryFromController);
assertSame(sessionRegistry, sessionRegistryFromFixationFilter);
}
@Test(expected=BeanDefinitionParsingException.class)
public void concurrentSessionSupportCantBeUsedWithIndependentControllerBean() throws Exception {
setContext(
"<authentication-manager alias='authManager' session-controller-ref='sc'/>" +
"<http auto-config='true'>" +
" <concurrent-session-control session-registry-alias='seshRegistry' expired-url='/expired'/>" +
"</http>" +
"<b:bean id='sc' class='org.springframework.security.concurrent.ConcurrentSessionControllerImpl'>" +
" <b:property name='sessionRegistry'>" +
" <b:bean class='org.springframework.security.concurrent.SessionRegistryImpl'/>" +
" </b:property>" +
"</b:bean>" + AUTH_PROVIDER_XML);
}
@Test(expected=BeanDefinitionParsingException.class)
public void concurrentSessionSupportCantBeUsedWithIndependentControllerBean2() throws Exception {
setContext(
"<http auto-config='true'>" +
" <concurrent-session-control session-registry-alias='seshRegistry' expired-url='/expired'/>" +
"</http>" +
"<b:bean id='sc' class='org.springframework.security.concurrent.ConcurrentSessionControllerImpl'>" +
" <b:property name='sessionRegistry'>" +
" <b:bean class='org.springframework.security.concurrent.SessionRegistryImpl'/>" +
" </b:property>" +
"</b:bean>" +
"<authentication-manager alias='authManager' session-controller-ref='sc'/>" + AUTH_PROVIDER_XML);
}
@Test(expected=ConcurrentLoginException.class)
public void concurrentSessionMaxSessionsIsCorrectlyConfigured() throws Exception {
setContext(
"<http auto-config='true'>" +
" <concurrent-session-control max-sessions='2' exception-if-maximum-exceeded='true' />" +
"</http>" + AUTH_PROVIDER_XML);
ConcurrentSessionControllerImpl seshController = (ConcurrentSessionControllerImpl) appContext.getBean(BeanIds.CONCURRENT_SESSION_CONTROLLER);
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("bob", "pass");
// Register 2 sessions and then check a third
MockHttpServletRequest req = new MockHttpServletRequest();
req.setSession(new MockHttpSession());
auth.setDetails(new WebAuthenticationDetails(req));
try {
seshController.checkAuthenticationAllowed(auth);
} catch (ConcurrentLoginException e) {
fail("First login should be allowed");
}
seshController.registerSuccessfulAuthentication(auth);
req.setSession(new MockHttpSession());
try {
seshController.checkAuthenticationAllowed(auth);
} catch (ConcurrentLoginException e) {
fail("Second login should be allowed");
}
auth.setDetails(new WebAuthenticationDetails(req));
seshController.registerSuccessfulAuthentication(auth);
req.setSession(new MockHttpSession());
auth.setDetails(new WebAuthenticationDetails(req));
seshController.checkAuthenticationAllowed(auth);
}
@Test
public void customEntryPointIsSupported() throws Exception {
setContext(
"<http auto-config='true' entry-point-ref='entryPoint'/>" +
"<b:bean id='entryPoint' class='org.springframework.security.MockAuthenticationEntryPoint'>" +
" <b:constructor-arg value='/customlogin'/>" +
"</b:bean>" + AUTH_PROVIDER_XML);
ExceptionTranslationFilter etf = (ExceptionTranslationFilter) getFilters("/someurl").get(AUTO_CONFIG_FILTERS-3);
assertTrue("ExceptionTranslationFilter should be configured with custom entry point",
etf.getAuthenticationEntryPoint() instanceof MockAuthenticationEntryPoint);
}
@Test
/** SEC-742 */
public void rememberMeServicesWorksWithoutBasicProcessingFilter() {
setContext(
" <http>" +
" <form-login login-page='/login.jsp' default-target-url='/messageList.html'/>" +
" <logout logout-success-url='/login.jsp'/>" +
" <anonymous username='guest' granted-authority='guest'/>" +
" <remember-me />" +
" </http>" + AUTH_PROVIDER_XML);
}
@Test
public void disablingSessionProtectionRemovesFilter() throws Exception {
setContext(
"<http auto-config='true' session-fixation-protection='none'/>" + AUTH_PROVIDER_XML);
List<Filter> filters = getFilters("/someurl");
assertFalse(filters.get(1) instanceof SessionFixationProtectionFilter);
}
/**
* See SEC-750. If the http security post processor causes beans to be instantiated too eagerly, they way miss
* additional processing. In this method we have a UserDetailsService which is referenced from the namespace
* and also has a post processor registered which will modify it.
*/
@Test
public void httpElementDoesntInterfereWithBeanPostProcessing() {
setContext(
"<http auto-config='true'/>" +
"<authentication-provider user-service-ref='myUserService'/>" +
"<b:bean id='myUserService' class='org.springframework.security.config.PostProcessedMockUserDetailsService'/>" +
"<b:bean id='beanPostProcessor' class='org.springframework.security.config.MockUserServiceBeanPostProcessor'/>"
);
PostProcessedMockUserDetailsService service = (PostProcessedMockUserDetailsService)appContext.getBean("myUserService");
assertEquals("Hello from the post processor!", service.getPostProcessorWasHere());
}
/**
* SEC-795. Two methods that exercise the scenarios that will or won't result in a protected login page warning.
* Check the log.
*/
@Test
public void unprotectedLoginPageDoesntResultInWarning() {
// Anonymous access configured
setContext(
" <http>" +
" <intercept-url pattern='/login.jsp*' access='IS_AUTHENTICATED_ANONYMOUSLY'/>" +
" <intercept-url pattern='/**' access='ROLE_A'/>" +
" <anonymous />" +
" <form-login login-page='/login.jsp' default-target-url='/messageList.html'/>" +
" </http>" + AUTH_PROVIDER_XML);
closeAppContext();
// No filters applied to login page
setContext(
" <http>" +
" <intercept-url pattern='/login.jsp*' filters='none'/>" +
" <intercept-url pattern='/**' access='ROLE_A'/>" +
" <anonymous />" +
" <form-login login-page='/login.jsp' default-target-url='/messageList.html'/>" +
" </http>" + AUTH_PROVIDER_XML);
}
@Test
public void protectedLoginPageResultsInWarning() {
// Protected, no anonymous filter configured.
setContext(
" <http>" +
" <intercept-url pattern='/**' access='ROLE_A'/>" +
" <form-login login-page='/login.jsp' default-target-url='/messageList.html'/>" +
" </http>" + AUTH_PROVIDER_XML);
closeAppContext();
// Protected, anonymous provider but no access
setContext(
" <http>" +
" <intercept-url pattern='/**' access='ROLE_A'/>" +
" <anonymous />" +
" <form-login login-page='/login.jsp' default-target-url='/messageList.html'/>" +
" </http>" + AUTH_PROVIDER_XML);
}
@Test
public void settingCreateSessionToAlwaysSetsFilterPropertiesCorrectly() throws Exception {
setContext("<http auto-config='true' create-session='always'/>" + AUTH_PROVIDER_XML);
Object filter = appContext.getBean(BeanIds.SECURITY_CONTEXT_PERSISTENCE_FILTER);
assertEquals(Boolean.TRUE, FieldUtils.getFieldValue(filter, "forceEagerSessionCreation"));
assertEquals(Boolean.TRUE, FieldUtils.getFieldValue(filter, "repo.allowSessionCreation"));
// Just check that the repo has url rewriting enabled by default
assertEquals(Boolean.FALSE, FieldUtils.getFieldValue(filter, "repo.disableUrlRewriting"));
}
@Test
public void settingCreateSessionToNeverSetsFilterPropertiesCorrectly() throws Exception {
setContext("<http auto-config='true' create-session='never'/>" + AUTH_PROVIDER_XML);
Object filter = appContext.getBean(BeanIds.SECURITY_CONTEXT_PERSISTENCE_FILTER);
assertEquals(Boolean.FALSE, FieldUtils.getFieldValue(filter, "forceEagerSessionCreation"));
assertEquals(Boolean.FALSE, FieldUtils.getFieldValue(filter, "repo.allowSessionCreation"));
}
/* SEC-934 */
@Test
public void supportsTwoIdenticalInterceptUrls() {
setContext(
"<http auto-config='true'>" +
" <intercept-url pattern='/someurl' access='ROLE_A'/>" +
" <intercept-url pattern='/someurl' access='ROLE_B'/>" +
"</http>" + AUTH_PROVIDER_XML);
FilterSecurityInterceptor fis = (FilterSecurityInterceptor) appContext.getBean(BeanIds.FILTER_SECURITY_INTERCEPTOR);
FilterInvocationSecurityMetadataSource fids = fis.getSecurityMetadataSource();
List<? extends ConfigAttribute> attrDef = fids.getAttributes(createFilterinvocation("/someurl", null));
assertEquals(1, attrDef.size());
assertTrue(attrDef.contains(new SecurityConfig("ROLE_B")));
}
@Test
public void supportsExternallyDefinedSecurityContextRepository() throws Exception {
setContext(
"<b:bean id='repo' class='org.springframework.security.context.HttpSessionSecurityContextRepository'/>" +
"<http create-session='always' security-context-repository-ref='repo'>" +
" <http-basic />" +
"</http>" + AUTH_PROVIDER_XML);
SecurityContextPersistenceFilter filter = (SecurityContextPersistenceFilter) appContext.getBean(BeanIds.SECURITY_CONTEXT_PERSISTENCE_FILTER);
HttpSessionSecurityContextRepository repo = (HttpSessionSecurityContextRepository) appContext.getBean("repo");
assertSame(repo, FieldUtils.getFieldValue(filter, "repo"));
assertTrue((Boolean)FieldUtils.getFieldValue(filter, "forceEagerSessionCreation"));
}
@Test(expected=BeanDefinitionParsingException.class)
public void cantUseUnsupportedSessionCreationAttributeWithExternallyDefinedSecurityContextRepository() throws Exception {
setContext(
"<b:bean id='repo' class='org.springframework.security.context.HttpSessionSecurityContextRepository'/>" +
"<http create-session='never' security-context-repository-ref='repo'>" +
" <http-basic />" +
"</http>" + AUTH_PROVIDER_XML);
}
@Test
public void expressionBasedAccessAllowsAndDeniesAccessAsExpected() throws Exception {
setContext(
" <http auto-config='true' use-expressions='true'>" +
" <intercept-url pattern='/secure*' access=\"hasRole('ROLE_A')\" />" +
" <intercept-url pattern='/**' access='permitAll()' />" +
" </http>" + AUTH_PROVIDER_XML);
FilterSecurityInterceptor fis = (FilterSecurityInterceptor) appContext.getBean(BeanIds.FILTER_SECURITY_INTERCEPTOR);
FilterInvocationSecurityMetadataSource fids = fis.getSecurityMetadataSource();
List<? extends ConfigAttribute> attrDef = fids.getAttributes(createFilterinvocation("/secure", null));
assertEquals(1, attrDef.size());
// Try an unprotected invocation
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("joe", "", "ROLE_A"));
fis.invoke(createFilterinvocation("/permitallurl", null));
// Try secure Url as a valid user
fis.invoke(createFilterinvocation("/securex", null));
// And as a user without the required role
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("joe", "", "ROLE_B"));
try {
fis.invoke(createFilterinvocation("/securex", null));
fail("Expected AccessDeniedInvocation");
} catch (AccessDeniedException expected) {
}
}
@Test
public void customSuccessAndFailureHandlersCanBeSetThroughTheNamespace() throws Exception {
setContext(
"<http>" +
" <form-login authentication-success-handler-ref='sh' authentication-failure-handler-ref='fh'/>" +
"</http>" +
"<b:bean id='sh' class='org.springframework.security.ui.SavedRequestAwareAuthenticationSuccessHandler'/>" +
"<b:bean id='fh' class='org.springframework.security.ui.SimpleUrlAuthenticationFailureHandler'/>" +
AUTH_PROVIDER_XML);
AuthenticationProcessingFilter apf = (AuthenticationProcessingFilter) appContext.getBean(BeanIds.FORM_LOGIN_FILTER);
AuthenticationSuccessHandler sh = (AuthenticationSuccessHandler) appContext.getBean("sh");
AuthenticationFailureHandler fh = (AuthenticationFailureHandler) appContext.getBean("fh");
assertSame(sh, FieldUtils.getFieldValue(apf, "successHandler"));
assertSame(fh, FieldUtils.getFieldValue(apf, "failureHandler"));
}
@Test
public void disablingUrlRewritingThroughTheNamespaceSetsCorrectPropertyOnContextRepo() throws Exception {
setContext("<http auto-config='true' disable-url-rewriting='true'/>" + AUTH_PROVIDER_XML);
Object filter = appContext.getBean(BeanIds.SECURITY_CONTEXT_PERSISTENCE_FILTER);
assertEquals(Boolean.TRUE, FieldUtils.getFieldValue(filter, "repo.disableUrlRewriting"));
}
private void setContext(String context) {
appContext = new InMemoryXmlApplicationContext(context);
}
@SuppressWarnings("unchecked")
private List<Filter> getFilters(String url) throws Exception {
FilterChainProxy fcp = (FilterChainProxy) appContext.getBean(BeanIds.FILTER_CHAIN_PROXY);
Method getFilters = fcp.getClass().getDeclaredMethod("getFilters", String.class);
getFilters.setAccessible(true);
return (List<Filter>) ReflectionUtils.invokeMethod(getFilters, fcp, new Object[] {url});
}
private FilterInvocation createFilterinvocation(String path, String method) {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod(method);
request.setRequestURI(null);
request.setServletPath(path);
return new FilterInvocation(request, new MockHttpServletResponse(), new MockFilterChain());
}
}

View File

@@ -0,0 +1,74 @@
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.context.SecurityContextHolder;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import org.springframework.security.util.AuthorityUtils;
/**
* @author Luke Taylor
* @version $Id$
*/
public class InterceptMethodsBeanDefinitionDecoratorTests {
private ClassPathXmlApplicationContext appContext;
private TestBusinessBean target;
@Before
public void loadContext() {
appContext = new ClassPathXmlApplicationContext("org/springframework/security/config/method-security.xml");
target = (TestBusinessBean) appContext.getBean("target");
}
@After
public void closeAppContext() {
if (appContext != null) {
appContext.close();
}
SecurityContextHolder.clearContext();
}
@Test
public void targetShouldAllowUnprotectedMethodInvocationWithNoContext() {
target.unprotected();
}
@Test
public void targetShouldPreventProtectedMethodInvocationWithNoContext() {
try {
target.doSomething();
fail("Expected AuthenticationCredentialsNotFoundException");
} catch (AuthenticationCredentialsNotFoundException expected) {
}
}
@Test
public void targetShouldAllowProtectedMethodInvocationWithCorrectRole() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
AuthorityUtils.createAuthorityList("ROLE_USER"));
SecurityContextHolder.getContext().setAuthentication(token);
target.doSomething();
}
@Test
public void targetShouldPreventProtectedMethodInvocationWithIncorrectRole() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
AuthorityUtils.createAuthorityList("ROLE_SOMEOTHERROLE"));
SecurityContextHolder.getContext().setAuthentication(token);
try {
target.doSomething();
fail("Expected AccessDeniedException");
} catch (AccessDeniedException expected) {
}
}
}

View File

@@ -0,0 +1,35 @@
package org.springframework.security.config;
import org.junit.After;
import org.junit.Test;
import org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException;
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
/**
* Tests which make sure invalid configurations are rejected by the namespace. In particular invalid top-level
* elements. These are likely to fail after the namespace has been updated using trang, but the spring-security.xsl
* transform has not been applied.
*
* @author Luke Taylor
* @version $Id$
*/
public class InvalidConfigurationTests {
private InMemoryXmlApplicationContext appContext;
@After
public void closeAppContext() {
if (appContext != null) {
appContext.close();
}
}
// Parser should throw a SAXParseException
@Test(expected=XmlBeanDefinitionStoreException.class)
public void passwordEncoderCannotAppearAtTopLevel() {
setContext("<password-encoder hash='md5'/>");
}
private void setContext(String context) {
appContext = new InMemoryXmlApplicationContext(context);
}
}

View File

@@ -0,0 +1,126 @@
package org.springframework.security.config;
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.Test;
import org.springframework.security.AuthenticationManager;
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
import org.springframework.security.providers.ProviderManager;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import org.springframework.security.providers.dao.DaoAuthenticationProvider;
import org.springframework.security.userdetails.UserDetails;
import org.springframework.security.userdetails.jdbc.JdbcUserDetailsManager;
import org.springframework.security.util.AuthorityUtils;
import org.springframework.security.util.FieldUtils;
/**
* @author Ben Alex
* @author Luke Taylor
* @version $Id$
*/
public class JdbcUserServiceBeanDefinitionParserTests {
private static String USER_CACHE_XML = "<b:bean id='userCache' class='org.springframework.security.providers.dao.MockUserCache'/>";
private static String DATA_SOURCE =
" <b:bean id='populator' class='org.springframework.security.config.DataSourcePopulator'>" +
" <b:property name='dataSource' ref='dataSource'/>" +
" </b:bean>" +
" <b:bean id='dataSource' class='org.springframework.security.TestDataSource'>" +
" <b:constructor-arg value='jdbcnamespaces'/>" +
" </b:bean>";
private InMemoryXmlApplicationContext appContext;
@After
public void closeAppContext() {
if (appContext != null) {
appContext.close();
}
}
@Test
public void validUsernameIsFound() {
setContext("<jdbc-user-service data-source-ref='dataSource'/>" + DATA_SOURCE);
JdbcUserDetailsManager mgr = (JdbcUserDetailsManager) appContext.getBean(BeanIds.USER_DETAILS_SERVICE);
assertNotNull(mgr.loadUserByUsername("rod"));
}
@Test
public void beanIdIsParsedCorrectly() {
setContext("<jdbc-user-service id='myUserService' data-source-ref='dataSource'/>" + DATA_SOURCE);
assertTrue(appContext.getBean("myUserService") instanceof JdbcUserDetailsManager);
}
@Test
public void usernameAndAuthorityQueriesAreParsedCorrectly() throws Exception {
String userQuery = "select username, password, true from users where username = ?";
String authoritiesQuery = "select username, authority from authorities where username = ? and 1 = 1";
setContext("<jdbc-user-service id='myUserService' " +
"data-source-ref='dataSource' " +
"users-by-username-query='"+ userQuery +"' " +
"authorities-by-username-query='" + authoritiesQuery + "'/>" + DATA_SOURCE);
JdbcUserDetailsManager mgr = (JdbcUserDetailsManager) appContext.getBean("myUserService");
assertEquals(userQuery, FieldUtils.getFieldValue(mgr, "usersByUsernameQuery"));
assertEquals(authoritiesQuery, FieldUtils.getFieldValue(mgr, "authoritiesByUsernameQuery"));
assertTrue(mgr.loadUserByUsername("rod") != null);
}
@Test
public void groupQueryIsParsedCorrectly() throws Exception {
setContext("<jdbc-user-service id='myUserService' " +
"data-source-ref='dataSource' " +
"group-authorities-by-username-query='blah blah'/>" + DATA_SOURCE);
JdbcUserDetailsManager mgr = (JdbcUserDetailsManager) appContext.getBean("myUserService");
assertEquals("blah blah", FieldUtils.getFieldValue(mgr, "groupAuthoritiesByUsernameQuery"));
assertTrue((Boolean)FieldUtils.getFieldValue(mgr, "enableGroups"));
}
@Test
public void cacheRefIsparsedCorrectly() {
setContext("<jdbc-user-service id='myUserService' cache-ref='userCache' data-source-ref='dataSource'/>"
+ DATA_SOURCE +USER_CACHE_XML);
CachingUserDetailsService cachingUserService =
(CachingUserDetailsService) appContext.getBean("myUserService" + AbstractUserDetailsServiceBeanDefinitionParser.CACHING_SUFFIX);
assertSame(cachingUserService.getUserCache(), appContext.getBean("userCache"));
assertNotNull(cachingUserService.loadUserByUsername("rod"));
assertNotNull(cachingUserService.loadUserByUsername("rod"));
}
@Test
public void isSupportedByAuthenticationProviderElement() {
setContext(
"<authentication-provider>" +
" <jdbc-user-service data-source-ref='dataSource'/>" +
"</authentication-provider>" + DATA_SOURCE);
AuthenticationManager mgr = (AuthenticationManager) appContext.getBean(BeanIds.AUTHENTICATION_MANAGER);
mgr.authenticate(new UsernamePasswordAuthenticationToken("rod", "koala"));
}
@Test
public void cacheIsInjectedIntoAuthenticationProvider() {
setContext(
"<authentication-provider>" +
" <jdbc-user-service cache-ref='userCache' data-source-ref='dataSource'/>" +
"</authentication-provider>" + DATA_SOURCE + USER_CACHE_XML);
ProviderManager mgr = (ProviderManager) appContext.getBean(BeanIds.AUTHENTICATION_MANAGER);
DaoAuthenticationProvider provider = (DaoAuthenticationProvider) mgr.getProviders().get(0);
assertSame(provider.getUserCache(), appContext.getBean("userCache"));
provider.authenticate(new UsernamePasswordAuthenticationToken("rod","koala"));
assertNotNull("Cache should contain user after authentication", provider.getUserCache().getUserFromCache("rod"));
}
@Test
public void rolePrefixIsUsedWhenSet() {
setContext("<jdbc-user-service id='myUserService' role-prefix='PREFIX_' data-source-ref='dataSource'/>" + DATA_SOURCE);
JdbcUserDetailsManager mgr = (JdbcUserDetailsManager) appContext.getBean("myUserService");
UserDetails rod = mgr.loadUserByUsername("rod");
assertTrue(AuthorityUtils.authorityListToSet(rod.getAuthorities()).contains("PREFIX_ROLE_SUPERVISOR"));
}
private void setContext(String context) {
appContext = new InMemoryXmlApplicationContext(context);
}
}

View File

@@ -0,0 +1,71 @@
package org.springframework.security.config;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.security.AccessDeniedException;
import org.springframework.security.AuthenticationCredentialsNotFoundException;
import org.springframework.security.annotation.BusinessService;
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
import org.springframework.security.context.SecurityContextHolder;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import org.springframework.security.util.AuthorityUtils;
/**
* @author Luke Taylor
* @version $Id$
*/
public class Jsr250AnnotationDrivenBeanDefinitionParserTests {
private InMemoryXmlApplicationContext appContext;
private BusinessService target;
@Before
public void loadContext() {
appContext = new InMemoryXmlApplicationContext(
"<b:bean id='target' class='org.springframework.security.annotation.Jsr250BusinessServiceImpl'/>" +
"<global-method-security jsr250-annotations='enabled'/>" + ConfigTestUtils.AUTH_PROVIDER_XML
);
target = (BusinessService) appContext.getBean("target");
}
@After
public void closeAppContext() {
if (appContext != null) {
appContext.close();
}
SecurityContextHolder.clearContext();
}
@Test(expected=AuthenticationCredentialsNotFoundException.class)
public void targetShouldPreventProtectedMethodInvocationWithNoContext() {
target.someUserMethod1();
}
@Test
public void permitAllShouldBeDefaultAttribute() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
AuthorityUtils.createAuthorityList("ROLE_USER"));
SecurityContextHolder.getContext().setAuthentication(token);
target.someOther(0);
}
@Test
public void targetShouldAllowProtectedMethodInvocationWithCorrectRole() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
AuthorityUtils.createAuthorityList("ROLE_USER"));
SecurityContextHolder.getContext().setAuthentication(token);
target.someUserMethod1();
}
@Test(expected=AccessDeniedException.class)
public void targetShouldPreventProtectedMethodInvocationWithIncorrectRole() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
AuthorityUtils.createAuthorityList("ROLE_SOMEOTHERROLE"));
SecurityContextHolder.getContext().setAuthentication(token);
target.someAdminMethod();
}
}

View File

@@ -0,0 +1,112 @@
package org.springframework.security.config;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.After;
import org.junit.Test;
import org.springframework.security.Authentication;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.SecurityConfigurationException;
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
import org.springframework.security.providers.ProviderManager;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import org.springframework.security.providers.ldap.LdapAuthenticationProvider;
import org.springframework.security.userdetails.ldap.InetOrgPersonContextMapper;
import org.springframework.security.userdetails.ldap.LdapUserDetailsImpl;
import org.springframework.security.util.FieldUtils;
/**
* @author Luke Taylor
* @version $Id$
*/
public class LdapProviderBeanDefinitionParserTests {
InMemoryXmlApplicationContext appCtx;
@After
public void closeAppContext() {
if (appCtx != null) {
appCtx.close();
appCtx = null;
}
}
@Test
public void simpleProviderAuthenticatesCorrectly() {
setContext("<ldap-server /> <ldap-authentication-provider group-search-filter='member={0}' />");
LdapAuthenticationProvider provider = getProvider();
Authentication auth = provider.authenticate(new UsernamePasswordAuthenticationToken("ben", "benspassword"));
LdapUserDetailsImpl ben = (LdapUserDetailsImpl) auth.getPrincipal();
assertEquals(3, ben.getAuthorities().size());
}
@Test(expected = SecurityConfigurationException.class)
public void missingServerEltCausesConfigException() {
setContext("<ldap-authentication-provider />");
}
@Test
public void supportsPasswordComparisonAuthentication() {
setContext("<ldap-server /> " +
"<ldap-authentication-provider user-dn-pattern='uid={0},ou=people'>" +
" <password-compare />" +
"</ldap-authentication-provider>");
LdapAuthenticationProvider provider = getProvider();
provider.authenticate(new UsernamePasswordAuthenticationToken("ben", "benspassword"));
}
@Test
public void supportsPasswordComparisonAuthenticationWithHashAttribute() {
setContext("<ldap-server /> " +
"<ldap-authentication-provider user-dn-pattern='uid={0},ou=people'>" +
" <password-compare password-attribute='uid' hash='plaintext'/>" +
"</ldap-authentication-provider>");
LdapAuthenticationProvider provider = getProvider();
provider.authenticate(new UsernamePasswordAuthenticationToken("ben", "ben"));
}
@Test
public void supportsPasswordComparisonAuthenticationWithPasswordEncoder() {
setContext("<ldap-server /> " +
"<ldap-authentication-provider user-dn-pattern='uid={0},ou=people'>" +
" <password-compare password-attribute='uid'>" +
" <password-encoder hash='plaintext'/>" +
" </password-compare>" +
"</ldap-authentication-provider>");
LdapAuthenticationProvider provider = getProvider();
provider.authenticate(new UsernamePasswordAuthenticationToken("ben", "ben"));
}
@Test
public void detectsNonStandardServerId() {
setContext("<ldap-server id='myServer'/> " +
"<ldap-authentication-provider />");
}
@Test
public void inetOrgContextMapperIsSupported() throws Exception {
setContext(
"<ldap-server id='someServer' url='ldap://127.0.0.1:343/dc=springframework,dc=org'/>" +
"<ldap-authentication-provider user-details-class='inetOrgPerson'/>");
LdapAuthenticationProvider provider = getProvider();
assertTrue(FieldUtils.getFieldValue(provider, "userDetailsContextMapper") instanceof InetOrgPersonContextMapper);
}
private void setContext(String context) {
appCtx = new InMemoryXmlApplicationContext(context);
}
private LdapAuthenticationProvider getProvider() {
ProviderManager authManager = (ProviderManager) appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER);
assertEquals(1, authManager.getProviders().size());
LdapAuthenticationProvider provider = (LdapAuthenticationProvider) authManager.getProviders().get(0);
return provider;
}
}

View File

@@ -0,0 +1,64 @@
package org.springframework.security.config;
import org.junit.After;
import org.junit.Test;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
/**
* @author Luke Taylor
* @version $Id$
*/
public class LdapServerBeanDefinitionParserTests {
InMemoryXmlApplicationContext appCtx;
@After
public void closeAppContext() {
if (appCtx != null) {
appCtx.close();
appCtx = null;
}
}
@Test
public void embeddedServerCreationContainsExpectedContextSourceAndData() {
appCtx = new InMemoryXmlApplicationContext("<ldap-server />");
DefaultSpringSecurityContextSource contextSource = (DefaultSpringSecurityContextSource) appCtx.getBean(BeanIds.CONTEXT_SOURCE);
// Check data is loaded
LdapTemplate template = new LdapTemplate(contextSource);
template.lookup("uid=ben,ou=people");
}
@Test
public void useOfUrlAttributeCreatesCorrectContextSource() {
// Create second "server" with a url pointing at embedded one
appCtx = new InMemoryXmlApplicationContext("<ldap-server port='33388'/>" +
"<ldap-server id='blah' url='ldap://127.0.0.1:33388/dc=springframework,dc=org' />");
// Check the default context source is still there.
appCtx.getBean(BeanIds.CONTEXT_SOURCE);
DefaultSpringSecurityContextSource contextSource = (DefaultSpringSecurityContextSource) appCtx.getBean("blah");
// Check data is loaded as before
LdapTemplate template = new LdapTemplate(contextSource);
template.lookup("uid=ben,ou=people");
}
@Test
public void loadingSpecificLdifFileIsSuccessful() {
appCtx = new InMemoryXmlApplicationContext(
"<ldap-server ldif='classpath*:test-server2.xldif' root='dc=monkeymachine,dc=co,dc=uk' />");
DefaultSpringSecurityContextSource contextSource = (DefaultSpringSecurityContextSource) appCtx.getBean(BeanIds.CONTEXT_SOURCE);
LdapTemplate template = new LdapTemplate(contextSource);
template.lookup("uid=pg,ou=gorillas");
}
}

View File

@@ -0,0 +1,129 @@
package org.springframework.security.config;
import java.util.Set;
import org.springframework.security.GrantedAuthorityImpl;
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
import org.springframework.security.util.AuthorityUtils;
import org.springframework.security.userdetails.UserDetailsService;
import org.springframework.security.userdetails.UserDetails;
import org.springframework.security.userdetails.ldap.InetOrgPerson;
import org.springframework.security.userdetails.ldap.Person;
import org.junit.Test;
import org.junit.After;
import static org.junit.Assert.*;
/**
* @author Luke Taylor
* @version $Id$
*/
public class LdapUserServiceBeanDefinitionParserTests {
private InMemoryXmlApplicationContext appCtx;
@After
public void closeAppContext() {
if (appCtx != null) {
appCtx.close();
appCtx = null;
}
}
@Test
public void minimalConfigurationIsParsedOk() throws Exception {
setContext("<ldap-user-service user-search-filter='(uid={0})' /><ldap-server url='ldap://127.0.0.1:343/dc=springframework,dc=org' />");
}
@Test
public void userServiceReturnsExpectedData() throws Exception {
setContext("<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' group-search-filter='member={0}' /><ldap-server />");
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
UserDetails ben = uds.loadUserByUsername("ben");
Set<String> authorities = AuthorityUtils.authorityListToSet(ben.getAuthorities());
assertEquals(3, authorities.size());
assertTrue(authorities.contains("ROLE_DEVELOPERS"));
}
@Test
public void differentUserSearchBaseWorksAsExpected() throws Exception {
setContext("<ldap-user-service id='ldapUDS' " +
" user-search-base='ou=otherpeople' " +
" user-search-filter='(cn={0})' " +
" group-search-filter='member={0}' /><ldap-server />");
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
UserDetails joe = uds.loadUserByUsername("Joe Smeth");
assertEquals("Joe Smeth", joe.getUsername());
}
@Test
public void rolePrefixIsSupported() throws Exception {
setContext(
"<ldap-user-service id='ldapUDS' " +
" user-search-filter='(uid={0})' " +
" group-search-filter='member={0}' role-prefix='PREFIX_'/>" +
"<ldap-user-service id='ldapUDSNoPrefix' " +
" user-search-filter='(uid={0})' " +
" group-search-filter='member={0}' role-prefix='none'/><ldap-server />");
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
UserDetails ben = uds.loadUserByUsername("ben");
assertTrue(AuthorityUtils.authorityListToSet(ben.getAuthorities()).contains("PREFIX_DEVELOPERS"));
uds = (UserDetailsService) appCtx.getBean("ldapUDSNoPrefix");
ben = uds.loadUserByUsername("ben");
assertTrue(AuthorityUtils.authorityListToSet(ben.getAuthorities()).contains("DEVELOPERS"));
}
@Test
public void differentGroupRoleAttributeWorksAsExpected() throws Exception {
setContext("<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' group-role-attribute='ou' group-search-filter='member={0}' /><ldap-server />");
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
UserDetails ben = uds.loadUserByUsername("ben");
Set<String> authorities = AuthorityUtils.authorityListToSet(ben.getAuthorities());
assertEquals(3, authorities.size());
assertTrue(authorities.contains(new GrantedAuthorityImpl("ROLE_DEVELOPER")));
}
@Test
public void isSupportedByAuthenticationProviderElement() {
setContext(
"<ldap-server url='ldap://127.0.0.1:343/dc=springframework,dc=org'/>" +
"<authentication-provider>" +
" <ldap-user-service user-search-filter='(uid={0})' />" +
"</authentication-provider>");
}
@Test
public void personContextMapperIsSupported() {
setContext(
"<ldap-server />" +
"<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' user-details-class='person'/>");
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
UserDetails ben = uds.loadUserByUsername("ben");
assertTrue(ben instanceof Person);
}
@Test
public void inetOrgContextMapperIsSupported() {
setContext(
"<ldap-server id='someServer'/>" +
"<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' user-details-class='inetOrgPerson'/>");
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
UserDetails ben = uds.loadUserByUsername("ben");
assertTrue(ben instanceof InetOrgPerson);
}
private void setContext(String context) {
appCtx = new InMemoryXmlApplicationContext(context);
}
}

View File

@@ -0,0 +1,25 @@
package org.springframework.security.config;
import java.util.List;
import org.springframework.security.AccessDeniedException;
import org.springframework.security.Authentication;
import org.springframework.security.ConfigAttribute;
import org.springframework.security.afterinvocation.AfterInvocationProvider;
public class MockAfterInvocationProvider implements AfterInvocationProvider {
public Object decide(Authentication authentication, Object object, List<ConfigAttribute> config, Object returnedObject)
throws AccessDeniedException {
return returnedObject;
}
public boolean supports(ConfigAttribute attribute) {
return true;
}
public boolean supports(Class<?> clazz) {
return true;
}
}

View File

@@ -0,0 +1,25 @@
package org.springframework.security.config;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* Test bean post processor which injects a message into a PostProcessedMockUserDetailsService.
*
* @author Luke Taylor
* @version $Id$
*/
public class MockUserServiceBeanPostProcessor implements BeanPostProcessor {
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof PostProcessedMockUserDetailsService) {
((PostProcessedMockUserDetailsService)bean).setPostProcessorWasHere("Hello from the post processor!");
}
return bean;
}
}

View File

@@ -0,0 +1,27 @@
package org.springframework.security.config;
import org.springframework.dao.DataAccessException;
import org.springframework.security.userdetails.UserDetails;
import org.springframework.security.userdetails.UserDetailsService;
import org.springframework.security.userdetails.UsernameNotFoundException;
public class PostProcessedMockUserDetailsService implements UserDetailsService {
private String postProcessorWasHere;
public PostProcessedMockUserDetailsService() {
this.postProcessorWasHere = "Post processor hasn't been yet";
}
public String getPostProcessorWasHere() {
return postProcessorWasHere;
}
public void setPostProcessorWasHere(String postProcessorWasHere) {
this.postProcessorWasHere = postProcessorWasHere;
}
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException, DataAccessException {
throw new UnsupportedOperationException("Not for actual use");
}
}

View File

@@ -0,0 +1,63 @@
package org.springframework.security.config;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.security.AccessDeniedException;
import org.springframework.security.AuthenticationCredentialsNotFoundException;
import org.springframework.security.annotation.BusinessService;
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
import org.springframework.security.context.SecurityContextHolder;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import org.springframework.security.util.AuthorityUtils;
/**
* @author Ben Alex
* @version $Id$
*/
public class SecuredAnnotationDrivenBeanDefinitionParserTests {
private InMemoryXmlApplicationContext appContext;
private BusinessService target;
@Before
public void loadContext() {
SecurityContextHolder.clearContext();
appContext = new InMemoryXmlApplicationContext(
"<b:bean id='target' class='org.springframework.security.annotation.BusinessServiceImpl'/>" +
"<global-method-security secured-annotations='enabled'/>" + ConfigTestUtils.AUTH_PROVIDER_XML
);
target = (BusinessService) appContext.getBean("target");
}
@After
public void closeAppContext() {
if (appContext != null) {
appContext.close();
}
SecurityContextHolder.clearContext();
}
@Test(expected=AuthenticationCredentialsNotFoundException.class)
public void targetShouldPreventProtectedMethodInvocationWithNoContext() {
target.someUserMethod1();
}
@Test
public void targetShouldAllowProtectedMethodInvocationWithCorrectRole() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
AuthorityUtils.createAuthorityList("ROLE_USER"));
SecurityContextHolder.getContext().setAuthentication(token);
target.someUserMethod1();
}
@Test(expected=AccessDeniedException.class)
public void targetShouldPreventProtectedMethodInvocationWithIncorrectRole() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
AuthorityUtils.createAuthorityList("ROLE_SOMEOTHER"));
SecurityContextHolder.getContext().setAuthentication(token);
target.someAdminMethod();
}
}

View File

@@ -0,0 +1,67 @@
package org.springframework.security.config;
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.Test;
import org.springframework.context.support.AbstractXmlApplicationContext;
import org.springframework.security.Authentication;
import org.springframework.security.AuthenticationException;
import org.springframework.security.concurrent.ConcurrentSessionController;
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
import org.springframework.security.util.FieldUtils;
/**
*
* @author Luke Taylor
* $Id$
*/
public class SessionRegistryInjectionBeanPostProcessorTests {
private AbstractXmlApplicationContext appContext;
@After
public void closeAppContext() {
if (appContext != null) {
appContext.close();
appContext = null;
}
}
private void setContext(String context) {
appContext = new InMemoryXmlApplicationContext(context);
}
@Test
public void sessionRegistryIsSetOnFiltersWhenUsingCustomControllerWithInternalRegistryBean() throws Exception {
setContext(
"<http auto-config='true'/>" +
"<b:bean id='sc' class='org.springframework.security.concurrent.ConcurrentSessionControllerImpl'>" +
" <b:property name='sessionRegistry'>" +
" <b:bean class='org.springframework.security.concurrent.SessionRegistryImpl'/>" +
" </b:property>" +
"</b:bean>" +
"<authentication-manager alias='authManager' session-controller-ref='sc'/>" +
ConfigTestUtils.AUTH_PROVIDER_XML);
assertNotNull(FieldUtils.getFieldValue(appContext.getBean(BeanIds.SESSION_FIXATION_PROTECTION_FILTER), "sessionRegistry"));
assertNotNull(FieldUtils.getFieldValue(appContext.getBean(BeanIds.FORM_LOGIN_FILTER), "sessionRegistry"));
}
@Test
public void sessionRegistryIsSetOnFiltersWhenUsingCustomControllerWithNonStandardController() throws Exception {
setContext(
"<http auto-config='true'/>" +
"<b:bean id='sc' class='org.springframework.security.config.SessionRegistryInjectionBeanPostProcessorTests$MockConcurrentSessionController'/>" +
"<b:bean id='sessionRegistry' class='org.springframework.security.concurrent.SessionRegistryImpl'/>" +
"<authentication-manager alias='authManager' session-controller-ref='sc'/>" +
ConfigTestUtils.AUTH_PROVIDER_XML);
assertNotNull(FieldUtils.getFieldValue(appContext.getBean(BeanIds.SESSION_FIXATION_PROTECTION_FILTER), "sessionRegistry"));
assertNotNull(FieldUtils.getFieldValue(appContext.getBean(BeanIds.FORM_LOGIN_FILTER), "sessionRegistry"));
}
public static class MockConcurrentSessionController implements ConcurrentSessionController {
public void checkAuthenticationAllowed(Authentication request) throws AuthenticationException {
}
public void registerSuccessfulAuthentication(Authentication authentication) {
}
}
}

View File

@@ -0,0 +1,18 @@
package org.springframework.security.config;
/**
* @author luke
* @version $Id$
*/
public interface TestBusinessBean {
void setInteger(int i);
int getInteger();
void setString(String s);
void doSomething();
void unprotected();
}

View File

@@ -0,0 +1,27 @@
package org.springframework.security.config;
/**
* @author luke
* @version $Id$
*/
public class TestBusinessBeanImpl implements TestBusinessBean {
public void setInteger(int i) {
}
public int getInteger() {
return 1314;
}
public void setString(String s) {
}
public String getString() {
return "A string.";
}
public void doSomething() {
}
public void unprotected() {
}
}

View File

@@ -0,0 +1,89 @@
package org.springframework.security.config;
import static org.junit.Assert.*;
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
import org.springframework.security.userdetails.UserDetails;
import org.springframework.security.userdetails.UserDetailsService;
import org.springframework.context.support.AbstractXmlApplicationContext;
import org.springframework.beans.FatalBeanException;
import org.junit.Test;
import org.junit.After;
/**
* @author Luke Taylor
* @version $Id$
*/
public class UserServiceBeanDefinitionParserTests {
private AbstractXmlApplicationContext appContext;
@After
public void closeAppContext() {
if (appContext != null) {
appContext.close();
}
}
@Test
public void userServiceWithValidPropertiesFileWorksSuccessfully() {
setContext(
"<user-service id='service' " +
"properties='classpath:org/springframework/security/config/users.properties'/>");
UserDetailsService userService = (UserDetailsService) appContext.getBean("service");
userService.loadUserByUsername("bob");
userService.loadUserByUsername("joe");
}
@Test
public void userServiceWithEmbeddedUsersWorksSuccessfully() {
setContext(
"<user-service id='service'>" +
" <user name='joe' password='joespassword' authorities='ROLE_A'/>" +
"</user-service>");
UserDetailsService userService = (UserDetailsService) appContext.getBean("service");
userService.loadUserByUsername("joe");
}
@Test
public void disabledAndEmbeddedFlagsAreSupported() {
setContext(
"<user-service id='service'>" +
" <user name='joe' password='joespassword' authorities='ROLE_A' locked='true'/>" +
" <user name='bob' password='bobspassword' authorities='ROLE_A' disabled='true'/>" +
"</user-service>");
UserDetailsService userService = (UserDetailsService) appContext.getBean("service");
UserDetails joe = userService.loadUserByUsername("joe");
assertFalse(joe.isAccountNonLocked());
UserDetails bob = userService.loadUserByUsername("bob");
assertFalse(bob.isEnabled());
}
@Test(expected=FatalBeanException.class)
public void userWithBothPropertiesAndEmbeddedUsersThrowsException() {
setContext(
"<user-service id='service' properties='doesntmatter.props'>" +
" <user name='joe' password='joespassword' authorities='ROLE_A'/>" +
"</user-service>");
UserDetailsService userService = (UserDetailsService) appContext.getBean("service");
userService.loadUserByUsername("joe");
}
@Test(expected= FatalBeanException.class)
public void multipleTopLevelUseWithoutIdThrowsException() {
setContext(
"<user-service properties='classpath:org/springframework/security/config/users.properties'/>" +
"<user-service properties='classpath:org/springframework/security/config/users.properties'/>");
}
@Test(expected= FatalBeanException.class)
public void userServiceWithMissingPropertiesFileThrowsException() {
setContext("<user-service id='service' properties='classpath:doesntexist.properties'/>");
}
private void setContext(String context) {
appContext = new InMemoryXmlApplicationContext(context);
}
}

View File

@@ -0,0 +1,77 @@
package org.springframework.security.intercept.method.aopalliance;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.AbstractXmlApplicationContext;
import org.springframework.security.AuthenticationCredentialsNotFoundException;
import org.springframework.security.ITargetObject;
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
import org.springframework.security.context.SecurityContextHolder;
/**
* Tests for SEC-428.
*
* @author Luke Taylor
* @author Ben Alex
*/
public class MethodSecurityInterceptorWithAopConfigTests {
static final String AUTH_PROVIDER_XML =
" <authentication-provider>" +
" <user-service>" +
" <user name='bob' password='bobspassword' authorities='ROLE_USER,ROLE_ADMIN' />" +
" <user name='bill' password='billspassword' authorities='ROLE_USER' />" +
" </user-service>" +
" </authentication-provider>";
static final String ACCESS_MANAGER_XML =
"<b:bean id='accessDecisionManager' class='org.springframework.security.vote.AffirmativeBased'>" +
" <b:property name='decisionVoters'>" +
" <b:list><b:bean class='org.springframework.security.vote.RoleVoter'/></b:list>" +
" </b:property>" +
"</b:bean>";
private AbstractXmlApplicationContext appContext;
@Before
public void clearContext() {
SecurityContextHolder.clearContext();
}
@After
public void closeAppContext() {
SecurityContextHolder.clearContext();
if (appContext != null) {
appContext.close();
appContext = null;
}
}
@Test(expected=AuthenticationCredentialsNotFoundException.class)
public void securityInterceptorIsAppliedWhenUsedWithAopConfig() {
setContext(
"<aop:config proxy-target-class=\"true\">" +
" <aop:pointcut id='targetMethods' expression='execution(* org.springframework.security.TargetObject.*(..))'/>" +
" <aop:advisor advice-ref='securityInterceptor' pointcut-ref='targetMethods' />" +
"</aop:config>" +
"<b:bean id='target' class='org.springframework.security.TargetObject'/>" +
"<b:bean id='securityInterceptor' class='org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor' autowire='byType' >" +
" <b:property name='securityMetadataSource'>" +
" <b:value>" +
"org.springframework.security.TargetObject.makeLower*=ROLE_A\n" +
"org.springframework.security.TargetObject.makeUpper*=ROLE_A\n" +
"org.springframework.security.TargetObject.computeHashCode*=ROLE_B\n" +
" </b:value>" +
" </b:property>" +
"</b:bean>" +
AUTH_PROVIDER_XML + ACCESS_MANAGER_XML);
ITargetObject target = (ITargetObject) appContext.getBean("target");
target.makeLowerCase("TEST");
}
private void setContext(String context) {
appContext = new InMemoryXmlApplicationContext(context);
}
}

View File

@@ -0,0 +1,178 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* 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.security.util;
import static org.junit.Assert.*;
import java.util.List;
import javax.servlet.Filter;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.MockFilterConfig;
import org.springframework.security.context.SecurityContextPersistenceFilter;
import org.springframework.security.ui.webapp.AuthenticationProcessingFilter;
/**
* Tests {@link FilterChainProxy}.
*
* @author Carlos Sanchez
* @author Ben Alex
* @version $Id$
*/
public class FilterChainProxyConfigTests {
private ClassPathXmlApplicationContext appCtx;
//~ Methods ========================================================================================================
@Before
public void loadContext() {
appCtx = new ClassPathXmlApplicationContext("org/springframework/security/util/filtertest-valid.xml");
}
@After
public void closeContext() {
if (appCtx != null) {
appCtx.close();
}
}
@Test
public void testDoNotFilter() throws Exception {
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("filterChain", FilterChainProxy.class);
MockFilter filter = (MockFilter) appCtx.getBean("mockFilter", MockFilter.class);
MockHttpServletRequest request = new MockHttpServletRequest();
request.setServletPath("/do/not/filter/somefile.html");
MockHttpServletResponse response = new MockHttpServletResponse();
MockFilterChain chain = new MockFilterChain(true);
filterChainProxy.doFilter(request, response, chain);
assertFalse(filter.isWasInitialized());
assertFalse(filter.isWasDoFiltered());
assertFalse(filter.isWasDestroyed());
}
@Test(expected=BeanCreationException.class)
public void misplacedUniversalPathShouldBeDetected() throws Exception {
appCtx.getBean("newFilterChainProxyWrongPathOrder", FilterChainProxy.class);
}
@Test
public void normalOperation() throws Exception {
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("filterChain", FilterChainProxy.class);
doNormalOperation(filterChainProxy);
}
@Test
public void normalOperationWithNewConfig() throws Exception {
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("newFilterChainProxy", FilterChainProxy.class);
checkPathAndFilterOrder(filterChainProxy);
doNormalOperation(filterChainProxy);
}
@Test
public void normalOperationWithNewConfigRegex() throws Exception {
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("newFilterChainProxyRegex", FilterChainProxy.class);
checkPathAndFilterOrder(filterChainProxy);
doNormalOperation(filterChainProxy);
}
@Test
public void normalOperationWithNewConfigNonNamespace() throws Exception {
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("newFilterChainProxyNonNamespace", FilterChainProxy.class);
checkPathAndFilterOrder(filterChainProxy);
doNormalOperation(filterChainProxy);
}
@Test
public void pathWithNoMatchHasNoFilters() throws Exception {
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("newFilterChainProxyNoDefaultPath", FilterChainProxy.class);
assertEquals(null, filterChainProxy.getFilters("/nomatch"));
}
@Test
public void urlStrippingPropertyIsRespected() throws Exception {
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("newFilterChainProxyNoDefaultPath", FilterChainProxy.class);
// Should only match if we are stripping the query string
String url = "/blah.bar?x=something";
assertNotNull(filterChainProxy.getFilters(url));
assertEquals(2, filterChainProxy.getFilters(url).size());
filterChainProxy.setStripQueryStringFromUrls(false);
assertNull(filterChainProxy.getFilters(url));
}
private void checkPathAndFilterOrder(FilterChainProxy filterChainProxy) throws Exception {
List<Filter> filters = filterChainProxy.getFilters("/foo/blah");
assertEquals(1, filters.size());
assertTrue(filters.get(0) instanceof MockFilter);
filters = filterChainProxy.getFilters("/some/other/path/blah");
assertNotNull(filters);
assertEquals(3, filters.size());
assertTrue(filters.get(0) instanceof SecurityContextPersistenceFilter);
assertTrue(filters.get(1) instanceof MockFilter);
assertTrue(filters.get(2) instanceof MockFilter);
filters = filterChainProxy.getFilters("/do/not/filter");
assertEquals(0, filters.size());
filters = filterChainProxy.getFilters("/another/nonspecificmatch");
assertEquals(3, filters.size());
assertTrue(filters.get(0) instanceof SecurityContextPersistenceFilter);
assertTrue(filters.get(1) instanceof AuthenticationProcessingFilter);
assertTrue(filters.get(2) instanceof MockFilter);
}
private void doNormalOperation(FilterChainProxy filterChainProxy) throws Exception {
MockFilter filter = (MockFilter) appCtx.getBean("mockFilter", MockFilter.class);
assertFalse(filter.isWasInitialized());
assertFalse(filter.isWasDoFiltered());
assertFalse(filter.isWasDestroyed());
filterChainProxy.init(new MockFilterConfig());
assertTrue(filter.isWasInitialized());
assertFalse(filter.isWasDoFiltered());
assertFalse(filter.isWasDestroyed());
MockHttpServletRequest request = new MockHttpServletRequest();
request.setServletPath("/foo/secure/super/somefile.html");
MockHttpServletResponse response = new MockHttpServletResponse();
MockFilterChain chain = new MockFilterChain(true);
filterChainProxy.doFilter(request, response, chain);
assertTrue(filter.isWasInitialized());
assertTrue(filter.isWasDoFiltered());
assertFalse(filter.isWasDestroyed());
request.setServletPath("/a/path/which/doesnt/match/any/filter.html");
filterChainProxy.doFilter(request, response, chain);
filterChainProxy.destroy();
assertTrue(filter.isWasInitialized());
assertTrue(filter.isWasDoFiltered());
assertTrue(filter.isWasDestroyed());
}
}