SEC-1953: Spring Security Java Config support

This is the initial migration of Spring Security Java Config from the
external project at
https://github.com/SpringSource/spring-security-javaconfig
This commit is contained in:
Rob Winch
2013-06-30 17:26:57 -05:00
parent fba4fec84b
commit d0c4e6ca72
140 changed files with 20023 additions and 12 deletions

View File

@@ -0,0 +1,25 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation;
/**
* Exists for mocking purposes to ensure that the Type information is found.
*
* @author Rob Winch
*/
public interface AnyObjectPostProcessor extends ObjectPostProcessor<Object> {
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation;
import javax.servlet.Filter
import org.springframework.beans.factory.NoSuchBeanDefinitionException
import org.springframework.context.ConfigurableApplicationContext
import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.mock.web.MockFilterChain
import org.springframework.mock.web.MockHttpServletRequest
import org.springframework.mock.web.MockHttpServletResponse
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.AuthenticationProvider
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
import org.springframework.security.core.Authentication
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.core.context.SecurityContextImpl
import org.springframework.security.web.FilterChainProxy
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor
import org.springframework.security.web.context.HttpRequestResponseHolder
import org.springframework.security.web.context.HttpSessionSecurityContextRepository
import spock.lang.AutoCleanup
import spock.lang.Specification
/**
*
* @author Rob Winch
*/
abstract class BaseSpringSpec extends Specification {
@AutoCleanup
ConfigurableApplicationContext context
MockHttpServletRequest request
MockHttpServletResponse response
MockFilterChain chain
def setup() {
request = new MockHttpServletRequest(method:"GET")
response = new MockHttpServletResponse()
chain = new MockFilterChain()
}
AuthenticationManagerBuilder authenticationBldr = new AuthenticationManagerBuilder().inMemoryAuthentication().and()
def cleanup() {
SecurityContextHolder.clearContext()
}
def loadConfig(Class<?>... configs) {
context = new AnnotationConfigApplicationContext(configs)
context
}
def findFilter(Class<?> filter, int index = 0) {
filterChain(index).filters.find { filter.isAssignableFrom(it.class)}
}
def filterChain(int index=0) {
filterChains()[index]
}
def filterChains() {
context.getBean(FilterChainProxy).filterChains
}
Filter getSpringSecurityFilterChain() {
context.getBean("springSecurityFilterChain",Filter.class)
}
AuthenticationManager authenticationManager() {
context.getBean(AuthenticationManager)
}
AuthenticationManager getAuthenticationManager() {
try {
authenticationManager().delegateBuilder.getObject()
} catch(NoSuchBeanDefinitionException e) {}
findFilter(FilterSecurityInterceptor).authenticationManager
}
List<AuthenticationProvider> authenticationProviders() {
List<AuthenticationProvider> providers = new ArrayList<AuthenticationProvider>()
AuthenticationManager authenticationManager = getAuthenticationManager()
while(authenticationManager?.providers) {
providers.addAll(authenticationManager.providers)
authenticationManager = authenticationManager.parent
}
providers
}
AuthenticationProvider findAuthenticationProvider(Class<?> provider) {
authenticationProviders().find { provider.isAssignableFrom(it.class) }
}
def login(String username="user", String role="ROLE_USER") {
login(new UsernamePasswordAuthenticationToken(username, null, AuthorityUtils.createAuthorityList(role)))
}
def login(Authentication auth) {
HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository()
HttpRequestResponseHolder requestResponseHolder = new HttpRequestResponseHolder(request, response)
repo.loadContext(requestResponseHolder)
repo.saveContext(new SecurityContextImpl(authentication:auth), requestResponseHolder.request, requestResponseHolder.response)
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation;
import org.springframework.context.ConfigurableApplicationContext
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.mock.web.MockFilterChain;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.web.FilterChainProxy;
import spock.lang.AutoCleanup
import spock.lang.Specification
/**
*
* @author Rob Winch
*/
abstract class BaseWebSpecuritySpec extends BaseSpringSpec {
FilterChainProxy springSecurityFilterChain
MockHttpServletRequest request
MockHttpServletResponse response
MockFilterChain chain
def setup() {
request = new MockHttpServletRequest()
response = new MockHttpServletResponse()
chain = new MockFilterChain()
}
def loadConfig(Class<?>... configs) {
super.loadConfig(configs)
springSecurityFilterChain = context.getBean(FilterChainProxy)
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation;
import java.util.ArrayList;
import java.util.List;
/**
* @author Rob Winch
*
*/
class ConcereteSecurityConfigurerAdapter extends SecurityConfigurerAdapter<Object, SecurityBuilder<Object>> {
private List<Object> list = new ArrayList<Object>();
@Override
public void configure(SecurityBuilder<Object> builder) throws Exception {
list = postProcess(list);
}
public ConcereteSecurityConfigurerAdapter list(List<Object> l) {
this.list = l;
return this;
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation;
import static org.fest.assertions.Assertions.assertThat;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import org.junit.Test;
/**
* @author Rob Winch
*
*/
public class ObjectPostProcessorTests {
@Test
public void convertTypes() {
assertThat((Object)PerformConversion.perform(new ArrayList<Object>())).isInstanceOf(LinkedList.class);
}
}
class ListToLinkedListObjectPostProcessor implements ObjectPostProcessor<List<?>>{
@Override
public <O extends List<?>> O postProcess(O l) {
return (O) new LinkedList(l);
}
}
class PerformConversion {
public static List<?> perform(ArrayList<?> l) {
return new ListToLinkedListObjectPostProcessor().postProcess(l);
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation
import spock.lang.Specification
/**
* @author Rob Winch
*
*/
class SecurityConfigurerAdapterTests extends Specification {
ConcereteSecurityConfigurerAdapter conf = new ConcereteSecurityConfigurerAdapter()
def "addPostProcessor closure"() {
setup:
SecurityBuilder<Object> builder = Mock()
conf.addObjectPostProcessor({ List l ->
l.add("a")
l
} as ObjectPostProcessor<List>)
when:
conf.init(builder)
conf.configure(builder)
then:
conf.list.contains("a")
}
}

View File

@@ -0,0 +1,90 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.authentication
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationEventPublisher
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.AuthenticationProvider
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.ObjectPostProcessor
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
/**
*
* @author Rob Winch
*
*/
class AuthenticationManagerBuilderTests extends BaseSpringSpec {
def "add(AuthenticationProvider) does not perform registration"() {
setup:
ObjectPostProcessor opp = Mock()
AuthenticationProvider provider = Mock()
AuthenticationManagerBuilder builder = new AuthenticationManagerBuilder().objectPostProcessor(opp)
when: "Adding an AuthenticationProvider"
builder.authenticationProvider(provider)
builder.build()
then: "AuthenticationProvider is not passed into LifecycleManager (it should be managed externally)"
0 * opp._(_ as AuthenticationProvider)
}
// https://github.com/SpringSource/spring-security-javaconfig/issues/132
def "#132 Custom AuthenticationEventPublisher with Web registerAuthentication"() {
setup:
AuthenticationEventPublisher aep = Mock()
when:
AuthenticationManager am = new AuthenticationManagerBuilder()
.authenticationEventPublisher(aep)
.inMemoryAuthentication()
.and()
.build()
then:
am.eventPublisher == aep
}
def "authentication-manager support multiple DaoAuthenticationProvider's"() {
setup:
loadConfig(MultiAuthenticationProvidersConfig)
when:
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password"))
then:
auth.name == "user"
auth.authorities*.authority == ['ROLE_USER']
when:
auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("admin","password"))
then:
auth.name == "admin"
auth.authorities*.authority.sort() == ['ROLE_ADMIN','ROLE_USER']
}
@EnableWebSecurity
@Configuration
static class MultiAuthenticationProvidersConfig extends WebSecurityConfigurerAdapter {
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.and()
.inMemoryAuthentication()
.withUser("admin").password("password").roles("USER","ADMIN")
}
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.authentication
import java.rmi.registry.Registry;
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.config.annotation.authentication.AuthenticationManagerBuilder
import org.springframework.security.config.annotation.authentication.configurers.userdetails.UserDetailsServiceConfigurer;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configurers.provisioning.InMemoryUserDetailsManagerConfigurer;
import org.springframework.security.core.userdetails.UserDetailsService;
/**
*
* @author Rob Winch
*/
@Configuration
class BaseAuthenticationConfig {
protected void registerAuthentication(
AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN").and()
}
@Bean
public AuthenticationManager authenticationManager() {
AuthenticationManagerBuilder registry = new AuthenticationManagerBuilder();
registerAuthentication(registry);
return registry.build();
}
}

View File

@@ -0,0 +1,92 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.authentication
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication
/**
*
* @author Rob Winch
*
*/
class NamespaceAuthenticationManagerTests extends BaseSpringSpec {
def "authentication-manager@erase-credentials=true (default)"() {
when:
loadConfig(EraseCredentialsTrueDefaultConfig)
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password"))
then:
auth.principal.password == null
auth.credentials == null
when: "authenticate the same user"
auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password"))
then: "successfully authenticate again"
noExceptionThrown()
}
@EnableWebSecurity
@Configuration
static class EraseCredentialsTrueDefaultConfig extends WebSecurityConfigurerAdapter {
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
// Only necessary to have access to verify the AuthenticationManager
@Bean
@Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
}
def "authentication-manager@erase-credentials=false"() {
when:
loadConfig(EraseCredentialsFalseConfig)
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password"))
then:
auth.credentials == "password"
auth.principal.password == "password"
}
@EnableWebSecurity
@Configuration
static class EraseCredentialsFalseConfig extends WebSecurityConfigurerAdapter {
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth
.eraseCredentials(false)
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
// Only necessary to have access to verify the AuthenticationManager
@Bean
@Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
}
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.authentication
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.dao.DaoAuthenticationProvider
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.provisioning.InMemoryUserDetailsManager
/**
*
* @author Rob Winch
*
*/
class NamespaceAuthenticationProviderTests extends BaseSpringSpec {
def "authentication-provider@ref"() {
when:
loadConfig(AuthenticationProviderRefConfig)
then:
authenticationProviders()[1] == AuthenticationProviderRefConfig.expected
}
@EnableWebSecurity
@Configuration
static class AuthenticationProviderRefConfig extends WebSecurityConfigurerAdapter {
static DaoAuthenticationProvider expected = new DaoAuthenticationProvider()
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationProvider(expected)
}
// Only necessary to have access to verify the AuthenticationManager
@Bean
@Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
}
def "authentication-provider@user-service-ref"() {
when:
loadConfig(UserServiceRefConfig)
then:
findAuthenticationProvider(DaoAuthenticationProvider).userDetailsService == UserServiceRefConfig.expected
}
@EnableWebSecurity
@Configuration
static class UserServiceRefConfig extends WebSecurityConfigurerAdapter {
static InMemoryUserDetailsManager expected = new InMemoryUserDetailsManager([] as Collection)
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(expected)
}
// Only necessary to have access to verify the AuthenticationManager
@Bean
@Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
}
}

View File

@@ -0,0 +1,188 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.authentication
import javax.sql.DataSource
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.authentication.dao.DaoAuthenticationProvider
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.NamespaceJdbcUserServiceTests.CustomJdbcUserServiceSampleConfig.CustomUserCache;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication
import org.springframework.security.core.userdetails.UserCache
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.provisioning.JdbcUserDetailsManager
/**
*
* @author Rob Winch
*
*/
class NamespaceJdbcUserServiceTests extends BaseSpringSpec {
def "jdbc-user-service"() {
when:
loadConfig(DataSourceConfig,JdbcUserServiceConfig)
then:
findAuthenticationProvider(DaoAuthenticationProvider).userDetailsService instanceof JdbcUserDetailsManager
}
@EnableWebSecurity
@Configuration
static class JdbcUserServiceConfig extends WebSecurityConfigurerAdapter {
@Autowired
private DataSource dataSource;
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.dataSource(dataSource) // jdbc-user-service@data-source-ref
}
// Only necessary to have access to verify the AuthenticationManager
@Bean
@Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
}
def "jdbc-user-service in memory testing sample"() {
when:
loadConfig(DataSourceConfig,JdbcUserServiceInMemorySampleConfig)
then:
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
auth.authorities.collect {it.authority} == ['ROLE_USER']
auth.name == "user"
}
@EnableWebSecurity
@Configuration
static class JdbcUserServiceInMemorySampleConfig extends WebSecurityConfigurerAdapter {
@Autowired
private DataSource dataSource;
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.dataSource(dataSource)
// imports the default schema (will fail if already exists)
.withDefaultSchema()
// adds this user automatically (will fail if already exists)
.withUser("user")
.password("password")
.roles("USER")
}
// Only necessary to have access to verify the AuthenticationManager
@Bean
@Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
}
@Configuration
static class DataSourceConfig {
@Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
return builder.setType(EmbeddedDatabaseType.HSQL).build();
}
}
def "jdbc-user-service custom"() {
when:
loadConfig(CustomDataSourceConfig,CustomJdbcUserServiceSampleConfig)
then:
findAuthenticationProvider(DaoAuthenticationProvider).userDetailsService.userCache instanceof CustomUserCache
when:
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
then:
auth.authorities.collect {it.authority}.sort() == ['ROLE_DBA','ROLE_USER']
auth.name == 'user'
}
@EnableWebSecurity
@Configuration
static class CustomJdbcUserServiceSampleConfig extends WebSecurityConfigurerAdapter {
@Autowired
private DataSource dataSource;
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
// jdbc-user-service@dataSource
.dataSource(dataSource)
// jdbc-user-service@cache-ref
.userCache(new CustomUserCache())
// jdbc-user-service@users-byusername-query
.usersByUsernameQuery("select principal,credentials,true from users where principal = ?")
// jdbc-user-service@authorities-by-username-query
.authoritiesByUsernameQuery("select principal,role from roles where principal = ?")
// jdbc-user-service@group-authorities-by-username-query
.groupAuthoritiesByUsername(JdbcUserDetailsManager.DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY)
// jdbc-user-service@role-prefix
.rolePrefix("ROLE_")
}
// Only necessary to have access to verify the AuthenticationManager
@Bean
@Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
static class CustomUserCache implements UserCache {
@Override
public UserDetails getUserFromCache(String username) {
return null;
}
@Override
public void putUserInCache(UserDetails user) {
}
@Override
public void removeUserFromCache(String username) {
}
}
}
@Configuration
static class CustomDataSourceConfig {
@Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
// simulate that the DB already has the schema loaded and users in it
.addScript("CustomJdbcUserServiceSampleConfig.sql")
return builder.setType(EmbeddedDatabaseType.HSQL).build();
}
}
}

View File

@@ -0,0 +1,126 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.authentication
import static org.springframework.security.config.annotation.authentication.PasswordEncoderConfigurerConfigs.*
import javax.sql.DataSource
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.configurers.ldap.LdapAuthenticationProviderConfigurer;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.authority.AuthorityUtils
import org.springframework.security.core.userdetails.User
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
import org.springframework.security.provisioning.InMemoryUserDetailsManager
/**
*
* @author Rob Winch
*
*/
class NamespacePasswordEncoderTests extends BaseSpringSpec {
def "password-encoder@ref with in memory"() {
when:
loadConfig(PasswordEncoderWithInMemoryConfig)
then:
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
}
@EnableWebSecurity
@Configuration
static class PasswordEncoderWithInMemoryConfig extends WebSecurityConfigurerAdapter {
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth)
throws Exception {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder()
auth
.inMemoryAuthentication()
.withUser("user").password(encoder.encode("password")).roles("USER").and()
.passwordEncoder(encoder)
}
}
def "password-encoder@ref with jdbc"() {
when:
loadConfig(PasswordEncoderWithJdbcConfig)
then:
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
}
@EnableWebSecurity
@Configuration
static class PasswordEncoderWithJdbcConfig extends WebSecurityConfigurerAdapter {
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth)
throws Exception {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder()
auth
.jdbcAuthentication()
.withDefaultSchema()
.dataSource(dataSource())
.withUser("user").password(encoder.encode("password")).roles("USER").and()
.passwordEncoder(encoder)
}
@Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
return builder.setType(EmbeddedDatabaseType.HSQL).build();
}
}
def "password-encoder@ref with userdetailsservice"() {
when:
loadConfig(PasswordEncoderWithUserDetailsServiceConfig)
then:
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
}
@EnableWebSecurity
@Configuration
static class PasswordEncoderWithUserDetailsServiceConfig extends WebSecurityConfigurerAdapter {
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth)
throws Exception {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder()
User user = new User("user",encoder.encode("password"), AuthorityUtils.createAuthorityList("ROLE_USER"))
InMemoryUserDetailsManager uds = new InMemoryUserDetailsManager([user])
auth
.userDetailsService(uds)
.passwordEncoder(encoder)
}
@Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
return builder.setType(EmbeddedDatabaseType.HSQL).build();
}
}
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.authentication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
/**
* Class Containing the {@link Configuration} for
* {@link PasswordEncoderConfigurerTests}. Separate to ensure the configuration
* compiles in Java (i.e. we are not using hidden methods).
*
* @author Rob Winch
* @since 3.2
*/
public class PasswordEncoderConfigurerConfigs {
@EnableWebSecurity
@Configuration
static class PasswordEncoderConfig extends WebSecurityConfigurerAdapter {
protected void registerAuthentication(
AuthenticationManagerBuilder auth) throws Exception {
BCryptPasswordEncoder encoder = passwordEncoder();
auth
.inMemoryAuthentication()
.withUser("user").password(encoder.encode("password")).roles("USER").and()
.passwordEncoder(encoder);
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
@EnableWebSecurity
@Configuration
static class PasswordEncoderNoAuthManagerLoadsConfig extends WebSecurityConfigurerAdapter {
protected void registerAuthentication(
AuthenticationManagerBuilder auth) throws Exception {
BCryptPasswordEncoder encoder = passwordEncoder();
auth
.inMemoryAuthentication()
.withUser("user").password(encoder.encode("password")).roles("USER").and()
.passwordEncoder(encoder);
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.authentication
import static org.springframework.security.config.annotation.authentication.PasswordEncoderConfigurerConfigs.*
import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.ldap.core.ContextSource;
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.AuthenticationProvider
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.SecurityBuilder;
import org.springframework.security.config.annotation.authentication.AuthenticationManagerBuilder
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.test.util.ReflectionTestUtils;
/**
*
* @author Rob Winch
*
*/
class PasswordEncoderConfigurerTests extends BaseSpringSpec {
def "password-encoder@ref with No AuthenticationManager Bean"() {
when:
loadConfig(PasswordEncoderNoAuthManagerLoadsConfig)
then:
noExceptionThrown()
}
def "password-encoder@ref with AuthenticationManagerBuilder"() {
when:
loadConfig(PasswordEncoderConfig)
AuthenticationManager authMgr = authenticationManager()
then:
authMgr.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
}
}

View File

@@ -0,0 +1,120 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.configuration
import javax.servlet.ServletConfig
import javax.servlet.ServletContext
import org.springframework.beans.factory.BeanClassLoaderAware
import org.springframework.beans.factory.BeanFactoryAware
import org.springframework.beans.factory.BeanNameAware
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContextAware
import org.springframework.context.ApplicationEventPublisherAware
import org.springframework.context.EnvironmentAware
import org.springframework.context.MessageSourceAware
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.mock.web.MockServletConfig
import org.springframework.mock.web.MockServletContext
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.configuration.AutowireBeanFactoryObjectPostProcessor;
import org.springframework.web.context.ServletConfigAware
import org.springframework.web.context.ServletContextAware
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext
/**
*
* @author Rob Winch
*/
class AutowireBeanFactoryObjectPostProcessorTests extends BaseSpringSpec {
def "Verify All Aware methods are invoked"() {
setup:
ApplicationContextAware contextAware = Mock(ApplicationContextAware)
ApplicationEventPublisherAware publisher = Mock(ApplicationEventPublisherAware)
BeanClassLoaderAware classloader = Mock(BeanClassLoaderAware)
BeanFactoryAware beanFactory = Mock(BeanFactoryAware)
EnvironmentAware environment = Mock(EnvironmentAware)
MessageSourceAware messageSource = Mock(MessageSourceAware)
ServletConfigAware servletConfig = Mock(ServletConfigAware)
ServletContextAware servletContext = Mock(ServletContextAware)
DisposableBean disposable = Mock(DisposableBean)
context = new AnnotationConfigWebApplicationContext([servletConfig:new MockServletConfig(),servletContext:new MockServletContext()])
context.register(Config)
context.refresh()
context.start()
ObjectPostProcessor opp = context.getBean(ObjectPostProcessor)
when:
opp.postProcess(contextAware)
then:
1 * contextAware.setApplicationContext(!null)
when:
opp.postProcess(publisher)
then:
1 * publisher.setApplicationEventPublisher(!null)
when:
opp.postProcess(classloader)
then:
1 * classloader.setBeanClassLoader(!null)
when:
opp.postProcess(beanFactory)
then:
1 * beanFactory.setBeanFactory(!null)
when:
opp.postProcess(environment)
then:
1 * environment.setEnvironment(!null)
when:
opp.postProcess(messageSource)
then:
1 * messageSource.setMessageSource(!null)
when:
opp.postProcess(servletConfig)
then:
1 * servletConfig.setServletConfig(!null)
when:
opp.postProcess(servletContext)
then:
1 * servletContext.setServletContext(!null)
when:
opp.postProcess(disposable)
context.close()
context = null
then:
1 * disposable.destroy()
}
@Configuration
static class Config {
@Bean
public ObjectPostProcessor objectPostProcessor(AutowireCapableBeanFactory beanFactory) {
return new AutowireBeanFactoryObjectPostProcessor(beanFactory);
}
}
}

View File

@@ -0,0 +1,85 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.method.configuration
import static org.fest.assertions.Assertions.assertThat
import static org.junit.Assert.fail
import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDecisionManager
import org.springframework.security.access.AccessDeniedException
import org.springframework.security.access.ConfigAttribute
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
import org.springframework.security.config.annotation.web.WebSecurityConfigurerAdapterTests.InMemoryAuthWithWebSecurityConfigurerAdapter
import org.springframework.security.core.Authentication
import org.springframework.security.core.authority.AuthorityUtils
/**
*
* @author Rob Winch
*/
public class GlobalMethodSecurityConfigurationTests extends BaseSpringSpec {
def "messages set when using GlobalMethodSecurityConfiguration"() {
when:
loadConfig(InMemoryAuthWithGlobalMethodSecurityConfig)
then:
authenticationManager.messages.messageSource instanceof ApplicationContext
}
def "AuthenticationEventPublisher is registered GlobalMethodSecurityConfiguration"() {
when:
loadConfig(InMemoryAuthWithGlobalMethodSecurityConfig)
then:
authenticationManager.eventPublisher instanceof DefaultAuthenticationEventPublisher
when:
Authentication auth = new UsernamePasswordAuthenticationToken("user",null,AuthorityUtils.createAuthorityList("ROLE_USER"))
authenticationManager.eventPublisher.publishAuthenticationSuccess(auth)
then:
InMemoryAuthWithGlobalMethodSecurityConfig.EVENT.authentication == auth
}
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class InMemoryAuthWithGlobalMethodSecurityConfig extends GlobalMethodSecurityConfiguration implements ApplicationListener<AuthenticationSuccessEvent> {
static AuthenticationSuccessEvent EVENT
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth)
throws Exception {
auth
.inMemoryAuthentication()
}
@Override
public void onApplicationEvent(AuthenticationSuccessEvent e) {
EVENT = e
}
}
AuthenticationManager getAuthenticationManager() {
context.getBean(MethodInterceptor).authenticationManager
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.method.configuration;
import javax.annotation.security.DenyAll
import org.springframework.security.access.annotation.Secured
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PreAuthorize
import org.springframework.security.core.Authentication
/**
*
* @author Rob Winch
*/
public interface MethodSecurityService {
@PreAuthorize("denyAll")
public String preAuthorize();
@Secured("ROLE_ADMIN")
public String secured();
@DenyAll
public String jsr250();
@Secured(["ROLE_USER","RUN_AS_SUPER"])
public Authentication runAs();
@PreAuthorize("permitAll")
public String preAuthorizePermitAll();
@PreAuthorize("hasPermission(#object,'read')")
public String hasPermission(String object);
@PostAuthorize("hasPermission(#object,'read')")
public String postHasPermission(String object);
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.method.configuration;
import org.springframework.security.core.Authentication
import org.springframework.security.core.context.SecurityContextHolder
/**
*
* @author Rob Winch
*
*/
public class MethodSecurityServiceImpl implements MethodSecurityService {
@Override
public String preAuthorize() {
return null;
}
@Override
public String secured() {
return null;
}
@Override
public String jsr250() {
return null;
}
@Override
public Authentication runAs() {
return SecurityContextHolder.getContext().getAuthentication();
}
@Override
public String preAuthorizePermitAll() {
return null;
}
@Override
public String hasPermission(String object) {
return null;
}
@Override
public String postHasPermission(String object) {
return null;
}
}

View File

@@ -0,0 +1,93 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.method.configuration
import static org.fest.assertions.Assertions.assertThat
import static org.junit.Assert.fail
import java.io.Serializable;
import org.springframework.context.ConfigurableApplicationContext
import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.context.annotation.Configuration
import org.springframework.security.access.AccessDeniedException
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler
import org.springframework.security.authentication.TestingAuthenticationToken
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.method.configuration.NamespaceGlobalMethodSecurityTests.BaseMethodConfig;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder
/**
*
* @author Rob Winch
*/
public class NamespaceGlobalMethodSecurityExpressionHandlerTests extends BaseSpringSpec {
def setup() {
SecurityContextHolder.getContext().setAuthentication(
new TestingAuthenticationToken("user", "password","ROLE_USER"))
}
def "global-method-security/expression-handler @PreAuthorize"() {
setup:
context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomAccessDecisionManagerConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
when:
service.hasPermission("granted")
then:
noExceptionThrown()
when:
service.hasPermission("denied")
then:
thrown(AccessDeniedException)
}
def "global-method-security/expression-handler @PostAuthorize"() {
setup:
context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomAccessDecisionManagerConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
when:
service.postHasPermission("granted")
then:
noExceptionThrown()
when:
service.postHasPermission("denied")
then:
thrown(AccessDeniedException)
}
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class CustomAccessDecisionManagerConfig extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityExpressionHandler expressionHandler() {
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler()
expressionHandler.permissionEvaluator = new PermissionEvaluator() {
boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
"granted" == targetDomainObject
}
boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
throw new UnsupportedOperationException()
}
}
return expressionHandler
}
}
}

View File

@@ -0,0 +1,443 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.method.configuration
import static org.fest.assertions.Assertions.assertThat
import static org.junit.Assert.fail
import java.lang.reflect.Method
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
import org.springframework.beans.factory.BeanCreationException
import org.springframework.context.ConfigurableApplicationContext
import org.springframework.context.annotation.AdviceMode
import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Import
import org.springframework.core.Ordered
import org.springframework.security.access.AccessDecisionManager
import org.springframework.security.access.AccessDeniedException
import org.springframework.security.access.ConfigAttribute
import org.springframework.security.access.SecurityConfig
import org.springframework.security.access.intercept.AfterInvocationManager
import org.springframework.security.access.intercept.RunAsManager
import org.springframework.security.access.intercept.RunAsManagerImpl
import org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor
import org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor
import org.springframework.security.access.method.AbstractMethodSecurityMetadataSource
import org.springframework.security.access.method.MethodSecurityMetadataSource
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.TestingAuthenticationToken
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.BaseAuthenticationConfig;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
import org.springframework.security.core.Authentication
import org.springframework.security.core.context.SecurityContextHolder
/**
*
* @author Rob Winch
*/
public class NamespaceGlobalMethodSecurityTests extends BaseSpringSpec {
def setup() {
SecurityContextHolder.getContext().setAuthentication(
new TestingAuthenticationToken("user", "password","ROLE_USER"))
}
// --- access-decision-manager-ref ---
def "custom AccessDecisionManager can be used"() {
setup: "Create an instance with an AccessDecisionManager that always denies access"
context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomAccessDecisionManagerConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
when:
service.preAuthorize()
then:
thrown(AccessDeniedException)
when:
service.secured()
then:
thrown(AccessDeniedException)
}
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public static class CustomAccessDecisionManagerConfig extends GlobalMethodSecurityConfiguration {
@Override
protected AccessDecisionManager accessDecisionManager() {
return new DenyAllAccessDecisionManager()
}
public static class DenyAllAccessDecisionManager implements AccessDecisionManager {
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) {
throw new AccessDeniedException("Always Denied")
}
public boolean supports(ConfigAttribute attribute) {
return true
}
public boolean supports(Class<?> clazz) {
return true
}
}
}
// --- authentication-manager-ref ---
def "custom AuthenticationManager can be used"() {
when:
context = new AnnotationConfigApplicationContext(CustomAuthenticationConfig)
MethodSecurityInterceptor interceptor = context.getBean(MethodSecurityInterceptor)
interceptor.authenticationManager.authenticate(SecurityContextHolder.context.authentication)
then:
thrown(UnsupportedOperationException)
}
@Configuration
@EnableGlobalMethodSecurity
public static class CustomAuthenticationConfig extends GlobalMethodSecurityConfiguration {
@Override
protected AuthenticationManager authenticationManager() {
return new AuthenticationManager() {
Authentication authenticate(Authentication authentication) {
throw new UnsupportedOperationException()
}
}
}
}
// --- jsr250-annotations ---
def "enable jsr250"() {
when:
context = new AnnotationConfigApplicationContext(Jsr250Config)
MethodSecurityService service = context.getBean(MethodSecurityService)
then: "@Secured and @PreAuthorize are ignored"
service.secured() == null
service.preAuthorize() == null
when: "@DenyAll method invoked"
service.jsr250()
then: "access is denied"
thrown(AccessDeniedException)
}
@EnableGlobalMethodSecurity(jsr250Enabled = true)
@Configuration
public static class Jsr250Config extends BaseMethodConfig {
}
// --- metadata-source-ref ---
def "custom MethodSecurityMetadataSource can be used with higher priority than other sources"() {
setup:
context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomMethodSecurityMetadataSourceConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
when:
service.preAuthorize()
then:
thrown(AccessDeniedException)
when:
service.secured()
then:
thrown(AccessDeniedException)
when:
service.jsr250()
then:
thrown(AccessDeniedException)
}
@Configuration
@EnableGlobalMethodSecurity
public static class CustomMethodSecurityMetadataSourceConfig extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityMetadataSource customMethodSecurityMetadataSource() {
return new AbstractMethodSecurityMetadataSource() {
public Collection<ConfigAttribute> getAttributes(Method method, Class<?> targetClass) {
// require ROLE_NOBODY for any method on MethodSecurityService class
return MethodSecurityService.isAssignableFrom(targetClass) ? [new SecurityConfig("ROLE_NOBODY")] : []
}
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null
}
}
}
}
// --- mode ---
def "aspectj mode works"() {
when:
context = new AnnotationConfigApplicationContext(AspectJModeConfig)
then:
AnnotationAwareAspectJAutoProxyCreator autoProxyCreator = context.getBean(AnnotationAwareAspectJAutoProxyCreator)
autoProxyCreator.proxyTargetClass == true
}
@Configuration
@EnableGlobalMethodSecurity(mode = AdviceMode.ASPECTJ, proxyTargetClass = true)
public static class AspectJModeConfig extends BaseMethodConfig {
}
def "aspectj mode works extending GlobalMethodSecurityConfiguration"() {
when:
context = new AnnotationConfigApplicationContext(BaseMethodConfig,AspectJModeExtendsGMSCConfig)
then:
AnnotationAwareAspectJAutoProxyCreator autoProxyCreator = context.getBean(AnnotationAwareAspectJAutoProxyCreator)
autoProxyCreator.proxyTargetClass == false
}
@Configuration
@EnableGlobalMethodSecurity(mode = AdviceMode.ASPECTJ)
public static class AspectJModeExtendsGMSCConfig extends GlobalMethodSecurityConfiguration {
}
// --- order ---
def order() {
when:
context = new AnnotationConfigApplicationContext(CustomOrderConfig)
MethodSecurityMetadataSourceAdvisor advisor = context.getBean(MethodSecurityMetadataSourceAdvisor)
then:
advisor.order == 135
}
@Configuration
@EnableGlobalMethodSecurity(order = 135)
public static class CustomOrderConfig extends BaseMethodConfig {
}
def "order is defaulted to Ordered.LOWEST_PRECEDENCE when using @EnableGlobalMethodSecurity"() {
when:
context = new AnnotationConfigApplicationContext(DefaultOrderConfig)
MethodSecurityMetadataSourceAdvisor advisor = context.getBean(MethodSecurityMetadataSourceAdvisor)
then:
advisor.order == Ordered.LOWEST_PRECEDENCE
}
@Configuration
@EnableGlobalMethodSecurity
public static class DefaultOrderConfig extends BaseMethodConfig {
}
def "order is defaulted to Ordered.LOWEST_PRECEDENCE when extending GlobalMethodSecurityConfiguration"() {
when:
context = new AnnotationConfigApplicationContext(BaseMethodConfig,DefaultOrderExtendsMethodSecurityConfig)
MethodSecurityMetadataSourceAdvisor advisor = context.getBean(MethodSecurityMetadataSourceAdvisor)
then:
advisor.order == Ordered.LOWEST_PRECEDENCE
}
@Configuration
@EnableGlobalMethodSecurity
public static class DefaultOrderExtendsMethodSecurityConfig extends GlobalMethodSecurityConfiguration {
}
// --- pre-post-annotations ---
def preAuthorize() {
when:
context = new AnnotationConfigApplicationContext(PreAuthorizeConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
then:
service.secured() == null
service.jsr250() == null
when:
service.preAuthorize()
then:
thrown(AccessDeniedException)
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public static class PreAuthorizeConfig extends BaseMethodConfig {
}
def "prePostEnabled extends GlobalMethodSecurityConfiguration"() {
when:
context = new AnnotationConfigApplicationContext(BaseMethodConfig,PreAuthorizeExtendsGMSCConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
then:
service.secured() == null
service.jsr250() == null
when:
service.preAuthorize()
then:
thrown(AccessDeniedException)
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public static class PreAuthorizeExtendsGMSCConfig extends GlobalMethodSecurityConfiguration {
}
// --- proxy-target-class ---
def "proxying classes works"() {
when:
context = new AnnotationConfigApplicationContext(ProxyTargetClass)
MethodSecurityServiceImpl service = context.getBean(MethodSecurityServiceImpl)
then:
noExceptionThrown()
}
@EnableGlobalMethodSecurity(proxyTargetClass = true)
@Configuration
public static class ProxyTargetClass extends BaseMethodConfig {
}
def "proxying interfaces works"() {
when:
context = new AnnotationConfigApplicationContext(PreAuthorizeConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
then: "we get an instance of the interface"
noExceptionThrown()
when: "try to cast to the class"
MethodSecurityServiceImpl serviceImpl = service
then: "we get a class cast exception"
thrown(ClassCastException)
}
// --- run-as-manager-ref ---
def "custom RunAsManager"() {
when:
context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomRunAsManagerConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
then:
service.runAs().authorities.find { it.authority == "ROLE_RUN_AS_SUPER"}
}
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true)
public static class CustomRunAsManagerConfig extends GlobalMethodSecurityConfiguration {
@Override
protected RunAsManager runAsManager() {
RunAsManagerImpl runAsManager = new RunAsManagerImpl()
runAsManager.setKey("some key")
return runAsManager
}
}
// --- secured-annotation ---
def "secured enabled"() {
setup:
context = new AnnotationConfigApplicationContext(SecuredConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
when:
service.secured()
then:
thrown(AccessDeniedException)
service.preAuthorize() == null
service.jsr250() == null
}
@EnableGlobalMethodSecurity(securedEnabled = true)
@Configuration
public static class SecuredConfig extends BaseMethodConfig {
}
// --- after-invocation-provider
def "custom AfterInvocationManager"() {
setup:
context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomAfterInvocationManagerConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
when:
service.preAuthorizePermitAll()
then:
AccessDeniedException e = thrown()
e.message == "custom AfterInvocationManager"
}
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class CustomAfterInvocationManagerConfig extends GlobalMethodSecurityConfiguration {
@Override
protected AfterInvocationManager afterInvocationManager() {
return new AfterInvocationManagerStub()
}
public static class AfterInvocationManagerStub implements AfterInvocationManager {
Object decide(Authentication authentication, Object object, Collection<ConfigAttribute> attributes,
Object returnedObject) throws AccessDeniedException {
throw new AccessDeniedException("custom AfterInvocationManager")
}
boolean supports(ConfigAttribute attribute) {
return true
}
boolean supports(Class<?> clazz) {
return true
}
}
}
// --- misc ---
def "good error message when no Enable annotation"() {
when:
context = new AnnotationConfigApplicationContext(ExtendsNoEnableAnntotationConfig)
MethodSecurityInterceptor interceptor = context.getBean(MethodSecurityInterceptor)
interceptor.authenticationManager.authenticate(SecurityContextHolder.context.authentication)
then:
BeanCreationException e = thrown()
e.message.contains(EnableGlobalMethodSecurity.class.getName() + " is required")
}
@Configuration
public static class ExtendsNoEnableAnntotationConfig extends GlobalMethodSecurityConfiguration {
@Override
protected AuthenticationManager authenticationManager() {
return new AuthenticationManager() {
Authentication authenticate(Authentication authentication) {
throw new UnsupportedOperationException()
}
}
}
}
def "import subclass of GlobalMethodSecurityConfiguration"() {
when:
context = new AnnotationConfigApplicationContext(ImportSubclassGMSCConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
then:
service.secured() == null
service.jsr250() == null
when:
service.preAuthorize()
then:
thrown(AccessDeniedException)
}
@Configuration
@Import(PreAuthorizeExtendsGMSCConfig)
public static class ImportSubclassGMSCConfig extends BaseMethodConfig {
}
@Configuration
public static class BaseMethodConfig extends BaseAuthenticationConfig {
@Bean
public MethodSecurityService methodSecurityService() {
return new MethodSecurityServiceImpl()
}
}
}

View File

@@ -0,0 +1,129 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.method.configuration
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.access.AccessDeniedException
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.TestingAuthenticationToken
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.AuthenticationManagerBuilder
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder
/**
* Demonstrate the samples
*
* @author Rob Winch
*
*/
public class SampleEnableGlobalMethodSecurityTests extends BaseSpringSpec {
def setup() {
SecurityContextHolder.getContext().setAuthentication(
new TestingAuthenticationToken("user", "password","ROLE_USER"))
}
def preAuthorize() {
when:
loadConfig(SampleWebSecurityConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
then:
service.secured() == null
service.jsr250() == null
when:
service.preAuthorize()
then:
thrown(AccessDeniedException)
}
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled=true)
public static class SampleWebSecurityConfig {
@Bean
public MethodSecurityService methodSecurityService() {
return new MethodSecurityServiceImpl()
}
@Bean
public AuthenticationManager authenticationManager() throws Exception {
return new AuthenticationManagerBuilder()
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN").and()
.and()
.build();
}
}
def 'custom permission handler'() {
when:
loadConfig(CustomPermissionEvaluatorWebSecurityConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
then:
service.hasPermission("allowed") == null
when:
service.hasPermission("denied") == null
then:
thrown(AccessDeniedException)
}
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled=true)
public static class CustomPermissionEvaluatorWebSecurityConfig extends GlobalMethodSecurityConfiguration {
@Bean
public MethodSecurityService methodSecurityService() {
return new MethodSecurityServiceImpl()
}
@Override
protected MethodSecurityExpressionHandler expressionHandler() {
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
expressionHandler.setPermissionEvaluator(new CustomPermissionEvaluator());
return expressionHandler;
}
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth)
throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
}
static class CustomPermissionEvaluator implements PermissionEvaluator {
public boolean hasPermission(Authentication authentication,
Object targetDomainObject, Object permission) {
return !"denied".equals(targetDomainObject);
}
public boolean hasPermission(Authentication authentication,
Serializable targetId, String targetType, Object permission) {
return !"denied".equals(targetId);
}
}
}

View File

@@ -0,0 +1,97 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.provisioning
import org.springframework.security.config.annotation.authentication.configurers.provisioning.UserDetailsManagerConfigurer;
import org.springframework.security.core.authority.SimpleGrantedAuthority
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.provisioning.InMemoryUserDetailsManager
import spock.lang.Specification
/**
*
* @author Rob Winch
*
*/
class UserDetailsManagerConfigurerTests extends Specification {
def "all attributes supported"() {
setup:
InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager([])
when:
UserDetails userDetails = new UserDetailsManagerConfigurer<UserDetailsManagerConfigurer<InMemoryUserDetailsManager>>(userDetailsManager)
.withUser("user")
.password("password")
.roles("USER")
.disabled(true)
.accountExpired(true)
.accountLocked(true)
.credentialsExpired(true)
.build()
then:
userDetails.username == 'user'
userDetails.password == 'password'
userDetails.authorities.collect { it.authority } == ["ROLE_USER"]
!userDetails.accountNonExpired
!userDetails.accountNonLocked
!userDetails.credentialsNonExpired
!userDetails.enabled
}
def "authorities(GrantedAuthorities...) works"() {
setup:
InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager([])
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER")
when:
UserDetails userDetails = new UserDetailsManagerConfigurer<UserDetailsManagerConfigurer<InMemoryUserDetailsManager>>(userDetailsManager)
.withUser("user")
.password("password")
.authorities(authority)
.build()
then:
userDetails.authorities == [authority] as Set
}
def "authorities(String...) works"() {
setup:
InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager([])
String authority = "ROLE_USER"
when:
UserDetails userDetails = new UserDetailsManagerConfigurer<UserDetailsManagerConfigurer<InMemoryUserDetailsManager>>(userDetailsManager)
.withUser("user")
.password("password")
.authorities(authority)
.build()
then:
userDetails.authorities.collect { it.authority } == [authority]
}
def "authorities(List) works"() {
setup:
InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager([])
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER")
when:
UserDetails userDetails = new UserDetailsManagerConfigurer<UserDetailsManagerConfigurer<InMemoryUserDetailsManager>>(userDetailsManager)
.withUser("user")
.password("password")
.authorities([authority])
.build()
then:
userDetails.authorities == [authority] as Set
}
}

View File

@@ -0,0 +1,171 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web
import org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.SecurityConfigurer
import org.springframework.security.config.annotation.SecurityConfigurerAdapter
import org.springframework.test.util.ReflectionTestUtils
import spock.lang.Specification
/**
* @author Rob Winch
*
*/
class AbstractConfiguredSecurityBuilderTests extends Specification {
ConcreteAbstractConfiguredBuilder builder = new ConcreteAbstractConfiguredBuilder()
def "Null ObjectPostProcessor rejected"() {
when:
new ConcreteAbstractConfiguredBuilder(null)
then:
thrown(IllegalArgumentException)
when:
builder.objectPostProcessor(null);
then:
thrown(IllegalArgumentException)
}
def "apply null is rejected"() {
when:
builder.apply(null)
then:
thrown(IllegalArgumentException)
}
def "Duplicate configurer is removed"() {
when:
builder.apply(new ConcreteConfigurer())
builder.apply(new ConcreteConfigurer())
then:
ReflectionTestUtils.getField(builder,"configurers").size() == 1
}
def "build twice fails"() {
setup:
builder.build()
when:
builder.build()
then:
thrown(IllegalStateException)
}
def "getObject before build fails"() {
when:
builder.getObject()
then:
thrown(IllegalStateException)
}
def "Configurer.init can apply another configurer"() {
setup:
DelegateConfigurer.CONF = Mock(SecurityConfigurerAdapter)
when:
builder.apply(new DelegateConfigurer())
builder.build()
then:
1 * DelegateConfigurer.CONF.init(builder)
1 * DelegateConfigurer.CONF.configure(builder)
}
def "getConfigurer with multi fails"() {
setup:
ConcreteAbstractConfiguredBuilder builder = new ConcreteAbstractConfiguredBuilder(ObjectPostProcessor.QUIESCENT_POSTPROCESSOR, true)
builder.apply(new DelegateConfigurer())
builder.apply(new DelegateConfigurer())
when:
builder.getConfigurer(DelegateConfigurer)
then: "Fail due to trying to obtain a single DelegateConfigurer and multiple are provided"
thrown(IllegalStateException)
}
def "removeConfigurer with multi fails"() {
setup:
ConcreteAbstractConfiguredBuilder builder = new ConcreteAbstractConfiguredBuilder(ObjectPostProcessor.QUIESCENT_POSTPROCESSOR, true)
builder.apply(new DelegateConfigurer())
builder.apply(new DelegateConfigurer())
when:
builder.removeConfigurer(DelegateConfigurer)
then: "Fail due to trying to remove and obtain a single DelegateConfigurer and multiple are provided"
thrown(IllegalStateException)
}
def "removeConfigurers with multi"() {
setup:
DelegateConfigurer c1 = new DelegateConfigurer()
DelegateConfigurer c2 = new DelegateConfigurer()
ConcreteAbstractConfiguredBuilder builder = new ConcreteAbstractConfiguredBuilder(ObjectPostProcessor.QUIESCENT_POSTPROCESSOR, true)
builder.apply(c1)
builder.apply(c2)
when:
def result = builder.removeConfigurers(DelegateConfigurer)
then:
result.size() == 2
result.contains(c1)
result.contains(c2)
builder.getConfigurers(DelegateConfigurer).empty
}
def "getConfigurers with multi"() {
setup:
DelegateConfigurer c1 = new DelegateConfigurer()
DelegateConfigurer c2 = new DelegateConfigurer()
ConcreteAbstractConfiguredBuilder builder = new ConcreteAbstractConfiguredBuilder(ObjectPostProcessor.QUIESCENT_POSTPROCESSOR, true)
builder.apply(c1)
builder.apply(c2)
when:
def result = builder.getConfigurers(DelegateConfigurer)
then:
result.size() == 2
result.contains(c1)
result.contains(c2)
builder.getConfigurers(DelegateConfigurer).size() == 2
}
private static class DelegateConfigurer extends SecurityConfigurerAdapter<Object, ConcreteAbstractConfiguredBuilder> {
private static SecurityConfigurer<Object, ConcreteAbstractConfiguredBuilder> CONF;
@Override
public void init(ConcreteAbstractConfiguredBuilder builder)
throws Exception {
builder.apply(CONF);
}
}
private static class ConcreteConfigurer extends SecurityConfigurerAdapter<Object, ConcreteAbstractConfiguredBuilder> { }
private static class ConcreteAbstractConfiguredBuilder extends AbstractConfiguredSecurityBuilder<Object, ConcreteAbstractConfiguredBuilder> {
public ConcreteAbstractConfiguredBuilder() {
}
public ConcreteAbstractConfiguredBuilder(ObjectPostProcessor<Object> objectPostProcessor) {
super(objectPostProcessor);
}
public ConcreteAbstractConfiguredBuilder(ObjectPostProcessor<Object> objectPostProcessor, boolean allowMulti) {
super(objectPostProcessor,allowMulti);
}
public Object performBuild() throws Exception {
return "success";
}
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web;
import static org.springframework.security.config.annotation.web.AbstractRequestMatcherConfigurer.RequestMatchers.*
import org.springframework.http.HttpMethod;
import org.springframework.security.web.util.AntPathRequestMatcher;
import org.springframework.security.web.util.RegexRequestMatcher;
import spock.lang.Specification;
/**
* @author Rob Winch
*
*/
class RequestMatchersTests extends Specification {
def "regexMatchers(GET,'/a.*') uses RegexRequestMatcher"() {
when:
def matchers = regexMatchers(HttpMethod.GET, "/a.*")
then: 'matcher is a RegexRequestMatcher'
matchers.collect {it.class } == [RegexRequestMatcher]
}
def "regexMatchers('/a.*') uses RegexRequestMatcher"() {
when:
def matchers = regexMatchers("/a.*")
then: 'matcher is a RegexRequestMatcher'
matchers.collect {it.class } == [RegexRequestMatcher]
}
def "antMatchers(GET,'/a.*') uses AntPathRequestMatcher"() {
when:
def matchers = antMatchers(HttpMethod.GET, "/a.*")
then: 'matcher is a RegexRequestMatcher'
matchers.collect {it.class } == [AntPathRequestMatcher]
}
def "antMatchers('/a.*') uses AntPathRequestMatcher"() {
when:
def matchers = antMatchers("/a.*")
then: 'matcher is a AntPathRequestMatcher'
matchers.collect {it.class } == [AntPathRequestMatcher]
}
}

View File

@@ -0,0 +1,321 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.annotation.Order
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.config.annotation.BaseWebSpecuritySpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.builders.WebSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
/**
* Demonstrate the samples
*
* @author Rob Winch
*
*/
public class SampleWebSecurityConfigurerAdapterTests extends BaseWebSpecuritySpec {
def "README HelloWorld Sample works"() {
setup: "Sample Config is loaded"
loadConfig(HelloWorldWebSecurityConfigurerAdapter)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getRedirectedUrl() == "http://localhost/login"
when: "fail to log in"
super.setup()
request.requestURI = "/login"
request.method = "POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to login error page"
response.getRedirectedUrl() == "/login?error"
when: "login success"
super.setup()
request.requestURI = "/login"
request.method = "POST"
request.parameters.username = ["user"] as String[]
request.parameters.password = ["password"] as String[]
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to default succes page"
response.getRedirectedUrl() == "/"
}
/**
* <code>
* <http use-expressions="true">
* <intercept-url pattern="/resources/**" access="permitAll"/>
* <intercept-url pattern="/**" access="authenticated"/>
* <logout
* logout-success-url="/login?logout"
* logout-url="/logout"
* <form-login
* authentication-failure-url="/login?error"
* login-page="/login" <!-- Except Spring Security renders the login page -->
* login-processing-url="/login" <!-- but only POST -->
* password-parameter="password"
* username-parameter="username"
* />
* </http>
* <authentication-manager>
* <authentication-provider>
* <user-service>
* <user username="user" password="password" authorities="ROLE_USER"/>
* </user-service>
* </authentication-provider>
* </authentication-manager>
* </code>
* @author Rob Winch
*/
@Configuration
@EnableWebSecurity
public static class HelloWorldWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth) {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
}
def "README Sample works"() {
setup: "Sample Config is loaded"
loadConfig(SampleWebSecurityConfigurerAdapter)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getRedirectedUrl() == "http://localhost/login"
when: "fail to log in"
super.setup()
request.requestURI = "/login"
request.method = "POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to login error page"
response.getRedirectedUrl() == "/login?error"
when: "login success"
super.setup()
request.requestURI = "/login"
request.method = "POST"
request.parameters.username = ["user"] as String[]
request.parameters.password = ["password"] as String[]
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to default succes page"
response.getRedirectedUrl() == "/"
}
/**
* <code>
* <http security="none" pattern="/resources/**"/>
* <http use-expressions="true">
* <intercept-url pattern="/logout" access="permitAll"/>
* <intercept-url pattern="/login" access="permitAll"/>
* <intercept-url pattern="/signup" access="permitAll"/>
* <intercept-url pattern="/about" access="permitAll"/>
* <intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
* <logout
* logout-success-url="/login?logout"
* logout-url="/logout"
* <form-login
* authentication-failure-url="/login?error"
* login-page="/login"
* login-processing-url="/login" <!-- but only POST -->
* password-parameter="password"
* username-parameter="username"
* />
* </http>
* <authentication-manager>
* <authentication-provider>
* <user-service>
* <user username="user" password="password" authorities="ROLE_USER"/>
* <user username="admin" password="password" authorities="ROLE_USER,ROLE_ADMIN"/>
* </user-service>
* </authentication-provider>
* </authentication-manager>
* </code>
* @author Rob Winch
*/
@Configuration
@EnableWebSecurity
public static class SampleWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeUrls()
.antMatchers("/signup","/about").permitAll()
.anyRequest().hasRole("USER")
.and()
.formLogin()
.loginUrl("/login")
// set permitAll for all URLs associated with Form Login
.permitAll();
}
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth) {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
}
def "README Multi http Sample works"() {
setup:
loadConfig(SampleMultiHttpSecurityConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getRedirectedUrl() == "http://localhost/login"
when: "fail to log in"
super.setup()
request.requestURI = "/login"
request.method = "POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to login error page"
response.getRedirectedUrl() == "/login?error"
when: "login success"
super.setup()
request.requestURI = "/login"
request.method = "POST"
request.parameters.username = ["user"] as String[]
request.parameters.password = ["password"] as String[]
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to default succes page"
response.getRedirectedUrl() == "/"
when: "request protected API URL"
super.setup()
request.servletPath = "/api/admin/test"
springSecurityFilterChain.doFilter(request,response,chain)
then: "get 403"
response.getStatus() == 403
when: "request API for admins with user"
super.setup()
request.servletPath = "/api/admin/test"
request.addHeader("Authorization", "Basic " + "user:password".bytes.encodeBase64().toString())
springSecurityFilterChain.doFilter(request,response,chain)
then: "get 403"
response.getStatus() == 403
when: "request API for admins with admin"
super.setup()
request.servletPath = "/api/admin/test"
request.addHeader("Authorization", "Basic " + "admin:password".bytes.encodeBase64().toString())
springSecurityFilterChain.doFilter(request,response,chain)
then: "get 200"
response.getStatus() == 200
}
/**
* <code>
* <http security="none" pattern="/resources/**"/>
* <http use-expressions="true" pattern="/api/**">
* <intercept-url pattern="/api/admin/**" access="hasRole('ROLE_ADMIN')"/>
* <intercept-url pattern="/api/**" access="hasRole('ROLE_USER')"/>
* <http-basic />
* </http>
* <http use-expressions="true">
* <intercept-url pattern="/logout" access="permitAll"/>
* <intercept-url pattern="/login" access="permitAll"/>
* <intercept-url pattern="/signup" access="permitAll"/>
* <intercept-url pattern="/about" access="permitAll"/>
* <intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
* <logout
* logout-success-url="/login?logout"
* logout-url="/logout"
* <form-login
* authentication-failure-url="/login?error"
* login-page="/login"
* login-processing-url="/login" <!-- but only POST -->
* password-parameter="password"
* username-parameter="username"
* />
* </http>
* <authentication-manager>
* <authentication-provider>
* <user-service>
* <user username="user" password="password" authorities="ROLE_USER"/>
* <user username="admin" password="password" authorities="ROLE_USER,ROLE_ADMIN"/>
* </user-service>
* </authentication-provider>
* </authentication-manager>
* </code>
* @author Rob Winch
*/
@Configuration
@EnableWebSecurity
public static class SampleMultiHttpSecurityConfig {
@Bean
public AuthenticationManager authenticationManager() {
return new AuthenticationManagerBuilder()
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN").and()
.and()
.build();
}
@Configuration
@Order(1)
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/api/**")
.authorizeUrls()
.antMatchers("/api/admin/**").hasRole("ADMIN")
.antMatchers("/api/**").hasRole("USER")
.and()
.httpBasic();
}
}
@Configuration
public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeUrls()
.antMatchers("/signup","/about").permitAll()
.anyRequest().hasRole("USER")
.and()
.formLogin()
.loginUrl("/login")
.permitAll();
}
}
}
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web;
import static org.springframework.security.config.annotation.web.WebSecurityConfigurerAdapterTestsConfigs.*
import static org.junit.Assert.*
import javax.sql.DataSource
import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationListener
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType
import org.springframework.ldap.core.support.BaseLdapPathContextSource
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.AuthenticationProvider
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.authentication.event.AuthenticationSuccessEvent
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.configurers.ldap.LdapAuthenticationProviderConfigurer;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication
import org.springframework.security.core.authority.AuthorityUtils
import org.springframework.security.ldap.DefaultSpringSecurityContextSource
/**
* @author Rob Winch
*
*/
class WebSecurityConfigurerAdapterTests extends BaseSpringSpec {
def "MessageSources populated on AuthenticationProviders"() {
when:
loadConfig(MessageSourcesPopulatedConfig)
List<AuthenticationProvider> providers = authenticationProviders()
then:
providers*.messages*.messageSource == [context,context,context,context]
}
def "messages set when using WebSecurityConfigurerAdapter"() {
when:
loadConfig(InMemoryAuthWithWebSecurityConfigurerAdapter)
then:
authenticationManager.messages.messageSource instanceof ApplicationContext
}
def "AuthenticationEventPublisher is registered for Web registerAuthentication"() {
when:
loadConfig(InMemoryAuthWithWebSecurityConfigurerAdapter)
then:
authenticationManager.parent.eventPublisher instanceof DefaultAuthenticationEventPublisher
when:
Authentication token = new UsernamePasswordAuthenticationToken("user","password")
authenticationManager.authenticate(token)
then: "We only receive the AuthenticationSuccessEvent once"
InMemoryAuthWithWebSecurityConfigurerAdapter.EVENTS.size() == 1
InMemoryAuthWithWebSecurityConfigurerAdapter.EVENTS[0].authentication.name == token.principal
}
@EnableWebSecurity
@Configuration
static class InMemoryAuthWithWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter implements ApplicationListener<AuthenticationSuccessEvent> {
static List<AuthenticationSuccessEvent> EVENTS = []
@Bean
@Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth)
throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
@Override
public void onApplicationEvent(AuthenticationSuccessEvent e) {
EVENTS.add(e)
}
}
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
/**
* @author Rob Winch
*
*/
public class WebSecurityConfigurerAdapterTestsConfigs {
// necessary because groovy resolves incorrect method when using generics
@Configuration
@EnableWebSecurity
static class MessageSourcesPopulatedConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/role1/**")
.authorizeUrls()
.anyRequest().hasRole("1");
}
@Bean
public BaseLdapPathContextSource contextSource() throws Exception {
DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource("ldap://127.0.0.1:33389/dc=springframework,dc=org");
contextSource.setUserDn("uid=admin,ou=system");
contextSource.setPassword("secret");
return contextSource;
}
@Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
return builder.setType(EmbeddedDatabaseType.HSQL).build();
}
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth)
throws Exception {
auth
.inMemoryAuthentication().and()
.jdbcAuthentication()
.dataSource(dataSource())
.and()
.ldapAuthentication()
.userDnPatterns("uid={0},ou=people")
.contextSource(contextSource());
}
}
}

View File

@@ -0,0 +1,120 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.builders
import javax.servlet.Filter
import javax.servlet.FilterChain
import javax.servlet.ServletException
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import org.springframework.beans.factory.BeanCreationException
import org.springframework.context.annotation.Configuration
import org.springframework.mock.web.MockFilterChain
import org.springframework.mock.web.MockHttpServletRequest
import org.springframework.mock.web.MockHttpServletResponse
import org.springframework.security.cas.web.CasAuthenticationFilter
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.web.configuration.BaseWebConfig
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
import org.springframework.web.filter.OncePerRequestFilter
/**
* HttpSecurity tests
*
* @author Rob Winch
*
*/
public class HttpSecurityTests extends BaseSpringSpec {
def "addFilter with unregistered Filter"() {
when:
loadConfig(UnregisteredFilterConfig)
then:
BeanCreationException success = thrown()
success.message.contains "The Filter class ${UnregisteredFilter.name} does not have a registered order and cannot be added without a specified order. Consider using addFilterBefore or addFilterAfter instead."
}
@Configuration
static class UnregisteredFilterConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.addFilter(new UnregisteredFilter())
}
}
static class UnregisteredFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
filterChain.doFilter(request, response);
}
}
// https://github.com/SpringSource/spring-security-javaconfig/issues/104
def "#104 addFilter CasAuthenticationFilter"() {
when:
loadConfig(CasAuthenticationFilterConfig)
then:
findFilter(CasAuthenticationFilter)
}
@Configuration
static class CasAuthenticationFilterConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.addFilter(new CasAuthenticationFilter())
}
}
def "requestMatchers() javadoc"() {
setup: "load configuration like the config on the requestMatchers() javadoc"
loadConfig(RequestMatcherRegistryConfigs)
when:
super.setup()
request.servletPath = "/oauth/a"
springSecurityFilterChain.doFilter(request, response, chain)
then:
response.status == 403
where:
servletPath | status
"/oauth/a" | 403
"/oauth/b" | 403
"/api/a" | 403
"/api/b" | 403
"/oauth2/b" | 200
"/api2/b" | 200
}
@EnableWebSecurity
@Configuration
static class RequestMatcherRegistryConfigs extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers()
.antMatchers("/api/**")
.antMatchers("/oauth/**")
.and()
.authorizeUrls()
.antMatchers("/**").hasRole("USER")
.and()
.httpBasic()
}
}
}

View File

@@ -0,0 +1,511 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.builders
import javax.servlet.http.HttpServletRequest
import org.springframework.context.annotation.Configuration
import org.springframework.security.access.AccessDecisionManager
import org.springframework.security.access.ConfigAttribute
import org.springframework.security.access.vote.AuthenticatedVoter
import org.springframework.security.access.vote.RoleVoter
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.BadCredentialsException
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.web.builders.NamespaceHttpTests.AuthenticationManagerRefConfig.CustomAuthenticationManager
import org.springframework.security.config.annotation.web.builders.NamespaceHttpTests.RequestMatcherRefConfig.MyRequestMatcher
import org.springframework.security.config.annotation.web.configuration.BaseWebConfig
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.annotation.web.configurers.SessionCreationPolicy
import org.springframework.security.config.annotation.web.configurers.UrlAuthorizationConfigurer
import org.springframework.security.core.Authentication
import org.springframework.security.core.AuthenticationException
import org.springframework.security.web.FilterInvocation
import org.springframework.security.web.access.ExceptionTranslationFilter
import org.springframework.security.web.access.expression.ExpressionBasedFilterInvocationSecurityMetadataSource
import org.springframework.security.web.access.expression.WebExpressionVoter
import org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter
import org.springframework.security.web.context.HttpSessionSecurityContextRepository
import org.springframework.security.web.context.NullSecurityContextRepository
import org.springframework.security.web.context.SecurityContextPersistenceFilter
import org.springframework.security.web.jaasapi.JaasApiIntegrationFilter
import org.springframework.security.web.savedrequest.HttpSessionRequestCache
import org.springframework.security.web.savedrequest.NullRequestCache
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter
import org.springframework.security.web.session.SessionManagementFilter
import org.springframework.security.web.util.RegexRequestMatcher
import org.springframework.security.web.util.RequestMatcher
/**
* Tests to verify that all the functionality of <http> attributes is present
*
* @author Rob Winch
*
*/
public class NamespaceHttpTests extends BaseSpringSpec {
def "http@access-decision-manager-ref"() {
setup:
AccessDecisionManagerRefConfig.ACCESS_DECISION_MGR = Mock(AccessDecisionManager)
AccessDecisionManagerRefConfig.ACCESS_DECISION_MGR.supports(FilterInvocation) >> true
AccessDecisionManagerRefConfig.ACCESS_DECISION_MGR.supports(_ as ConfigAttribute) >> true
when:
loadConfig(AccessDecisionManagerRefConfig)
then:
findFilter(FilterSecurityInterceptor).accessDecisionManager == AccessDecisionManagerRefConfig.ACCESS_DECISION_MGR
}
@Configuration
static class AccessDecisionManagerRefConfig extends BaseWebConfig {
static AccessDecisionManager ACCESS_DECISION_MGR
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeUrls()
.anyRequest().permitAll()
.accessDecisionManager(ACCESS_DECISION_MGR)
}
}
def "http@access-denied-page"() {
when:
loadConfig(AccessDeniedPageConfig)
then:
findFilter(ExceptionTranslationFilter).accessDeniedHandler.errorPage == "/AccessDeniedPageConfig"
}
@Configuration
static class AccessDeniedPageConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.accessDeniedPage("/AccessDeniedPageConfig")
}
}
def "http@authentication-manager-ref"() {
when: "Specify AuthenticationManager"
loadConfig(AuthenticationManagerRefConfig)
then: "Populates the AuthenticationManager"
findFilter(FilterSecurityInterceptor).authenticationManager.parent.class == CustomAuthenticationManager
}
@Configuration
static class AuthenticationManagerRefConfig extends BaseWebConfig {
// demo authentication-manager-ref (could be any value)
@Override
protected AuthenticationManager authenticationManager() throws Exception {
return new CustomAuthenticationManager();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeUrls()
.anyRequest().hasRole("USER");
}
static class CustomAuthenticationManager implements AuthenticationManager {
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
throw new BadCredentialsException("This always fails");
}
}
}
// Note: There is no http@auto-config equivalent in Java Config
def "http@create-session=always"() {
when:
loadConfig(IfRequiredConfig)
then:
findFilter(SecurityContextPersistenceFilter).forceEagerSessionCreation == false
findFilter(SecurityContextPersistenceFilter).repo.allowSessionCreation == true
findFilter(SessionManagementFilter).securityContextRepository.allowSessionCreation == true
findFilter(ExceptionTranslationFilter).requestCache.class == HttpSessionRequestCache
}
@Configuration
static class CreateSessionAlwaysConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.always);
}
}
def "http@create-session=stateless"() {
when:
loadConfig(CreateSessionStatelessConfig)
then:
findFilter(SecurityContextPersistenceFilter).forceEagerSessionCreation == false
findFilter(SecurityContextPersistenceFilter).repo.class == NullSecurityContextRepository
findFilter(SessionManagementFilter).securityContextRepository.class == NullSecurityContextRepository
findFilter(ExceptionTranslationFilter).requestCache.class == NullRequestCache
findFilter(RequestCacheAwareFilter).requestCache.class == NullRequestCache
}
@Configuration
static class CreateSessionStatelessConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.stateless);
}
}
def "http@create-session=ifRequired"() {
when:
loadConfig(IfRequiredConfig)
then:
findFilter(SecurityContextPersistenceFilter).forceEagerSessionCreation == false
findFilter(SecurityContextPersistenceFilter).repo.allowSessionCreation == true
findFilter(SessionManagementFilter).securityContextRepository.allowSessionCreation == true
}
@Configuration
static class IfRequiredConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.ifRequired);
}
}
def "http@create-session defaults to ifRequired"() {
when:
loadConfig(IfRequiredConfig)
then:
findFilter(SecurityContextPersistenceFilter).forceEagerSessionCreation == false
findFilter(SecurityContextPersistenceFilter).repo.allowSessionCreation == true
findFilter(SessionManagementFilter).securityContextRepository.allowSessionCreation == true
}
def "http@create-session=never"() {
when:
loadConfig(CreateSessionNeverConfig)
then:
findFilter(SecurityContextPersistenceFilter).forceEagerSessionCreation == false
findFilter(SecurityContextPersistenceFilter).repo.allowSessionCreation == false
findFilter(SessionManagementFilter).securityContextRepository.allowSessionCreation == false
}
@Configuration
static class CreateSessionNeverConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.never);
}
}
@Configuration
static class DefaultCreateSessionConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
}
}
def "http@disable-url-rewriting = true (default for Java Config)"() {
when:
loadConfig(DefaultUrlRewritingConfig)
then:
findFilter(SecurityContextPersistenceFilter).repo.disableUrlRewriting
}
@Configuration
static class DefaultUrlRewritingConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
}
}
// http@disable-url-rewriting is on by default to disable it create a custom HttpSecurityContextRepository and use security-context-repository-ref
def "http@disable-url-rewriting = false"() {
when:
loadConfig(EnableUrlRewritingConfig)
then:
findFilter(SecurityContextPersistenceFilter).repo.disableUrlRewriting == false
}
@Configuration
static class EnableUrlRewritingConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
HttpSessionSecurityContextRepository repository = new HttpSessionSecurityContextRepository()
repository.disableUrlRewriting = false // explicitly configured (not necessary due to default values)
http.
securityContext()
.securityContextRepository(repository)
}
}
def "http@entry-point-ref"() {
when:
loadConfig(EntryPointRefConfig)
then:
findFilter(ExceptionTranslationFilter).authenticationEntryPoint.loginFormUrl == "/EntryPointRefConfig"
}
@Configuration
static class EntryPointRefConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/EntryPointRefConfig"))
}
}
def "http@jaas-api-provision"() {
when:
loadConfig(JaasApiProvisionConfig)
then:
findFilter(JaasApiIntegrationFilter)
}
@Configuration
static class JaasApiProvisionConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.addFilter(new JaasApiIntegrationFilter())
}
}
// http@name is not available since it can be done w/ standard bean configuration easily
def "http@once-per-request=true"() {
when:
loadConfig(OncePerRequestConfig)
then:
findFilter(FilterSecurityInterceptor).observeOncePerRequest
}
@Configuration
static class OncePerRequestConfig extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeUrls()
.anyRequest().hasRole("USER");
}
}
def "http@once-per-request=false"() {
when:
loadConfig(OncePerRequestFalseConfig)
then:
!findFilter(FilterSecurityInterceptor).observeOncePerRequest
}
@Configuration
static class OncePerRequestFalseConfig extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.
authorizeUrls()
.filterSecurityInterceptorOncePerRequest(false)
.antMatchers("/users**","/sessions/**").hasRole("ADMIN")
.antMatchers("/signup").permitAll()
.anyRequest().hasRole("USER");
}
}
// http@path-type is not available (instead request matcher instances are used)
// http@pattern is not available (instead see the tests http@request-matcher-ref ant or http@request-matcher-ref regex)
def "http@realm"() {
when:
loadConfig(RealmConfig)
then:
findFilter(BasicAuthenticationFilter).authenticationEntryPoint.realmName == "RealmConfig"
}
@Configuration
static class RealmConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic().realmName("RealmConfig")
}
}
// http@request-matcher is not available (instead request matcher instances are used)
def "http@request-matcher-ref ant"() {
when:
loadConfig(RequestMatcherAntConfig)
then:
filterChain(0).requestMatcher.pattern == "/api/**"
}
@Configuration
static class RequestMatcherAntConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/api/**")
}
}
def "http@request-matcher-ref regex"() {
when:
loadConfig(RequestMatcherRegexConfig)
then:
filterChain(0).requestMatcher.class == RegexRequestMatcher
filterChain(0).requestMatcher.pattern.matcher("/regex/a")
filterChain(0).requestMatcher.pattern.matcher("/regex/b")
!filterChain(0).requestMatcher.pattern.matcher("/regex1/b")
}
@Configuration
static class RequestMatcherRegexConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.regexMatcher("/regex/.*")
}
}
def "http@request-matcher-ref"() {
when:
loadConfig(RequestMatcherRefConfig)
then:
filterChain(0).requestMatcher.class == MyRequestMatcher
}
@Configuration
static class RequestMatcherRefConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatcher(new MyRequestMatcher());
}
static class MyRequestMatcher implements RequestMatcher {
public boolean matches(HttpServletRequest request) {
return true;
}
}
}
def "http@security=none"() {
when:
loadConfig(SecurityNoneConfig)
then:
filterChain(0).requestMatcher.pattern == "/resources/**"
filterChain(0).filters.empty
filterChain(1).requestMatcher.pattern == "/public/**"
filterChain(1).filters.empty
}
@Configuration
static class SecurityNoneConfig extends BaseWebConfig {
@Override
public void configure(WebSecurity web)
throws Exception {
web
.ignoring()
.antMatchers("/resources/**","/public/**")
}
@Override
protected void configure(HttpSecurity http) throws Exception {}
}
def "http@security-context-repository-ref"() {
when:
loadConfig(SecurityContextRepoConfig)
then:
findFilter(SecurityContextPersistenceFilter).repo.class == NullSecurityContextRepository
}
@Configuration
static class SecurityContextRepoConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.securityContext()
.securityContextRepository(new NullSecurityContextRepository()) // security-context-repository-ref
}
}
def "http@servlet-api-provision=false"() {
when:
loadConfig(ServletApiProvisionConfig)
then:
findFilter(SecurityContextHolderAwareRequestFilter) == null
}
@Configuration
static class ServletApiProvisionConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http.servletApi().disable()
}
}
def "http@servlet-api-provision defaults to true"() {
when:
loadConfig(ServletApiProvisionDefaultsConfig)
then:
findFilter(SecurityContextHolderAwareRequestFilter) != null
}
@Configuration
static class ServletApiProvisionDefaultsConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
}
}
def "http@use-expressions=true"() {
when:
loadConfig(UseExpressionsConfig)
then:
findFilter(FilterSecurityInterceptor).securityMetadataSource.class == ExpressionBasedFilterInvocationSecurityMetadataSource
findFilter(FilterSecurityInterceptor).accessDecisionManager.decisionVoters.collect { it.class } == [WebExpressionVoter]
}
@Configuration
@EnableWebSecurity
static class UseExpressionsConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeUrls()
.antMatchers("/users**","/sessions/**").hasRole("USER")
.antMatchers("/signup").permitAll()
.anyRequest().hasRole("USER")
}
}
def "http@use-expressions=false"() {
when:
loadConfig(DisableUseExpressionsConfig)
then:
findFilter(FilterSecurityInterceptor).securityMetadataSource.class == DefaultFilterInvocationSecurityMetadataSource
findFilter(FilterSecurityInterceptor).accessDecisionManager.decisionVoters.collect { it.class } == [RoleVoter, AuthenticatedVoter]
}
@Configuration
@EnableWebSecurity
static class DisableUseExpressionsConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.apply(new UrlAuthorizationConfigurer())
.antMatchers("/users**","/sessions/**").hasRole("USER")
.antMatchers("/signup").hasRole("ANONYMOUS")
.anyRequest().hasRole("USER")
}
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configuration;
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
/**
*
* @author Rob Winch
*/
@Configuration
@EnableWebSecurity
public abstract class BaseWebConfig extends WebSecurityConfigurerAdapter {
BaseWebConfig(boolean disableDefaults) {
super(disableDefaults)
}
BaseWebConfig() {
}
protected void registerAuthentication(
AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configuration;
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.mock.web.MockHttpServletRequest
import org.springframework.security.authentication.AnonymousAuthenticationToken
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
import org.springframework.security.config.annotation.web.builders.DebugFilter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter
class EnableWebSecurityTests extends BaseSpringSpec {
def "@Bean(BeanIds.AUTHENTICATION_MANAGER) includes HttpSecurity's AuthenticationManagerBuilder"() {
when:
loadConfig(SecurityConfig)
AuthenticationManager authenticationManager = context.getBean(AuthenticationManager)
AnonymousAuthenticationToken anonymousAuthToken = findFilter(AnonymousAuthenticationFilter).createAuthentication(new MockHttpServletRequest())
then:
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
authenticationManager.authenticate(anonymousAuthToken)
}
@EnableWebSecurity
@Configuration
static class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth)
throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeUrls()
.antMatchers("/*").hasRole("USER")
.and()
.formLogin();
}
}
def "@EnableWebSecurity on superclass"() {
when:
loadConfig(ChildSecurityConfig)
then:
context.getBean("springSecurityFilterChain", DebugFilter)
}
@Configuration
static class ChildSecurityConfig extends DebugSecurityConfig {
}
@Configuration
@EnableWebSecurity(debug=true)
static class DebugSecurityConfig extends WebSecurityConfigurerAdapter {
}
}

View File

@@ -0,0 +1,217 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configuration;
import static org.junit.Assert.*
import java.util.List;
import org.springframework.beans.factory.BeanCreationException
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration
import org.springframework.core.annotation.Order
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.builders.WebSecurity
import org.springframework.security.web.FilterChainProxy
import org.springframework.security.web.SecurityFilterChain
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
import org.springframework.security.web.access.expression.WebSecurityExpressionHandler;
import org.springframework.security.web.util.AnyRequestMatcher
/**
* @author Rob Winch
*
*/
class WebSecurityConfigurationTests extends BaseSpringSpec {
def "WebSecurityConfigurers are sorted"() {
when:
loadConfig(SortedWebSecurityConfigurerAdaptersConfig);
List<SecurityFilterChain> filterChains = context.getBean(FilterChainProxy).filterChains
then:
filterChains[0].requestMatcher.pattern == "/ignore1"
filterChains[0].filters.empty
filterChains[1].requestMatcher.pattern == "/ignore2"
filterChains[1].filters.empty
filterChains[2].requestMatcher.pattern == "/role1/**"
filterChains[3].requestMatcher.pattern == "/role2/**"
filterChains[4].requestMatcher.pattern == "/role3/**"
filterChains[5].requestMatcher.class == AnyRequestMatcher
}
@Configuration
@EnableWebSecurity
static class SortedWebSecurityConfigurerAdaptersConfig {
public AuthenticationManager authenticationManager() throws Exception {
return new AuthenticationManagerBuilder()
.inMemoryAuthentication()
.withUser("marissa").password("koala").roles("USER").and()
.withUser("paul").password("emu").roles("USER").and()
.and()
.build();
}
@Configuration
@Order(1)
public static class WebConfigurer1 extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/ignore1","/ignore2");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/role1/**")
.authorizeUrls()
.anyRequest().hasRole("1");
}
}
@Configuration
@Order(2)
public static class WebConfigurer2 extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/role2/**")
.authorizeUrls()
.anyRequest().hasRole("2");
}
}
@Configuration
@Order(3)
public static class WebConfigurer3 extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/role3/**")
.authorizeUrls()
.anyRequest().hasRole("3");
}
}
@Configuration
public static class WebConfigurer4 extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeUrls()
.anyRequest().hasRole("4");
}
}
}
def "WebSecurityConfigurers fails with duplicate order"() {
when:
loadConfig(DuplicateOrderConfig);
then:
BeanCreationException e = thrown()
e.message.contains "@Order on WebSecurityConfigurers must be unique"
}
@Configuration
@EnableWebSecurity
static class DuplicateOrderConfig {
public AuthenticationManager authenticationManager() throws Exception {
return new AuthenticationManagerBuilder()
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.and()
.build();
}
@Configuration
public static class WebConfigurer1 extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/role1/**")
.authorizeUrls()
.anyRequest().hasRole("1");
}
}
@Configuration
public static class WebConfigurer2 extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/role2/**")
.authorizeUrls()
.anyRequest().hasRole("2");
}
}
}
def "Override privilegeEvaluator"() {
setup:
WebInvocationPrivilegeEvaluator privilegeEvaluator = Mock()
PrivilegeEvaluatorConfigurerAdapterConfig.PE = privilegeEvaluator
when:
loadConfig(PrivilegeEvaluatorConfigurerAdapterConfig)
then:
context.getBean(WebInvocationPrivilegeEvaluator) == privilegeEvaluator
}
@EnableWebSecurity
@Configuration
static class PrivilegeEvaluatorConfigurerAdapterConfig extends WebSecurityConfigurerAdapter {
static WebInvocationPrivilegeEvaluator PE
@Override
public void configure(WebSecurity web) throws Exception {
web
.privilegeEvaluator(PE)
}
}
def "Override webSecurityExpressionHandler"() {
setup:
WebSecurityExpressionHandler expressionHandler = Mock()
WebSecurityExpressionHandlerConfig.EH = expressionHandler
when:
loadConfig(WebSecurityExpressionHandlerConfig)
then:
context.getBean(WebSecurityExpressionHandler) == expressionHandler
}
@EnableWebSecurity
@Configuration
static class WebSecurityExpressionHandlerConfig extends WebSecurityConfigurerAdapter {
@SuppressWarnings("deprecation")
static WebSecurityExpressionHandler EH
@Override
public void configure(WebSecurity web) throws Exception {
web
.expressionHandler(EH)
}
}
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers;
import java.util.List;
import org.springframework.http.HttpMethod;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractRequestMatcherMappingConfigurer;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.AntPathRequestMatcher;
import org.springframework.security.web.util.RegexRequestMatcher;
import org.springframework.security.web.util.RequestMatcher;
import spock.lang.Specification;
/**
* @author Rob Winch
*
*/
class AbstractRequestMatcherMappingConfigurerTests extends Specification {
ConcreteAbstractRequestMatcherMappingConfigurer registry = new ConcreteAbstractRequestMatcherMappingConfigurer()
def "regexMatchers(GET,'/a.*') uses RegexRequestMatcher"() {
when:
def matchers = registry.regexMatchers(HttpMethod.GET,"/a.*")
then: 'matcher is a RegexRequestMatcher'
matchers.collect {it.class } == [RegexRequestMatcher]
}
def "regexMatchers('/a.*') uses RegexRequestMatcher"() {
when:
def matchers = registry.regexMatchers("/a.*")
then: 'matcher is a RegexRequestMatcher'
matchers.collect {it.class } == [RegexRequestMatcher]
}
def "antMatchers(GET,'/a.*') uses AntPathRequestMatcher"() {
when:
def matchers = registry.antMatchers(HttpMethod.GET, "/a.*")
then: 'matcher is a RegexRequestMatcher'
matchers.collect {it.class } == [AntPathRequestMatcher]
}
def "antMatchers('/a.*') uses AntPathRequestMatcher"() {
when:
def matchers = registry.antMatchers("/a.*")
then: 'matcher is a AntPathRequestMatcher'
matchers.collect {it.class } == [AntPathRequestMatcher]
}
static class ConcreteAbstractRequestMatcherMappingConfigurer extends AbstractRequestMatcherMappingConfigurer<HttpSecurity,List<RequestMatcher>,DefaultSecurityFilterChain> {
List<AccessDecisionVoter> decisionVoters() {
return null;
}
List<RequestMatcher> chainRequestMatchersInternal(List<RequestMatcher> requestMatchers) {
return requestMatchers;
}
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers
import org.springframework.security.config.annotation.AnyObjectPostProcessor
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.access.channel.ChannelDecisionManagerImpl
import org.springframework.security.web.access.channel.ChannelProcessingFilter
import org.springframework.security.web.access.channel.InsecureChannelProcessor
import org.springframework.security.web.access.channel.SecureChannelProcessor
/**
*
* @author Rob Winch
*/
class ChannelSecurityConfigurerTests extends BaseSpringSpec {
def "requiresChannel ObjectPostProcessor"() {
setup: "initialize the AUTH_FILTER as a mock"
AnyObjectPostProcessor objectPostProcessor = Mock()
when:
HttpSecurity http = new HttpSecurity(objectPostProcessor, authenticationBldr, [:])
http
.requiresChannel()
.anyRequest().requiresSecure()
.and()
.build()
then: "InsecureChannelProcessor is registered with LifecycleManager"
1 * objectPostProcessor.postProcess(_ as InsecureChannelProcessor) >> {InsecureChannelProcessor o -> o}
and: "SecureChannelProcessor is registered with LifecycleManager"
1 * objectPostProcessor.postProcess(_ as SecureChannelProcessor) >> {SecureChannelProcessor o -> o}
and: "ChannelDecisionManagerImpl is registered with LifecycleManager"
1 * objectPostProcessor.postProcess(_ as ChannelDecisionManagerImpl) >> {ChannelDecisionManagerImpl o -> o}
and: "ChannelProcessingFilter is registered with LifecycleManager"
1 * objectPostProcessor.postProcess(_ as ChannelProcessingFilter) >> {ChannelProcessingFilter o -> o}
}
}

View File

@@ -0,0 +1,159 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers
import org.springframework.beans.factory.BeanCreationException
import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.mock.web.MockFilterChain
import org.springframework.mock.web.MockHttpServletRequest
import org.springframework.mock.web.MockHttpServletResponse
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.BaseWebConfig;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.DefaultSecurityFilterChain
import org.springframework.security.web.FilterChainProxy
import org.springframework.security.web.access.ExceptionTranslationFilter
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
import org.springframework.security.web.authentication.logout.LogoutFilter
import org.springframework.security.web.context.SecurityContextPersistenceFilter
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter
import org.springframework.security.web.session.SessionManagementFilter;
import org.springframework.security.web.util.AnyRequestMatcher
/**
*
* @author Rob Winch
*/
class DefaultFiltersTests extends BaseSpringSpec {
def missingConfigMessage = "At least one non-null instance of "+ WebSecurityConfigurer.class.getSimpleName()+" must be exposed as a @Bean when using @EnableWebSecurity. Hint try extending "+ WebSecurityConfigurerAdapter.class.getSimpleName()
def "DefaultSecurityFilterChainBuilder cannot be null"() {
when:
context = new AnnotationConfigApplicationContext(FilterChainProxyBuilderMissingConfig)
then:
BeanCreationException e = thrown()
e.message.contains missingConfigMessage
}
@Configuration
@EnableWebSecurity
static class FilterChainProxyBuilderMissingConfig { }
def "FilterChainProxyBuilder no DefaultSecurityFilterChainBuilder specified"() {
when:
context = new AnnotationConfigApplicationContext(FilterChainProxyBuilderNoSecurityFilterBuildersConfig)
then:
BeanCreationException e = thrown()
e.message.contains missingConfigMessage
}
@Configuration
@EnableWebSecurity
static class FilterChainProxyBuilderNoSecurityFilterBuildersConfig {
@Bean
public WebSecurity filterChainProxyBuilder() {
new WebSecurity()
.ignoring()
.antMatchers("/resources/**")
}
}
def "null WebInvocationPrivilegeEvaluator"() {
when:
context = new AnnotationConfigApplicationContext(NullWebInvocationPrivilegeEvaluatorConfig)
then:
List<DefaultSecurityFilterChain> filterChains = context.getBean(FilterChainProxy).filterChains
filterChains.size() == 1
filterChains[0].requestMatcher instanceof AnyRequestMatcher
filterChains[0].filters.size() == 1
filterChains[0].filters.find { it instanceof UsernamePasswordAuthenticationFilter }
}
@Configuration
@EnableWebSecurity
static class NullWebInvocationPrivilegeEvaluatorConfig extends BaseWebConfig {
NullWebInvocationPrivilegeEvaluatorConfig() {
super(true)
}
protected void configure(HttpSecurity http) {
http.formLogin()
}
}
def "FilterChainProxyBuilder ignoring resources"() {
when:
context = new AnnotationConfigApplicationContext(FilterChainProxyBuilderIgnoringConfig)
then:
List<DefaultSecurityFilterChain> filterChains = context.getBean(FilterChainProxy).filterChains
filterChains.size() == 2
filterChains[0].requestMatcher.pattern == '/resources/**'
filterChains[0].filters.empty
filterChains[1].requestMatcher instanceof AnyRequestMatcher
filterChains[1].filters.collect { it.class } ==
[SecurityContextPersistenceFilter, LogoutFilter, RequestCacheAwareFilter,
SecurityContextHolderAwareRequestFilter, AnonymousAuthenticationFilter, SessionManagementFilter,
ExceptionTranslationFilter, FilterSecurityInterceptor ]
}
@Configuration
@EnableWebSecurity
static class FilterChainProxyBuilderIgnoringConfig extends BaseWebConfig {
@Override
public void configure(WebSecurity builder) throws Exception {
builder
.ignoring()
.antMatchers("/resources/**");
}
@Override
protected void configure(HttpSecurity http) {
http
.authorizeUrls()
.anyRequest().hasRole("USER");
}
}
def "DefaultFilters.permitAll()"() {
when:
context = new AnnotationConfigApplicationContext(DefaultFiltersConfigPermitAll)
then:
FilterChainProxy filterChain = context.getBean(FilterChainProxy)
expect:
MockHttpServletResponse response = new MockHttpServletResponse()
filterChain.doFilter(new MockHttpServletRequest(servletPath : uri, queryString: query), response, new MockFilterChain())
response.redirectedUrl == null
where:
uri | query
"/logout" | null
}
@Configuration
@EnableWebSecurity
static class DefaultFiltersConfigPermitAll extends BaseWebConfig {
protected void configure(HttpSecurity http) {
}
}
}

View File

@@ -0,0 +1,343 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers
import javax.servlet.http.HttpSession
import org.springframework.context.annotation.Configuration
import org.springframework.mock.web.MockFilterChain
import org.springframework.mock.web.MockHttpServletRequest
import org.springframework.mock.web.MockHttpServletResponse
import org.springframework.security.config.annotation.AnyObjectPostProcessor
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.BaseWebConfig;
import org.springframework.security.config.annotation.web.configurers.DefaultLoginPageConfigurer;
import org.springframework.security.web.FilterChainProxy
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler
import org.springframework.security.web.authentication.ui.DefaultLoginPageViewFilter;
/**
* Tests to verify that {@link DefaultLoginPageConfigurer} works
*
* @author Rob Winch
*
*/
public class DefaultLoginPageConfigurerTests extends BaseSpringSpec {
FilterChainProxy springSecurityFilterChain
MockHttpServletRequest request
MockHttpServletResponse response
MockFilterChain chain
def setup() {
request = new MockHttpServletRequest(method:"GET")
response = new MockHttpServletResponse()
chain = new MockFilterChain()
}
def "http/form-login default login generating page"() {
setup:
loadConfig(DefaultLoginPageConfig)
springSecurityFilterChain = context.getBean(FilterChainProxy)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
findFilter(DefaultLoginPageViewFilter)
response.getRedirectedUrl() == "http://localhost/login"
when: "request the login page"
setup()
request.requestURI = "/login"
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
<h3>Login with Username and Password</h3><form name='f' action='/login' method='POST'>
<table>
<tr><td>User:</td><td><input type='text' name='username' value=''></td></tr>
<tr><td>Password:</td><td><input type='password' name='password'/></td></tr>
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
</table>
</form></body></html>"""
when: "fail to log in"
setup()
request.requestURI = "/login"
request.method = "POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to login error page"
response.getRedirectedUrl() == "/login?error"
when: "request the error page"
HttpSession session = request.session
setup()
request.session = session
request.requestURI = "/login"
request.queryString = "error"
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
<p><font color='red'>Your login attempt was not successful, try again.<br/><br/>Reason: Bad credentials</font></p><h3>Login with Username and Password</h3><form name='f' action='/login' method='POST'>
<table>
<tr><td>User:</td><td><input type='text' name='username' value=''></td></tr>
<tr><td>Password:</td><td><input type='password' name='password'/></td></tr>
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
</table>
</form></body></html>"""
when: "login success"
setup()
request.requestURI = "/login"
request.method = "POST"
request.parameters.username = ["user"] as String[]
request.parameters.password = ["password"] as String[]
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to default succes page"
response.getRedirectedUrl() == "/"
}
def "logout success renders"() {
setup:
loadConfig(DefaultLoginPageConfig)
springSecurityFilterChain = context.getBean(FilterChainProxy)
when: "logout success"
request.requestURI = "/login"
request.queryString = "logout"
request.method = "GET"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to default success page"
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
<p><font color='green'>You have been logged out</font></p><h3>Login with Username and Password</h3><form name='f' action='/login' method='POST'>
<table>
<tr><td>User:</td><td><input type='text' name='username' value=''></td></tr>
<tr><td>Password:</td><td><input type='password' name='password'/></td></tr>
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
</table>
</form></body></html>"""
}
@Configuration
static class DefaultLoginPageConfig extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) {
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.formLogin()
}
}
def "custom logout success handler prevents rendering"() {
setup:
loadConfig(DefaultLoginPageCustomLogoutSuccessHandlerConfig)
springSecurityFilterChain = context.getBean(FilterChainProxy)
when: "logout success"
request.requestURI = "/login"
request.queryString = "logout"
request.method = "GET"
springSecurityFilterChain.doFilter(request,response,chain)
then: "default success page is NOT rendered (application is in charge of it)"
response.getContentAsString() == ""
}
@Configuration
static class DefaultLoginPageCustomLogoutSuccessHandlerConfig extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) {
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.logout()
.logoutSuccessHandler(new SimpleUrlLogoutSuccessHandler())
.and()
.formLogin()
}
}
def "custom logout success url prevents rendering"() {
setup:
loadConfig(DefaultLoginPageCustomLogoutConfig)
springSecurityFilterChain = context.getBean(FilterChainProxy)
when: "logout success"
request.requestURI = "/login"
request.queryString = "logout"
request.method = "GET"
springSecurityFilterChain.doFilter(request,response,chain)
then: "default success page is NOT rendered (application is in charge of it)"
response.getContentAsString() == ""
}
@Configuration
static class DefaultLoginPageCustomLogoutConfig extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) {
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.logout()
.logoutSuccessUrl("/login?logout")
.and()
.formLogin()
}
}
def "http/form-login default login with remember me"() {
setup:
loadConfig(DefaultLoginPageWithRememberMeConfig)
springSecurityFilterChain = context.getBean(FilterChainProxy)
when: "request the login page"
setup()
request.requestURI = "/login"
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
<h3>Login with Username and Password</h3><form name='f' action='/login' method='POST'>
<table>
<tr><td>User:</td><td><input type='text' name='username' value=''></td></tr>
<tr><td>Password:</td><td><input type='password' name='password'/></td></tr>
<tr><td><input type='checkbox' name='remember-me'/></td><td>Remember me on this computer.</td></tr>
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
</table>
</form></body></html>"""
}
@Configuration
static class DefaultLoginPageWithRememberMeConfig extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) {
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.formLogin()
.and()
.rememberMe()
}
}
def "http/form-login default login with openid"() {
setup:
loadConfig(DefaultLoginPageWithOpenIDConfig)
springSecurityFilterChain = context.getBean(FilterChainProxy)
when: "request the login page"
request.requestURI = "/login"
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getContentAsString() == """<html><head><title>Login Page</title></head><h3>Login with OpenID Identity</h3><form name='oidf' action='/login/openid' method='POST'>
<table>
<tr><td>Identity:</td><td><input type='text' size='30' name='openid_identifier'/></td></tr>
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
</table>
</form></body></html>"""
}
@Configuration
static class DefaultLoginPageWithOpenIDConfig extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) {
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.openidLogin()
}
}
def "http/form-login default login with openid, form login, and rememberme"() {
setup:
loadConfig(DefaultLoginPageWithFormLoginOpenIDRememberMeConfig)
springSecurityFilterChain = context.getBean(FilterChainProxy)
when: "request the login page"
request.requestURI = "/login"
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
<h3>Login with Username and Password</h3><form name='f' action='/login' method='POST'>
<table>
<tr><td>User:</td><td><input type='text' name='username' value=''></td></tr>
<tr><td>Password:</td><td><input type='password' name='password'/></td></tr>
<tr><td><input type='checkbox' name='remember-me'/></td><td>Remember me on this computer.</td></tr>
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
</table>
</form><h3>Login with OpenID Identity</h3><form name='oidf' action='/login/openid' method='POST'>
<table>
<tr><td>Identity:</td><td><input type='text' size='30' name='openid_identifier'/></td></tr>
<tr><td><input type='checkbox' name='remember-me'></td><td>Remember me on this computer.</td></tr>
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
</table>
</form></body></html>"""
}
@Configuration
static class DefaultLoginPageWithFormLoginOpenIDRememberMeConfig extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) {
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.rememberMe()
.and()
.formLogin()
.and()
.openidLogin()
}
}
def "default login with custom AuthenticationEntryPoint"() {
when:
loadConfig(DefaultLoginWithCustomAuthenticationEntryPointConfig)
then:
!findFilter(DefaultLoginPageViewFilter)
}
@Configuration
static class DefaultLoginWithCustomAuthenticationEntryPointConfig extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) {
http
.exceptionHandling()
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
.and()
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.formLogin()
}
}
def "DefaultLoginPage ObjectPostProcessor"() {
setup:
AnyObjectPostProcessor objectPostProcessor = Mock()
when:
HttpSecurity http = new HttpSecurity(objectPostProcessor, authenticationBldr, [:])
DefaultLoginPageConfigurer defaultLoginConfig = new DefaultLoginPageConfigurer([builder:http])
defaultLoginConfig.addObjectPostProcessor(objectPostProcessor)
http
// must set builder manually due to groovy not selecting correct method
.apply(defaultLoginConfig).and()
.formLogin()
.and()
.build()
then: "DefaultLoginPageGeneratingFilter is registered with LifecycleManager"
1 * objectPostProcessor.postProcess(_ as DefaultLoginPageViewFilter) >> {DefaultLoginPageViewFilter o -> o}
1 * objectPostProcessor.postProcess(_ as UsernamePasswordAuthenticationFilter) >> {UsernamePasswordAuthenticationFilter o -> o}
1 * objectPostProcessor.postProcess(_ as LoginUrlAuthenticationEntryPoint) >> {LoginUrlAuthenticationEntryPoint o -> o}
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers
import org.springframework.security.config.annotation.AnyObjectPostProcessor
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.access.ExceptionTranslationFilter
/**
*
* @author Rob Winch
*/
class ExceptionHandlingConfigurerTests extends BaseSpringSpec {
def "exception ObjectPostProcessor"() {
setup: "initialize the AUTH_FILTER as a mock"
AnyObjectPostProcessor opp = Mock()
when:
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
http
.exceptionHandling()
.and()
.build()
then: "ExceptionTranslationFilter is registered with LifecycleManager"
1 * opp.postProcess(_ as ExceptionTranslationFilter) >> {ExceptionTranslationFilter o -> o}
}
}

View File

@@ -0,0 +1,413 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.vote.AffirmativeBased;
import org.springframework.security.authentication.RememberMeAuthenticationToken
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.SecurityExpressions.*
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
public class ExpressionUrlAuthorizationConfigurerTests extends BaseSpringSpec {
def "hasAnyAuthority('ROLE_USER')"() {
when:
def expression = ExpressionUrlAuthorizationConfigurer.hasAnyAuthority("ROLE_USER")
then:
expression == "hasAnyAuthority('ROLE_USER')"
}
def "hasAnyAuthority('ROLE_USER','ROLE_ADMIN')"() {
when:
def expression = ExpressionUrlAuthorizationConfigurer.hasAnyAuthority("ROLE_USER","ROLE_ADMIN")
then:
expression == "hasAnyAuthority('ROLE_USER','ROLE_ADMIN')"
}
def "hasRole('ROLE_USER') is rejected due to starting with ROLE_"() {
when:
def expression = ExpressionUrlAuthorizationConfigurer.hasRole("ROLE_USER")
then:
IllegalArgumentException e = thrown()
e.message == "role should not start with 'ROLE_' since it is automatically inserted. Got 'ROLE_USER'"
}
def "authorizeUrls() uses AffirmativeBased AccessDecisionManager"() {
when: "Load Config with no specific AccessDecisionManager"
loadConfig(NoSpecificAccessDecessionManagerConfig)
then: "AccessDecessionManager matches the HttpSecurityBuilder's default"
findFilter(FilterSecurityInterceptor).accessDecisionManager.class == AffirmativeBased
}
@EnableWebSecurity
@Configuration
static class NoSpecificAccessDecessionManagerConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeUrls()
.anyRequest().hasRole("USER")
}
}
def "authorizeUrls() no requests"() {
when: "Load Config with no requests"
loadConfig(NoRequestsConfig)
then: "A meaningful exception is thrown"
BeanCreationException success = thrown()
success.message.contains "At least one mapping is required (i.e. authorizeUrls().anyRequest.authenticated())"
}
@EnableWebSecurity
@Configuration
static class NoRequestsConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeUrls()
}
}
def "authorizeUrls() incomplete mapping"() {
when: "Load Config with incomplete mapping"
loadConfig(IncompleteMappingConfig)
then: "A meaningful exception is thrown"
BeanCreationException success = thrown()
success.message.contains "An incomplete mapping was found for "
}
@EnableWebSecurity
@Configuration
static class IncompleteMappingConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeUrls()
.antMatchers("/a").authenticated()
.anyRequest()
}
}
def "authorizeUrls() hasAuthority"() {
setup:
loadConfig(HasAuthorityConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == 403
when:
super.setup()
login()
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == 200
when:
super.setup()
login("user","ROLE_INVALID")
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == 403
}
@EnableWebSecurity
@Configuration
static class HasAuthorityConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.and()
.authorizeUrls()
.anyRequest().hasAuthority("ROLE_USER")
}
}
def "authorizeUrls() hasAnyAuthority"() {
setup:
loadConfig(HasAnyAuthorityConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == 403
when:
super.setup()
login("user","ROLE_ADMIN")
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == 200
when:
super.setup()
login("user","ROLE_DBA")
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == 200
when:
super.setup()
login("user","ROLE_INVALID")
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == 403
}
@EnableWebSecurity
@Configuration
static class HasAnyAuthorityConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.and()
.authorizeUrls()
.anyRequest().hasAnyAuthority("ROLE_ADMIN","ROLE_DBA")
}
}
def "authorizeUrls() hasIpAddress"() {
setup:
loadConfig(HasIpAddressConfig)
when:
request.remoteAddr = "192.168.1.1"
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == 403
when:
super.setup()
request.remoteAddr = "192.168.1.0"
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == 200
}
@EnableWebSecurity
@Configuration
static class HasIpAddressConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.and()
.authorizeUrls()
.anyRequest().hasIpAddress("192.168.1.0")
}
}
def "authorizeUrls() anonymous"() {
setup:
loadConfig(AnonymousConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == 200
when:
super.setup()
login()
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == 403
}
@EnableWebSecurity
@Configuration
static class AnonymousConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.and()
.authorizeUrls()
.anyRequest().anonymous()
}
}
def "authorizeUrls() rememberMe"() {
setup:
loadConfig(RememberMeConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == 403
when:
super.setup()
login(new RememberMeAuthenticationToken("key", "user", AuthorityUtils.createAuthorityList("ROLE_USER")))
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == 200
}
@EnableWebSecurity
@Configuration
static class RememberMeConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.rememberMe()
.and()
.httpBasic()
.and()
.authorizeUrls()
.anyRequest().rememberMe()
}
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth)
throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
}
def "authorizeUrls() denyAll"() {
setup:
loadConfig(DenyAllConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == 403
when:
super.setup()
login(new RememberMeAuthenticationToken("key", "user", AuthorityUtils.createAuthorityList("ROLE_USER")))
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == 403
}
@EnableWebSecurity
@Configuration
static class DenyAllConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.and()
.authorizeUrls()
.anyRequest().denyAll()
}
}
def "authorizeUrls() not denyAll"() {
setup:
loadConfig(NotDenyAllConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == 200
when:
super.setup()
login(new RememberMeAuthenticationToken("key", "user", AuthorityUtils.createAuthorityList("ROLE_USER")))
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == 200
}
@EnableWebSecurity
@Configuration
static class NotDenyAllConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.and()
.authorizeUrls()
.anyRequest().not().denyAll()
}
}
def "authorizeUrls() fullyAuthenticated"() {
setup:
loadConfig(FullyAuthenticatedConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == 403
when:
super.setup()
login(new RememberMeAuthenticationToken("key", "user", AuthorityUtils.createAuthorityList("ROLE_USER")))
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == 403
when:
super.setup()
login()
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == 200
}
@EnableWebSecurity
@Configuration
static class FullyAuthenticatedConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.rememberMe()
.and()
.httpBasic()
.and()
.authorizeUrls()
.anyRequest().fullyAuthenticated()
}
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth)
throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
}
def "authorizeUrls() access"() {
setup:
loadConfig(AccessConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then: "Access is granted due to GET"
response.status == 200
when:
super.setup()
login()
request.method = "POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "Access is granted due to role"
response.status == 200
when:
super.setup()
request.method = "POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "Access is denied"
response.status == 403
}
@EnableWebSecurity
@Configuration
static class AccessConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.rememberMe()
.and()
.httpBasic()
.and()
.authorizeUrls()
.anyRequest().access("hasRole('ROLE_USER') or request.method == 'GET'")
}
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth)
throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
}
}

View File

@@ -0,0 +1,214 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers
import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.context.annotation.Configuration
import org.springframework.mock.web.MockFilterChain
import org.springframework.mock.web.MockHttpServletRequest
import org.springframework.mock.web.MockHttpServletResponse
import org.springframework.security.authentication.BadCredentialsException
import org.springframework.security.config.annotation.AnyObjectPostProcessor
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.builders.WebSecurity
import org.springframework.security.config.annotation.web.configuration.BaseWebConfig
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.web.AuthenticationEntryPoint
import org.springframework.security.web.FilterChainProxy
import org.springframework.security.web.PortMapper
import org.springframework.security.web.access.ExceptionTranslationFilter
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter
import org.springframework.security.web.authentication.AuthenticationFailureHandler
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
import org.springframework.security.web.authentication.logout.LogoutFilter
import org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy
import org.springframework.security.web.context.SecurityContextPersistenceFilter
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter
import org.springframework.security.web.session.SessionManagementFilter
import org.springframework.security.web.util.AnyRequestMatcher
import org.springframework.test.util.ReflectionTestUtils
/**
*
* @author Rob Winch
*/
class FormLoginConfigurerTests extends BaseSpringSpec {
def "Form Login"() {
when: "load formLogin()"
context = new AnnotationConfigApplicationContext(FormLoginConfig)
then: "FilterChains configured correctly"
def filterChains = filterChains()
filterChains.size() == 2
filterChains[0].requestMatcher.pattern == '/resources/**'
filterChains[0].filters.empty
filterChains[1].requestMatcher instanceof AnyRequestMatcher
filterChains[1].filters.collect { it.class.name.contains('$') ? it.class.superclass : it.class } ==
[SecurityContextPersistenceFilter, LogoutFilter, UsernamePasswordAuthenticationFilter,
RequestCacheAwareFilter, SecurityContextHolderAwareRequestFilter,
AnonymousAuthenticationFilter, SessionManagementFilter, ExceptionTranslationFilter, FilterSecurityInterceptor ]
and: "UsernamePasswordAuthentictionFilter is configured correctly"
UsernamePasswordAuthenticationFilter authFilter = findFilter(UsernamePasswordAuthenticationFilter,1)
authFilter.usernameParameter == "username"
authFilter.passwordParameter == "password"
authFilter.failureHandler.defaultFailureUrl == "/login?error"
authFilter.successHandler.defaultTargetUrl == "/"
authFilter.requiresAuthentication(new MockHttpServletRequest(requestURI : "/login", method: "POST"), new MockHttpServletResponse())
!authFilter.requiresAuthentication(new MockHttpServletRequest(requestURI : "/login", method: "GET"), new MockHttpServletResponse())
and: "SessionFixationProtectionStrategy is configured correctly"
SessionFixationProtectionStrategy sessionStrategy = ReflectionTestUtils.getField(authFilter,"sessionStrategy")
sessionStrategy.migrateSessionAttributes
and: "Exception handling is configured correctly"
AuthenticationEntryPoint authEntryPoint = filterChains[1].filters.find { it instanceof ExceptionTranslationFilter}.authenticationEntryPoint
MockHttpServletResponse response = new MockHttpServletResponse()
authEntryPoint.commence(new MockHttpServletRequest(requestURI: "/private/"), response, new BadCredentialsException(""))
response.redirectedUrl == "http://localhost/login"
}
@Configuration
@EnableWebSecurity
static class FormLoginConfig extends BaseWebConfig {
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**");
}
@Override
protected void configure(HttpSecurity http) {
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.formLogin()
.loginUrl("/login")
}
}
def "FormLogin.permitAll()"() {
when: "load formLogin() with permitAll"
context = new AnnotationConfigApplicationContext(FormLoginConfigPermitAll)
then: "the formLogin URLs are granted access"
FilterChainProxy filterChain = context.getBean(FilterChainProxy)
MockHttpServletResponse response = new MockHttpServletResponse()
filterChain.doFilter(new MockHttpServletRequest(servletPath : servletPath, requestURI: servletPath, queryString: query, method: method), response, new MockFilterChain())
response.redirectedUrl == redirectUrl
where:
servletPath | method | query | redirectUrl
"/login" | "GET" | null | null
"/login" | "POST" | null | "/login?error"
"/login" | "GET" | "error" | null
}
@Configuration
@EnableWebSecurity
static class FormLoginConfigPermitAll extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) {
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.formLogin()
.permitAll()
}
}
def "FormLogin uses PortMapper"() {
when: "load formLogin() with permitAll"
FormLoginUsesPortMapperConfig.PORT_MAPPER = Mock(PortMapper)
loadConfig(FormLoginUsesPortMapperConfig)
then: "the formLogin URLs are granted access"
findFilter(ExceptionTranslationFilter).authenticationEntryPoint.portMapper == FormLoginUsesPortMapperConfig.PORT_MAPPER
}
@Configuration
@EnableWebSecurity
static class FormLoginUsesPortMapperConfig extends BaseWebConfig {
static PortMapper PORT_MAPPER
@Override
protected void configure(HttpSecurity http) {
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.formLogin()
.permitAll()
.and()
.portMapper()
.portMapper(PORT_MAPPER)
}
}
def "FormLogin permitAll ignores failureUrl when failureHandler set"() {
setup:
PermitAllIgnoresFailureHandlerConfig.FAILURE_HANDLER = Mock(AuthenticationFailureHandler)
loadConfig(PermitAllIgnoresFailureHandlerConfig)
FilterChainProxy springSecurityFilterChain = context.getBean(FilterChainProxy)
when: "access default failureUrl and configured explicit FailureHandler"
MockHttpServletRequest request = new MockHttpServletRequest(requestURI:"/login",queryString:"error")
MockHttpServletResponse response = new MockHttpServletResponse()
springSecurityFilterChain.doFilter(request,response,new MockFilterChain())
then: "access is not granted to the failure handler (sent to login page)"
response.status == 302
}
@EnableWebSecurity
@Configuration
static class PermitAllIgnoresFailureHandlerConfig extends BaseWebConfig {
static AuthenticationFailureHandler FAILURE_HANDLER
@Override
protected void configure(HttpSecurity http) {
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.formLogin()
.failureHandler(FAILURE_HANDLER)
.permitAll()
}
}
def "formLogin ObjectPostProcessor"() {
setup: "initialize the AUTH_FILTER as a mock"
AnyObjectPostProcessor opp = Mock()
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
when:
http
.formLogin()
.and()
.build()
then: "UsernamePasswordAuthenticationFilter is registered with LifecycleManager"
1 * opp.postProcess(_ as UsernamePasswordAuthenticationFilter) >> {UsernamePasswordAuthenticationFilter o -> o}
and: "LoginUrlAuthenticationEntryPoint is registered with LifecycleManager"
1 * opp.postProcess(_ as LoginUrlAuthenticationEntryPoint) >> {LoginUrlAuthenticationEntryPoint o -> o}
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers
import org.springframework.security.config.annotation.AnyObjectPostProcessor
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter
/**
*
* @author Rob Winch
*/
class HttpBasicConfigurerTests extends BaseSpringSpec {
def "httBasic ObjectPostProcessor"() {
setup:
AnyObjectPostProcessor opp = Mock()
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
when:
http
.httpBasic()
.and()
.build()
then: "ExceptionTranslationFilter is registered with LifecycleManager"
1 * opp.postProcess(_ as BasicAuthenticationFilter) >> {BasicAuthenticationFilter o -> o}
}
}

View File

@@ -0,0 +1,114 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication
import org.springframework.security.core.AuthenticationException
import org.springframework.security.web.FilterChainProxy
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor
import org.springframework.stereotype.Component
/**
*
* @author Rob Winch
*/
class Issue55Tests extends BaseSpringSpec {
def "WebSecurityConfigurerAdapter defaults to @Autowired"() {
when:
loadConfig(WebSecurityConfigurerAdapterDefaultsAuthManagerConfig)
then:
context.getBean(FilterChainProxy)
findFilter(FilterSecurityInterceptor).authenticationManager.parent.class == CustomAuthenticationManager
}
@Configuration
@EnableWebSecurity
static class WebSecurityConfigurerAdapterDefaultsAuthManagerConfig {
@Component
public static class WebSecurityAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeUrls()
.anyRequest().hasRole("USER");
}
}
@Configuration
public static class AuthenticationManagerConfiguration {
@Bean
public AuthenticationManager authenticationManager() throws Exception {
return new CustomAuthenticationManager();
}
}
}
def "multi http WebSecurityConfigurerAdapter defaults to @Autowired"() {
when:
loadConfig(MultiWebSecurityConfigurerAdapterDefaultsAuthManagerConfig)
then:
context.getBean(FilterChainProxy)
findFilter(FilterSecurityInterceptor).authenticationManager.parent.class == CustomAuthenticationManager
findFilter(FilterSecurityInterceptor,1).authenticationManager.parent.class == CustomAuthenticationManager
}
@Configuration
@EnableWebSecurity
static class MultiWebSecurityConfigurerAdapterDefaultsAuthManagerConfig {
@Component
@Order(1)
public static class ApiWebSecurityAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/api/**")
.authorizeUrls()
.anyRequest().hasRole("USER");
}
}
@Component
public static class WebSecurityAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeUrls()
.anyRequest().hasRole("USER");
}
}
@Configuration
public static class AuthenticationManagerConfiguration {
@Bean
public AuthenticationManager authenticationManager() throws Exception {
return new CustomAuthenticationManager();
}
}
}
static class CustomAuthenticationManager implements AuthenticationManager {
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
return null;
}
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers
import org.springframework.security.config.annotation.AnyObjectPostProcessor
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.authentication.preauth.j2ee.J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource
import org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter
/**
*
* @author Rob Winch
*/
class JeeConfigurerTests extends BaseSpringSpec {
def "jee ObjectPostProcessor"() {
setup:
AnyObjectPostProcessor opp = Mock()
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
when:
http
.jee()
.and()
.build()
then: "J2eePreAuthenticatedProcessingFilter is registered with LifecycleManager"
1 * opp.postProcess(_ as J2eePreAuthenticatedProcessingFilter) >> {J2eePreAuthenticatedProcessingFilter o -> o}
and: "J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource is registered with LifecycleManager"
1 * opp.postProcess(_ as J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource) >> {J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource o -> o}
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers
import org.springframework.security.config.annotation.AnyObjectPostProcessor
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.authentication.logout.LogoutFilter
/**
*
* @author Rob Winch
*/
class LogoutConfigurerTests extends BaseSpringSpec {
def "logout ObjectPostProcessor"() {
setup:
AnyObjectPostProcessor opp = Mock()
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
when:
http
.logout()
.and()
.build()
then: "LogoutFilter is registered with LifecycleManager"
1 * opp.postProcess(_ as LogoutFilter) >> {LogoutFilter o -> o}
}
}

View File

@@ -0,0 +1,78 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.access.AccessDecisionManager
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute
import org.springframework.security.authentication.AnonymousAuthenticationToken
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.web.builders.DebugFilter;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.web.AuthenticationEntryPoint
import org.springframework.security.web.FilterInvocation
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
import org.springframework.security.web.access.ExceptionTranslationFilter
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.security.web.context.NullSecurityContextRepository;
import org.springframework.security.web.context.SecurityContextPersistenceFilter
import org.springframework.security.web.jaasapi.JaasApiIntegrationFilter;
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
import org.springframework.security.web.util.AntPathRequestMatcher
import org.springframework.security.web.util.AnyRequestMatcher;
import org.springframework.security.web.util.RequestMatcher
import spock.lang.Ignore;
/**
* Tests to verify that all the functionality of <anonymous> attributes is present
*
* @author Rob Winch
*
*/
public class NamespaceDebugTests extends BaseSpringSpec {
def "debug=true"() {
when: "Load configuraiton with debug enabled"
loadConfig(DebugWebSecurity)
then: "The DebugFilter is present"
context.getBean("springSecurityFilterChain").class == DebugFilter
}
@Configuration
@EnableWebSecurity(debug=true)
static class DebugWebSecurity extends WebSecurityConfigurerAdapter {
}
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.BaseSpringSpec;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.BaseWebConfig;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.ExceptionTranslationFilter;
/**
* Tests to verify that all the functionality of <access-denied-handler> attributes is present
*
* @author Rob Winch
*
*/
public class NamespaceHttpAccessDeniedHandlerTests extends BaseSpringSpec {
def "http/access-denied-handler@error-page"() {
when:
loadConfig(AccessDeniedPageConfig)
then:
findFilter(ExceptionTranslationFilter).accessDeniedHandler.errorPage == "/AccessDeniedPageConfig"
}
@Configuration
static class AccessDeniedPageConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) {
http.
exceptionHandling()
.accessDeniedPage("/AccessDeniedPageConfig")
}
}
def "http/access-denied-handler@ref"() {
when:
loadConfig(AccessDeniedHandlerRefConfig)
then:
findFilter(ExceptionTranslationFilter).accessDeniedHandler.class == AccessDeniedHandlerRefConfig.CustomAccessDeniedHandler
}
@Configuration
static class AccessDeniedHandlerRefConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) {
CustomAccessDeniedHandler accessDeniedHandler = new CustomAccessDeniedHandler()
http.
exceptionHandling()
.accessDeniedHandler(accessDeniedHandler)
}
static class CustomAccessDeniedHandler implements AccessDeniedHandler {
public void handle(HttpServletRequest request,
HttpServletResponse response,
AccessDeniedException accessDeniedException)
throws IOException, ServletException {
}
}
}
}

View File

@@ -0,0 +1,129 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AnonymousAuthenticationToken
import org.springframework.security.config.annotation.BaseSpringSpec;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.BaseWebConfig;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
/**
* Tests to verify that all the functionality of <anonymous> attributes is present
*
* @author Rob Winch
*
*/
public class NamespaceHttpAnonymousTests extends BaseSpringSpec {
def "http/anonymous@enabled = true (default)"() {
when:
loadConfig(AnonymousConfig)
then:
def filter = findFilter(AnonymousAuthenticationFilter)
filter != null
def authManager = findFilter(FilterSecurityInterceptor).authenticationManager
authManager.authenticate(new AnonymousAuthenticationToken(filter.key, filter.principal, filter.authorities)).authenticated
}
@Configuration
static class AnonymousConfig extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) {
http
.authorizeUrls()
.anyRequest().hasRole("USER");
}
}
def "http/anonymous@enabled = false"() {
when:
loadConfig(AnonymousDisabledConfig)
then:
findFilter(AnonymousAuthenticationFilter) == null
}
@Configuration
static class AnonymousDisabledConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) {
http.anonymous().disable()
}
}
def "http/anonymous@granted-authority"() {
when:
loadConfig(AnonymousGrantedAuthorityConfig)
then:
findFilter(AnonymousAuthenticationFilter).authorities == AuthorityUtils.createAuthorityList("ROLE_ANON")
}
@Configuration
static class AnonymousGrantedAuthorityConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) {
http
.anonymous()
.authorities("ROLE_ANON")
}
}
def "http/anonymous@key"() {
when:
loadConfig(AnonymousKeyConfig)
then:
def filter = findFilter(AnonymousAuthenticationFilter)
filter != null
filter.key == "AnonymousKeyConfig"
def authManager = findFilter(FilterSecurityInterceptor).authenticationManager
authManager.authenticate(new AnonymousAuthenticationToken(filter.key, filter.principal, filter.authorities)).authenticated
}
@Configuration
static class AnonymousKeyConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) {
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.anonymous().key("AnonymousKeyConfig")
}
}
def "http/anonymous@username"() {
when:
loadConfig(AnonymousUsernameConfig)
then:
def filter = findFilter(AnonymousAuthenticationFilter)
filter != null
filter.principal == "AnonymousUsernameConfig"
def authManager = findFilter(FilterSecurityInterceptor).authenticationManager
authManager.authenticate(new AnonymousAuthenticationToken(filter.key, filter.principal, filter.authorities)).principal == "AnonymousUsernameConfig"
}
@Configuration
static class AnonymousUsernameConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) {
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.anonymous().principal("AnonymousUsernameConfig")
}
}
}

View File

@@ -0,0 +1,169 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.mock.web.MockFilterChain;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.config.annotation.BaseSpringSpec;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.BaseWebConfig;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
/**
* Tests to verify that all the functionality of <http-basic> attributes is present
*
* @author Rob Winch
*
*/
public class NamespaceHttpBasicTests extends BaseSpringSpec {
FilterChainProxy springSecurityFilterChain
MockHttpServletRequest request
MockHttpServletResponse response
MockFilterChain chain
def setup() {
request = new MockHttpServletRequest()
response = new MockHttpServletResponse()
chain = new MockFilterChain()
}
def "http/http-basic"() {
setup:
loadConfig(HttpBasicConfig)
springSecurityFilterChain = context.getBean(FilterChainProxy)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == HttpServletResponse.SC_FORBIDDEN
when: "fail to log in"
setup()
login("user","invalid")
springSecurityFilterChain.doFilter(request,response,chain)
then: "unauthorized"
response.status == HttpServletResponse.SC_UNAUTHORIZED
response.getHeader("WWW-Authenticate") == 'Basic realm="Spring Security Application"'
when: "login success"
setup()
login()
then: "sent to default succes page"
!response.committed
}
@Configuration
static class HttpBasicConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) {
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.httpBasic();
}
}
def "http@realm"() {
setup:
loadConfig(CustomHttpBasicConfig)
springSecurityFilterChain = context.getBean(FilterChainProxy)
when:
login("user","invalid")
springSecurityFilterChain.doFilter(request,response,chain)
then: "unauthorized"
response.status == HttpServletResponse.SC_UNAUTHORIZED
response.getHeader("WWW-Authenticate") == 'Basic realm="Custom Realm"'
}
@Configuration
static class CustomHttpBasicConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) {
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.httpBasic().realmName("Custom Realm");
}
}
def "http-basic@authentication-details-source-ref"() {
when:
loadConfig(AuthenticationDetailsSourceHttpBasicConfig)
springSecurityFilterChain = context.getBean(FilterChainProxy)
then:
findFilter(BasicAuthenticationFilter).authenticationDetailsSource.class == CustomAuthenticationDetailsSource
}
@Configuration
static class AuthenticationDetailsSourceHttpBasicConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) {
http
.httpBasic()
.authenticationDetailsSource(new CustomAuthenticationDetailsSource())
}
}
static class CustomAuthenticationDetailsSource extends WebAuthenticationDetailsSource {}
def "http-basic@entry-point-ref"() {
setup:
loadConfig(EntryPointRefHttpBasicConfig)
springSecurityFilterChain = context.getBean(FilterChainProxy)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == HttpServletResponse.SC_FORBIDDEN
when: "fail to log in"
setup()
login("user","invalid")
springSecurityFilterChain.doFilter(request,response,chain)
then: "custom"
response.status == HttpServletResponse.SC_INTERNAL_SERVER_ERROR
when: "login success"
setup()
login()
then: "sent to default succes page"
!response.committed
}
@Configuration
static class EntryPointRefHttpBasicConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) {
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.httpBasic()
.authenticationEntryPoint(new AuthenticationEntryPoint() {
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR)
}
})
}
}
def login(String username="user",String password="password") {
def credentials = username + ":" + password
request.addHeader("Authorization", "Basic " + credentials.bytes.encodeBase64())
}
}

View File

@@ -0,0 +1,170 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.access.AccessDecisionManager
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute
import org.springframework.security.authentication.AnonymousAuthenticationToken
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.BaseWebConfig;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.web.AuthenticationEntryPoint
import org.springframework.security.web.FilterInvocation
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
import org.springframework.security.web.access.ExceptionTranslationFilter
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.security.web.context.NullSecurityContextRepository;
import org.springframework.security.web.context.SecurityContextPersistenceFilter
import org.springframework.security.web.jaasapi.JaasApiIntegrationFilter;
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
import org.springframework.security.web.util.AntPathRequestMatcher
import org.springframework.security.web.util.AnyRequestMatcher;
import org.springframework.security.web.util.RequestMatcher
import spock.lang.Ignore;
/**
* Tests to verify that all the functionality of <anonymous> attributes is present
*
* @author Rob Winch
*
*/
public class NamespaceHttpCustomFilterTests extends BaseSpringSpec {
def "http/custom-filter@before"() {
when:
loadConfig(CustomFilterBeforeConfig)
then:
filterChain().filters[0].class == CustomFilter
}
@Configuration
static class CustomFilterBeforeConfig extends BaseWebConfig {
CustomFilterBeforeConfig() {
// do not add the default filters to make testing easier
super(true)
}
protected void configure(HttpSecurity http) {
http
.addFilterBefore(new CustomFilter(), UsernamePasswordAuthenticationFilter.class)
.formLogin()
}
}
def "http/custom-filter@after"() {
when:
loadConfig(CustomFilterAfterConfig)
then:
filterChain().filters[1].class == CustomFilter
}
@Configuration
static class CustomFilterAfterConfig extends BaseWebConfig {
CustomFilterAfterConfig() {
// do not add the default filters to make testing easier
super(true)
}
protected void configure(HttpSecurity http) {
http
.addFilterAfter(new CustomFilter(), UsernamePasswordAuthenticationFilter.class)
.formLogin()
}
}
def "http/custom-filter@position"() {
when:
loadConfig(CustomFilterPositionConfig)
then:
filterChain().filters.collect { it.class } == [CustomFilter]
}
@Configuration
static class CustomFilterPositionConfig extends BaseWebConfig {
CustomFilterPositionConfig() {
// do not add the default filters to make testing easier
super(true)
}
protected void configure(HttpSecurity http) {
http
// this works so long as the CustomFilter extends one of the standard filters
// if not, use addFilterBefore or addFilterAfter
.addFilter(new CustomFilter())
}
}
def "http/custom-filter no AuthenticationManager in HttpSecurity"() {
when:
loadConfig(NoAuthenticationManagerInHtppConfigurationConfig)
then:
filterChain().filters[0].class == CustomFilter
}
@Configuration
@EnableWebSecurity
static class NoAuthenticationManagerInHtppConfigurationConfig extends WebSecurityConfigurerAdapter {
NoAuthenticationManagerInHtppConfigurationConfig() {
super(true)
}
protected AuthenticationManager authenticationManager()
throws Exception {
return new CustomAuthenticationManager();
}
@Override
protected void configure(HttpSecurity http) {
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.addFilterBefore(new CustomFilter(), UsernamePasswordAuthenticationFilter.class)
}
}
static class CustomFilter extends UsernamePasswordAuthenticationFilter {}
static class CustomAuthenticationManager implements AuthenticationManager {
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
return null;
}
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers
import org.springframework.context.annotation.Configuration
import org.springframework.expression.spel.standard.SpelExpressionParser
import org.springframework.security.access.expression.SecurityExpressionHandler
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.BaseWebConfig;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
/**
* Tests to verify that all the functionality of <anonymous> attributes is present
*
* @author Rob Winch
*
*/
public class NamespaceHttpExpressionHandlerTests extends BaseSpringSpec {
def "http/expression-handler@ref"() {
when:
def parser = new SpelExpressionParser()
ExpressionHandlerConfig.EXPRESSION_HANDLER = Mock(SecurityExpressionHandler.class)
ExpressionHandlerConfig.EXPRESSION_HANDLER.getExpressionParser() >> parser
loadConfig(ExpressionHandlerConfig)
then:
noExceptionThrown()
}
@Configuration
@EnableWebSecurity
static class ExpressionHandlerConfig extends BaseWebConfig {
static EXPRESSION_HANDLER;
protected void configure(HttpSecurity http) {
http
.authorizeUrls()
.expressionHandler(EXPRESSION_HANDLER)
.antMatchers("/users**","/sessions/**").hasRole("ADMIN")
.antMatchers("/signup").permitAll()
.anyRequest().hasRole("USER")
}
}
}

View File

@@ -0,0 +1,110 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers;
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import org.springframework.context.annotation.Configuration
import org.springframework.mock.web.MockFilterChain
import org.springframework.mock.web.MockHttpServletRequest
import org.springframework.mock.web.MockHttpServletResponse
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.builders.WebSecurity
import org.springframework.security.config.annotation.web.configuration.BaseWebConfig
import org.springframework.security.web.FilterChainProxy
import org.springframework.security.web.firewall.DefaultHttpFirewall
import org.springframework.security.web.firewall.FirewalledRequest
import org.springframework.security.web.firewall.RequestRejectedException
/**
* Tests to verify that all the functionality of <http-firewall> attributes is present
*
* @author Rob Winch
*
*/
public class NamespaceHttpFirewallTests extends BaseSpringSpec {
FilterChainProxy springSecurityFilterChain
MockHttpServletRequest request
MockHttpServletResponse response
MockFilterChain chain
def setup() {
request = new MockHttpServletRequest()
response = new MockHttpServletResponse()
chain = new MockFilterChain()
}
def "http-firewall"() {
setup:
loadConfig(HttpFirewallConfig)
springSecurityFilterChain = context.getBean(FilterChainProxy)
request.setPathInfo("/public/../private/")
when:
springSecurityFilterChain.doFilter(request,response,chain)
then: "the default firewall is used"
thrown(RequestRejectedException)
}
@Configuration
static class HttpFirewallConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) {
}
}
def "http-firewall@ref"() {
setup:
loadConfig(CustomHttpFirewallConfig)
springSecurityFilterChain = context.getBean(FilterChainProxy)
request.setParameter("deny", "true")
when:
springSecurityFilterChain.doFilter(request,response,chain)
then: "the custom firewall is used"
thrown(RequestRejectedException)
}
@Configuration
static class CustomHttpFirewallConfig extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) { }
@Override
public void configure(WebSecurity builder) throws Exception {
builder
.httpFirewall(new CustomHttpFirewall())
}
}
static class CustomHttpFirewall extends DefaultHttpFirewall {
@Override
public FirewalledRequest getFirewalledRequest(HttpServletRequest request)
throws RequestRejectedException {
if(request.getParameter("deny")) {
throw new RequestRejectedException("custom rejection")
}
return super.getFirewalledRequest(request)
}
@Override
public HttpServletResponse getFirewalledResponse(
HttpServletResponse response) {
return super.getFirewalledRequest(response)
}
}
}

View File

@@ -0,0 +1,170 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers
import org.springframework.context.annotation.Configuration
import org.springframework.mock.web.MockFilterChain
import org.springframework.mock.web.MockHttpServletRequest
import org.springframework.mock.web.MockHttpServletResponse
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.builders.WebSecurity
import org.springframework.security.config.annotation.web.configuration.BaseWebConfig
import org.springframework.security.web.FilterChainProxy
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource
/**
* Tests to verify that all the functionality of <anonymous> attributes is present
*
* @author Rob Winch
*
*/
public class NamespaceHttpFormLoginTests extends BaseSpringSpec {
FilterChainProxy springSecurityFilterChain
def "http/form-login"() {
setup:
loadConfig(FormLoginConfig)
springSecurityFilterChain = context.getBean(FilterChainProxy)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getRedirectedUrl() == "http://localhost/login"
when: "fail to log in"
super.setup()
request.requestURI = "/login"
request.method = "POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to login error page"
response.getRedirectedUrl() == "/login?error"
when: "login success"
super.setup()
request.requestURI = "/login"
request.method = "POST"
request.parameters.username = ["user"] as String[]
request.parameters.password = ["password"] as String[]
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to default succes page"
response.getRedirectedUrl() == "/"
}
@Configuration
static class FormLoginConfig extends BaseWebConfig {
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**");
}
@Override
protected void configure(HttpSecurity http) {
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.formLogin()
}
}
def "http/form-login custom"() {
setup:
loadConfig(FormLoginCustomConfig)
springSecurityFilterChain = context.getBean(FilterChainProxy)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getRedirectedUrl() == "http://localhost/authentication/login"
when: "fail to log in"
super.setup()
request.requestURI = "/authentication/login/process"
request.method = "POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to login error page"
response.getRedirectedUrl() == "/authentication/login?failed"
when: "login success"
super.setup()
request.requestURI = "/authentication/login/process"
request.method = "POST"
request.parameters.j_username = ["user"] as String[]
request.parameters.j_password = ["password"] as String[]
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to default succes page"
response.getRedirectedUrl() == "/default"
}
@Configuration
static class FormLoginCustomConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
boolean alwaysUseDefaultSuccess = true;
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.formLogin()
.usernameParameter("j_username") // form-login@username-parameter
.passwordParameter("j_password") // form-login@password-parameter
.loginPage("/authentication/login") // form-login@login-page
.failureUrl("/authentication/login?failed") // form-login@authentication-failure-url
.loginProcessingUrl("/authentication/login/process") // form-login@login-processing-url
.defaultSuccessUrl("/default", alwaysUseDefaultSuccess) // form-login@default-target-url / form-login@always-use-default-target
}
}
def "http/form-login custom refs"() {
when:
loadConfig(FormLoginCustomRefsConfig)
springSecurityFilterChain = context.getBean(FilterChainProxy)
then: "CustomWebAuthenticationDetailsSource is used"
findFilter(UsernamePasswordAuthenticationFilter).authenticationDetailsSource.class == CustomWebAuthenticationDetailsSource
when: "fail to log in"
request.requestURI = "/login"
request.method = "POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to login error page"
response.getRedirectedUrl() == "/custom/failure"
when: "login success"
super.setup()
request.requestURI = "/login"
request.method = "POST"
request.parameters.username = ["user"] as String[]
request.parameters.password = ["password"] as String[]
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to default succes page"
response.getRedirectedUrl() == "/custom/targetUrl"
}
@Configuration
static class FormLoginCustomRefsConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.loginPage("/login")
.failureHandler(new SimpleUrlAuthenticationFailureHandler("/custom/failure")) // form-login@authentication-failure-handler-ref
.successHandler(new SavedRequestAwareAuthenticationSuccessHandler( defaultTargetUrl : "/custom/targetUrl" )) // form-login@authentication-success-handler-ref
.authenticationDetailsSource(new CustomWebAuthenticationDetailsSource()) // form-login@authentication-details-source-ref
.and();
}
}
static class CustomWebAuthenticationDetailsSource extends WebAuthenticationDetailsSource {}
}

View File

@@ -0,0 +1,171 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers
import javax.servlet.http.HttpServletResponse
import org.springframework.context.annotation.Configuration
import org.springframework.http.HttpMethod;
import org.springframework.mock.web.MockFilterChain
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextImpl
import org.springframework.security.web.FilterChainProxy
import org.springframework.security.web.context.HttpRequestResponseHolder
import org.springframework.security.web.context.HttpSessionSecurityContextRepository
/**
* Tests to verify that all the functionality of <intercept-url> attributes is present
*
* @author Rob Winch
*
*/
public class NamespaceHttpInterceptUrlTests extends BaseSpringSpec {
def "http/intercept-url denied when not logged in"() {
setup:
loadConfig(HttpInterceptUrlConfig)
request.servletPath == "/users"
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == HttpServletResponse.SC_FORBIDDEN
}
def "http/intercept-url denied when logged in"() {
setup:
loadConfig(HttpInterceptUrlConfig)
login()
request.setServletPath("/users")
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == HttpServletResponse.SC_FORBIDDEN
}
def "http/intercept-url allowed when logged in"() {
setup:
loadConfig(HttpInterceptUrlConfig)
login("admin","ROLE_ADMIN")
request.setServletPath("/users")
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == HttpServletResponse.SC_OK
!response.isCommitted()
}
def "http/intercept-url@method=POST"() {
setup:
loadConfig(HttpInterceptUrlConfig)
when:
login()
request.setServletPath("/admin/post")
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == HttpServletResponse.SC_OK
!response.isCommitted()
when:
super.setup()
login()
request.setServletPath("/admin/post")
request.setMethod("POST")
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == HttpServletResponse.SC_FORBIDDEN
when:
super.setup()
login("admin","ROLE_ADMIN")
request.setServletPath("/admin/post")
request.setMethod("POST")
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == HttpServletResponse.SC_OK
!response.committed
}
def "http/intercept-url@requires-channel"() {
setup:
loadConfig(HttpInterceptUrlConfig)
when:
request.setServletPath("/login")
request.setRequestURI("/login")
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.redirectedUrl == "https://localhost/login"
when:
super.setup()
request.setServletPath("/secured/a")
request.setRequestURI("/secured/a")
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.redirectedUrl == "https://localhost/secured/a"
when:
super.setup()
request.setSecure(true)
request.setScheme("https")
request.setServletPath("/user")
request.setRequestURI("/user")
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.redirectedUrl == "http://localhost/user"
}
@Configuration
@EnableWebSecurity
static class HttpInterceptUrlConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeUrls()
// the line below is similar to intercept-url@pattern:
// <intercept-url pattern="/users**" access="hasRole('ROLE_ADMIN')"/>
// <intercept-url pattern="/sessions/**" access="hasRole('ROLE_ADMIN')"/>
.antMatchers("/users**","/sessions/**").hasRole("ADMIN")
// the line below is similar to intercept-url@method:
// <intercept-url pattern="/admin/post" access="hasRole('ROLE_ADMIN')" method="POST"/>
// <intercept-url pattern="/admin/another-post/**" access="hasRole('ROLE_ADMIN')" method="POST"/>
.antMatchers(HttpMethod.POST, "/admin/post","/admin/another-post/**").hasRole("ADMIN")
.antMatchers("/signup").permitAll()
.anyRequest().hasRole("USER")
.and()
.requiresChannel()
// NOTE: channel security is configured separately of authorization (i.e. intercept-url@access
// the line below is similar to intercept-url@requires-channel="https":
// <intercept-url pattern="/login" requires-channel="https"/>
// <intercept-url pattern="/secured/**" requires-channel="https"/>
.antMatchers("/login","/secured/**").requiresSecure()
// the line below is similar to intercept-url@requires-channel="http":
// <intercept-url pattern="/**" requires-channel="http"/>
.anyRequest().requiresInsecure()
}
protected void registerAuthentication(
AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN")
}
}
}

View File

@@ -0,0 +1,145 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.mock.web.MockFilterChain
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse
import org.springframework.security.access.AccessDecisionManager
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute
import org.springframework.security.authentication.AnonymousAuthenticationToken
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.codec.Base64;
import org.springframework.security.web.AuthenticationEntryPoint
import org.springframework.security.web.FilterChainProxy
import org.springframework.security.web.FilterInvocation
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
import org.springframework.security.web.access.ExceptionTranslationFilter
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedGrantedAuthoritiesUserDetailsService;
import org.springframework.security.web.authentication.preauth.j2ee.J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource;
import org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.security.web.context.NullSecurityContextRepository;
import org.springframework.security.web.context.SecurityContextPersistenceFilter
import org.springframework.security.web.jaasapi.JaasApiIntegrationFilter;
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
import org.springframework.security.web.util.AntPathRequestMatcher
import org.springframework.security.web.util.AnyRequestMatcher;
import org.springframework.security.web.util.RequestMatcher
import org.springframework.test.util.ReflectionTestUtils;
/**
* Tests to verify that all the functionality of <jee> attributes is present
*
* @author Rob Winch
*
*/
public class NamespaceHttpJeeTests extends BaseSpringSpec {
def "http/jee@mappable-roles"() {
when:
loadConfig(JeeMappableRolesConfig)
J2eePreAuthenticatedProcessingFilter filter = findFilter(J2eePreAuthenticatedProcessingFilter)
AuthenticationManager authenticationManager = ReflectionTestUtils.getField(filter,"authenticationManager")
then:
authenticationManager
filter.authenticationDetailsSource.class == J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource
filter.authenticationDetailsSource.j2eeMappableRoles == ["ROLE_USER", "ROLE_ADMIN"] as Set
authenticationManager.providers.find { it instanceof PreAuthenticatedAuthenticationProvider }.preAuthenticatedUserDetailsService.class == PreAuthenticatedGrantedAuthoritiesUserDetailsService
}
@Configuration
@EnableWebSecurity
public static class JeeMappableRolesConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.jee()
.mappableRoles("USER","ADMIN");
}
}
def "http/jee@user-service-ref"() {
when:
loadConfig(JeeUserServiceRefConfig)
J2eePreAuthenticatedProcessingFilter filter = findFilter(J2eePreAuthenticatedProcessingFilter)
AuthenticationManager authenticationManager = ReflectionTestUtils.getField(filter,"authenticationManager")
then:
authenticationManager
filter.authenticationDetailsSource.class == J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource
filter.authenticationDetailsSource.j2eeMappableRoles == ["ROLE_USER", "ROLE_ADMIN"] as Set
authenticationManager.providers.find { it instanceof PreAuthenticatedAuthenticationProvider }.preAuthenticatedUserDetailsService.class == CustomUserService
}
@Configuration
@EnableWebSecurity
public static class JeeUserServiceRefConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.jee()
.mappableAuthorities("ROLE_USER","ROLE_ADMIN")
.authenticatedUserDetailsService(new CustomUserService());
}
}
static class CustomUserService implements AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> {
public UserDetails loadUserDetails(
PreAuthenticatedAuthenticationToken token)
throws UsernameNotFoundException {
return null;
}
}
}

View File

@@ -0,0 +1,171 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.mock.web.MockFilterChain
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse
import org.springframework.security.access.AccessDecisionManager
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute
import org.springframework.security.authentication.AnonymousAuthenticationToken
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.BaseWebConfig;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextImpl
import org.springframework.security.crypto.codec.Base64;
import org.springframework.security.web.AuthenticationEntryPoint
import org.springframework.security.web.FilterChainProxy
import org.springframework.security.web.FilterInvocation
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
import org.springframework.security.web.access.ExceptionTranslationFilter
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.context.HttpRequestResponseHolder
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.security.web.context.NullSecurityContextRepository;
import org.springframework.security.web.context.SecurityContextPersistenceFilter
import org.springframework.security.web.jaasapi.JaasApiIntegrationFilter;
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
import org.springframework.security.web.util.AntPathRequestMatcher
import org.springframework.security.web.util.AnyRequestMatcher;
import org.springframework.security.web.util.RequestMatcher
/**
* Tests to verify that all the functionality of <logout> attributes is present
*
* @author Rob Winch
*
*/
public class NamespaceHttpLogoutTests extends BaseSpringSpec {
FilterChainProxy springSecurityFilterChain
MockHttpServletRequest request
MockHttpServletResponse response
MockFilterChain chain
def setup() {
request = new MockHttpServletRequest()
response = new MockHttpServletResponse()
chain = new MockFilterChain()
}
def "http/logout"() {
setup:
loadConfig(HttpLogoutConfig)
springSecurityFilterChain = context.getBean(FilterChainProxy)
login()
request.setRequestURI("/logout")
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
!authenticated()
!request.getSession(false)
response.redirectedUrl == "/login?logout"
!response.getCookies()
}
@Configuration
static class HttpLogoutConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
}
}
def "http/logout custom"() {
setup:
loadConfig(CustomHttpLogoutConfig)
springSecurityFilterChain = context.getBean(FilterChainProxy)
login()
request.setRequestURI("/custom-logout")
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
!authenticated()
request.getSession(false)
response.redirectedUrl == "/logout-success"
response.getCookies().length == 1
response.getCookies()[0].name == "remove"
response.getCookies()[0].maxAge == 0
}
@Configuration
static class CustomHttpLogoutConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.logout()
.deleteCookies("remove") // logout@delete-cookies
.invalidateHttpSession(false) // logout@invalidate-session=false (default is true)
.logoutUrl("/custom-logout") // logout@logout-url (default is /logout)
.logoutSuccessUrl("/logout-success") // logout@success-url (default is /login?logout)
}
}
def "http/logout@success-handler-ref"() {
setup:
loadConfig(SuccessHandlerRefHttpLogoutConfig)
springSecurityFilterChain = context.getBean(FilterChainProxy)
login()
request.setRequestURI("/logout")
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
!authenticated()
!request.getSession(false)
response.redirectedUrl == "/SuccessHandlerRefHttpLogoutConfig"
!response.getCookies()
}
@Configuration
static class SuccessHandlerRefHttpLogoutConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
SimpleUrlLogoutSuccessHandler logoutSuccessHandler = new SimpleUrlLogoutSuccessHandler(defaultTargetUrl:"/SuccessHandlerRefHttpLogoutConfig")
http
.logout()
.logoutSuccessHandler(logoutSuccessHandler)
}
}
def login(String username="user", String role="ROLE_USER") {
HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository()
HttpRequestResponseHolder requestResponseHolder = new HttpRequestResponseHolder(request, response)
repo.loadContext(requestResponseHolder)
repo.saveContext(new SecurityContextImpl(authentication: new UsernamePasswordAuthenticationToken(username, null, AuthorityUtils.createAuthorityList(role))), requestResponseHolder.request, requestResponseHolder.response)
}
def authenticated() {
HttpRequestResponseHolder requestResponseHolder = new HttpRequestResponseHolder(request, response)
new HttpSessionSecurityContextRepository().loadContext(requestResponseHolder)?.authentication?.authenticated
}
}

View File

@@ -0,0 +1,243 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.mock.web.MockFilterChain
import org.springframework.mock.web.MockHttpServletRequest
import org.springframework.mock.web.MockHttpServletResponse
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.BaseWebConfig;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService
import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper;
import org.springframework.security.openid.OpenID4JavaConsumer
import org.springframework.security.openid.OpenIDAuthenticationFilter
import org.springframework.security.openid.OpenIDAuthenticationProvider
import org.springframework.security.openid.OpenIDAuthenticationToken;
import org.springframework.security.web.FilterChainProxy
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource
/**
* Tests to verify that all the functionality of <openid-login> attributes is present
*
* @author Rob Winch
*
*/
public class NamespaceHttpOpenIDLoginTests extends BaseSpringSpec {
FilterChainProxy springSecurityFilterChain
MockHttpServletRequest request
MockHttpServletResponse response
MockFilterChain chain
def setup() {
request = new MockHttpServletRequest()
response = new MockHttpServletResponse()
chain = new MockFilterChain()
}
def "http/openid-login"() {
when:
loadConfig(OpenIDLoginConfig)
springSecurityFilterChain = context.getBean(FilterChainProxy)
then:
findFilter(OpenIDAuthenticationFilter).consumer.class == OpenID4JavaConsumer
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getRedirectedUrl() == "http://localhost/login"
when: "fail to log in"
setup()
request.requestURI = "/login/openid"
request.method = "POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to login error page"
response.getRedirectedUrl() == "/login?error"
}
@Configuration
static class OpenIDLoginConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) {
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.openidLogin()
.permitAll();
}
}
def "http/openid-login/attribute-exchange"() {
when:
loadConfig(OpenIDLoginAttributeExchangeConfig)
springSecurityFilterChain = context.getBean(FilterChainProxy)
OpenID4JavaConsumer consumer = findFilter(OpenIDAuthenticationFilter).consumer
then:
consumer.class == OpenID4JavaConsumer
def googleAttrs = consumer.attributesToFetchFactory.createAttributeList("https://www.google.com/1")
googleAttrs[0].name == "email"
googleAttrs[0].type == "http://axschema.org/contact/email"
googleAttrs[0].required
googleAttrs[1].name == "firstname"
googleAttrs[1].type == "http://axschema.org/namePerson/first"
googleAttrs[1].required
googleAttrs[2].name == "lastname"
googleAttrs[2].type == "http://axschema.org/namePerson/last"
googleAttrs[2].required
def yahooAttrs = consumer.attributesToFetchFactory.createAttributeList("https://rwinch.yahoo.com/rwinch/id")
yahooAttrs[0].name == "email"
yahooAttrs[0].type == "http://schema.openid.net/contact/email"
yahooAttrs[0].required
yahooAttrs[1].name == "fullname"
yahooAttrs[1].type == "http://axschema.org/namePerson"
yahooAttrs[1].required
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getRedirectedUrl() == "http://localhost/login"
when: "fail to log in"
setup()
request.requestURI = "/login/openid"
request.method = "POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to login error page"
response.getRedirectedUrl() == "/login?error"
}
@Configuration
static class OpenIDLoginAttributeExchangeConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) {
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.openidLogin()
.attributeExchange("https://www.google.com/.*") // attribute-exchange@identifier-match
.attribute("email") // openid-attribute@name
.type("http://axschema.org/contact/email") // openid-attribute@type
.required(true) // openid-attribute@required
.count(1) // openid-attribute@count
.and()
.attribute("firstname")
.type("http://axschema.org/namePerson/first")
.required(true)
.and()
.attribute("lastname")
.type("http://axschema.org/namePerson/last")
.required(true)
.and()
.and()
.attributeExchange(".*yahoo.com.*")
.attribute("email")
.type("http://schema.openid.net/contact/email")
.required(true)
.and()
.attribute("fullname")
.type("http://axschema.org/namePerson")
.required(true)
.and()
.and()
.permitAll();
}
}
def "http/openid-login custom"() {
setup:
loadConfig(OpenIDLoginCustomConfig)
springSecurityFilterChain = context.getBean(FilterChainProxy)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getRedirectedUrl() == "http://localhost/authentication/login"
when: "fail to log in"
setup()
request.requestURI = "/authentication/login/process"
request.method = "POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to login error page"
response.getRedirectedUrl() == "/authentication/login?failed"
}
@Configuration
static class OpenIDLoginCustomConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
boolean alwaysUseDefaultSuccess = true;
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.openidLogin()
.permitAll()
.loginPage("/authentication/login") // openid-login@login-page
.failureUrl("/authentication/login?failed") // openid-login@authentication-failure-url
.loginProcessingUrl("/authentication/login/process") // openid-login@login-processing-url
.defaultSuccessUrl("/default", alwaysUseDefaultSuccess) // openid-login@default-target-url / openid-login@always-use-default-target
}
}
def "http/openid-login custom refs"() {
when:
OpenIDLoginCustomRefsConfig.AUDS = Mock(AuthenticationUserDetailsService)
loadConfig(OpenIDLoginCustomRefsConfig)
springSecurityFilterChain = context.getBean(FilterChainProxy)
then: "CustomWebAuthenticationDetailsSource is used"
findFilter(OpenIDAuthenticationFilter).authenticationDetailsSource.class == CustomWebAuthenticationDetailsSource
findAuthenticationProvider(OpenIDAuthenticationProvider).userDetailsService == OpenIDLoginCustomRefsConfig.AUDS
when: "fail to log in"
request.requestURI = "/login/openid"
request.method = "POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to login error page"
response.getRedirectedUrl() == "/custom/failure"
}
@Configuration
static class OpenIDLoginCustomRefsConfig extends BaseWebConfig {
static AuthenticationUserDetailsService AUDS
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.openidLogin()
// if using UserDetailsService wrap with new UserDetailsByNameServiceWrapper<OpenIDAuthenticationToken>()
.authenticationUserDetailsService(AUDS) // openid-login@user-service-ref
.failureHandler(new SimpleUrlAuthenticationFailureHandler("/custom/failure")) // openid-login@authentication-failure-handler-ref
.successHandler(new SavedRequestAwareAuthenticationSuccessHandler( defaultTargetUrl : "/custom/targetUrl" )) // openid-login@authentication-success-handler-ref
.authenticationDetailsSource(new CustomWebAuthenticationDetailsSource()); // openid-login@authentication-details-source-ref
}
// only necessary to have easy access to the AuthenticationManager for testing/verification
@Bean
@Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
}
static class CustomWebAuthenticationDetailsSource extends WebAuthenticationDetailsSource {}
}

View File

@@ -0,0 +1,117 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers
import org.springframework.context.annotation.Configuration
import org.springframework.mock.web.MockFilterChain
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextImpl
import org.springframework.security.web.FilterChainProxy
import org.springframework.security.web.context.HttpRequestResponseHolder
import org.springframework.security.web.context.HttpSessionSecurityContextRepository
/**
* Tests to verify that all the functionality of <port-mappings> attributes is present
*
* @author Rob Winch
*
*/
public class NamespaceHttpPortMappingsTests extends BaseSpringSpec {
FilterChainProxy springSecurityFilterChain
MockHttpServletRequest request
MockHttpServletResponse response
MockFilterChain chain
def setup() {
request = new MockHttpServletRequest()
request.setMethod("GET")
response = new MockHttpServletResponse()
chain = new MockFilterChain()
}
def "http/port-mapper works with http/intercept-url@requires-channel"() {
setup:
loadConfig(HttpInterceptUrlWithPortMapperConfig)
springSecurityFilterChain = context.getBean(FilterChainProxy)
when:
request.setServletPath("/login")
request.setRequestURI("/login")
request.setServerPort(9080);
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.redirectedUrl == "https://localhost:9443/login"
when:
setup()
request.setServletPath("/secured/a")
request.setRequestURI("/secured/a")
request.setServerPort(9080);
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.redirectedUrl == "https://localhost:9443/secured/a"
when:
setup()
request.setSecure(true)
request.setScheme("https")
request.setServerPort(9443);
request.setServletPath("/user")
request.setRequestURI("/user")
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.redirectedUrl == "http://localhost:9080/user"
}
@Configuration
@EnableWebSecurity
static class HttpInterceptUrlWithPortMapperConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.portMapper()
.http(9080).mapsTo(9443)
.and()
.requiresChannel()
.antMatchers("/login","/secured/**").requiresSecure()
.anyRequest().requiresInsecure()
}
protected void registerAuthentication(
AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN")
}
}
def login(String username="user", String role="ROLE_USER") {
HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository()
HttpRequestResponseHolder requestResponseHolder = new HttpRequestResponseHolder(request, response)
repo.loadContext(requestResponseHolder)
repo.saveContext(new SecurityContextImpl(authentication: new UsernamePasswordAuthenticationToken(username, null, AuthorityUtils.createAuthorityList(role))), requestResponseHolder.request, requestResponseHolder.response)
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.BaseSpringSpec;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.BaseWebConfig;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
/**
* Tests to verify that all the functionality of <request-cache> attributes is present
*
* @author Rob Winch
*
*/
public class NamespaceHttpRequestCacheTests extends BaseSpringSpec {
def "http/request-cache@ref"() {
setup:
RequestCacheRefConfig.REQUEST_CACHE = Mock(RequestCache)
when:
loadConfig(RequestCacheRefConfig)
then:
findFilter(ExceptionTranslationFilter).requestCache == RequestCacheRefConfig.REQUEST_CACHE
}
@Configuration
static class RequestCacheRefConfig extends BaseWebConfig {
static RequestCache REQUEST_CACHE
protected void configure(HttpSecurity http) {
http.
requestCache()
.requestCache(REQUEST_CACHE)
}
}
def "http/request-cache@ref defaults to HttpSessionRequestCache"() {
when:
loadConfig(DefaultRequestCacheRefConfig)
then:
findFilter(ExceptionTranslationFilter).requestCache.class == HttpSessionRequestCache
}
@Configuration
static class DefaultRequestCacheRefConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) {
}
}
}

View File

@@ -0,0 +1,275 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers;
import java.security.cert.CertificateFactory
import java.security.cert.X509Certificate
import javax.servlet.http.HttpServletRequest
import org.springframework.context.annotation.Configuration
import org.springframework.mock.web.MockFilterChain
import org.springframework.mock.web.MockHttpServletRequest
import org.springframework.mock.web.MockHttpServletResponse
import org.springframework.security.authentication.AuthenticationDetailsSource
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.authority.AuthorityUtils
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService
import org.springframework.security.core.userdetails.User
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper
import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.security.core.userdetails.UsernameNotFoundException
import org.springframework.security.web.FilterChainProxy
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken
import org.springframework.security.web.authentication.preauth.PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails
import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter
import org.springframework.security.web.context.HttpRequestResponseHolder
import org.springframework.security.web.context.HttpSessionSecurityContextRepository
import org.springframework.test.util.ReflectionTestUtils
/**
* Tests to verify that all the functionality of <jee> attributes is present
*
* @author Rob Winch
*
*/
public class NamespaceHttpX509Tests extends BaseSpringSpec {
FilterChainProxy springSecurityFilterChain
MockHttpServletRequest request
MockHttpServletResponse response
MockFilterChain chain
def setup() {
request = new MockHttpServletRequest()
response = new MockHttpServletResponse()
chain = new MockFilterChain()
}
def "http/x509 can authenticate"() {
setup:
X509Certificate certificate = loadCert("rod.cer")
loadConfig(X509Config)
springSecurityFilterChain = context.getBean(FilterChainProxy)
when:
request.setAttribute("javax.servlet.request.X509Certificate", [certificate] as X509Certificate[] )
springSecurityFilterChain.doFilter(request, response, chain);
then:
response.status == 200
authentication().name == 'rod'
}
def "http/x509"() {
when:
loadConfig(X509Config)
X509AuthenticationFilter filter = findFilter(X509AuthenticationFilter)
AuthenticationManager authenticationManager = ReflectionTestUtils.getField(filter,"authenticationManager")
then:
authenticationManager
filter.authenticationDetailsSource.class == WebAuthenticationDetailsSource
authenticationManager.providers.find { it instanceof PreAuthenticatedAuthenticationProvider }.preAuthenticatedUserDetailsService.class == UserDetailsByNameServiceWrapper
}
@Configuration
@EnableWebSecurity
public static class X509Config extends WebSecurityConfigurerAdapter {
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.
inMemoryAuthentication()
.withUser("rod").password("password").roles("USER","ADMIN");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.x509();
}
}
def "http/x509@authentication-details-source-ref"() {
setup:
AuthenticationDetailsSourceRefConfig.AUTHENTICATION_DETAILS_SOURCE = Mock(AuthenticationDetailsSource)
when:
loadConfig(AuthenticationDetailsSourceRefConfig)
X509AuthenticationFilter filter = findFilter(X509AuthenticationFilter)
AuthenticationManager authenticationManager = ReflectionTestUtils.getField(filter,"authenticationManager")
then:
authenticationManager
filter.authenticationDetailsSource == AuthenticationDetailsSourceRefConfig.AUTHENTICATION_DETAILS_SOURCE
authenticationManager.providers.find { it instanceof PreAuthenticatedAuthenticationProvider }.preAuthenticatedUserDetailsService.class == UserDetailsByNameServiceWrapper
}
@Configuration
@EnableWebSecurity
public static class AuthenticationDetailsSourceRefConfig extends WebSecurityConfigurerAdapter {
static AuthenticationDetailsSource<HttpServletRequest, PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails> AUTHENTICATION_DETAILS_SOURCE
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.
inMemoryAuthentication()
.withUser("rod").password("password").roles("USER","ADMIN");
}
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.x509()
.authenticationDetailsSource(AUTHENTICATION_DETAILS_SOURCE);
}
}
def "http/x509@subject-principal-regex"() {
setup:
X509Certificate certificate = loadCert("rodatexampledotcom.cer")
loadConfig(SubjectPrincipalRegexConfig)
springSecurityFilterChain = context.getBean(FilterChainProxy)
when:
request.setAttribute("javax.servlet.request.X509Certificate", [certificate] as X509Certificate[] )
springSecurityFilterChain.doFilter(request, response, chain);
then:
response.status == 200
authentication().name == 'rod'
}
@Configuration
@EnableWebSecurity
public static class SubjectPrincipalRegexConfig extends WebSecurityConfigurerAdapter {
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.
inMemoryAuthentication()
.withUser("rod").password("password").roles("USER","ADMIN");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.x509()
.subjectPrincipalRegex('CN=(.*?)@example.com(?:,|$)');
}
}
def "http/x509@user-service-ref"() {
setup:
X509Certificate certificate = loadCert("rodatexampledotcom.cer")
loadConfig(UserDetailsServiceRefConfig)
springSecurityFilterChain = context.getBean(FilterChainProxy)
when:
request.setAttribute("javax.servlet.request.X509Certificate", [certificate] as X509Certificate[] )
springSecurityFilterChain.doFilter(request, response, chain);
then:
response.status == 200
authentication().name == 'customuser'
}
@Configuration
@EnableWebSecurity
public static class UserDetailsServiceRefConfig extends WebSecurityConfigurerAdapter {
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.
inMemoryAuthentication()
.withUser("rod").password("password").roles("USER","ADMIN");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.x509()
.userDetailsService(new CustomUserDetailsService());
}
}
def "http/x509 custom AuthenticationUserDetailsService"() {
setup:
X509Certificate certificate = loadCert("rodatexampledotcom.cer")
loadConfig(AuthenticationUserDetailsServiceConfig)
springSecurityFilterChain = context.getBean(FilterChainProxy)
when:
request.setAttribute("javax.servlet.request.X509Certificate", [certificate] as X509Certificate[] )
springSecurityFilterChain.doFilter(request, response, chain);
then:
response.status == 200
authentication().name == 'customuser'
}
@Configuration
@EnableWebSecurity
public static class AuthenticationUserDetailsServiceConfig extends WebSecurityConfigurerAdapter {
static AuthenticationDetailsSource<HttpServletRequest, PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails> AUTHENTICATION_DETAILS_SOURCE
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.
inMemoryAuthentication()
.withUser("rod").password("password").roles("USER","ADMIN");
}
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.x509()
.userDetailsService(new CustomUserDetailsService());
}
}
def loadCert(String location) {
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
certFactory.generateCertificate(Thread.currentThread().contextClassLoader.getResourceAsStream(location))
}
static class CustomUserDetailsService implements UserDetailsService {
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
return new User("customuser", "password", AuthorityUtils.createAuthorityList("ROLE_USER"));
}
}
static class CustomAuthenticationUserDetailsService implements AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> {
public UserDetails loadUserDetails(
PreAuthenticatedAuthenticationToken token)
throws UsernameNotFoundException {
return new User("customuser", "password", AuthorityUtils.createAuthorityList("ROLE_USER"));
}
}
def authentication() {
HttpRequestResponseHolder requestResponseHolder = new HttpRequestResponseHolder(request, response)
new HttpSessionSecurityContextRepository().loadContext(requestResponseHolder)?.authentication
}
}

View File

@@ -0,0 +1,345 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.BaseWebConfig;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import javax.servlet.http.Cookie
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration
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.authentication.AuthenticationManager
import org.springframework.security.authentication.RememberMeAuthenticationToken;
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContext
import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.security.web.FilterChainProxy
import org.springframework.security.web.authentication.AuthenticationSuccessHandler
import org.springframework.security.web.authentication.RememberMeServices
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices
import org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter
import org.springframework.security.web.context.HttpRequestResponseHolder
import org.springframework.security.web.context.HttpSessionSecurityContextRepository
import org.springframework.test.util.ReflectionTestUtils;
/**
* Tests to verify that all the functionality of <anonymous> attributes is present
*
* @author Rob Winch
*
*/
public class NamespaceRememberMeTests extends BaseSpringSpec {
FilterChainProxy springSecurityFilterChain
MockHttpServletRequest request
MockHttpServletResponse response
MockFilterChain chain
def setup() {
request = new MockHttpServletRequest()
response = new MockHttpServletResponse()
chain = new MockFilterChain()
}
def "http/remember-me"() {
setup:
loadConfig(RememberMeConfig)
springSecurityFilterChain = context.getBean(FilterChainProxy)
when: "login with remember me"
setup()
request.requestURI = "/login"
request.method = "POST"
request.parameters.username = ["user"] as String[]
request.parameters.password = ["password"] as String[]
request.parameters.'remember-me' = ["true"] as String[]
springSecurityFilterChain.doFilter(request,response,chain)
Cookie rememberMeCookie = getRememberMeCookie()
then: "response contains remember me cookie"
rememberMeCookie != null
when: "session expires"
setup()
request.setCookies(rememberMeCookie)
request.requestURI = "/abc"
springSecurityFilterChain.doFilter(request,response,chain)
MockHttpSession session = request.getSession()
then: "initialized to RememberMeAuthenticationToken"
SecurityContext context = new HttpSessionSecurityContextRepository().loadContext(new HttpRequestResponseHolder(request, response))
context.getAuthentication() instanceof RememberMeAuthenticationToken
when: "logout"
setup()
request.setSession(session)
request.setCookies(rememberMeCookie)
request.requestURI = "/logout"
springSecurityFilterChain.doFilter(request,response,chain)
rememberMeCookie = getRememberMeCookie()
then: "logout cookie expired"
response.getRedirectedUrl() == "/login?logout"
rememberMeCookie.maxAge == 0
when: "use remember me after logout"
setup()
request.setCookies(rememberMeCookie)
request.requestURI = "/abc"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to default login page"
response.getRedirectedUrl() == "http://localhost/login"
}
@Configuration
static class RememberMeConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.formLogin()
.and()
.rememberMe()
}
}
def "http/remember-me@services-ref"() {
setup:
RememberMeServicesRefConfig.REMEMBER_ME_SERVICES = Mock(RememberMeServices)
when: "use custom remember-me services"
loadConfig(RememberMeServicesRefConfig)
then: "custom remember-me services used"
findFilter(RememberMeAuthenticationFilter).rememberMeServices == RememberMeServicesRefConfig.REMEMBER_ME_SERVICES
findFilter(UsernamePasswordAuthenticationFilter).rememberMeServices == RememberMeServicesRefConfig.REMEMBER_ME_SERVICES
}
@Configuration
static class RememberMeServicesRefConfig extends BaseWebConfig {
static RememberMeServices REMEMBER_ME_SERVICES
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.and()
.rememberMe()
.rememberMeServices(REMEMBER_ME_SERVICES)
}
}
def "http/remember-me@authentication-success-handler-ref"() {
setup:
AuthSuccessConfig.SUCCESS_HANDLER = Mock(AuthenticationSuccessHandler)
when: "use custom success handler"
loadConfig(AuthSuccessConfig)
then: "custom remember-me success handler is used"
findFilter(RememberMeAuthenticationFilter).successHandler == AuthSuccessConfig.SUCCESS_HANDLER
}
@Configuration
static class AuthSuccessConfig extends BaseWebConfig {
static AuthenticationSuccessHandler SUCCESS_HANDLER
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.and()
.rememberMe()
.authenticationSuccessHandler(SUCCESS_HANDLER)
}
}
// http/remember-me@data-source-ref is not supported directly. Instead use http/remember-me@token-repository-ref example
def "http/remember-me@key"() {
when: "use custom key"
loadConfig(KeyConfig)
AuthenticationManager authManager = context.getBean(AuthenticationManager)
then: "custom key services used"
findFilter(RememberMeAuthenticationFilter).rememberMeServices.key == "KeyConfig"
authManager.authenticate(new RememberMeAuthenticationToken("KeyConfig", "user", AuthorityUtils.createAuthorityList("ROLE_USER")))
}
@Configuration
static class KeyConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.and()
.rememberMe()
.key("KeyConfig")
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
}
// http/remember-me@services-alias is not supported use standard aliasing instead (i.e. @Bean("alias"))
def "http/remember-me@token-repository-ref"() {
setup:
TokenRepositoryRefConfig.TOKEN_REPOSITORY = Mock(PersistentTokenRepository)
when: "use custom token services"
loadConfig(TokenRepositoryRefConfig)
then: "custom token services used with PersistentTokenBasedRememberMeServices"
PersistentTokenBasedRememberMeServices rememberMeServices = findFilter(RememberMeAuthenticationFilter).rememberMeServices
findFilter(RememberMeAuthenticationFilter).rememberMeServices.tokenRepository == TokenRepositoryRefConfig.TOKEN_REPOSITORY
}
@Configuration
static class TokenRepositoryRefConfig extends BaseWebConfig {
static PersistentTokenRepository TOKEN_REPOSITORY
protected void configure(HttpSecurity http) throws Exception {
// JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl()
// tokenRepository.setDataSource(dataSource);
http
.formLogin()
.and()
.rememberMe()
.tokenRepository(TOKEN_REPOSITORY)
}
}
def "http/remember-me@token-validity-seconds"() {
when: "use token validity"
loadConfig(TokenValiditySecondsConfig)
then: "custom token validity used"
findFilter(RememberMeAuthenticationFilter).rememberMeServices.tokenValiditySeconds == 1
}
@Configuration
static class TokenValiditySecondsConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.and()
.rememberMe()
.tokenValiditySeconds(1)
}
}
def "http/remember-me@token-validity-seconds default"() {
when: "use token validity"
loadConfig(DefaultTokenValiditySecondsConfig)
then: "custom token validity used"
findFilter(RememberMeAuthenticationFilter).rememberMeServices.tokenValiditySeconds == AbstractRememberMeServices.TWO_WEEKS_S
}
@Configuration
static class DefaultTokenValiditySecondsConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.and()
.rememberMe()
}
}
def "http/remember-me@use-secure-cookie"() {
when: "use secure cookies = true"
loadConfig(UseSecureCookieConfig)
then: "secure cookies will be used"
ReflectionTestUtils.getField(findFilter(RememberMeAuthenticationFilter).rememberMeServices, "useSecureCookie") == true
}
@Configuration
static class UseSecureCookieConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.and()
.rememberMe()
.useSecureCookie(true)
}
}
def "http/remember-me@use-secure-cookie defaults"() {
when: "use secure cookies not specified"
loadConfig(DefaultUseSecureCookieConfig)
then: "secure cookies will be null (use secure if the request is secure)"
ReflectionTestUtils.getField(findFilter(RememberMeAuthenticationFilter).rememberMeServices, "useSecureCookie") == null
}
@Configuration
static class DefaultUseSecureCookieConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.and()
.rememberMe()
}
}
def "http/remember-me defaults UserDetailsService with custom UserDetailsService"() {
setup:
DefaultsUserDetailsServiceWithDaoConfig.USERDETAILS_SERVICE = Mock(UserDetailsService)
when: "use secure cookies not specified"
loadConfig(DefaultsUserDetailsServiceWithDaoConfig)
then: "RememberMeServices defaults to the custom UserDetailsService"
ReflectionTestUtils.getField(findFilter(RememberMeAuthenticationFilter).rememberMeServices, "userDetailsService") == DefaultsUserDetailsServiceWithDaoConfig.USERDETAILS_SERVICE
}
@Configuration
@EnableWebSecurity
static class DefaultsUserDetailsServiceWithDaoConfig extends WebSecurityConfigurerAdapter {
static UserDetailsService USERDETAILS_SERVICE
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.and()
.rememberMe()
}
protected void registerAuthentication(
AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(USERDETAILS_SERVICE);
}
}
def "http/remember-me@user-service-ref"() {
setup:
UserServiceRefConfig.USERDETAILS_SERVICE = Mock(UserDetailsService)
when: "use custom UserDetailsService"
loadConfig(UserServiceRefConfig)
then: "custom UserDetailsService is used"
ReflectionTestUtils.getField(findFilter(RememberMeAuthenticationFilter).rememberMeServices, "userDetailsService") == UserServiceRefConfig.USERDETAILS_SERVICE
}
@Configuration
static class UserServiceRefConfig extends BaseWebConfig {
static UserDetailsService USERDETAILS_SERVICE
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.and()
.rememberMe()
.userDetailsService(USERDETAILS_SERVICE)
}
}
Cookie getRememberMeCookie(String cookieName="remember-me") {
response.getCookie(cookieName)
}
}

View File

@@ -0,0 +1,160 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.ObjectPostProcessor
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.session.SessionRegistry
import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy
import org.springframework.security.web.context.SecurityContextPersistenceFilter
import org.springframework.security.web.context.SecurityContextRepository
import org.springframework.security.web.session.ConcurrentSessionFilter
import org.springframework.security.web.session.SessionManagementFilter
/**
*
* @author Rob Winch
*/
class NamespaceSessionManagementTests extends BaseSpringSpec {
def "http/session-management"() {
when:
loadConfig(SessionManagementConfig)
then:
findFilter(SessionManagementFilter).sessionAuthenticationStrategy instanceof SessionFixationProtectionStrategy
}
@EnableWebSecurity
@Configuration
static class SessionManagementConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// enabled by default
}
}
def "http/session-management custom"() {
setup:
CustomSessionManagementConfig.SR = Mock(SessionRegistry)
when:
loadConfig(CustomSessionManagementConfig)
then:
findFilter(SessionManagementFilter).invalidSessionStrategy.destinationUrl == "/invalid-session"
findFilter(SessionManagementFilter).failureHandler.defaultFailureUrl == "/session-auth-error"
findFilter(SessionManagementFilter).sessionAuthenticationStrategy.maximumSessions == 1
findFilter(SessionManagementFilter).sessionAuthenticationStrategy.exceptionIfMaximumExceeded
findFilter(SessionManagementFilter).sessionAuthenticationStrategy.sessionRegistry == CustomSessionManagementConfig.SR
findFilter(ConcurrentSessionFilter).expiredUrl == "/expired-session"
}
@EnableWebSecurity
@Configuration
static class CustomSessionManagementConfig extends WebSecurityConfigurerAdapter {
static SessionRegistry SR
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.invalidSessionUrl("/invalid-session") // session-management@invalid-session-url
.sessionAuthenticationErrorUrl("/session-auth-error") // session-management@session-authentication-error-url
.maximumSessions(1) // session-management/concurrency-control@max-sessions
.maxSessionsPreventsLogin(true) // session-management/concurrency-control@error-if-maximum-exceeded
.expiredUrl("/expired-session") // session-management/concurrency-control@expired-url
.sessionRegistry(SR) // session-management/concurrency-control@session-registry-ref
}
}
def "http/session-management refs"() {
setup:
RefsSessionManagementConfig.SAS = Mock(SessionAuthenticationStrategy)
when:
loadConfig(RefsSessionManagementConfig)
then:
findFilter(SessionManagementFilter).sessionAuthenticationStrategy == RefsSessionManagementConfig.SAS
}
@EnableWebSecurity
@Configuration
static class RefsSessionManagementConfig extends WebSecurityConfigurerAdapter {
static SessionAuthenticationStrategy SAS
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionAuthenticationStrategy(SAS) // session-management@session-authentication-strategy-ref
}
}
def "http/session-management@session-fixation-protection=none"() {
when:
loadConfig(SFPNoneSessionManagementConfig)
then:
findFilter(SessionManagementFilter).sessionAuthenticationStrategy.class == NullAuthenticatedSessionStrategy
}
@EnableWebSecurity
@Configuration
static class SFPNoneSessionManagementConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionAuthenticationStrategy(new NullAuthenticatedSessionStrategy())
}
}
def "http/session-management@session-fixation-protection=migrateSession (default)"() {
when:
loadConfig(SFPMigrateSessionManagementConfig)
then:
findFilter(SessionManagementFilter).sessionAuthenticationStrategy.migrateSessionAttributes
}
@EnableWebSecurity
@Configuration
static class SFPMigrateSessionManagementConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
}
}
def "http/session-management@session-fixation-protection=newSession"() {
when:
loadConfig(SFPNewSessionSessionManagementConfig)
then:
!findFilter(SessionManagementFilter).sessionAuthenticationStrategy.migrateSessionAttributes
}
@EnableWebSecurity
@Configuration
static class SFPNewSessionSessionManagementConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionAuthenticationStrategy(new SessionFixationProtectionStrategy(migrateSessionAttributes : false))
}
}
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.annotation.Configuration
import org.springframework.mock.web.MockHttpServletRequest
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.util.RequestMatcher
/**
* @author Rob Winch
*
*/
class PermitAllSupportTests extends BaseSpringSpec {
def "PermitAllSupport.ExactUrlRequestMatcher"() {
expect:
RequestMatcher matcher = new PermitAllSupport.ExactUrlRequestMatcher(processUrl)
matcher.matches(new MockHttpServletRequest(requestURI:requestURI,contextPath:contextPath,queryString: query)) == matches
where:
processUrl | requestURI | contextPath | query | matches
"/login" | "/sample/login" | "/sample" | null | true
"/login" | "/sample/login" | "/sample" | "error" | false
"/login?error" | "/sample/login" | "/sample" | "error" | true
}
def "PermitAllSupport throws Exception when authorizedUrls() not invoked"() {
when:
loadConfig(NoAuthorizedUrlsConfig)
then:
BeanCreationException e = thrown()
e.message.contains "permitAll only works with HttpSecurity.authorizeUrls"
}
@EnableWebSecurity
@Configuration
static class NoAuthorizedUrlsConfig extends WebSecurityConfigurerAdapter {
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth)
throws Exception {
auth
.inMemoryAuthentication()
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.permitAll()
}
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.AnyObjectPostProcessor
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter
/**
* Tests for RememberMeConfigurer that flex edge cases. {@link NamespaceRememberMeTests} demonstrate mapping of the XML namespace to Java Config.
*
* @author Rob Winch
*/
public class RememberMeConfigurerTests extends BaseSpringSpec {
def "rememberMe() null UserDetailsService provides meaningful error"() {
when: "Load Config without UserDetailsService specified"
loadConfig(NullUserDetailsConfig)
then: "A good error message is provided"
Exception success = thrown()
success.message.contains "Invoke RememberMeConfigurer#userDetailsService(UserDetailsService) or see its javadoc for alternative approaches."
}
@EnableWebSecurity
@Configuration
static class NullUserDetailsConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeUrls()
.anyRequest().hasRole("USER")
.and()
.formLogin()
.and()
.rememberMe()
}
}
def "rememberMe ObjectPostProcessor"() {
setup:
AnyObjectPostProcessor opp = Mock()
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
UserDetailsService uds = authenticationBldr.getDefaultUserDetailsService()
when:
http
.rememberMe()
.userDetailsService(authenticationBldr.getDefaultUserDetailsService())
.and()
.build()
then: "RememberMeAuthenticationFilter is registered with LifecycleManager"
1 * opp.postProcess(_ as RememberMeAuthenticationFilter) >> {RememberMeAuthenticationFilter o -> o}
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers
import org.springframework.security.config.annotation.AnyObjectPostProcessor
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter
/**
*
* @author Rob Winch
*/
class RequestCacheConfigurerTests extends BaseSpringSpec {
def "requestCache ObjectPostProcessor"() {
setup:
AnyObjectPostProcessor opp = Mock()
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
when:
http
.requestCache()
.and()
.build()
then: "RequestCacheAwareFilter is registered with LifecycleManager"
1 * opp.postProcess(_ as RequestCacheAwareFilter) >> {RequestCacheAwareFilter o -> o}
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers
import org.springframework.security.config.annotation.AnyObjectPostProcessor
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.context.SecurityContextPersistenceFilter
/**
*
* @author Rob Winch
*/
class SecurityContextConfigurerTests extends BaseSpringSpec {
def "securityContext ObjectPostProcessor"() {
setup:
AnyObjectPostProcessor opp = Mock()
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
when:
http
.securityContext()
.and()
.build()
then: "SecurityContextPersistenceFilter is registered with LifecycleManager"
1 * opp.postProcess(_ as SecurityContextPersistenceFilter) >> {SecurityContextPersistenceFilter o -> o}
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers
import org.springframework.security.config.annotation.AnyObjectPostProcessor
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter
/**
*
* @author Rob Winch
*/
class ServletApiConfigurerTests extends BaseSpringSpec {
def "servletApi ObjectPostProcessor"() {
setup:
AnyObjectPostProcessor opp = Mock()
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
when:
http
.servletApi()
.and()
.build()
then: "SecurityContextHolderAwareRequestFilter is registered with LifecycleManager"
1 * opp.postProcess(_ as SecurityContextHolderAwareRequestFilter) >> {SecurityContextHolderAwareRequestFilter o -> o}
}
}

View File

@@ -0,0 +1,108 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.AnyObjectPostProcessor
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.SessionCreationPolicy;
import org.springframework.security.web.access.ExceptionTranslationFilter
import org.springframework.security.web.context.SecurityContextPersistenceFilter
import org.springframework.security.web.context.SecurityContextRepository
import org.springframework.security.web.savedrequest.RequestCache
import org.springframework.security.web.session.ConcurrentSessionFilter
import org.springframework.security.web.session.SessionManagementFilter
/**
*
* @author Rob Winch
*/
class SessionManagementConfigurerTests extends BaseSpringSpec {
def "sessionManagement does not override explicit RequestCache"() {
setup:
SessionManagementDoesNotOverrideExplicitRequestCacheConfig.REQUEST_CACHE = Mock(RequestCache)
when:
loadConfig(SessionManagementDoesNotOverrideExplicitRequestCacheConfig)
then:
findFilter(ExceptionTranslationFilter).requestCache == SessionManagementDoesNotOverrideExplicitRequestCacheConfig.REQUEST_CACHE
}
@EnableWebSecurity
@Configuration
static class SessionManagementDoesNotOverrideExplicitRequestCacheConfig extends WebSecurityConfigurerAdapter {
static RequestCache REQUEST_CACHE
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestCache()
.requestCache(REQUEST_CACHE)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.stateless)
}
}
def "sessionManagement does not override explict SecurityContextRepository"() {
setup:
SessionManagementDoesNotOverrideExplicitSecurityContextRepositoryConfig.SECURITY_CONTEXT_REPO = Mock(SecurityContextRepository)
when:
loadConfig(SessionManagementDoesNotOverrideExplicitSecurityContextRepositoryConfig)
then:
findFilter(SecurityContextPersistenceFilter).repo == SessionManagementDoesNotOverrideExplicitSecurityContextRepositoryConfig.SECURITY_CONTEXT_REPO
}
@Configuration
@EnableWebSecurity
static class SessionManagementDoesNotOverrideExplicitSecurityContextRepositoryConfig extends WebSecurityConfigurerAdapter {
static SecurityContextRepository SECURITY_CONTEXT_REPO
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.securityContext()
.securityContextRepository(SECURITY_CONTEXT_REPO)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.stateless)
}
}
def "sessionManagement ObjectPostProcessor"() {
setup:
AnyObjectPostProcessor opp = Mock()
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
when:
http
.sessionManagement()
.maximumSessions(1)
.and()
.and()
.build()
then: "SessionManagementFilter is registered with LifecycleManager"
1 * opp.postProcess(_ as SessionManagementFilter) >> {SessionManagementFilter o -> o}
and: "ConcurrentSessionFilter is registered with LifecycleManager"
1 * opp.postProcess(_ as ConcurrentSessionFilter) >> {ConcurrentSessionFilter o -> o}
}
}

View File

@@ -0,0 +1,79 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers;
import org.springframework.context.annotation.Configuration
import org.springframework.security.access.vote.AffirmativeBased
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.SecurityExpressions.*
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.UrlAuthorizationConfigurer;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor
/**
*
* @author Rob Winch
*
*/
public class UrlAuthorizationsTests extends BaseSpringSpec {
def "hasAnyAuthority('ROLE_USER')"() {
when:
def expression = UrlAuthorizationConfigurer.hasAnyAuthority("ROLE_USER")
then:
expression == ["ROLE_USER"]
}
def "hasAnyAuthority('ROLE_USER','ROLE_ADMIN')"() {
when:
def expression = UrlAuthorizationConfigurer.hasAnyAuthority("ROLE_USER","ROLE_ADMIN")
then:
expression == ["ROLE_USER","ROLE_ADMIN"]
}
def "hasAnyRole('USER')"() {
when:
def expression = UrlAuthorizationConfigurer.hasAnyRole("USER")
then:
expression == ["ROLE_USER"]
}
def "hasAnyRole('ROLE_USER','ROLE_ADMIN')"() {
when:
def expression = UrlAuthorizationConfigurer.hasAnyRole("USER","ADMIN")
then:
expression == ["ROLE_USER","ROLE_ADMIN"]
}
def "uses AffirmativeBased AccessDecisionManager"() {
when: "Load Config with no specific AccessDecisionManager"
loadConfig(NoSpecificAccessDecessionManagerConfig)
then: "AccessDecessionManager matches the HttpSecurityBuilder's default"
findFilter(FilterSecurityInterceptor).accessDecisionManager.class == AffirmativeBased
}
@EnableWebSecurity
@Configuration
static class NoSpecificAccessDecessionManagerConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.apply(new UrlAuthorizationConfigurer())
.anyRequest().hasRole("USER")
}
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers
import org.springframework.security.config.annotation.AnyObjectPostProcessor
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter
/**
*
* @author Rob Winch
*/
class X509ConfigurerTests extends BaseSpringSpec {
def "x509 ObjectPostProcessor"() {
setup:
AnyObjectPostProcessor opp = Mock()
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
when:
http
.x509()
.and()
.build()
then: "X509AuthenticationFilter is registered with LifecycleManager"
1 * opp.postProcess(_ as X509AuthenticationFilter) >> {X509AuthenticationFilter o -> o}
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers.openid
import org.springframework.security.config.annotation.AnyObjectPostProcessor
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper
import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.security.openid.OpenIDAuthenticationFilter
import org.springframework.security.openid.OpenIDAuthenticationProvider
import org.springframework.security.openid.OpenIDAuthenticationToken
/**
*
* @author Rob Winch
*/
class OpenIDLoginConfigurerTests extends BaseSpringSpec {
def "openidLogin ObjectPostProcessor"() {
setup:
AnyObjectPostProcessor opp = Mock()
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
UserDetailsService uds = authenticationBldr.getDefaultUserDetailsService()
when:
http
.openidLogin()
.authenticationUserDetailsService(new UserDetailsByNameServiceWrapper<OpenIDAuthenticationToken>(uds))
.and()
.build()
then: "OpenIDAuthenticationFilter is registered with LifecycleManager"
1 * opp.postProcess(_ as OpenIDAuthenticationFilter) >> {OpenIDAuthenticationFilter o -> o}
and: "OpenIDAuthenticationProvider is registered with LifecycleManager"
1 * opp.postProcess(_ as OpenIDAuthenticationProvider) >> {OpenIDAuthenticationProvider o -> o}
}
}

View File

@@ -0,0 +1,13 @@
create table users(principal varchar_ignorecase(50) not null primary key,credentials varchar_ignorecase(50) not null);
create table roles (principal varchar_ignorecase(50) not null,role varchar_ignorecase(50) not null,constraint fk_roles_users foreign key(principal) references users(principal));
create unique index ix_auth_principal on roles (principal,role);
create table groups (id bigint generated by default as identity(start with 0) primary key,group_name varchar_ignorecase(50) not null);
create table group_authorities (group_id bigint not null,authority varchar(50) not null,constraint fk_group_authorities_group foreign key(group_id) references groups(id));
create table group_members (id bigint generated by default as identity(start with 0) primary key,username varchar(50) not null,group_id bigint not null,constraint fk_group_members_group foreign key(group_id) references groups(id));
insert into users values('user','password');
insert into roles values('user','USER');
insert into groups values(1,'OPERATIONS');
insert into group_authorities values(1,'DBA');
insert into group_members values(1,'user',1);

Binary file not shown.

Binary file not shown.