SEC-1126: separated out spring-security-config module containing namespace configuration classes and resources
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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>";
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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() {
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user