SEC-2915: groovy/gradle spaces->tabs
This commit is contained in:
+52
-52
@@ -20,65 +20,65 @@ import org.springframework.security.CollectingAppListener
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
abstract class AbstractXmlConfigTests extends Specification {
|
||||
AbstractXmlApplicationContext appContext;
|
||||
Writer writer;
|
||||
MarkupBuilder xml;
|
||||
ApplicationListener appListener;
|
||||
AbstractXmlApplicationContext appContext;
|
||||
Writer writer;
|
||||
MarkupBuilder xml;
|
||||
ApplicationListener appListener;
|
||||
|
||||
def setup() {
|
||||
writer = new StringWriter()
|
||||
xml = new MarkupBuilder(writer)
|
||||
appListener = new CollectingAppListener()
|
||||
}
|
||||
def setup() {
|
||||
writer = new StringWriter()
|
||||
xml = new MarkupBuilder(writer)
|
||||
appListener = new CollectingAppListener()
|
||||
}
|
||||
|
||||
def cleanup() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
appContext = null;
|
||||
}
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
def cleanup() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
appContext = null;
|
||||
}
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
def mockBean(Class clazz, String id = clazz.simpleName) {
|
||||
xml.'b:bean'(id: id, 'class': Mockito.class.name, 'factory-method':'mock') {
|
||||
'b:constructor-arg'(value : clazz.name)
|
||||
'b:constructor-arg'(value : id)
|
||||
}
|
||||
}
|
||||
def mockBean(Class clazz, String id = clazz.simpleName) {
|
||||
xml.'b:bean'(id: id, 'class': Mockito.class.name, 'factory-method':'mock') {
|
||||
'b:constructor-arg'(value : clazz.name)
|
||||
'b:constructor-arg'(value : id)
|
||||
}
|
||||
}
|
||||
|
||||
def bean(String name, Class clazz) {
|
||||
xml.'b:bean'(id: name, 'class': clazz.name)
|
||||
}
|
||||
def bean(String name, Class clazz) {
|
||||
xml.'b:bean'(id: name, 'class': clazz.name)
|
||||
}
|
||||
|
||||
def bean(String name, String clazz) {
|
||||
xml.'b:bean'(id: name, 'class': clazz)
|
||||
}
|
||||
def bean(String name, String clazz) {
|
||||
xml.'b:bean'(id: name, 'class': clazz)
|
||||
}
|
||||
|
||||
def bean(String name, String clazz, List constructorArgs) {
|
||||
xml.'b:bean'(id: name, 'class': clazz) {
|
||||
constructorArgs.each { val ->
|
||||
'b:constructor-arg'(value: val)
|
||||
}
|
||||
}
|
||||
}
|
||||
def bean(String name, String clazz, List constructorArgs) {
|
||||
xml.'b:bean'(id: name, 'class': clazz) {
|
||||
constructorArgs.each { val ->
|
||||
'b:constructor-arg'(value: val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def bean(String name, String clazz, Map properties, Map refs) {
|
||||
xml.'b:bean'(id: name, 'class': clazz) {
|
||||
properties.each {key, val ->
|
||||
'b:property'(name: key, value: val)
|
||||
}
|
||||
refs.each {key, val ->
|
||||
'b:property'(name: key, ref: val)
|
||||
}
|
||||
}
|
||||
}
|
||||
def bean(String name, String clazz, Map properties, Map refs) {
|
||||
xml.'b:bean'(id: name, 'class': clazz) {
|
||||
properties.each {key, val ->
|
||||
'b:property'(name: key, value: val)
|
||||
}
|
||||
refs.each {key, val ->
|
||||
'b:property'(name: key, ref: val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def createAppContext() {
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
}
|
||||
def createAppContext() {
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
}
|
||||
|
||||
def createAppContext(String extraXml) {
|
||||
appContext = new InMemoryXmlApplicationContext(writer.toString() + extraXml);
|
||||
appContext.addApplicationListener(appListener);
|
||||
}
|
||||
def createAppContext(String extraXml) {
|
||||
appContext = new InMemoryXmlApplicationContext(writer.toString() + extraXml);
|
||||
appContext.addApplicationListener(appListener);
|
||||
}
|
||||
}
|
||||
|
||||
+96
-96
@@ -5,7 +5,7 @@
|
||||
* 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
|
||||
* 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,
|
||||
@@ -51,119 +51,119 @@ import spock.lang.Specification
|
||||
* @author Rob Winch
|
||||
*/
|
||||
abstract class BaseSpringSpec extends Specification {
|
||||
@AutoCleanup
|
||||
ConfigurableApplicationContext context
|
||||
@AutoCleanup
|
||||
ConfigurableApplicationContext oppContext
|
||||
@AutoCleanup
|
||||
ConfigurableApplicationContext context
|
||||
@AutoCleanup
|
||||
ConfigurableApplicationContext oppContext
|
||||
|
||||
MockHttpServletRequest request
|
||||
MockHttpServletResponse response
|
||||
MockFilterChain chain
|
||||
CsrfToken csrfToken
|
||||
AuthenticationManagerBuilder authenticationBldr
|
||||
MockHttpServletRequest request
|
||||
MockHttpServletResponse response
|
||||
MockFilterChain chain
|
||||
CsrfToken csrfToken
|
||||
AuthenticationManagerBuilder authenticationBldr
|
||||
|
||||
def setup() {
|
||||
authenticationBldr = createAuthenticationManagerBuilder()
|
||||
setupWeb(null)
|
||||
}
|
||||
def setup() {
|
||||
authenticationBldr = createAuthenticationManagerBuilder()
|
||||
setupWeb(null)
|
||||
}
|
||||
|
||||
def setupWeb(httpSession = null) {
|
||||
request = new MockHttpServletRequest(method:"GET")
|
||||
if(httpSession) {
|
||||
request.session = httpSession
|
||||
}
|
||||
response = new MockHttpServletResponse()
|
||||
chain = new MockFilterChain()
|
||||
setupCsrf()
|
||||
}
|
||||
def setupWeb(httpSession = null) {
|
||||
request = new MockHttpServletRequest(method:"GET")
|
||||
if(httpSession) {
|
||||
request.session = httpSession
|
||||
}
|
||||
response = new MockHttpServletResponse()
|
||||
chain = new MockFilterChain()
|
||||
setupCsrf()
|
||||
}
|
||||
|
||||
def setupCsrf(csrfTokenValue="BaseSpringSpec_CSRFTOKEN",req=request,resp=response) {
|
||||
csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN","_csrf",csrfTokenValue)
|
||||
new HttpSessionCsrfTokenRepository().saveToken(csrfToken, req, resp)
|
||||
req.setParameter(csrfToken.parameterName, csrfToken.token)
|
||||
}
|
||||
def setupCsrf(csrfTokenValue="BaseSpringSpec_CSRFTOKEN",req=request,resp=response) {
|
||||
csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN","_csrf",csrfTokenValue)
|
||||
new HttpSessionCsrfTokenRepository().saveToken(csrfToken, req, resp)
|
||||
req.setParameter(csrfToken.parameterName, csrfToken.token)
|
||||
}
|
||||
|
||||
def cleanup() {
|
||||
SecurityContextHolder.clearContext()
|
||||
}
|
||||
def cleanup() {
|
||||
SecurityContextHolder.clearContext()
|
||||
}
|
||||
|
||||
def loadConfig(Class<?>... configs) {
|
||||
context = new AnnotationConfigApplicationContext(configs)
|
||||
context
|
||||
}
|
||||
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 findFilter(Class<?> filter, int index = 0) {
|
||||
filterChain(index).filters.find { filter.isAssignableFrom(it.class)}
|
||||
}
|
||||
|
||||
def filterChain(int index=0) {
|
||||
filterChains()[index]
|
||||
}
|
||||
def filterChain(int index=0) {
|
||||
filterChains()[index]
|
||||
}
|
||||
|
||||
def filterChains() {
|
||||
context.getBean(FilterChainProxy).filterChains
|
||||
}
|
||||
def filterChains() {
|
||||
context.getBean(FilterChainProxy).filterChains
|
||||
}
|
||||
|
||||
Filter getSpringSecurityFilterChain() {
|
||||
context.getBean("springSecurityFilterChain",Filter.class)
|
||||
}
|
||||
Filter getSpringSecurityFilterChain() {
|
||||
context.getBean("springSecurityFilterChain",Filter.class)
|
||||
}
|
||||
|
||||
def getResponseHeaders() {
|
||||
def headers = [:]
|
||||
response.headerNames.each { name ->
|
||||
headers.put(name, response.getHeaderValues(name).join(','))
|
||||
}
|
||||
return headers
|
||||
}
|
||||
def getResponseHeaders() {
|
||||
def headers = [:]
|
||||
response.headerNames.each { name ->
|
||||
headers.put(name, response.getHeaderValues(name).join(','))
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
AuthenticationManager authenticationManager() {
|
||||
context.getBean(AuthenticationManager)
|
||||
}
|
||||
AuthenticationManager authenticationManager() {
|
||||
context.getBean(AuthenticationManager)
|
||||
}
|
||||
|
||||
AuthenticationManager getAuthenticationManager() {
|
||||
try {
|
||||
authenticationManager().delegateBuilder.getObject()
|
||||
} catch(NoSuchBeanDefinitionException e) {
|
||||
} catch(MissingPropertyException e) {}
|
||||
findFilter(FilterSecurityInterceptor).authenticationManager
|
||||
}
|
||||
AuthenticationManager getAuthenticationManager() {
|
||||
try {
|
||||
authenticationManager().delegateBuilder.getObject()
|
||||
} catch(NoSuchBeanDefinitionException e) {
|
||||
} catch(MissingPropertyException 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
|
||||
}
|
||||
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) }
|
||||
}
|
||||
AuthenticationProvider findAuthenticationProvider(Class<?> provider) {
|
||||
authenticationProviders().find { provider.isAssignableFrom(it.class) }
|
||||
}
|
||||
|
||||
def getCurrentAuthentication() {
|
||||
new HttpSessionSecurityContextRepository().loadContext(new HttpRequestResponseHolder(request, response)).authentication
|
||||
}
|
||||
def getCurrentAuthentication() {
|
||||
new HttpSessionSecurityContextRepository().loadContext(new HttpRequestResponseHolder(request, response)).authentication
|
||||
}
|
||||
|
||||
def login(String username="user", String role="ROLE_USER") {
|
||||
login(new UsernamePasswordAuthenticationToken(username, null, AuthorityUtils.createAuthorityList(role)))
|
||||
}
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
def createAuthenticationManagerBuilder() {
|
||||
oppContext = new AnnotationConfigApplicationContext(ObjectPostProcessorConfiguration, AuthenticationConfiguration)
|
||||
AuthenticationManagerBuilder auth = new AuthenticationManagerBuilder(objectPostProcessor)
|
||||
auth.inMemoryAuthentication().and()
|
||||
}
|
||||
def createAuthenticationManagerBuilder() {
|
||||
oppContext = new AnnotationConfigApplicationContext(ObjectPostProcessorConfiguration, AuthenticationConfiguration)
|
||||
AuthenticationManagerBuilder auth = new AuthenticationManagerBuilder(objectPostProcessor)
|
||||
auth.inMemoryAuthentication().and()
|
||||
}
|
||||
|
||||
def getObjectPostProcessor() {
|
||||
oppContext.getBean(ObjectPostProcessor)
|
||||
}
|
||||
def getObjectPostProcessor() {
|
||||
oppContext.getBean(ObjectPostProcessor)
|
||||
}
|
||||
}
|
||||
+15
-15
@@ -5,7 +5,7 @@
|
||||
* 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
|
||||
* 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,
|
||||
@@ -22,19 +22,19 @@ import spock.lang.Specification
|
||||
*
|
||||
*/
|
||||
class SecurityConfigurerAdapterTests extends Specification {
|
||||
ConcereteSecurityConfigurerAdapter conf = new ConcereteSecurityConfigurerAdapter()
|
||||
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")
|
||||
}
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
+52
-52
@@ -5,7 +5,7 @@
|
||||
* 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
|
||||
* 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,
|
||||
@@ -39,62 +39,62 @@ import spock.lang.Specification
|
||||
@ContextConfiguration(classes=[ApplicationConfig,SecurityConfig])
|
||||
@Transactional
|
||||
class Issue50Tests extends Specification {
|
||||
@Autowired
|
||||
private FilterChainProxy springSecurityFilterChain
|
||||
@Autowired
|
||||
private AuthenticationManager authenticationManager
|
||||
@Autowired
|
||||
private UserRepository userRepo
|
||||
@Autowired
|
||||
private FilterChainProxy springSecurityFilterChain
|
||||
@Autowired
|
||||
private AuthenticationManager authenticationManager
|
||||
@Autowired
|
||||
private UserRepository userRepo
|
||||
|
||||
def setup() {
|
||||
SecurityContextHolder.context.authentication = new TestingAuthenticationToken("test",null,"ROLE_ADMIN")
|
||||
}
|
||||
def setup() {
|
||||
SecurityContextHolder.context.authentication = new TestingAuthenticationToken("test",null,"ROLE_ADMIN")
|
||||
}
|
||||
|
||||
def cleanup() {
|
||||
SecurityContextHolder.clearContext()
|
||||
}
|
||||
def cleanup() {
|
||||
SecurityContextHolder.clearContext()
|
||||
}
|
||||
|
||||
// https://github.com/SpringSource/spring-security-javaconfig/issues/50
|
||||
def "#50 - GlobalMethodSecurityConfiguration should load AuthenticationManager lazily"() {
|
||||
when:
|
||||
"Configuration Loads"
|
||||
then: "GlobalMethodSecurityConfiguration loads AuthenticationManager lazily"
|
||||
noExceptionThrown()
|
||||
}
|
||||
// https://github.com/SpringSource/spring-security-javaconfig/issues/50
|
||||
def "#50 - GlobalMethodSecurityConfiguration should load AuthenticationManager lazily"() {
|
||||
when:
|
||||
"Configuration Loads"
|
||||
then: "GlobalMethodSecurityConfiguration loads AuthenticationManager lazily"
|
||||
noExceptionThrown()
|
||||
}
|
||||
|
||||
def "AuthenticationManager will not authenticate missing user"() {
|
||||
when:
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("test", "password"))
|
||||
then:
|
||||
thrown(UsernameNotFoundException)
|
||||
}
|
||||
def "AuthenticationManager will not authenticate missing user"() {
|
||||
when:
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("test", "password"))
|
||||
then:
|
||||
thrown(UsernameNotFoundException)
|
||||
}
|
||||
|
||||
def "AuthenticationManager will not authenticate with invalid password"() {
|
||||
when:
|
||||
User user = new User(username:"test",password:"password")
|
||||
userRepo.save(user)
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.username , "invalid"))
|
||||
then:
|
||||
thrown(BadCredentialsException)
|
||||
}
|
||||
def "AuthenticationManager will not authenticate with invalid password"() {
|
||||
when:
|
||||
User user = new User(username:"test",password:"password")
|
||||
userRepo.save(user)
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.username , "invalid"))
|
||||
then:
|
||||
thrown(BadCredentialsException)
|
||||
}
|
||||
|
||||
def "AuthenticationManager can be used to authenticate a user"() {
|
||||
when:
|
||||
User user = new User(username:"test",password:"password")
|
||||
userRepo.save(user)
|
||||
Authentication result = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.username , user.password))
|
||||
then:
|
||||
result.principal == user.username
|
||||
}
|
||||
def "AuthenticationManager can be used to authenticate a user"() {
|
||||
when:
|
||||
User user = new User(username:"test",password:"password")
|
||||
userRepo.save(user)
|
||||
Authentication result = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.username , user.password))
|
||||
then:
|
||||
result.principal == user.username
|
||||
}
|
||||
|
||||
def "Global Method Security is enabled and works"() {
|
||||
setup:
|
||||
SecurityContextHolder.context.authentication = new TestingAuthenticationToken("test",null,"ROLE_USER")
|
||||
when:
|
||||
User user = new User(username:"denied",password:"password")
|
||||
userRepo.save(user)
|
||||
Authentication result = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.username , user.password))
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
}
|
||||
def "Global Method Security is enabled and works"() {
|
||||
setup:
|
||||
SecurityContextHolder.context.authentication = new TestingAuthenticationToken("test",null,"ROLE_USER")
|
||||
when:
|
||||
User user = new User(username:"denied",password:"password")
|
||||
userRepo.save(user)
|
||||
Authentication result = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.username , user.password))
|
||||
then:
|
||||
thrown(AccessDeniedException)
|
||||
}
|
||||
}
|
||||
|
||||
+80
-80
@@ -5,7 +5,7 @@
|
||||
* 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
|
||||
* 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,
|
||||
@@ -44,100 +44,100 @@ import org.springframework.web.context.support.AnnotationConfigWebApplicationCon
|
||||
|
||||
public class Sec2758Tests extends BaseSpringSpec {
|
||||
|
||||
def cleanup() {
|
||||
SecurityContextHolder.clearContext()
|
||||
}
|
||||
def cleanup() {
|
||||
SecurityContextHolder.clearContext()
|
||||
}
|
||||
|
||||
def "SEC-2758: Verify Passivity Restored with Advice from JIRA"() {
|
||||
setup:
|
||||
SecurityContextHolder.context.authentication = new TestingAuthenticationToken("user", "pass", "USER")
|
||||
loadConfig(SecurityConfig)
|
||||
Service service = context.getBean(Service)
|
||||
def "SEC-2758: Verify Passivity Restored with Advice from JIRA"() {
|
||||
setup:
|
||||
SecurityContextHolder.context.authentication = new TestingAuthenticationToken("user", "pass", "USER")
|
||||
loadConfig(SecurityConfig)
|
||||
Service service = context.getBean(Service)
|
||||
|
||||
when:
|
||||
findFilter(FilterSecurityInterceptor).doFilter(new MockHttpServletRequest(), new MockHttpServletResponse(), new MockFilterChain())
|
||||
then:
|
||||
noExceptionThrown()
|
||||
when:
|
||||
findFilter(FilterSecurityInterceptor).doFilter(new MockHttpServletRequest(), new MockHttpServletResponse(), new MockFilterChain())
|
||||
then:
|
||||
noExceptionThrown()
|
||||
|
||||
when:
|
||||
service.doPreAuthorize()
|
||||
then:
|
||||
noExceptionThrown()
|
||||
when:
|
||||
service.doPreAuthorize()
|
||||
then:
|
||||
noExceptionThrown()
|
||||
|
||||
when:
|
||||
service.doJsr250()
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
when:
|
||||
service.doJsr250()
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableGlobalMethodSecurity(prePostEnabled=true)
|
||||
static class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
@EnableGlobalMethodSecurity(prePostEnabled=true)
|
||||
static class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasAnyAuthority("USER");
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasAnyAuthority("USER");
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").authorities("USER")
|
||||
}
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").authorities("USER")
|
||||
}
|
||||
|
||||
@Bean
|
||||
Service service() {
|
||||
return new ServiceImpl()
|
||||
}
|
||||
@Bean
|
||||
Service service() {
|
||||
return new ServiceImpl()
|
||||
}
|
||||
|
||||
@Bean
|
||||
static DefaultRolesPrefixPostProcessor defaultRolesPrefixPostProcessor() {
|
||||
new DefaultRolesPrefixPostProcessor()
|
||||
}
|
||||
}
|
||||
@Bean
|
||||
static DefaultRolesPrefixPostProcessor defaultRolesPrefixPostProcessor() {
|
||||
new DefaultRolesPrefixPostProcessor()
|
||||
}
|
||||
}
|
||||
|
||||
interface Service {
|
||||
void doPreAuthorize()
|
||||
void doJsr250()
|
||||
}
|
||||
interface Service {
|
||||
void doPreAuthorize()
|
||||
void doJsr250()
|
||||
}
|
||||
|
||||
static class ServiceImpl implements Service {
|
||||
@PreAuthorize("hasRole('USER')")
|
||||
void doPreAuthorize() {}
|
||||
static class ServiceImpl implements Service {
|
||||
@PreAuthorize("hasRole('USER')")
|
||||
void doPreAuthorize() {}
|
||||
|
||||
@RolesAllowed("USER")
|
||||
void doJsr250() {}
|
||||
}
|
||||
@RolesAllowed("USER")
|
||||
void doJsr250() {}
|
||||
}
|
||||
|
||||
static class DefaultRolesPrefixPostProcessor implements BeanPostProcessor, PriorityOrdered {
|
||||
static class DefaultRolesPrefixPostProcessor implements BeanPostProcessor, PriorityOrdered {
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
if(bean instanceof Jsr250MethodSecurityMetadataSource) {
|
||||
((Jsr250MethodSecurityMetadataSource) bean).setDefaultRolePrefix(null);
|
||||
}
|
||||
if(bean instanceof DefaultMethodSecurityExpressionHandler) {
|
||||
((DefaultMethodSecurityExpressionHandler) bean).setDefaultRolePrefix(null);
|
||||
}
|
||||
if(bean instanceof DefaultWebSecurityExpressionHandler) {
|
||||
((DefaultWebSecurityExpressionHandler) bean).setDefaultRolePrefix(null);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
if(bean instanceof Jsr250MethodSecurityMetadataSource) {
|
||||
((Jsr250MethodSecurityMetadataSource) bean).setDefaultRolePrefix(null);
|
||||
}
|
||||
if(bean instanceof DefaultMethodSecurityExpressionHandler) {
|
||||
((DefaultMethodSecurityExpressionHandler) bean).setDefaultRolePrefix(null);
|
||||
}
|
||||
if(bean instanceof DefaultWebSecurityExpressionHandler) {
|
||||
((DefaultWebSecurityExpressionHandler) bean).setDefaultRolePrefix(null);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return PriorityOrdered.HIGHEST_PRECEDENCE;
|
||||
}
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return PriorityOrdered.HIGHEST_PRECEDENCE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+25
-25
@@ -5,7 +5,7 @@
|
||||
* 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
|
||||
* 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,
|
||||
@@ -29,31 +29,31 @@ import spock.lang.Specification;
|
||||
*/
|
||||
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(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 "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(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]
|
||||
}
|
||||
def "antMatchers('/a.*') uses AntPathRequestMatcher"() {
|
||||
when:
|
||||
def matchers = antMatchers("/a.*")
|
||||
then: 'matcher is a AntPathRequestMatcher'
|
||||
matchers.collect {it.class } == [AntPathRequestMatcher]
|
||||
}
|
||||
}
|
||||
|
||||
+379
-379
@@ -5,7 +5,7 @@
|
||||
* 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
|
||||
* 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,
|
||||
@@ -60,440 +60,440 @@ import org.springframework.security.web.util.matcher.RequestMatcher
|
||||
*
|
||||
*/
|
||||
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
|
||||
}
|
||||
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
|
||||
@Configuration
|
||||
static class AccessDecisionManagerRefConfig extends BaseWebConfig {
|
||||
static AccessDecisionManager ACCESS_DECISION_MGR
|
||||
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().permitAll()
|
||||
.accessDecisionManager(ACCESS_DECISION_MGR)
|
||||
}
|
||||
}
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().permitAll()
|
||||
.accessDecisionManager(ACCESS_DECISION_MGR)
|
||||
}
|
||||
}
|
||||
|
||||
def "http@access-denied-page"() {
|
||||
when:
|
||||
loadConfig(AccessDeniedPageConfig)
|
||||
then:
|
||||
findFilter(ExceptionTranslationFilter).accessDeniedHandler.errorPage == "/AccessDeniedPageConfig"
|
||||
}
|
||||
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")
|
||||
}
|
||||
}
|
||||
@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
|
||||
}
|
||||
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)
|
||||
@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 AuthenticationManager authenticationManager() throws Exception {
|
||||
return new CustomAuthenticationManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER");
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER");
|
||||
}
|
||||
|
||||
static class CustomAuthenticationManager implements AuthenticationManager {
|
||||
public Authentication authenticate(Authentication authentication)
|
||||
throws AuthenticationException {
|
||||
throw new BadCredentialsException("This always fails");
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
// 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
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
@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
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
@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
|
||||
}
|
||||
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.IF_REQUIRED);
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class IfRequiredConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.sessionManagement()
|
||||
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
|
||||
}
|
||||
}
|
||||
|
||||
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 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
|
||||
}
|
||||
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 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 {
|
||||
}
|
||||
}
|
||||
@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
|
||||
}
|
||||
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 {
|
||||
}
|
||||
}
|
||||
@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
|
||||
// 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
|
||||
}
|
||||
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)
|
||||
@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)
|
||||
}
|
||||
}
|
||||
http.
|
||||
securityContext()
|
||||
.securityContextRepository(repository)
|
||||
}
|
||||
}
|
||||
|
||||
def "http@entry-point-ref"() {
|
||||
when:
|
||||
loadConfig(EntryPointRefConfig)
|
||||
then:
|
||||
findFilter(ExceptionTranslationFilter).authenticationEntryPoint.loginFormUrl == "/EntryPointRefConfig"
|
||||
}
|
||||
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"))
|
||||
}
|
||||
}
|
||||
@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)
|
||||
}
|
||||
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())
|
||||
}
|
||||
}
|
||||
@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
|
||||
// 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
|
||||
}
|
||||
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
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER");
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class OncePerRequestConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER");
|
||||
}
|
||||
}
|
||||
|
||||
def "http@once-per-request=false"() {
|
||||
when:
|
||||
loadConfig(OncePerRequestFalseConfig)
|
||||
then:
|
||||
!findFilter(FilterSecurityInterceptor).observeOncePerRequest
|
||||
}
|
||||
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.
|
||||
authorizeRequests()
|
||||
.filterSecurityInterceptorOncePerRequest(false)
|
||||
.antMatchers("/users**","/sessions/**").hasRole("ADMIN")
|
||||
.antMatchers("/signup").permitAll()
|
||||
.anyRequest().hasRole("USER");
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class OncePerRequestFalseConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.
|
||||
authorizeRequests()
|
||||
.filterSecurityInterceptorOncePerRequest(false)
|
||||
.antMatchers("/users**","/sessions/**").hasRole("ADMIN")
|
||||
.antMatchers("/signup").permitAll()
|
||||
.anyRequest().hasRole("USER");
|
||||
}
|
||||
}
|
||||
|
||||
def "http@realm"() {
|
||||
setup:
|
||||
loadConfig(RealmConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getHeader("WWW-Authenticate") == 'Basic realm="RealmConfig"'
|
||||
}
|
||||
def "http@realm"() {
|
||||
setup:
|
||||
loadConfig(RealmConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getHeader("WWW-Authenticate") == 'Basic realm="RealmConfig"'
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class RealmConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.httpBasic().realmName("RealmConfig")
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class RealmConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.httpBasic().realmName("RealmConfig")
|
||||
}
|
||||
}
|
||||
|
||||
// http@request-matcher is not available (instead request matcher instances are used)
|
||||
// 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/**"
|
||||
}
|
||||
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/**")
|
||||
}
|
||||
}
|
||||
@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")
|
||||
}
|
||||
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/.*")
|
||||
}
|
||||
}
|
||||
@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
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@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
|
||||
}
|
||||
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 {
|
||||
@Configuration
|
||||
static class SecurityNoneConfig extends BaseWebConfig {
|
||||
|
||||
@Override
|
||||
public void configure(WebSecurity web)
|
||||
throws Exception {
|
||||
web
|
||||
.ignoring()
|
||||
.antMatchers("/resources/**","/public/**")
|
||||
}
|
||||
@Override
|
||||
public void configure(WebSecurity web)
|
||||
throws Exception {
|
||||
web
|
||||
.ignoring()
|
||||
.antMatchers("/resources/**","/public/**")
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
def "http@security-context-repository-ref"() {
|
||||
when:
|
||||
loadConfig(SecurityContextRepoConfig)
|
||||
then:
|
||||
findFilter(SecurityContextPersistenceFilter).repo.class == NullSecurityContextRepository
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
@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
|
||||
}
|
||||
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()
|
||||
}
|
||||
}
|
||||
@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
|
||||
}
|
||||
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 {
|
||||
}
|
||||
}
|
||||
@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]
|
||||
}
|
||||
def "http@use-expressions=true"() {
|
||||
when:
|
||||
loadConfig(UseExpressionsConfig)
|
||||
then:
|
||||
findFilter(FilterSecurityInterceptor).securityMetadataSource.class == ExpressionBasedFilterInvocationSecurityMetadataSource
|
||||
findFilter(FilterSecurityInterceptor).accessDecisionManager.decisionVoters.collect { it.class } == [WebExpressionVoter]
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class UseExpressionsConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.antMatchers("/users**","/sessions/**").hasRole("USER")
|
||||
.antMatchers("/signup").permitAll()
|
||||
.anyRequest().hasRole("USER")
|
||||
}
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class UseExpressionsConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.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]
|
||||
}
|
||||
def "http@use-expressions=false"() {
|
||||
when:
|
||||
loadConfig(DisableUseExpressionsConfig)
|
||||
then:
|
||||
findFilter(FilterSecurityInterceptor).securityMetadataSource.class == DefaultFilterInvocationSecurityMetadataSource
|
||||
findFilter(FilterSecurityInterceptor).accessDecisionManager.decisionVoters.collect { it.class } == [RoleVoter, AuthenticatedVoter]
|
||||
}
|
||||
}
|
||||
|
||||
+12
-12
@@ -5,7 +5,7 @@
|
||||
* 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
|
||||
* 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,
|
||||
@@ -24,17 +24,17 @@ import org.springframework.security.config.annotation.authentication.builders.Au
|
||||
*/
|
||||
@EnableWebSecurity
|
||||
public abstract class BaseWebConfig extends WebSecurityConfigurerAdapter {
|
||||
BaseWebConfig(boolean disableDefaults) {
|
||||
super(disableDefaults)
|
||||
}
|
||||
BaseWebConfig(boolean disableDefaults) {
|
||||
super(disableDefaults)
|
||||
}
|
||||
|
||||
BaseWebConfig() {
|
||||
}
|
||||
BaseWebConfig() {
|
||||
}
|
||||
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER").and()
|
||||
.withUser("admin").password("password").roles("USER", "ADMIN");
|
||||
}
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER").and()
|
||||
.withUser("admin").password("password").roles("USER", "ADMIN");
|
||||
}
|
||||
}
|
||||
+72
-72
@@ -5,7 +5,7 @@
|
||||
* 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
|
||||
* 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,
|
||||
@@ -28,86 +28,86 @@ import org.springframework.security.config.annotation.authentication.builders.Au
|
||||
|
||||
public class Sec2515Tests extends BaseSpringSpec {
|
||||
|
||||
def "SEC-2515: Prevent StackOverflow with bean graph cycle"() {
|
||||
when:
|
||||
loadConfig(StackOverflowSecurityConfig)
|
||||
then:
|
||||
thrown(FatalBeanException)
|
||||
}
|
||||
def "SEC-2515: Prevent StackOverflow with bean graph cycle"() {
|
||||
when:
|
||||
loadConfig(StackOverflowSecurityConfig)
|
||||
then:
|
||||
thrown(FatalBeanException)
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class StackOverflowSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class StackOverflowSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManagerBean()
|
||||
throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManagerBean()
|
||||
throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
}
|
||||
|
||||
def "Custom Name Prevent StackOverflow with bean graph cycle"() {
|
||||
when:
|
||||
loadConfig(StackOverflowSecurityConfig)
|
||||
then:
|
||||
thrown(FatalBeanException)
|
||||
}
|
||||
def "Custom Name Prevent StackOverflow with bean graph cycle"() {
|
||||
when:
|
||||
loadConfig(StackOverflowSecurityConfig)
|
||||
then:
|
||||
thrown(FatalBeanException)
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CustomBeanNameStackOverflowSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class CustomBeanNameStackOverflowSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
@Bean(name="custom")
|
||||
public AuthenticationManager authenticationManagerBean()
|
||||
throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
@Bean(name="custom")
|
||||
public AuthenticationManager authenticationManagerBean()
|
||||
throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
}
|
||||
|
||||
def "SEC-2549: Can load with child classloader"() {
|
||||
setup:
|
||||
CanLoadWithChildConfig.AM = Mock(AuthenticationManager)
|
||||
context = new AnnotationConfigApplicationContext()
|
||||
context.classLoader = new URLClassLoader(new URL[0], context.classLoader)
|
||||
context.register(CanLoadWithChildConfig)
|
||||
context.refresh()
|
||||
when:
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
|
||||
then:
|
||||
noExceptionThrown()
|
||||
1 * CanLoadWithChildConfig.AM.authenticate(_) >> new TestingAuthenticationToken("user","password","ROLE_USER")
|
||||
}
|
||||
def "SEC-2549: Can load with child classloader"() {
|
||||
setup:
|
||||
CanLoadWithChildConfig.AM = Mock(AuthenticationManager)
|
||||
context = new AnnotationConfigApplicationContext()
|
||||
context.classLoader = new URLClassLoader(new URL[0], context.classLoader)
|
||||
context.register(CanLoadWithChildConfig)
|
||||
context.refresh()
|
||||
when:
|
||||
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
|
||||
then:
|
||||
noExceptionThrown()
|
||||
1 * CanLoadWithChildConfig.AM.authenticate(_) >> new TestingAuthenticationToken("user","password","ROLE_USER")
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CanLoadWithChildConfig extends WebSecurityConfigurerAdapter {
|
||||
static AuthenticationManager AM
|
||||
@Bean
|
||||
public AuthenticationManager am() {
|
||||
AM
|
||||
}
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class CanLoadWithChildConfig extends WebSecurityConfigurerAdapter {
|
||||
static AuthenticationManager AM
|
||||
@Bean
|
||||
public AuthenticationManager am() {
|
||||
AM
|
||||
}
|
||||
}
|
||||
|
||||
def "SEC-2515: @Bean still works when configure(AuthenticationManagerBuilder) used"() {
|
||||
when:
|
||||
loadConfig(SecurityConfig)
|
||||
then:
|
||||
noExceptionThrown();
|
||||
}
|
||||
def "SEC-2515: @Bean still works when configure(AuthenticationManagerBuilder) used"() {
|
||||
when:
|
||||
loadConfig(SecurityConfig)
|
||||
then:
|
||||
noExceptionThrown();
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManagerBean()
|
||||
throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
@Override
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManagerBean()
|
||||
throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth)
|
||||
throws Exception {
|
||||
auth.inMemoryAuthentication()
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth)
|
||||
throws Exception {
|
||||
auth.inMemoryAuthentication()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+75
-75
@@ -5,7 +5,7 @@
|
||||
* 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
|
||||
* 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,
|
||||
@@ -36,83 +36,83 @@ import org.springframework.stereotype.Component
|
||||
*/
|
||||
class Issue55Tests extends BaseSpringSpec {
|
||||
|
||||
def "WebSecurityConfigurerAdapter defaults to @Autowired"() {
|
||||
setup:
|
||||
TestingAuthenticationToken token = new TestingAuthenticationToken("test", "this")
|
||||
when:
|
||||
loadConfig(WebSecurityConfigurerAdapterDefaultsAuthManagerConfig)
|
||||
then:
|
||||
context.getBean(FilterChainProxy)
|
||||
findFilter(FilterSecurityInterceptor).authenticationManager.authenticate(token) == CustomAuthenticationManager.RESULT
|
||||
}
|
||||
def "WebSecurityConfigurerAdapter defaults to @Autowired"() {
|
||||
setup:
|
||||
TestingAuthenticationToken token = new TestingAuthenticationToken("test", "this")
|
||||
when:
|
||||
loadConfig(WebSecurityConfigurerAdapterDefaultsAuthManagerConfig)
|
||||
then:
|
||||
context.getBean(FilterChainProxy)
|
||||
findFilter(FilterSecurityInterceptor).authenticationManager.authenticate(token) == CustomAuthenticationManager.RESULT
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class WebSecurityConfigurerAdapterDefaultsAuthManagerConfig {
|
||||
@Component
|
||||
public static class WebSecurityAdapter extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class WebSecurityConfigurerAdapterDefaultsAuthManagerConfig {
|
||||
@Component
|
||||
public static class WebSecurityAdapter extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER");
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
public static class AuthenticationManagerConfiguration {
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager() throws Exception {
|
||||
return new CustomAuthenticationManager();
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER");
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
public static class AuthenticationManagerConfiguration {
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager() throws Exception {
|
||||
return new CustomAuthenticationManager();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def "multi http WebSecurityConfigurerAdapter defaults to @Autowired"() {
|
||||
setup:
|
||||
TestingAuthenticationToken token = new TestingAuthenticationToken("test", "this")
|
||||
when:
|
||||
loadConfig(MultiWebSecurityConfigurerAdapterDefaultsAuthManagerConfig)
|
||||
then:
|
||||
context.getBean(FilterChainProxy)
|
||||
findFilter(FilterSecurityInterceptor).authenticationManager.authenticate(token) == CustomAuthenticationManager.RESULT
|
||||
findFilter(FilterSecurityInterceptor,1).authenticationManager.authenticate(token) == CustomAuthenticationManager.RESULT
|
||||
}
|
||||
def "multi http WebSecurityConfigurerAdapter defaults to @Autowired"() {
|
||||
setup:
|
||||
TestingAuthenticationToken token = new TestingAuthenticationToken("test", "this")
|
||||
when:
|
||||
loadConfig(MultiWebSecurityConfigurerAdapterDefaultsAuthManagerConfig)
|
||||
then:
|
||||
context.getBean(FilterChainProxy)
|
||||
findFilter(FilterSecurityInterceptor).authenticationManager.authenticate(token) == CustomAuthenticationManager.RESULT
|
||||
findFilter(FilterSecurityInterceptor,1).authenticationManager.authenticate(token) == CustomAuthenticationManager.RESULT
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class MultiWebSecurityConfigurerAdapterDefaultsAuthManagerConfig {
|
||||
@Component
|
||||
@Order(1)
|
||||
public static class ApiWebSecurityAdapter extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.antMatcher("/api/**")
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER");
|
||||
}
|
||||
}
|
||||
@Component
|
||||
public static class WebSecurityAdapter extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER");
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
public static class AuthenticationManagerConfiguration {
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager() throws Exception {
|
||||
return new CustomAuthenticationManager();
|
||||
}
|
||||
}
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class MultiWebSecurityConfigurerAdapterDefaultsAuthManagerConfig {
|
||||
@Component
|
||||
@Order(1)
|
||||
public static class ApiWebSecurityAdapter extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.antMatcher("/api/**")
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER");
|
||||
}
|
||||
}
|
||||
@Component
|
||||
public static class WebSecurityAdapter extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER");
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
public static class AuthenticationManagerConfiguration {
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager() throws Exception {
|
||||
return new CustomAuthenticationManager();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class CustomAuthenticationManager implements AuthenticationManager {
|
||||
static Authentication RESULT = new TestingAuthenticationToken("test", "this","ROLE_USER")
|
||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||
return RESULT;
|
||||
}
|
||||
}
|
||||
static class CustomAuthenticationManager implements AuthenticationManager {
|
||||
static Authentication RESULT = new TestingAuthenticationToken("test", "this","ROLE_USER")
|
||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||
return RESULT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
* 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
|
||||
* 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,
|
||||
|
||||
+10
-10
@@ -5,7 +5,7 @@
|
||||
* 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
|
||||
* 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,
|
||||
@@ -29,15 +29,15 @@ import org.springframework.stereotype.Service
|
||||
@Service("authProvider")
|
||||
public class TestAuthenticationProvider implements AuthenticationProvider {
|
||||
|
||||
@Autowired
|
||||
public TestAuthenticationProvider(AuthProviderDependency authProviderDependency) {
|
||||
}
|
||||
@Autowired
|
||||
public TestAuthenticationProvider(AuthProviderDependency authProviderDependency) {
|
||||
}
|
||||
|
||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public boolean supports(Class<?> authentication) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
public boolean supports(Class<?> authentication) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,11 +23,11 @@ package org.springframework.security.config.doc
|
||||
* @see XsdDocumentedSpec
|
||||
*/
|
||||
class Attribute {
|
||||
def name
|
||||
def desc
|
||||
def elmt
|
||||
def name
|
||||
def desc
|
||||
def elmt
|
||||
|
||||
def getId() {
|
||||
return "${elmt.id}-${name}".toString()
|
||||
}
|
||||
def getId() {
|
||||
return "${elmt.id}-${name}".toString()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,68 +23,68 @@ package org.springframework.security.config.doc
|
||||
* @see XsdDocumentedSpec
|
||||
*/
|
||||
class Element {
|
||||
def name
|
||||
def desc
|
||||
def attrs
|
||||
/**
|
||||
* Contains the elements that extend this element (i.e. any-user-service contains ldap-user-service)
|
||||
*/
|
||||
def subGrps = []
|
||||
def childElmts = [:]
|
||||
def parentElmts = [:]
|
||||
def name
|
||||
def desc
|
||||
def attrs
|
||||
/**
|
||||
* Contains the elements that extend this element (i.e. any-user-service contains ldap-user-service)
|
||||
*/
|
||||
def subGrps = []
|
||||
def childElmts = [:]
|
||||
def parentElmts = [:]
|
||||
|
||||
def getId() {
|
||||
return "nsa-${name}".toString()
|
||||
}
|
||||
def getId() {
|
||||
return "nsa-${name}".toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the ids related to this Element including attributes, parent elements, and child elements.
|
||||
*
|
||||
* <p>
|
||||
* The expected ids to be found are documented below.
|
||||
* <ul>
|
||||
* <li>Elements - any xml element will have the nsa-<element>. For example the http element will have the id
|
||||
* nsa-http</li>
|
||||
* <li>Parent Section - Any element with a parent other than beans will have a section named
|
||||
* nsa-<element>-parents. For example, authentication-provider would have a section id of
|
||||
* nsa-authentication-provider-parents. The section would then contain a list of links pointing to the
|
||||
* documentation for each parent element.</li>
|
||||
* <li>Attributes Section - Any element with attributes will have a section with the id
|
||||
* nsa-<element>-attributes. For example the http element would require a section with the id
|
||||
* http-attributes.</li>
|
||||
* <li>Attribute - Each attribute of an element would have an id of nsa-<element>-<attributeName>. For
|
||||
* example the attribute create-session for the http attribute would have the id http-create-session.</li>
|
||||
* <li>Child Section - Any element with a child element will have a section named nsa-<element>-children.
|
||||
* For example, authentication-provider would have a section id of nsa-authentication-provider-children. The
|
||||
* section would then contain a list of links pointing to the documentation for each child element.</li>
|
||||
* </ul>
|
||||
* @return
|
||||
*/
|
||||
def getIds() {
|
||||
def ids = [id]
|
||||
childElmts.values()*.ids.each { ids.addAll it }
|
||||
attrs*.id.each { ids.add it }
|
||||
if(childElmts) {
|
||||
ids.add id+'-children'
|
||||
}
|
||||
if(attrs) {
|
||||
ids.add id+'-attributes'
|
||||
}
|
||||
if(parentElmts) {
|
||||
ids.add id+'-parents'
|
||||
}
|
||||
ids
|
||||
}
|
||||
/**
|
||||
* Gets all the ids related to this Element including attributes, parent elements, and child elements.
|
||||
*
|
||||
* <p>
|
||||
* The expected ids to be found are documented below.
|
||||
* <ul>
|
||||
* <li>Elements - any xml element will have the nsa-<element>. For example the http element will have the id
|
||||
* nsa-http</li>
|
||||
* <li>Parent Section - Any element with a parent other than beans will have a section named
|
||||
* nsa-<element>-parents. For example, authentication-provider would have a section id of
|
||||
* nsa-authentication-provider-parents. The section would then contain a list of links pointing to the
|
||||
* documentation for each parent element.</li>
|
||||
* <li>Attributes Section - Any element with attributes will have a section with the id
|
||||
* nsa-<element>-attributes. For example the http element would require a section with the id
|
||||
* http-attributes.</li>
|
||||
* <li>Attribute - Each attribute of an element would have an id of nsa-<element>-<attributeName>. For
|
||||
* example the attribute create-session for the http attribute would have the id http-create-session.</li>
|
||||
* <li>Child Section - Any element with a child element will have a section named nsa-<element>-children.
|
||||
* For example, authentication-provider would have a section id of nsa-authentication-provider-children. The
|
||||
* section would then contain a list of links pointing to the documentation for each child element.</li>
|
||||
* </ul>
|
||||
* @return
|
||||
*/
|
||||
def getIds() {
|
||||
def ids = [id]
|
||||
childElmts.values()*.ids.each { ids.addAll it }
|
||||
attrs*.id.each { ids.add it }
|
||||
if(childElmts) {
|
||||
ids.add id+'-children'
|
||||
}
|
||||
if(attrs) {
|
||||
ids.add id+'-attributes'
|
||||
}
|
||||
if(parentElmts) {
|
||||
ids.add id+'-parents'
|
||||
}
|
||||
ids
|
||||
}
|
||||
|
||||
def getAllChildElmts() {
|
||||
def result = [:]
|
||||
childElmts.values()*.subGrps*.each { elmt -> result.put(elmt.name,elmt) }
|
||||
result + childElmts
|
||||
}
|
||||
def getAllChildElmts() {
|
||||
def result = [:]
|
||||
childElmts.values()*.subGrps*.each { elmt -> result.put(elmt.name,elmt) }
|
||||
result + childElmts
|
||||
}
|
||||
|
||||
def getAllParentElmts() {
|
||||
def result = [:]
|
||||
parentElmts.values()*.subGrps*.each { elmt -> result.put(elmt.name,elmt) }
|
||||
result + parentElmts
|
||||
}
|
||||
def getAllParentElmts() {
|
||||
def result = [:]
|
||||
parentElmts.values()*.subGrps*.each { elmt -> result.put(elmt.name,elmt) }
|
||||
result + parentElmts
|
||||
}
|
||||
}
|
||||
|
||||
+139
-139
@@ -23,155 +23,155 @@ import groovy.xml.Namespace
|
||||
* @author Rob Winch
|
||||
*/
|
||||
class SpringSecurityXsdParser {
|
||||
private def rootElement
|
||||
private def rootElement
|
||||
|
||||
private def xs = new Namespace("http://www.w3.org/2001/XMLSchema", 'xs')
|
||||
private def attrElmts = [] as Set
|
||||
private def elementNameToElement = [:] as Map
|
||||
private def xs = new Namespace("http://www.w3.org/2001/XMLSchema", 'xs')
|
||||
private def attrElmts = [] as Set
|
||||
private def elementNameToElement = [:] as Map
|
||||
|
||||
/**
|
||||
* Returns a map of the element name to the {@link Element}.
|
||||
* @return
|
||||
*/
|
||||
Map<String,Element> parse() {
|
||||
elements(rootElement)
|
||||
elementNameToElement
|
||||
}
|
||||
/**
|
||||
* Returns a map of the element name to the {@link Element}.
|
||||
* @return
|
||||
*/
|
||||
Map<String,Element> parse() {
|
||||
elements(rootElement)
|
||||
elementNameToElement
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Map of the name to an Element object of all the children of element.
|
||||
*
|
||||
* @param element
|
||||
* @return
|
||||
*/
|
||||
private def elements(element) {
|
||||
def elementNameToElement = [:] as Map
|
||||
element.children().each { c->
|
||||
if(c.name() == 'element') {
|
||||
def e = elmt(c)
|
||||
elementNameToElement.put(e.name,e)
|
||||
} else {
|
||||
elementNameToElement.putAll(elements(c))
|
||||
}
|
||||
}
|
||||
elementNameToElement
|
||||
}
|
||||
/**
|
||||
* Creates a Map of the name to an Element object of all the children of element.
|
||||
*
|
||||
* @param element
|
||||
* @return
|
||||
*/
|
||||
private def elements(element) {
|
||||
def elementNameToElement = [:] as Map
|
||||
element.children().each { c->
|
||||
if(c.name() == 'element') {
|
||||
def e = elmt(c)
|
||||
elementNameToElement.put(e.name,e)
|
||||
} else {
|
||||
elementNameToElement.putAll(elements(c))
|
||||
}
|
||||
}
|
||||
elementNameToElement
|
||||
}
|
||||
|
||||
/**
|
||||
* Any children that are attribute will be returned as an Attribute object.
|
||||
* @param element
|
||||
* @return a collection of Attribute objects that are children of element.
|
||||
*/
|
||||
private def attrs(element) {
|
||||
def r = []
|
||||
element.children().each { c->
|
||||
if(c.name() == 'attribute') {
|
||||
r.add(attr(c))
|
||||
}else if(c.name() == 'element') {
|
||||
}else {
|
||||
r.addAll(attrs(c))
|
||||
}
|
||||
}
|
||||
r
|
||||
}
|
||||
/**
|
||||
* Any children that are attribute will be returned as an Attribute object.
|
||||
* @param element
|
||||
* @return a collection of Attribute objects that are children of element.
|
||||
*/
|
||||
private def attrs(element) {
|
||||
def r = []
|
||||
element.children().each { c->
|
||||
if(c.name() == 'attribute') {
|
||||
r.add(attr(c))
|
||||
}else if(c.name() == 'element') {
|
||||
}else {
|
||||
r.addAll(attrs(c))
|
||||
}
|
||||
}
|
||||
r
|
||||
}
|
||||
|
||||
/**
|
||||
* Any children will be searched for an attributeGroup, each of it's children will be returned as an Attribute
|
||||
* @param element
|
||||
* @return
|
||||
*/
|
||||
private def attrgrps(element) {
|
||||
def r = []
|
||||
element.children().each { c->
|
||||
if(c.name() == 'element') {
|
||||
}else if (c.name() == 'attributeGroup') {
|
||||
if(c.attributes().get('name')) {
|
||||
r.addAll(attrgrp(c))
|
||||
} else {
|
||||
def n = c.attributes().get('ref').split(':')[1]
|
||||
def attrGrp = findNode(element,n)
|
||||
r.addAll(attrgrp(attrGrp))
|
||||
}
|
||||
} else {
|
||||
r.addAll(attrgrps(c))
|
||||
}
|
||||
}
|
||||
r
|
||||
}
|
||||
/**
|
||||
* Any children will be searched for an attributeGroup, each of it's children will be returned as an Attribute
|
||||
* @param element
|
||||
* @return
|
||||
*/
|
||||
private def attrgrps(element) {
|
||||
def r = []
|
||||
element.children().each { c->
|
||||
if(c.name() == 'element') {
|
||||
}else if (c.name() == 'attributeGroup') {
|
||||
if(c.attributes().get('name')) {
|
||||
r.addAll(attrgrp(c))
|
||||
} else {
|
||||
def n = c.attributes().get('ref').split(':')[1]
|
||||
def attrGrp = findNode(element,n)
|
||||
r.addAll(attrgrp(attrGrp))
|
||||
}
|
||||
} else {
|
||||
r.addAll(attrgrps(c))
|
||||
}
|
||||
}
|
||||
r
|
||||
}
|
||||
|
||||
private def findNode(c,name) {
|
||||
def root = c
|
||||
while(root.name() != 'schema') {
|
||||
root = root.parent()
|
||||
}
|
||||
def result = root.breadthFirst().find { child-> name == child.@name?.text() }
|
||||
assert result?.@name?.text() == name
|
||||
result
|
||||
}
|
||||
private def findNode(c,name) {
|
||||
def root = c
|
||||
while(root.name() != 'schema') {
|
||||
root = root.parent()
|
||||
}
|
||||
def result = root.breadthFirst().find { child-> name == child.@name?.text() }
|
||||
assert result?.@name?.text() == name
|
||||
result
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes an individual attributeGroup by obtaining all the attributes and then looking for more attributeGroup elements and prcessing them.
|
||||
* @param e
|
||||
* @return all the attributes for a specific attributeGroup and any child attributeGroups
|
||||
*/
|
||||
private def attrgrp(e) {
|
||||
def attrs = attrs(e)
|
||||
attrs.addAll(attrgrps(e))
|
||||
attrs
|
||||
}
|
||||
/**
|
||||
* Processes an individual attributeGroup by obtaining all the attributes and then looking for more attributeGroup elements and prcessing them.
|
||||
* @param e
|
||||
* @return all the attributes for a specific attributeGroup and any child attributeGroups
|
||||
*/
|
||||
private def attrgrp(e) {
|
||||
def attrs = attrs(e)
|
||||
attrs.addAll(attrgrps(e))
|
||||
attrs
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the description for a specific element
|
||||
* @param element
|
||||
* @return
|
||||
*/
|
||||
private def desc(element) {
|
||||
return element['annotation']['documentation']
|
||||
}
|
||||
/**
|
||||
* Obtains the description for a specific element
|
||||
* @param element
|
||||
* @return
|
||||
*/
|
||||
private def desc(element) {
|
||||
return element['annotation']['documentation']
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an element creates an attribute from it.
|
||||
* @param n
|
||||
* @return
|
||||
*/
|
||||
private def attr(n) {
|
||||
new Attribute(desc: desc(n), name: n.@name.text())
|
||||
}
|
||||
/**
|
||||
* Given an element creates an attribute from it.
|
||||
* @param n
|
||||
* @return
|
||||
*/
|
||||
private def attr(n) {
|
||||
new Attribute(desc: desc(n), name: n.@name.text())
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an element creates an Element out of it by collecting all its attributes and child elements.
|
||||
*
|
||||
* @param n
|
||||
* @return
|
||||
*/
|
||||
private def elmt(n) {
|
||||
def name = n.@ref.text()
|
||||
if(name) {
|
||||
name = name.split(':')[1]
|
||||
n = findNode(n,name)
|
||||
} else {
|
||||
name = n.@name.text()
|
||||
}
|
||||
if(elementNameToElement.containsKey(name)) {
|
||||
return elementNameToElement.get(name)
|
||||
}
|
||||
attrElmts.add(name)
|
||||
def e = new Element()
|
||||
e.name = n.@name.text()
|
||||
e.desc = desc(n)
|
||||
e.childElmts = elements(n)
|
||||
e.attrs = attrs(n)
|
||||
e.attrs.addAll(attrgrps(n))
|
||||
e.attrs*.elmt = e
|
||||
e.childElmts.values()*.each { it.parentElmts.put(e.name,e) }
|
||||
/**
|
||||
* Given an element creates an Element out of it by collecting all its attributes and child elements.
|
||||
*
|
||||
* @param n
|
||||
* @return
|
||||
*/
|
||||
private def elmt(n) {
|
||||
def name = n.@ref.text()
|
||||
if(name) {
|
||||
name = name.split(':')[1]
|
||||
n = findNode(n,name)
|
||||
} else {
|
||||
name = n.@name.text()
|
||||
}
|
||||
if(elementNameToElement.containsKey(name)) {
|
||||
return elementNameToElement.get(name)
|
||||
}
|
||||
attrElmts.add(name)
|
||||
def e = new Element()
|
||||
e.name = n.@name.text()
|
||||
e.desc = desc(n)
|
||||
e.childElmts = elements(n)
|
||||
e.attrs = attrs(n)
|
||||
e.attrs.addAll(attrgrps(n))
|
||||
e.attrs*.elmt = e
|
||||
e.childElmts.values()*.each { it.parentElmts.put(e.name,e) }
|
||||
|
||||
def subGrpName = n.@substitutionGroup.text()
|
||||
if(subGrpName) {
|
||||
def subGrp = elmt(findNode(n,subGrpName.split(":")[1]))
|
||||
subGrp.subGrps.add(e)
|
||||
}
|
||||
def subGrpName = n.@substitutionGroup.text()
|
||||
if(subGrpName) {
|
||||
def subGrp = elmt(findNode(n,subGrpName.split(":")[1]))
|
||||
subGrp.subGrps.add(e)
|
||||
}
|
||||
|
||||
elementNameToElement.put(name,e)
|
||||
e
|
||||
}
|
||||
elementNameToElement.put(name,e)
|
||||
e
|
||||
}
|
||||
}
|
||||
|
||||
+150
-150
@@ -29,167 +29,167 @@ import spock.lang.*
|
||||
*/
|
||||
class XsdDocumentedTests extends Specification {
|
||||
|
||||
def ignoredIds = ['nsa-any-user-service','nsa-any-user-service-parents','nsa-authentication','nsa-websocket-security','nsa-ldap','nsa-method-security','nsa-web']
|
||||
@Shared def reference = new File('../docs/manual/src/docs/asciidoc/index.adoc')
|
||||
def ignoredIds = ['nsa-any-user-service','nsa-any-user-service-parents','nsa-authentication','nsa-websocket-security','nsa-ldap','nsa-method-security','nsa-web']
|
||||
@Shared def reference = new File('../docs/manual/src/docs/asciidoc/index.adoc')
|
||||
|
||||
@Shared File schema31xDocument = new File('src/main/resources/org/springframework/security/config/spring-security-3.1.xsd')
|
||||
@Shared File schemaDocument = new File('src/main/resources/org/springframework/security/config/spring-security-4.0.xsd')
|
||||
@Shared Map<String,Element> elementNameToElement
|
||||
@Shared GPathResult schemaRootElement
|
||||
@Shared File schema31xDocument = new File('src/main/resources/org/springframework/security/config/spring-security-3.1.xsd')
|
||||
@Shared File schemaDocument = new File('src/main/resources/org/springframework/security/config/spring-security-4.0.xsd')
|
||||
@Shared Map<String,Element> elementNameToElement
|
||||
@Shared GPathResult schemaRootElement
|
||||
|
||||
def setupSpec() {
|
||||
schemaRootElement = new XmlSlurper().parse(schemaDocument)
|
||||
elementNameToElement = new SpringSecurityXsdParser(rootElement: schemaRootElement).parse()
|
||||
}
|
||||
def setupSpec() {
|
||||
schemaRootElement = new XmlSlurper().parse(schemaDocument)
|
||||
elementNameToElement = new SpringSecurityXsdParser(rootElement: schemaRootElement).parse()
|
||||
}
|
||||
|
||||
def cleanupSpec() {
|
||||
reference = null
|
||||
schema31xDocument = null
|
||||
schemaDocument = null
|
||||
elementNameToElement = null
|
||||
schemaRootElement = null
|
||||
}
|
||||
def cleanupSpec() {
|
||||
reference = null
|
||||
schema31xDocument = null
|
||||
schemaDocument = null
|
||||
elementNameToElement = null
|
||||
schemaRootElement = null
|
||||
}
|
||||
|
||||
def 'SEC-2139: named-security-filter are all defined and ordered properly'() {
|
||||
setup:
|
||||
def expectedFilters = (EnumSet.allOf(SecurityFilters) as List).sort { it.order }
|
||||
when:
|
||||
def nsf = schemaRootElement.simpleType.find { it.@name == 'named-security-filter' }
|
||||
def nsfValues = nsf.children().children().collect { c ->
|
||||
Enum.valueOf(SecurityFilters, c.@value.toString())
|
||||
}
|
||||
then:
|
||||
expectedFilters == nsfValues
|
||||
}
|
||||
def 'SEC-2139: named-security-filter are all defined and ordered properly'() {
|
||||
setup:
|
||||
def expectedFilters = (EnumSet.allOf(SecurityFilters) as List).sort { it.order }
|
||||
when:
|
||||
def nsf = schemaRootElement.simpleType.find { it.@name == 'named-security-filter' }
|
||||
def nsfValues = nsf.children().children().collect { c ->
|
||||
Enum.valueOf(SecurityFilters, c.@value.toString())
|
||||
}
|
||||
then:
|
||||
expectedFilters == nsfValues
|
||||
}
|
||||
|
||||
def 'SEC-2139: 3.1.x named-security-filter are all defined and ordered properly'() {
|
||||
setup:
|
||||
def expectedFilters = ["FIRST", "CHANNEL_FILTER", "SECURITY_CONTEXT_FILTER", "CONCURRENT_SESSION_FILTER", "LOGOUT_FILTER", "X509_FILTER",
|
||||
"PRE_AUTH_FILTER", "CAS_FILTER", "FORM_LOGIN_FILTER", "OPENID_FILTER", "LOGIN_PAGE_FILTER", "DIGEST_AUTH_FILTER","BASIC_AUTH_FILTER",
|
||||
"REQUEST_CACHE_FILTER", "SERVLET_API_SUPPORT_FILTER", "JAAS_API_SUPPORT_FILTER", "REMEMBER_ME_FILTER", "ANONYMOUS_FILTER",
|
||||
"SESSION_MANAGEMENT_FILTER", "EXCEPTION_TRANSLATION_FILTER", "FILTER_SECURITY_INTERCEPTOR", "SWITCH_USER_FILTER", "LAST"].collect {
|
||||
Enum.valueOf(SecurityFilters, it)
|
||||
}
|
||||
def schema31xRootElement = new XmlSlurper().parse(schema31xDocument)
|
||||
when:
|
||||
def nsf = schema31xRootElement.simpleType.find { it.@name == 'named-security-filter' }
|
||||
def nsfValues = nsf.children().children().collect { c ->
|
||||
Enum.valueOf(SecurityFilters, c.@value.toString())
|
||||
}
|
||||
then:
|
||||
expectedFilters == nsfValues
|
||||
}
|
||||
def 'SEC-2139: 3.1.x named-security-filter are all defined and ordered properly'() {
|
||||
setup:
|
||||
def expectedFilters = ["FIRST", "CHANNEL_FILTER", "SECURITY_CONTEXT_FILTER", "CONCURRENT_SESSION_FILTER", "LOGOUT_FILTER", "X509_FILTER",
|
||||
"PRE_AUTH_FILTER", "CAS_FILTER", "FORM_LOGIN_FILTER", "OPENID_FILTER", "LOGIN_PAGE_FILTER", "DIGEST_AUTH_FILTER","BASIC_AUTH_FILTER",
|
||||
"REQUEST_CACHE_FILTER", "SERVLET_API_SUPPORT_FILTER", "JAAS_API_SUPPORT_FILTER", "REMEMBER_ME_FILTER", "ANONYMOUS_FILTER",
|
||||
"SESSION_MANAGEMENT_FILTER", "EXCEPTION_TRANSLATION_FILTER", "FILTER_SECURITY_INTERCEPTOR", "SWITCH_USER_FILTER", "LAST"].collect {
|
||||
Enum.valueOf(SecurityFilters, it)
|
||||
}
|
||||
def schema31xRootElement = new XmlSlurper().parse(schema31xDocument)
|
||||
when:
|
||||
def nsf = schema31xRootElement.simpleType.find { it.@name == 'named-security-filter' }
|
||||
def nsfValues = nsf.children().children().collect { c ->
|
||||
Enum.valueOf(SecurityFilters, c.@value.toString())
|
||||
}
|
||||
then:
|
||||
expectedFilters == nsfValues
|
||||
}
|
||||
|
||||
/**
|
||||
* This will check to ensure that the expected number of xsd documents are found to ensure that we are validating
|
||||
* against the current xsd document. If this test fails, all that is needed is to update the schemaDocument
|
||||
* and the expected size for this test.
|
||||
* @return
|
||||
*/
|
||||
def 'the latest schema is being validated'() {
|
||||
when: 'all the schemas are found'
|
||||
def schemas = schemaDocument.getParentFile().list().findAll { it.endsWith('.xsd') }
|
||||
then: 'the count is equal to 8, if not then schemaDocument needs updated'
|
||||
schemas.size() == 9
|
||||
}
|
||||
/**
|
||||
* This will check to ensure that the expected number of xsd documents are found to ensure that we are validating
|
||||
* against the current xsd document. If this test fails, all that is needed is to update the schemaDocument
|
||||
* and the expected size for this test.
|
||||
* @return
|
||||
*/
|
||||
def 'the latest schema is being validated'() {
|
||||
when: 'all the schemas are found'
|
||||
def schemas = schemaDocument.getParentFile().list().findAll { it.endsWith('.xsd') }
|
||||
then: 'the count is equal to 8, if not then schemaDocument needs updated'
|
||||
schemas.size() == 9
|
||||
}
|
||||
|
||||
/**
|
||||
* This uses a naming convention for the ids of the appendix to ensure that the entire appendix is documented.
|
||||
* The naming convention for the ids is documented in {@link Element#getIds()}.
|
||||
* @return
|
||||
*/
|
||||
def 'the entire schema is included in the appendix documentation'() {
|
||||
setup: 'get all the documented ids and the expected ids'
|
||||
def documentedIds = []
|
||||
reference.eachLine { line ->
|
||||
if(line.matches("\\[\\[(nsa-.*)\\]\\]")) {
|
||||
documentedIds.add(line.substring(2,line.length() - 2))
|
||||
}
|
||||
}
|
||||
when: 'the schema is compared to the appendix documentation'
|
||||
def expectedIds = [] as Set
|
||||
elementNameToElement*.value*.ids*.each { expectedIds.addAll it }
|
||||
documentedIds.removeAll ignoredIds
|
||||
expectedIds.removeAll ignoredIds
|
||||
def undocumentedIds = (expectedIds - documentedIds)
|
||||
def shouldNotBeDocumented = (documentedIds - expectedIds)
|
||||
then: 'all the elements and attributes are documented'
|
||||
shouldNotBeDocumented.empty
|
||||
undocumentedIds.empty
|
||||
}
|
||||
/**
|
||||
* This uses a naming convention for the ids of the appendix to ensure that the entire appendix is documented.
|
||||
* The naming convention for the ids is documented in {@link Element#getIds()}.
|
||||
* @return
|
||||
*/
|
||||
def 'the entire schema is included in the appendix documentation'() {
|
||||
setup: 'get all the documented ids and the expected ids'
|
||||
def documentedIds = []
|
||||
reference.eachLine { line ->
|
||||
if(line.matches("\\[\\[(nsa-.*)\\]\\]")) {
|
||||
documentedIds.add(line.substring(2,line.length() - 2))
|
||||
}
|
||||
}
|
||||
when: 'the schema is compared to the appendix documentation'
|
||||
def expectedIds = [] as Set
|
||||
elementNameToElement*.value*.ids*.each { expectedIds.addAll it }
|
||||
documentedIds.removeAll ignoredIds
|
||||
expectedIds.removeAll ignoredIds
|
||||
def undocumentedIds = (expectedIds - documentedIds)
|
||||
def shouldNotBeDocumented = (documentedIds - expectedIds)
|
||||
then: 'all the elements and attributes are documented'
|
||||
shouldNotBeDocumented.empty
|
||||
undocumentedIds.empty
|
||||
}
|
||||
|
||||
/**
|
||||
* This test ensures that any element that has children or parents contains a section that has links pointing to that
|
||||
* documentation.
|
||||
* @return
|
||||
*/
|
||||
def 'validate parents and children are linked in the appendix documentation'() {
|
||||
when: "get all the links for each element's children and parents"
|
||||
def docAttrNameToChildren = [:]
|
||||
def docAttrNameToParents = [:]
|
||||
/**
|
||||
* This test ensures that any element that has children or parents contains a section that has links pointing to that
|
||||
* documentation.
|
||||
* @return
|
||||
*/
|
||||
def 'validate parents and children are linked in the appendix documentation'() {
|
||||
when: "get all the links for each element's children and parents"
|
||||
def docAttrNameToChildren = [:]
|
||||
def docAttrNameToParents = [:]
|
||||
|
||||
def currentDocAttrNameToElmt
|
||||
def docAttrName
|
||||
def currentDocAttrNameToElmt
|
||||
def docAttrName
|
||||
|
||||
reference.eachLine { line ->
|
||||
if(line.matches('^\\[\\[.*\\]\\]$')) {
|
||||
def id = line.substring(2,line.length() - 2)
|
||||
if(id.endsWith("-children")) {
|
||||
docAttrName = id.substring(0,id.length() - 9)
|
||||
currentDocAttrNameToElmt = docAttrNameToChildren
|
||||
} else if(id.endsWith("-parents")) {
|
||||
docAttrName = id.substring(0,id.length() - 8)
|
||||
currentDocAttrNameToElmt = docAttrNameToParents
|
||||
} else if(docAttrName && !id.startsWith(docAttrName)) {
|
||||
currentDocAttrNameToElmt = null
|
||||
docAttrName = null
|
||||
}
|
||||
}
|
||||
reference.eachLine { line ->
|
||||
if(line.matches('^\\[\\[.*\\]\\]$')) {
|
||||
def id = line.substring(2,line.length() - 2)
|
||||
if(id.endsWith("-children")) {
|
||||
docAttrName = id.substring(0,id.length() - 9)
|
||||
currentDocAttrNameToElmt = docAttrNameToChildren
|
||||
} else if(id.endsWith("-parents")) {
|
||||
docAttrName = id.substring(0,id.length() - 8)
|
||||
currentDocAttrNameToElmt = docAttrNameToParents
|
||||
} else if(docAttrName && !id.startsWith(docAttrName)) {
|
||||
currentDocAttrNameToElmt = null
|
||||
docAttrName = null
|
||||
}
|
||||
}
|
||||
|
||||
if(docAttrName) {
|
||||
def expression = '^\\* <<(nsa-.*),.*>>$'
|
||||
if(line.matches(expression)) {
|
||||
String elmtId = line.replaceAll(expression, '$1')
|
||||
currentDocAttrNameToElmt.get(docAttrName, []).add(elmtId)
|
||||
}
|
||||
}
|
||||
}
|
||||
if(docAttrName) {
|
||||
def expression = '^\\* <<(nsa-.*),.*>>$'
|
||||
if(line.matches(expression)) {
|
||||
String elmtId = line.replaceAll(expression, '$1')
|
||||
currentDocAttrNameToElmt.get(docAttrName, []).add(elmtId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def schemaAttrNameToParents = [:]
|
||||
def schemaAttrNameToChildren = [:]
|
||||
elementNameToElement.each { entry ->
|
||||
def key = 'nsa-'+entry.key
|
||||
if(ignoredIds.contains(key)) {
|
||||
return
|
||||
}
|
||||
def parentIds = entry.value.allParentElmts.values()*.id.findAll { !ignoredIds.contains(it) }.sort()
|
||||
if(parentIds) {
|
||||
schemaAttrNameToParents.put(key,parentIds)
|
||||
}
|
||||
def childIds = entry.value.allChildElmts.values()*.id.findAll { !ignoredIds.contains(it) }.sort()
|
||||
if(childIds) {
|
||||
schemaAttrNameToChildren.put(key,childIds)
|
||||
}
|
||||
}
|
||||
then: "the expected parents and children are all documented"
|
||||
schemaAttrNameToChildren.sort() == docAttrNameToChildren.sort()
|
||||
schemaAttrNameToParents.sort() == docAttrNameToParents.sort()
|
||||
}
|
||||
def schemaAttrNameToParents = [:]
|
||||
def schemaAttrNameToChildren = [:]
|
||||
elementNameToElement.each { entry ->
|
||||
def key = 'nsa-'+entry.key
|
||||
if(ignoredIds.contains(key)) {
|
||||
return
|
||||
}
|
||||
def parentIds = entry.value.allParentElmts.values()*.id.findAll { !ignoredIds.contains(it) }.sort()
|
||||
if(parentIds) {
|
||||
schemaAttrNameToParents.put(key,parentIds)
|
||||
}
|
||||
def childIds = entry.value.allChildElmts.values()*.id.findAll { !ignoredIds.contains(it) }.sort()
|
||||
if(childIds) {
|
||||
schemaAttrNameToChildren.put(key,childIds)
|
||||
}
|
||||
}
|
||||
then: "the expected parents and children are all documented"
|
||||
schemaAttrNameToChildren.sort() == docAttrNameToChildren.sort()
|
||||
schemaAttrNameToParents.sort() == docAttrNameToParents.sort()
|
||||
}
|
||||
|
||||
/**
|
||||
* This test checks each xsd element and ensures there is documentation for it.
|
||||
* @return
|
||||
*/
|
||||
def 'entire xsd is documented'() {
|
||||
when: "validate that the entire xsd contains documentation"
|
||||
def notDocElmtIds = elementNameToElement.values().findAll {
|
||||
!it.desc.text() && !ignoredIds.contains(it.id)
|
||||
}*.id.sort().join("\n")
|
||||
def notDocAttrIds = elementNameToElement.values()*.attrs.flatten().findAll {
|
||||
!it.desc.text() && !ignoredIds.contains(it.id)
|
||||
}*.id.sort().join("\n")
|
||||
then: "all the elements and attributes have some documentation"
|
||||
!notDocElmtIds
|
||||
!notDocAttrIds
|
||||
}
|
||||
/**
|
||||
* This test checks each xsd element and ensures there is documentation for it.
|
||||
* @return
|
||||
*/
|
||||
def 'entire xsd is documented'() {
|
||||
when: "validate that the entire xsd contains documentation"
|
||||
def notDocElmtIds = elementNameToElement.values().findAll {
|
||||
!it.desc.text() && !ignoredIds.contains(it.id)
|
||||
}*.id.sort().join("\n")
|
||||
def notDocAttrIds = elementNameToElement.values()*.attrs.flatten().findAll {
|
||||
!it.desc.text() && !ignoredIds.contains(it.id)
|
||||
}*.id.sort().join("\n")
|
||||
then: "all the elements and attributes have some documentation"
|
||||
!notDocElmtIds
|
||||
!notDocAttrIds
|
||||
}
|
||||
}
|
||||
|
||||
+39
-39
@@ -28,55 +28,55 @@ import javax.servlet.http.HttpServletRequest
|
||||
*
|
||||
*/
|
||||
abstract class AbstractHttpConfigTests extends AbstractXmlConfigTests {
|
||||
final int AUTO_CONFIG_FILTERS = 14;
|
||||
final int AUTO_CONFIG_FILTERS = 14;
|
||||
|
||||
def httpAutoConfig(Closure c) {
|
||||
xml.http(['auto-config': 'true', 'use-expressions':false], c)
|
||||
}
|
||||
def httpAutoConfig(Closure c) {
|
||||
xml.http(['auto-config': 'true', 'use-expressions':false], c)
|
||||
}
|
||||
|
||||
def httpAutoConfig(String matcher, Closure c) {
|
||||
xml.http(['auto-config': 'true', 'use-expressions':false, 'request-matcher': matcher], c)
|
||||
}
|
||||
def httpAutoConfig(String matcher, Closure c) {
|
||||
xml.http(['auto-config': 'true', 'use-expressions':false, 'request-matcher': matcher], c)
|
||||
}
|
||||
|
||||
def interceptUrl(String path, String authz) {
|
||||
xml.'intercept-url'(pattern: path, access: authz)
|
||||
}
|
||||
def interceptUrl(String path, String authz) {
|
||||
xml.'intercept-url'(pattern: path, access: authz)
|
||||
}
|
||||
|
||||
def interceptUrl(String path, String httpMethod, String authz) {
|
||||
xml.'intercept-url'(pattern: path, method: httpMethod, access: authz)
|
||||
}
|
||||
def interceptUrl(String path, String httpMethod, String authz) {
|
||||
xml.'intercept-url'(pattern: path, method: httpMethod, access: authz)
|
||||
}
|
||||
|
||||
Filter getFilter(Class type) {
|
||||
List filters = getFilters("/any");
|
||||
Filter getFilter(Class type) {
|
||||
List filters = getFilters("/any");
|
||||
|
||||
for (f in filters) {
|
||||
if (f.class.isAssignableFrom(type)) {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
for (f in filters) {
|
||||
if (f.class.isAssignableFrom(type)) {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
List getFilters(String url) {
|
||||
springSecurityFilterChain.getFilters(url)
|
||||
}
|
||||
List getFilters(String url) {
|
||||
springSecurityFilterChain.getFilters(url)
|
||||
}
|
||||
|
||||
Filter getSpringSecurityFilterChain() {
|
||||
appContext.getBean(BeanIds.FILTER_CHAIN_PROXY)
|
||||
}
|
||||
Filter getSpringSecurityFilterChain() {
|
||||
appContext.getBean(BeanIds.FILTER_CHAIN_PROXY)
|
||||
}
|
||||
|
||||
FilterInvocation createFilterinvocation(String path, String method) {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setMethod(method);
|
||||
request.setRequestURI(null);
|
||||
request.setServletPath(path);
|
||||
FilterInvocation createFilterinvocation(String path, String method) {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setMethod(method);
|
||||
request.setRequestURI(null);
|
||||
request.setServletPath(path);
|
||||
|
||||
return new FilterInvocation(request, new MockHttpServletResponse(), new MockFilterChain());
|
||||
}
|
||||
return new FilterInvocation(request, new MockHttpServletResponse(), new MockFilterChain());
|
||||
}
|
||||
|
||||
def basicLogin(HttpServletRequest request, String username="user",String password="password") {
|
||||
def credentials = username + ":" + password
|
||||
request.addHeader("Authorization", "Basic " + credentials.bytes.encodeBase64())
|
||||
}
|
||||
def basicLogin(HttpServletRequest request, String username="user",String password="password") {
|
||||
def credentials = username + ":" + password
|
||||
request.addHeader("Authorization", "Basic " + credentials.bytes.encodeBase64())
|
||||
}
|
||||
}
|
||||
|
||||
+30
-30
@@ -10,38 +10,38 @@ import org.springframework.security.web.access.ExceptionTranslationFilter
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
class AccessDeniedConfigTests extends AbstractHttpConfigTests {
|
||||
def invalidAccessDeniedUrlIsDetected() {
|
||||
when:
|
||||
httpAutoConfig() {
|
||||
'access-denied-handler'('error-page':'noLeadingSlash')
|
||||
}
|
||||
createAppContext();
|
||||
then:
|
||||
thrown(BeanCreationException)
|
||||
}
|
||||
def invalidAccessDeniedUrlIsDetected() {
|
||||
when:
|
||||
httpAutoConfig() {
|
||||
'access-denied-handler'('error-page':'noLeadingSlash')
|
||||
}
|
||||
createAppContext();
|
||||
then:
|
||||
thrown(BeanCreationException)
|
||||
}
|
||||
|
||||
def accessDeniedHandlerIsSetCorectly() {
|
||||
httpAutoConfig() {
|
||||
'access-denied-handler'(ref: 'adh')
|
||||
}
|
||||
bean('adh', AccessDeniedHandlerImpl)
|
||||
createAppContext();
|
||||
def accessDeniedHandlerIsSetCorectly() {
|
||||
httpAutoConfig() {
|
||||
'access-denied-handler'(ref: 'adh')
|
||||
}
|
||||
bean('adh', AccessDeniedHandlerImpl)
|
||||
createAppContext();
|
||||
|
||||
def filter = getFilter(ExceptionTranslationFilter.class);
|
||||
def adh = appContext.getBean("adh");
|
||||
def filter = getFilter(ExceptionTranslationFilter.class);
|
||||
def adh = appContext.getBean("adh");
|
||||
|
||||
expect:
|
||||
filter.accessDeniedHandler == adh
|
||||
}
|
||||
expect:
|
||||
filter.accessDeniedHandler == adh
|
||||
}
|
||||
|
||||
def void accessDeniedHandlerPageAndRefAreMutuallyExclusive() {
|
||||
when:
|
||||
httpAutoConfig {
|
||||
'access-denied-handler'('error-page': '/go-away', ref: 'adh')
|
||||
}
|
||||
createAppContext();
|
||||
bean('adh', AccessDeniedHandlerImpl)
|
||||
then:
|
||||
thrown(BeanDefinitionParsingException)
|
||||
}
|
||||
def void accessDeniedHandlerPageAndRefAreMutuallyExclusive() {
|
||||
when:
|
||||
httpAutoConfig {
|
||||
'access-denied-handler'('error-page': '/go-away', ref: 'adh')
|
||||
}
|
||||
createAppContext();
|
||||
bean('adh', AccessDeniedHandlerImpl)
|
||||
then:
|
||||
thrown(BeanDefinitionParsingException)
|
||||
}
|
||||
}
|
||||
|
||||
+282
-282
@@ -43,303 +43,303 @@ import spock.lang.Unroll
|
||||
* @author Rob Winch
|
||||
*/
|
||||
class CsrfConfigTests extends AbstractHttpConfigTests {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest()
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
MockHttpServletRequest request = new MockHttpServletRequest()
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
|
||||
@Unroll
|
||||
def 'csrf is enabled by default'() {
|
||||
setup:
|
||||
httpAutoConfig {
|
||||
}
|
||||
createAppContext()
|
||||
when:
|
||||
request.method = httpMethod
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == httpStatus
|
||||
where:
|
||||
httpMethod | httpStatus
|
||||
'POST' | HttpServletResponse.SC_FORBIDDEN
|
||||
'PUT' | HttpServletResponse.SC_FORBIDDEN
|
||||
'PATCH' | HttpServletResponse.SC_FORBIDDEN
|
||||
'DELETE' | HttpServletResponse.SC_FORBIDDEN
|
||||
'INVALID' | HttpServletResponse.SC_FORBIDDEN
|
||||
'GET' | HttpServletResponse.SC_OK
|
||||
'HEAD' | HttpServletResponse.SC_OK
|
||||
'TRACE' | HttpServletResponse.SC_OK
|
||||
'OPTIONS' | HttpServletResponse.SC_OK
|
||||
}
|
||||
@Unroll
|
||||
def 'csrf is enabled by default'() {
|
||||
setup:
|
||||
httpAutoConfig {
|
||||
}
|
||||
createAppContext()
|
||||
when:
|
||||
request.method = httpMethod
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == httpStatus
|
||||
where:
|
||||
httpMethod | httpStatus
|
||||
'POST' | HttpServletResponse.SC_FORBIDDEN
|
||||
'PUT' | HttpServletResponse.SC_FORBIDDEN
|
||||
'PATCH' | HttpServletResponse.SC_FORBIDDEN
|
||||
'DELETE' | HttpServletResponse.SC_FORBIDDEN
|
||||
'INVALID' | HttpServletResponse.SC_FORBIDDEN
|
||||
'GET' | HttpServletResponse.SC_OK
|
||||
'HEAD' | HttpServletResponse.SC_OK
|
||||
'TRACE' | HttpServletResponse.SC_OK
|
||||
'OPTIONS' | HttpServletResponse.SC_OK
|
||||
}
|
||||
|
||||
def 'csrf disabled'() {
|
||||
when:
|
||||
httpAutoConfig {
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
then:
|
||||
!getFilter(CsrfFilter)
|
||||
}
|
||||
def 'csrf disabled'() {
|
||||
when:
|
||||
httpAutoConfig {
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
then:
|
||||
!getFilter(CsrfFilter)
|
||||
}
|
||||
|
||||
@Unroll
|
||||
def 'csrf defaults'() {
|
||||
setup:
|
||||
httpAutoConfig {
|
||||
'csrf'()
|
||||
}
|
||||
createAppContext()
|
||||
when:
|
||||
request.method = httpMethod
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == httpStatus
|
||||
where:
|
||||
httpMethod | httpStatus
|
||||
'POST' | HttpServletResponse.SC_FORBIDDEN
|
||||
'PUT' | HttpServletResponse.SC_FORBIDDEN
|
||||
'PATCH' | HttpServletResponse.SC_FORBIDDEN
|
||||
'DELETE' | HttpServletResponse.SC_FORBIDDEN
|
||||
'INVALID' | HttpServletResponse.SC_FORBIDDEN
|
||||
'GET' | HttpServletResponse.SC_OK
|
||||
'HEAD' | HttpServletResponse.SC_OK
|
||||
'TRACE' | HttpServletResponse.SC_OK
|
||||
'OPTIONS' | HttpServletResponse.SC_OK
|
||||
}
|
||||
@Unroll
|
||||
def 'csrf defaults'() {
|
||||
setup:
|
||||
httpAutoConfig {
|
||||
'csrf'()
|
||||
}
|
||||
createAppContext()
|
||||
when:
|
||||
request.method = httpMethod
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == httpStatus
|
||||
where:
|
||||
httpMethod | httpStatus
|
||||
'POST' | HttpServletResponse.SC_FORBIDDEN
|
||||
'PUT' | HttpServletResponse.SC_FORBIDDEN
|
||||
'PATCH' | HttpServletResponse.SC_FORBIDDEN
|
||||
'DELETE' | HttpServletResponse.SC_FORBIDDEN
|
||||
'INVALID' | HttpServletResponse.SC_FORBIDDEN
|
||||
'GET' | HttpServletResponse.SC_OK
|
||||
'HEAD' | HttpServletResponse.SC_OK
|
||||
'TRACE' | HttpServletResponse.SC_OK
|
||||
'OPTIONS' | HttpServletResponse.SC_OK
|
||||
}
|
||||
|
||||
def 'csrf default creates CsrfRequestDataValueProcessor'() {
|
||||
when:
|
||||
httpAutoConfig {
|
||||
'csrf'()
|
||||
}
|
||||
createAppContext()
|
||||
then:
|
||||
appContext.getBean("requestDataValueProcessor",RequestDataValueProcessor)
|
||||
}
|
||||
def 'csrf default creates CsrfRequestDataValueProcessor'() {
|
||||
when:
|
||||
httpAutoConfig {
|
||||
'csrf'()
|
||||
}
|
||||
createAppContext()
|
||||
then:
|
||||
appContext.getBean("requestDataValueProcessor",RequestDataValueProcessor)
|
||||
}
|
||||
|
||||
def 'csrf custom AccessDeniedHandler'() {
|
||||
setup:
|
||||
httpAutoConfig {
|
||||
'access-denied-handler'(ref:'adh')
|
||||
'csrf'()
|
||||
}
|
||||
mockBean(AccessDeniedHandler,'adh')
|
||||
createAppContext()
|
||||
AccessDeniedHandler adh = appContext.getBean(AccessDeniedHandler)
|
||||
request.method = "POST"
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
verify(adh).handle(any(HttpServletRequest),any(HttpServletResponse),any(AccessDeniedException))
|
||||
response.status == HttpServletResponse.SC_OK // our mock doesn't do anything
|
||||
}
|
||||
def 'csrf custom AccessDeniedHandler'() {
|
||||
setup:
|
||||
httpAutoConfig {
|
||||
'access-denied-handler'(ref:'adh')
|
||||
'csrf'()
|
||||
}
|
||||
mockBean(AccessDeniedHandler,'adh')
|
||||
createAppContext()
|
||||
AccessDeniedHandler adh = appContext.getBean(AccessDeniedHandler)
|
||||
request.method = "POST"
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
verify(adh).handle(any(HttpServletRequest),any(HttpServletResponse),any(AccessDeniedException))
|
||||
response.status == HttpServletResponse.SC_OK // our mock doesn't do anything
|
||||
}
|
||||
|
||||
def "csrf disables posts for RequestCache"() {
|
||||
setup:
|
||||
httpAutoConfig {
|
||||
'csrf'('token-repository-ref':'repo')
|
||||
'intercept-url'(pattern:"/**",access:'ROLE_USER')
|
||||
}
|
||||
mockBean(CsrfTokenRepository,'repo')
|
||||
createAppContext()
|
||||
CsrfTokenRepository repo = appContext.getBean("repo",CsrfTokenRepository)
|
||||
CsrfToken token = new DefaultCsrfToken("X-CSRF-TOKEN","_csrf", "abc")
|
||||
when(repo.loadToken(any(HttpServletRequest))).thenReturn(token)
|
||||
when(repo.generateToken(any(HttpServletRequest))).thenReturn(token)
|
||||
request.setParameter(token.parameterName,token.token)
|
||||
request.servletPath = "/some-url"
|
||||
request.requestURI = "/some-url"
|
||||
request.method = "POST"
|
||||
when: "CSRF passes and our session times out"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to the login page"
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == "http://localhost/login"
|
||||
when: "authenticate successfully"
|
||||
response = new MockHttpServletResponse()
|
||||
request = new MockHttpServletRequest(session: request.session)
|
||||
request.servletPath = "/login"
|
||||
request.setParameter(token.parameterName,token.token)
|
||||
request.setParameter("username","user")
|
||||
request.setParameter("password","password")
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to default success because we don't want csrf attempts made prior to authentication to pass"
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == "/"
|
||||
}
|
||||
def "csrf disables posts for RequestCache"() {
|
||||
setup:
|
||||
httpAutoConfig {
|
||||
'csrf'('token-repository-ref':'repo')
|
||||
'intercept-url'(pattern:"/**",access:'ROLE_USER')
|
||||
}
|
||||
mockBean(CsrfTokenRepository,'repo')
|
||||
createAppContext()
|
||||
CsrfTokenRepository repo = appContext.getBean("repo",CsrfTokenRepository)
|
||||
CsrfToken token = new DefaultCsrfToken("X-CSRF-TOKEN","_csrf", "abc")
|
||||
when(repo.loadToken(any(HttpServletRequest))).thenReturn(token)
|
||||
when(repo.generateToken(any(HttpServletRequest))).thenReturn(token)
|
||||
request.setParameter(token.parameterName,token.token)
|
||||
request.servletPath = "/some-url"
|
||||
request.requestURI = "/some-url"
|
||||
request.method = "POST"
|
||||
when: "CSRF passes and our session times out"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to the login page"
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == "http://localhost/login"
|
||||
when: "authenticate successfully"
|
||||
response = new MockHttpServletResponse()
|
||||
request = new MockHttpServletRequest(session: request.session)
|
||||
request.servletPath = "/login"
|
||||
request.setParameter(token.parameterName,token.token)
|
||||
request.setParameter("username","user")
|
||||
request.setParameter("password","password")
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to default success because we don't want csrf attempts made prior to authentication to pass"
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == "/"
|
||||
}
|
||||
|
||||
def "csrf enables gets for RequestCache"() {
|
||||
setup:
|
||||
httpAutoConfig {
|
||||
'csrf'('token-repository-ref':'repo')
|
||||
'intercept-url'(pattern:"/**",access:'ROLE_USER')
|
||||
}
|
||||
mockBean(CsrfTokenRepository,'repo')
|
||||
createAppContext()
|
||||
CsrfTokenRepository repo = appContext.getBean("repo",CsrfTokenRepository)
|
||||
CsrfToken token = new DefaultCsrfToken("X-CSRF-TOKEN","_csrf", "abc")
|
||||
when(repo.loadToken(any(HttpServletRequest))).thenReturn(token)
|
||||
when(repo.generateToken(any(HttpServletRequest))).thenReturn(token)
|
||||
request.setParameter(token.parameterName,token.token)
|
||||
request.servletPath = "/some-url"
|
||||
request.requestURI = "/some-url"
|
||||
request.method = "GET"
|
||||
when: "CSRF passes and our session times out"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to the login page"
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == "http://localhost/login"
|
||||
when: "authenticate successfully"
|
||||
response = new MockHttpServletResponse()
|
||||
request = new MockHttpServletRequest(session: request.session)
|
||||
request.servletPath = "/login"
|
||||
request.setParameter(token.parameterName,token.token)
|
||||
request.setParameter("username","user")
|
||||
request.setParameter("password","password")
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to original URL since it was a GET"
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == "http://localhost/some-url"
|
||||
}
|
||||
def "csrf enables gets for RequestCache"() {
|
||||
setup:
|
||||
httpAutoConfig {
|
||||
'csrf'('token-repository-ref':'repo')
|
||||
'intercept-url'(pattern:"/**",access:'ROLE_USER')
|
||||
}
|
||||
mockBean(CsrfTokenRepository,'repo')
|
||||
createAppContext()
|
||||
CsrfTokenRepository repo = appContext.getBean("repo",CsrfTokenRepository)
|
||||
CsrfToken token = new DefaultCsrfToken("X-CSRF-TOKEN","_csrf", "abc")
|
||||
when(repo.loadToken(any(HttpServletRequest))).thenReturn(token)
|
||||
when(repo.generateToken(any(HttpServletRequest))).thenReturn(token)
|
||||
request.setParameter(token.parameterName,token.token)
|
||||
request.servletPath = "/some-url"
|
||||
request.requestURI = "/some-url"
|
||||
request.method = "GET"
|
||||
when: "CSRF passes and our session times out"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to the login page"
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == "http://localhost/login"
|
||||
when: "authenticate successfully"
|
||||
response = new MockHttpServletResponse()
|
||||
request = new MockHttpServletRequest(session: request.session)
|
||||
request.servletPath = "/login"
|
||||
request.setParameter(token.parameterName,token.token)
|
||||
request.setParameter("username","user")
|
||||
request.setParameter("password","password")
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to original URL since it was a GET"
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == "http://localhost/some-url"
|
||||
}
|
||||
|
||||
def "SEC-2422: csrf expire CSRF token and session-management invalid-session-url"() {
|
||||
setup:
|
||||
httpAutoConfig {
|
||||
'csrf'()
|
||||
'session-management'('invalid-session-url': '/error/sessionError')
|
||||
}
|
||||
createAppContext()
|
||||
request.setParameter("_csrf","abc")
|
||||
request.method = "POST"
|
||||
when: "No existing expected CsrfToken (session times out) and a POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to the session timeout page page"
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == "/error/sessionError"
|
||||
when: "Existing expected CsrfToken and a POST (invalid token provided)"
|
||||
response = new MockHttpServletResponse()
|
||||
request = new MockHttpServletRequest(session: request.session, method:'POST')
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "Access Denied occurs"
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
}
|
||||
def "SEC-2422: csrf expire CSRF token and session-management invalid-session-url"() {
|
||||
setup:
|
||||
httpAutoConfig {
|
||||
'csrf'()
|
||||
'session-management'('invalid-session-url': '/error/sessionError')
|
||||
}
|
||||
createAppContext()
|
||||
request.setParameter("_csrf","abc")
|
||||
request.method = "POST"
|
||||
when: "No existing expected CsrfToken (session times out) and a POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to the session timeout page page"
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == "/error/sessionError"
|
||||
when: "Existing expected CsrfToken and a POST (invalid token provided)"
|
||||
response = new MockHttpServletResponse()
|
||||
request = new MockHttpServletRequest(session: request.session, method:'POST')
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "Access Denied occurs"
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
}
|
||||
|
||||
def "csrf requireCsrfProtectionMatcher"() {
|
||||
setup:
|
||||
httpAutoConfig {
|
||||
'csrf'('request-matcher-ref':'matcher')
|
||||
}
|
||||
mockBean(RequestMatcher,'matcher')
|
||||
createAppContext()
|
||||
request.method = 'POST'
|
||||
RequestMatcher matcher = appContext.getBean("matcher",RequestMatcher)
|
||||
when:
|
||||
when(matcher.matches(any(HttpServletRequest))).thenReturn(false)
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when:
|
||||
when(matcher.matches(any(HttpServletRequest))).thenReturn(true)
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
}
|
||||
def "csrf requireCsrfProtectionMatcher"() {
|
||||
setup:
|
||||
httpAutoConfig {
|
||||
'csrf'('request-matcher-ref':'matcher')
|
||||
}
|
||||
mockBean(RequestMatcher,'matcher')
|
||||
createAppContext()
|
||||
request.method = 'POST'
|
||||
RequestMatcher matcher = appContext.getBean("matcher",RequestMatcher)
|
||||
when:
|
||||
when(matcher.matches(any(HttpServletRequest))).thenReturn(false)
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when:
|
||||
when(matcher.matches(any(HttpServletRequest))).thenReturn(true)
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
}
|
||||
|
||||
def "csrf csrfTokenRepository"() {
|
||||
setup:
|
||||
httpAutoConfig {
|
||||
'csrf'('token-repository-ref':'repo')
|
||||
}
|
||||
mockBean(CsrfTokenRepository,'repo')
|
||||
createAppContext()
|
||||
CsrfTokenRepository repo = appContext.getBean("repo",CsrfTokenRepository)
|
||||
CsrfToken token = new DefaultCsrfToken("X-CSRF-TOKEN","_csrf", "abc")
|
||||
when(repo.loadToken(any(HttpServletRequest))).thenReturn(token)
|
||||
request.setParameter(token.parameterName,token.token)
|
||||
request.method = "POST"
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when:
|
||||
request.setParameter(token.parameterName,token.token+"INVALID")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
}
|
||||
def "csrf csrfTokenRepository"() {
|
||||
setup:
|
||||
httpAutoConfig {
|
||||
'csrf'('token-repository-ref':'repo')
|
||||
}
|
||||
mockBean(CsrfTokenRepository,'repo')
|
||||
createAppContext()
|
||||
CsrfTokenRepository repo = appContext.getBean("repo",CsrfTokenRepository)
|
||||
CsrfToken token = new DefaultCsrfToken("X-CSRF-TOKEN","_csrf", "abc")
|
||||
when(repo.loadToken(any(HttpServletRequest))).thenReturn(token)
|
||||
request.setParameter(token.parameterName,token.token)
|
||||
request.method = "POST"
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when:
|
||||
request.setParameter(token.parameterName,token.token+"INVALID")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
}
|
||||
|
||||
def "csrf clears on login"() {
|
||||
setup:
|
||||
httpAutoConfig {
|
||||
'csrf'('token-repository-ref':'repo')
|
||||
}
|
||||
mockBean(CsrfTokenRepository,'repo')
|
||||
createAppContext()
|
||||
CsrfTokenRepository repo = appContext.getBean("repo",CsrfTokenRepository)
|
||||
CsrfToken token = new DefaultCsrfToken("X-CSRF-TOKEN","_csrf", "abc")
|
||||
when(repo.loadToken(any(HttpServletRequest))).thenReturn(token)
|
||||
when(repo.generateToken(any(HttpServletRequest))).thenReturn(token)
|
||||
request.setParameter(token.parameterName,token.token)
|
||||
request.method = "POST"
|
||||
request.setParameter("username","user")
|
||||
request.setParameter("password","password")
|
||||
request.servletPath = "/login"
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
verify(repo, atLeastOnce()).saveToken(eq(null),any(HttpServletRequest), any(HttpServletResponse))
|
||||
}
|
||||
def "csrf clears on login"() {
|
||||
setup:
|
||||
httpAutoConfig {
|
||||
'csrf'('token-repository-ref':'repo')
|
||||
}
|
||||
mockBean(CsrfTokenRepository,'repo')
|
||||
createAppContext()
|
||||
CsrfTokenRepository repo = appContext.getBean("repo",CsrfTokenRepository)
|
||||
CsrfToken token = new DefaultCsrfToken("X-CSRF-TOKEN","_csrf", "abc")
|
||||
when(repo.loadToken(any(HttpServletRequest))).thenReturn(token)
|
||||
when(repo.generateToken(any(HttpServletRequest))).thenReturn(token)
|
||||
request.setParameter(token.parameterName,token.token)
|
||||
request.method = "POST"
|
||||
request.setParameter("username","user")
|
||||
request.setParameter("password","password")
|
||||
request.servletPath = "/login"
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
verify(repo, atLeastOnce()).saveToken(eq(null),any(HttpServletRequest), any(HttpServletResponse))
|
||||
}
|
||||
|
||||
def "csrf clears on logout"() {
|
||||
setup:
|
||||
httpAutoConfig {
|
||||
'csrf'('token-repository-ref':'repo')
|
||||
}
|
||||
mockBean(CsrfTokenRepository,'repo')
|
||||
createAppContext()
|
||||
CsrfTokenRepository repo = appContext.getBean("repo",CsrfTokenRepository)
|
||||
CsrfToken token = new DefaultCsrfToken("X-CSRF-TOKEN","_csrf", "abc")
|
||||
when(repo.loadToken(any(HttpServletRequest))).thenReturn(token)
|
||||
request.setParameter(token.parameterName,token.token)
|
||||
request.method = "POST"
|
||||
request.servletPath = "/logout"
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
verify(repo).saveToken(eq(null),any(HttpServletRequest), any(HttpServletResponse))
|
||||
}
|
||||
def "csrf clears on logout"() {
|
||||
setup:
|
||||
httpAutoConfig {
|
||||
'csrf'('token-repository-ref':'repo')
|
||||
}
|
||||
mockBean(CsrfTokenRepository,'repo')
|
||||
createAppContext()
|
||||
CsrfTokenRepository repo = appContext.getBean("repo",CsrfTokenRepository)
|
||||
CsrfToken token = new DefaultCsrfToken("X-CSRF-TOKEN","_csrf", "abc")
|
||||
when(repo.loadToken(any(HttpServletRequest))).thenReturn(token)
|
||||
request.setParameter(token.parameterName,token.token)
|
||||
request.method = "POST"
|
||||
request.servletPath = "/logout"
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
verify(repo).saveToken(eq(null),any(HttpServletRequest), any(HttpServletResponse))
|
||||
}
|
||||
|
||||
def "SEC-2495: csrf disables logout on GET"() {
|
||||
setup:
|
||||
httpAutoConfig {
|
||||
'csrf'()
|
||||
}
|
||||
createAppContext()
|
||||
login()
|
||||
request.method = "GET"
|
||||
request.requestURI = "/logout"
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
getAuthentication(request) != null
|
||||
}
|
||||
def "SEC-2495: csrf disables logout on GET"() {
|
||||
setup:
|
||||
httpAutoConfig {
|
||||
'csrf'()
|
||||
}
|
||||
createAppContext()
|
||||
login()
|
||||
request.method = "GET"
|
||||
request.requestURI = "/logout"
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
getAuthentication(request) != null
|
||||
}
|
||||
|
||||
|
||||
def login(String username="user", String role="ROLE_USER") {
|
||||
login(new UsernamePasswordAuthenticationToken(username, null, AuthorityUtils.createAuthorityList(role)))
|
||||
}
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
def getAuthentication(HttpServletRequest request) {
|
||||
HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository()
|
||||
HttpRequestResponseHolder requestResponseHolder = new HttpRequestResponseHolder(request, response)
|
||||
repo.loadContext(requestResponseHolder)?.authentication
|
||||
}
|
||||
def getAuthentication(HttpServletRequest request) {
|
||||
HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository()
|
||||
HttpRequestResponseHolder requestResponseHolder = new HttpRequestResponseHolder(request, response)
|
||||
repo.loadContext(requestResponseHolder)?.authentication
|
||||
}
|
||||
}
|
||||
|
||||
+75
-75
@@ -10,104 +10,104 @@ import org.springframework.mock.web.MockHttpServletResponse
|
||||
*/
|
||||
class FormLoginBeanDefinitionParserTests extends AbstractHttpConfigTests {
|
||||
|
||||
def 'form-login default login page'() {
|
||||
setup:
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(method:'GET',requestURI:'/login')
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
httpAutoConfig {
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
|
||||
def 'form-login default login page'() {
|
||||
setup:
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(method:'GET',requestURI:'/login')
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
httpAutoConfig {
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
when:
|
||||
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>
|
||||
<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>"""
|
||||
}
|
||||
}
|
||||
|
||||
def 'form-login default login page custom attributes'() {
|
||||
setup:
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(method:'GET',requestURI:'/login')
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
httpAutoConfig {
|
||||
'form-login'('login-processing-url':'/login_custom','username-parameter':'custom_user','password-parameter':'custom_password')
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.custom_user.focus();'>
|
||||
def 'form-login default login page custom attributes'() {
|
||||
setup:
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(method:'GET',requestURI:'/login')
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
httpAutoConfig {
|
||||
'form-login'('login-processing-url':'/login_custom','username-parameter':'custom_user','password-parameter':'custom_password')
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.custom_user.focus();'>
|
||||
<h3>Login with Username and Password</h3><form name='f' action='/login_custom' method='POST'>
|
||||
<table>
|
||||
<tr><td>User:</td><td><input type='text' name='custom_user' value=''></td></tr>
|
||||
<tr><td>Password:</td><td><input type='password' name='custom_password'/></td></tr>
|
||||
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
|
||||
<tr><td>User:</td><td><input type='text' name='custom_user' value=''></td></tr>
|
||||
<tr><td>Password:</td><td><input type='password' name='custom_password'/></td></tr>
|
||||
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
|
||||
</table>
|
||||
</form></body></html>"""
|
||||
}
|
||||
}
|
||||
|
||||
def 'openid-login default login page'() {
|
||||
setup:
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(method:'GET',requestURI:'/login')
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
httpAutoConfig {
|
||||
'openid-login'()
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
|
||||
def 'openid-login default login page'() {
|
||||
setup:
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(method:'GET',requestURI:'/login')
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
httpAutoConfig {
|
||||
'openid-login'()
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
when:
|
||||
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>
|
||||
<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><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>
|
||||
<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>"""
|
||||
}
|
||||
}
|
||||
|
||||
def 'openid-login default login page custom attributes'() {
|
||||
setup:
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(method:'GET',requestURI:'/login')
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
httpAutoConfig {
|
||||
'openid-login'('login-processing-url':'/login_custom')
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
|
||||
def 'openid-login default login page custom attributes'() {
|
||||
setup:
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(method:'GET',requestURI:'/login')
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
httpAutoConfig {
|
||||
'openid-login'('login-processing-url':'/login_custom')
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
when:
|
||||
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>
|
||||
<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><h3>Login with OpenID Identity</h3><form name='oidf' action='/login_custom' 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>
|
||||
<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>"""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+75
-75
@@ -15,93 +15,93 @@ import org.springframework.util.ReflectionUtils;
|
||||
*/
|
||||
class FormLoginConfigTests extends AbstractHttpConfigTests {
|
||||
|
||||
def formLoginWithNoLoginPageAddsDefaultLoginPageFilter() {
|
||||
httpAutoConfig('ant') {
|
||||
form-login()
|
||||
}
|
||||
createAppContext()
|
||||
filtersMatchExpectedAutoConfigList();
|
||||
}
|
||||
def formLoginWithNoLoginPageAddsDefaultLoginPageFilter() {
|
||||
httpAutoConfig('ant') {
|
||||
form-login()
|
||||
}
|
||||
createAppContext()
|
||||
filtersMatchExpectedAutoConfigList();
|
||||
}
|
||||
|
||||
def 'Form login alwaysUseDefaultTarget sets correct property'() {
|
||||
xml.http {
|
||||
'form-login'('default-target-url':'/default', 'always-use-default-target': 'true')
|
||||
}
|
||||
createAppContext()
|
||||
def filter = getFilter(UsernamePasswordAuthenticationFilter.class);
|
||||
def 'Form login alwaysUseDefaultTarget sets correct property'() {
|
||||
xml.http {
|
||||
'form-login'('default-target-url':'/default', 'always-use-default-target': 'true')
|
||||
}
|
||||
createAppContext()
|
||||
def filter = getFilter(UsernamePasswordAuthenticationFilter.class);
|
||||
|
||||
expect:
|
||||
FieldUtils.getFieldValue(filter, 'successHandler.defaultTargetUrl') == '/default';
|
||||
FieldUtils.getFieldValue(filter, 'successHandler.alwaysUseDefaultTargetUrl');
|
||||
}
|
||||
expect:
|
||||
FieldUtils.getFieldValue(filter, 'successHandler.defaultTargetUrl') == '/default';
|
||||
FieldUtils.getFieldValue(filter, 'successHandler.alwaysUseDefaultTargetUrl');
|
||||
}
|
||||
|
||||
def 'form-login attributes support SpEL'() {
|
||||
setup:
|
||||
def spelUrl = '#{T(org.springframework.security.config.http.WebConfigUtilsTest).URL}'
|
||||
def expectedUrl = WebConfigUtilsTest.URL
|
||||
when:
|
||||
xml.http {
|
||||
'form-login'('default-target-url': spelUrl , 'authentication-failure-url': spelUrl, 'login-page': spelUrl)
|
||||
}
|
||||
createAppContext()
|
||||
def unPwdFilter = getFilter(UsernamePasswordAuthenticationFilter)
|
||||
def exTransFilter = getFilter(ExceptionTranslationFilter)
|
||||
def 'form-login attributes support SpEL'() {
|
||||
setup:
|
||||
def spelUrl = '#{T(org.springframework.security.config.http.WebConfigUtilsTest).URL}'
|
||||
def expectedUrl = WebConfigUtilsTest.URL
|
||||
when:
|
||||
xml.http {
|
||||
'form-login'('default-target-url': spelUrl , 'authentication-failure-url': spelUrl, 'login-page': spelUrl)
|
||||
}
|
||||
createAppContext()
|
||||
def unPwdFilter = getFilter(UsernamePasswordAuthenticationFilter)
|
||||
def exTransFilter = getFilter(ExceptionTranslationFilter)
|
||||
|
||||
then:
|
||||
unPwdFilter.successHandler.defaultTargetUrl == expectedUrl
|
||||
unPwdFilter
|
||||
FieldUtils.getFieldValue(unPwdFilter, 'successHandler.defaultTargetUrl') == expectedUrl
|
||||
FieldUtils.getFieldValue(unPwdFilter, 'failureHandler.defaultFailureUrl') == expectedUrl
|
||||
FieldUtils.getFieldValue(exTransFilter, 'authenticationEntryPoint.loginFormUrl') == expectedUrl
|
||||
}
|
||||
then:
|
||||
unPwdFilter.successHandler.defaultTargetUrl == expectedUrl
|
||||
unPwdFilter
|
||||
FieldUtils.getFieldValue(unPwdFilter, 'successHandler.defaultTargetUrl') == expectedUrl
|
||||
FieldUtils.getFieldValue(unPwdFilter, 'failureHandler.defaultFailureUrl') == expectedUrl
|
||||
FieldUtils.getFieldValue(exTransFilter, 'authenticationEntryPoint.loginFormUrl') == expectedUrl
|
||||
}
|
||||
|
||||
def invalidLoginPageIsDetected() {
|
||||
when:
|
||||
xml.http {
|
||||
'form-login'('login-page': 'noLeadingSlash')
|
||||
}
|
||||
createAppContext()
|
||||
def invalidLoginPageIsDetected() {
|
||||
when:
|
||||
xml.http {
|
||||
'form-login'('login-page': 'noLeadingSlash')
|
||||
}
|
||||
createAppContext()
|
||||
|
||||
then:
|
||||
BeanCreationException e = thrown();
|
||||
}
|
||||
then:
|
||||
BeanCreationException e = thrown();
|
||||
}
|
||||
|
||||
def invalidDefaultTargetUrlIsDetected() {
|
||||
when:
|
||||
xml.http {
|
||||
'form-login'('default-target-url': 'noLeadingSlash')
|
||||
}
|
||||
createAppContext()
|
||||
def invalidDefaultTargetUrlIsDetected() {
|
||||
when:
|
||||
xml.http {
|
||||
'form-login'('default-target-url': 'noLeadingSlash')
|
||||
}
|
||||
createAppContext()
|
||||
|
||||
then:
|
||||
BeanCreationException e = thrown();
|
||||
}
|
||||
then:
|
||||
BeanCreationException e = thrown();
|
||||
}
|
||||
|
||||
def customSuccessAndFailureHandlersCanBeSetThroughTheNamespace() {
|
||||
xml.http {
|
||||
'form-login'('authentication-success-handler-ref': 'sh', 'authentication-failure-handler-ref':'fh')
|
||||
}
|
||||
bean('sh', SavedRequestAwareAuthenticationSuccessHandler.class.name)
|
||||
bean('fh', SimpleUrlAuthenticationFailureHandler.class.name)
|
||||
createAppContext()
|
||||
def customSuccessAndFailureHandlersCanBeSetThroughTheNamespace() {
|
||||
xml.http {
|
||||
'form-login'('authentication-success-handler-ref': 'sh', 'authentication-failure-handler-ref':'fh')
|
||||
}
|
||||
bean('sh', SavedRequestAwareAuthenticationSuccessHandler.class.name)
|
||||
bean('fh', SimpleUrlAuthenticationFailureHandler.class.name)
|
||||
createAppContext()
|
||||
|
||||
def apf = getFilter(UsernamePasswordAuthenticationFilter.class);
|
||||
def apf = getFilter(UsernamePasswordAuthenticationFilter.class);
|
||||
|
||||
expect:
|
||||
FieldUtils.getFieldValue(apf, "successHandler") == appContext.getBean("sh");
|
||||
FieldUtils.getFieldValue(apf, "failureHandler") == appContext.getBean("fh")
|
||||
}
|
||||
expect:
|
||||
FieldUtils.getFieldValue(apf, "successHandler") == appContext.getBean("sh");
|
||||
FieldUtils.getFieldValue(apf, "failureHandler") == appContext.getBean("fh")
|
||||
}
|
||||
|
||||
def usernameAndPasswordParametersCanBeSetThroughNamespace() {
|
||||
xml.http {
|
||||
'form-login'('username-parameter': 'xname', 'password-parameter':'xpass')
|
||||
}
|
||||
createAppContext()
|
||||
def usernameAndPasswordParametersCanBeSetThroughNamespace() {
|
||||
xml.http {
|
||||
'form-login'('username-parameter': 'xname', 'password-parameter':'xpass')
|
||||
}
|
||||
createAppContext()
|
||||
|
||||
def apf = getFilter(UsernamePasswordAuthenticationFilter.class);
|
||||
def apf = getFilter(UsernamePasswordAuthenticationFilter.class);
|
||||
|
||||
expect:
|
||||
apf.usernameParameter == 'xname';
|
||||
apf.passwordParameter == 'xpass'
|
||||
}
|
||||
expect:
|
||||
apf.usernameParameter == 'xname';
|
||||
apf.passwordParameter == 'xpass'
|
||||
}
|
||||
}
|
||||
|
||||
+15
-15
@@ -43,20 +43,20 @@ import static org.mockito.Mockito.*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
class HttpConfigTests extends AbstractHttpConfigTests {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest('GET','/secure')
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
MockHttpServletRequest request = new MockHttpServletRequest('GET','/secure')
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
|
||||
def 'http minimal configuration works'() {
|
||||
setup:
|
||||
xml.http() {}
|
||||
createAppContext("""<user-service>
|
||||
<user name="user" password="password" authorities="ROLE_USER" />
|
||||
</user-service>""")
|
||||
when: 'request protected URL'
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'sent to login page'
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == 'http://localhost/login'
|
||||
}
|
||||
def 'http minimal configuration works'() {
|
||||
setup:
|
||||
xml.http() {}
|
||||
createAppContext("""<user-service>
|
||||
<user name="user" password="password" authorities="ROLE_USER" />
|
||||
</user-service>""")
|
||||
when: 'request protected URL'
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'sent to login page'
|
||||
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
|
||||
response.redirectedUrl == 'http://localhost/login'
|
||||
}
|
||||
}
|
||||
+616
-616
File diff suppressed because it is too large
Load Diff
+113
-113
@@ -23,132 +23,132 @@ import javax.servlet.Filter
|
||||
*/
|
||||
class OpenIDConfigTests extends AbstractHttpConfigTests {
|
||||
|
||||
def openIDAndFormLoginWorkTogether() {
|
||||
xml.http() {
|
||||
'openid-login'()
|
||||
'form-login'()
|
||||
}
|
||||
createAppContext()
|
||||
def openIDAndFormLoginWorkTogether() {
|
||||
xml.http() {
|
||||
'openid-login'()
|
||||
'form-login'()
|
||||
}
|
||||
createAppContext()
|
||||
|
||||
def etf = getFilter(ExceptionTranslationFilter)
|
||||
def ap = etf.getAuthenticationEntryPoint();
|
||||
def etf = getFilter(ExceptionTranslationFilter)
|
||||
def ap = etf.getAuthenticationEntryPoint();
|
||||
|
||||
expect:
|
||||
ap.loginFormUrl == "/login"
|
||||
// Default login filter should be present since we haven't specified any login URLs
|
||||
getFilter(DefaultLoginPageGeneratingFilter) != null
|
||||
}
|
||||
expect:
|
||||
ap.loginFormUrl == "/login"
|
||||
// Default login filter should be present since we haven't specified any login URLs
|
||||
getFilter(DefaultLoginPageGeneratingFilter) != null
|
||||
}
|
||||
|
||||
def formLoginEntryPointTakesPrecedenceIfLoginUrlIsSet() {
|
||||
xml.http() {
|
||||
'openid-login'()
|
||||
'form-login'('login-page': '/form-page')
|
||||
}
|
||||
createAppContext()
|
||||
def formLoginEntryPointTakesPrecedenceIfLoginUrlIsSet() {
|
||||
xml.http() {
|
||||
'openid-login'()
|
||||
'form-login'('login-page': '/form-page')
|
||||
}
|
||||
createAppContext()
|
||||
|
||||
expect:
|
||||
getFilter(ExceptionTranslationFilter).authenticationEntryPoint.loginFormUrl == '/form-page'
|
||||
}
|
||||
expect:
|
||||
getFilter(ExceptionTranslationFilter).authenticationEntryPoint.loginFormUrl == '/form-page'
|
||||
}
|
||||
|
||||
def openIDEntryPointTakesPrecedenceIfLoginUrlIsSet() {
|
||||
xml.http() {
|
||||
'openid-login'('login-page': '/openid-page')
|
||||
'form-login'()
|
||||
}
|
||||
createAppContext()
|
||||
def openIDEntryPointTakesPrecedenceIfLoginUrlIsSet() {
|
||||
xml.http() {
|
||||
'openid-login'('login-page': '/openid-page')
|
||||
'form-login'()
|
||||
}
|
||||
createAppContext()
|
||||
|
||||
expect:
|
||||
getFilter(ExceptionTranslationFilter).authenticationEntryPoint.loginFormUrl == '/openid-page'
|
||||
}
|
||||
expect:
|
||||
getFilter(ExceptionTranslationFilter).authenticationEntryPoint.loginFormUrl == '/openid-page'
|
||||
}
|
||||
|
||||
def multipleLoginPagesCausesError() {
|
||||
when:
|
||||
xml.http() {
|
||||
'openid-login'('login-page': '/openid-page')
|
||||
'form-login'('login-page': '/form-page')
|
||||
}
|
||||
createAppContext()
|
||||
then:
|
||||
thrown(BeanDefinitionParsingException)
|
||||
}
|
||||
def multipleLoginPagesCausesError() {
|
||||
when:
|
||||
xml.http() {
|
||||
'openid-login'('login-page': '/openid-page')
|
||||
'form-login'('login-page': '/form-page')
|
||||
}
|
||||
createAppContext()
|
||||
then:
|
||||
thrown(BeanDefinitionParsingException)
|
||||
}
|
||||
|
||||
def openIDAndRememberMeWorkTogether() {
|
||||
xml.debug()
|
||||
xml.http() {
|
||||
interceptUrl('/**', 'denyAll')
|
||||
'openid-login'()
|
||||
'remember-me'()
|
||||
'csrf'(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
def openIDAndRememberMeWorkTogether() {
|
||||
xml.debug()
|
||||
xml.http() {
|
||||
interceptUrl('/**', 'denyAll')
|
||||
'openid-login'()
|
||||
'remember-me'()
|
||||
'csrf'(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
|
||||
// Default login filter should be present since we haven't specified any login URLs
|
||||
def loginFilter = getFilter(DefaultLoginPageGeneratingFilter)
|
||||
def openIDFilter = getFilter(OpenIDAuthenticationFilter)
|
||||
openIDFilter.setConsumer(new OpenIDConsumer() {
|
||||
public String beginConsumption(HttpServletRequest req, String claimedIdentity, String returnToUrl, String realm)
|
||||
throws OpenIDConsumerException {
|
||||
return "http://testopenid.com?openid.return_to=" + returnToUrl;
|
||||
}
|
||||
// Default login filter should be present since we haven't specified any login URLs
|
||||
def loginFilter = getFilter(DefaultLoginPageGeneratingFilter)
|
||||
def openIDFilter = getFilter(OpenIDAuthenticationFilter)
|
||||
openIDFilter.setConsumer(new OpenIDConsumer() {
|
||||
public String beginConsumption(HttpServletRequest req, String claimedIdentity, String returnToUrl, String realm)
|
||||
throws OpenIDConsumerException {
|
||||
return "http://testopenid.com?openid.return_to=" + returnToUrl;
|
||||
}
|
||||
|
||||
public OpenIDAuthenticationToken endConsumption(HttpServletRequest req) throws OpenIDConsumerException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
})
|
||||
Set<String> returnToUrlParameters = new HashSet<String>()
|
||||
returnToUrlParameters.add(AbstractRememberMeServices.DEFAULT_PARAMETER)
|
||||
openIDFilter.setReturnToUrlParameters(returnToUrlParameters)
|
||||
assert loginFilter.openIDrememberMeParameter != null
|
||||
public OpenIDAuthenticationToken endConsumption(HttpServletRequest req) throws OpenIDConsumerException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
})
|
||||
Set<String> returnToUrlParameters = new HashSet<String>()
|
||||
returnToUrlParameters.add(AbstractRememberMeServices.DEFAULT_PARAMETER)
|
||||
openIDFilter.setReturnToUrlParameters(returnToUrlParameters)
|
||||
assert loginFilter.openIDrememberMeParameter != null
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(method:'GET');
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(method:'GET');
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
when: "Initial request is made"
|
||||
Filter fc = appContext.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN)
|
||||
request.setServletPath("/something.html")
|
||||
fc.doFilter(request, response, new MockFilterChain())
|
||||
then: "Redirected to login"
|
||||
response.getRedirectedUrl().endsWith("/login")
|
||||
when: "Login page is requested"
|
||||
request.setServletPath("/login")
|
||||
request.setRequestURI("/login")
|
||||
response = new MockHttpServletResponse()
|
||||
fc.doFilter(request, response, new MockFilterChain())
|
||||
then: "Remember-me choice is added to page"
|
||||
response.getContentAsString().contains(AbstractRememberMeServices.DEFAULT_PARAMETER)
|
||||
when: "Login is submitted with remember-me selected"
|
||||
request.servletPath = "/login/openid"
|
||||
request.setParameter(OpenIDAuthenticationFilter.DEFAULT_CLAIMED_IDENTITY_FIELD, "http://hey.openid.com/")
|
||||
request.setParameter(AbstractRememberMeServices.DEFAULT_PARAMETER, "on")
|
||||
response = new MockHttpServletResponse();
|
||||
fc.doFilter(request, response, new MockFilterChain());
|
||||
String expectedReturnTo = request.getRequestURL().append("?")
|
||||
.append(AbstractRememberMeServices.DEFAULT_PARAMETER)
|
||||
.append("=").append("on").toString();
|
||||
then: "return_to URL contains remember-me choice"
|
||||
response.getRedirectedUrl() == "http://testopenid.com?openid.return_to=" + expectedReturnTo
|
||||
}
|
||||
when: "Initial request is made"
|
||||
Filter fc = appContext.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN)
|
||||
request.setServletPath("/something.html")
|
||||
fc.doFilter(request, response, new MockFilterChain())
|
||||
then: "Redirected to login"
|
||||
response.getRedirectedUrl().endsWith("/login")
|
||||
when: "Login page is requested"
|
||||
request.setServletPath("/login")
|
||||
request.setRequestURI("/login")
|
||||
response = new MockHttpServletResponse()
|
||||
fc.doFilter(request, response, new MockFilterChain())
|
||||
then: "Remember-me choice is added to page"
|
||||
response.getContentAsString().contains(AbstractRememberMeServices.DEFAULT_PARAMETER)
|
||||
when: "Login is submitted with remember-me selected"
|
||||
request.servletPath = "/login/openid"
|
||||
request.setParameter(OpenIDAuthenticationFilter.DEFAULT_CLAIMED_IDENTITY_FIELD, "http://hey.openid.com/")
|
||||
request.setParameter(AbstractRememberMeServices.DEFAULT_PARAMETER, "on")
|
||||
response = new MockHttpServletResponse();
|
||||
fc.doFilter(request, response, new MockFilterChain());
|
||||
String expectedReturnTo = request.getRequestURL().append("?")
|
||||
.append(AbstractRememberMeServices.DEFAULT_PARAMETER)
|
||||
.append("=").append("on").toString();
|
||||
then: "return_to URL contains remember-me choice"
|
||||
response.getRedirectedUrl() == "http://testopenid.com?openid.return_to=" + expectedReturnTo
|
||||
}
|
||||
|
||||
def openIDWithAttributeExchangeConfigurationIsParsedCorrectly() {
|
||||
xml.http() {
|
||||
'openid-login'() {
|
||||
'attribute-exchange'() {
|
||||
'openid-attribute'(name: 'nickname', type: 'http://schema.openid.net/namePerson/friendly')
|
||||
'openid-attribute'(name: 'email', type: 'http://schema.openid.net/contact/email', required: 'true',
|
||||
'count': '2')
|
||||
}
|
||||
}
|
||||
}
|
||||
createAppContext()
|
||||
def openIDWithAttributeExchangeConfigurationIsParsedCorrectly() {
|
||||
xml.http() {
|
||||
'openid-login'() {
|
||||
'attribute-exchange'() {
|
||||
'openid-attribute'(name: 'nickname', type: 'http://schema.openid.net/namePerson/friendly')
|
||||
'openid-attribute'(name: 'email', type: 'http://schema.openid.net/contact/email', required: 'true',
|
||||
'count': '2')
|
||||
}
|
||||
}
|
||||
}
|
||||
createAppContext()
|
||||
|
||||
List attributes = getFilter(OpenIDAuthenticationFilter).consumer.attributesToFetchFactory.createAttributeList('http://someid')
|
||||
List attributes = getFilter(OpenIDAuthenticationFilter).consumer.attributesToFetchFactory.createAttributeList('http://someid')
|
||||
|
||||
expect:
|
||||
attributes.size() == 2
|
||||
attributes[0].name == 'nickname'
|
||||
attributes[0].type == 'http://schema.openid.net/namePerson/friendly'
|
||||
!attributes[0].required
|
||||
attributes[1].required
|
||||
attributes[1].getCount() == 2
|
||||
}
|
||||
expect:
|
||||
attributes.size() == 2
|
||||
attributes[0].name == 'nickname'
|
||||
attributes[0].type == 'http://schema.openid.net/namePerson/friendly'
|
||||
!attributes[0].required
|
||||
attributes[1].required
|
||||
attributes[1].getCount() == 2
|
||||
}
|
||||
}
|
||||
|
||||
+68
-68
@@ -5,7 +5,7 @@
|
||||
* 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
|
||||
* 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,
|
||||
@@ -85,80 +85,80 @@ import org.springframework.security.authentication.AuthenticationManager
|
||||
class InterceptUrlConfigTests extends AbstractHttpConfigTests {
|
||||
|
||||
def "SEC-2256: intercept-url method is not given priority"() {
|
||||
when:
|
||||
httpAutoConfig {
|
||||
'intercept-url'(pattern: '/anyurl', access: "ROLE_USER")
|
||||
'intercept-url'(pattern: '/anyurl', 'method':'GET',access: 'ROLE_ADMIN')
|
||||
}
|
||||
createAppContext()
|
||||
when:
|
||||
httpAutoConfig {
|
||||
'intercept-url'(pattern: '/anyurl', access: "ROLE_USER")
|
||||
'intercept-url'(pattern: '/anyurl', 'method':'GET',access: 'ROLE_ADMIN')
|
||||
}
|
||||
createAppContext()
|
||||
|
||||
def fids = getFilter(FilterSecurityInterceptor).securityMetadataSource
|
||||
def attrs = fids.getAttributes(createFilterinvocation("/anyurl", "GET"))
|
||||
def attrsPost = fids.getAttributes(createFilterinvocation("/anyurl", "POST"))
|
||||
def fids = getFilter(FilterSecurityInterceptor).securityMetadataSource
|
||||
def attrs = fids.getAttributes(createFilterinvocation("/anyurl", "GET"))
|
||||
def attrsPost = fids.getAttributes(createFilterinvocation("/anyurl", "POST"))
|
||||
|
||||
then:
|
||||
attrs.size() == 1
|
||||
attrs.contains(new SecurityConfig("ROLE_USER"))
|
||||
attrsPost.size() == 1
|
||||
attrsPost.contains(new SecurityConfig("ROLE_USER"))
|
||||
then:
|
||||
attrs.size() == 1
|
||||
attrs.contains(new SecurityConfig("ROLE_USER"))
|
||||
attrsPost.size() == 1
|
||||
attrsPost.contains(new SecurityConfig("ROLE_USER"))
|
||||
}
|
||||
|
||||
def "SEC-2355: intercept-url support patch"() {
|
||||
setup:
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(method:'GET')
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
xml.http('use-expressions':false) {
|
||||
'http-basic'()
|
||||
'intercept-url'(pattern: '/**', 'method':'PATCH',access: 'ROLE_ADMIN')
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
when: 'Method other than PATCH is used'
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'The response is OK'
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when: 'Method of PATCH is used'
|
||||
request = new MockHttpServletRequest(method:'PATCH')
|
||||
response = new MockHttpServletResponse()
|
||||
chain = new MockFilterChain()
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then: 'The response is unauthorized'
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
setup:
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(method:'GET')
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
xml.http('use-expressions':false) {
|
||||
'http-basic'()
|
||||
'intercept-url'(pattern: '/**', 'method':'PATCH',access: 'ROLE_ADMIN')
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
when: 'Method other than PATCH is used'
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'The response is OK'
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when: 'Method of PATCH is used'
|
||||
request = new MockHttpServletRequest(method:'PATCH')
|
||||
response = new MockHttpServletResponse()
|
||||
chain = new MockFilterChain()
|
||||
springSecurityFilterChain.doFilter(request, response, chain)
|
||||
then: 'The response is unauthorized'
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
}
|
||||
|
||||
def "intercept-url supports hasAnyRoles"() {
|
||||
setup:
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(method:'GET')
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
xml.http('use-expressions':true) {
|
||||
'http-basic'()
|
||||
'intercept-url'(pattern: '/**', access: "hasAnyRole('ROLE_DEVELOPER','ROLE_USER')")
|
||||
csrf(disabled:true)
|
||||
}
|
||||
when:
|
||||
createAppContext()
|
||||
then: 'no error'
|
||||
noExceptionThrown()
|
||||
when: 'ROLE_USER can access'
|
||||
login(request, 'user', 'password')
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'The response is OK'
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when: 'ROLE_A cannot access'
|
||||
request = new MockHttpServletRequest(method:'GET')
|
||||
response = new MockHttpServletResponse()
|
||||
chain = new MockFilterChain()
|
||||
login(request, 'bob', 'bobspassword')
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'The response is Forbidden'
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
def "intercept-url supports hasAnyRoles"() {
|
||||
setup:
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(method:'GET')
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
xml.http('use-expressions':true) {
|
||||
'http-basic'()
|
||||
'intercept-url'(pattern: '/**', access: "hasAnyRole('ROLE_DEVELOPER','ROLE_USER')")
|
||||
csrf(disabled:true)
|
||||
}
|
||||
when:
|
||||
createAppContext()
|
||||
then: 'no error'
|
||||
noExceptionThrown()
|
||||
when: 'ROLE_USER can access'
|
||||
login(request, 'user', 'password')
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'The response is OK'
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
when: 'ROLE_A cannot access'
|
||||
request = new MockHttpServletRequest(method:'GET')
|
||||
response = new MockHttpServletResponse()
|
||||
chain = new MockFilterChain()
|
||||
login(request, 'bob', 'bobspassword')
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: 'The response is Forbidden'
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
def login(MockHttpServletRequest request, String username, String password) {
|
||||
String toEncode = username + ':' + password
|
||||
request.addHeader('Authorization','Basic ' + new String(Base64.encode(toEncode.getBytes('UTF-8'))))
|
||||
}
|
||||
def login(MockHttpServletRequest request, String username, String password) {
|
||||
String toEncode = username + ':' + password
|
||||
request.addHeader('Authorization','Basic ' + new String(Base64.encode(toEncode.getBytes('UTF-8'))))
|
||||
}
|
||||
}
|
||||
+668
-668
File diff suppressed because it is too large
Load Diff
+94
-94
@@ -24,110 +24,110 @@ import org.springframework.security.web.SecurityFilterChain
|
||||
*/
|
||||
class MultiHttpBlockConfigTests extends AbstractHttpConfigTests {
|
||||
|
||||
def multipleHttpElementsAreSupported () {
|
||||
when: "Two <http> elements are used"
|
||||
xml.http(pattern: '/stateless/**', 'create-session': 'stateless') {
|
||||
'http-basic'()
|
||||
}
|
||||
xml.http(pattern: '/stateful/**') {
|
||||
'form-login'()
|
||||
}
|
||||
createAppContext()
|
||||
FilterChainProxy fcp = appContext.getBean(BeanIds.FILTER_CHAIN_PROXY)
|
||||
def filterChains = fcp.getFilterChains();
|
||||
def multipleHttpElementsAreSupported () {
|
||||
when: "Two <http> elements are used"
|
||||
xml.http(pattern: '/stateless/**', 'create-session': 'stateless') {
|
||||
'http-basic'()
|
||||
}
|
||||
xml.http(pattern: '/stateful/**') {
|
||||
'form-login'()
|
||||
}
|
||||
createAppContext()
|
||||
FilterChainProxy fcp = appContext.getBean(BeanIds.FILTER_CHAIN_PROXY)
|
||||
def filterChains = fcp.getFilterChains();
|
||||
|
||||
then:
|
||||
filterChains.size() == 2
|
||||
filterChains[0].requestMatcher.pattern == '/stateless/**'
|
||||
}
|
||||
then:
|
||||
filterChains.size() == 2
|
||||
filterChains[0].requestMatcher.pattern == '/stateless/**'
|
||||
}
|
||||
|
||||
def duplicateHttpElementsAreRejected () {
|
||||
when: "Two <http> elements are used"
|
||||
xml.http('create-session': 'stateless') {
|
||||
'http-basic'()
|
||||
}
|
||||
xml.http() {
|
||||
'form-login'()
|
||||
}
|
||||
createAppContext()
|
||||
then:
|
||||
BeanCreationException e = thrown()
|
||||
e.cause instanceof IllegalArgumentException
|
||||
}
|
||||
def duplicateHttpElementsAreRejected () {
|
||||
when: "Two <http> elements are used"
|
||||
xml.http('create-session': 'stateless') {
|
||||
'http-basic'()
|
||||
}
|
||||
xml.http() {
|
||||
'form-login'()
|
||||
}
|
||||
createAppContext()
|
||||
then:
|
||||
BeanCreationException e = thrown()
|
||||
e.cause instanceof IllegalArgumentException
|
||||
}
|
||||
|
||||
def duplicatePatternsAreRejected () {
|
||||
when: "Two <http> elements with the same pattern are used"
|
||||
xml.http(pattern: '/stateless/**', 'create-session': 'stateless') {
|
||||
'http-basic'()
|
||||
}
|
||||
xml.http(pattern: '/stateless/**') {
|
||||
'form-login'()
|
||||
}
|
||||
createAppContext()
|
||||
then:
|
||||
BeanCreationException e = thrown()
|
||||
e.cause instanceof IllegalArgumentException
|
||||
}
|
||||
def duplicatePatternsAreRejected () {
|
||||
when: "Two <http> elements with the same pattern are used"
|
||||
xml.http(pattern: '/stateless/**', 'create-session': 'stateless') {
|
||||
'http-basic'()
|
||||
}
|
||||
xml.http(pattern: '/stateless/**') {
|
||||
'form-login'()
|
||||
}
|
||||
createAppContext()
|
||||
then:
|
||||
BeanCreationException e = thrown()
|
||||
e.cause instanceof IllegalArgumentException
|
||||
}
|
||||
|
||||
|
||||
def 'SEC-1937: http@authentication-manager-ref and multi authentication-mananager'() {
|
||||
setup:
|
||||
xml.http('authentication-manager-ref' : 'authManager', 'pattern' : '/first/**') {
|
||||
'form-login'('login-processing-url': '/first/login')
|
||||
csrf(disabled:true)
|
||||
}
|
||||
xml.http('authentication-manager-ref' : 'authManager2') {
|
||||
'form-login'()
|
||||
csrf(disabled:true)
|
||||
}
|
||||
mockBean(UserDetailsService,'uds')
|
||||
mockBean(UserDetailsService,'uds2')
|
||||
createAppContext("""
|
||||
def 'SEC-1937: http@authentication-manager-ref and multi authentication-mananager'() {
|
||||
setup:
|
||||
xml.http('authentication-manager-ref' : 'authManager', 'pattern' : '/first/**') {
|
||||
'form-login'('login-processing-url': '/first/login')
|
||||
csrf(disabled:true)
|
||||
}
|
||||
xml.http('authentication-manager-ref' : 'authManager2') {
|
||||
'form-login'()
|
||||
csrf(disabled:true)
|
||||
}
|
||||
mockBean(UserDetailsService,'uds')
|
||||
mockBean(UserDetailsService,'uds2')
|
||||
createAppContext("""
|
||||
<authentication-manager id="authManager">
|
||||
<authentication-provider user-service-ref="uds" />
|
||||
<authentication-provider user-service-ref="uds" />
|
||||
</authentication-manager>
|
||||
<authentication-manager id="authManager2">
|
||||
<authentication-provider user-service-ref="uds2" />
|
||||
<authentication-provider user-service-ref="uds2" />
|
||||
</authentication-manager>
|
||||
""")
|
||||
UserDetailsService uds = appContext.getBean('uds')
|
||||
UserDetailsService uds2 = appContext.getBean('uds2')
|
||||
when:
|
||||
MockHttpServletRequest request = new MockHttpServletRequest()
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
request.servletPath = "/first/login"
|
||||
request.requestURI = "/first/login"
|
||||
request.method = 'POST'
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
verify(uds).loadUserByUsername(anyString()) || true
|
||||
verifyZeroInteractions(uds2) || true
|
||||
when:
|
||||
MockHttpServletRequest request2 = new MockHttpServletRequest()
|
||||
MockHttpServletResponse response2 = new MockHttpServletResponse()
|
||||
MockFilterChain chain2 = new MockFilterChain()
|
||||
request2.servletPath = "/login"
|
||||
request2.requestURI = "/login"
|
||||
request2.method = 'POST'
|
||||
springSecurityFilterChain.doFilter(request2,response2,chain2)
|
||||
then:
|
||||
verify(uds2).loadUserByUsername(anyString()) || true
|
||||
verifyNoMoreInteractions(uds) || true
|
||||
}
|
||||
UserDetailsService uds = appContext.getBean('uds')
|
||||
UserDetailsService uds2 = appContext.getBean('uds2')
|
||||
when:
|
||||
MockHttpServletRequest request = new MockHttpServletRequest()
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
request.servletPath = "/first/login"
|
||||
request.requestURI = "/first/login"
|
||||
request.method = 'POST'
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
verify(uds).loadUserByUsername(anyString()) || true
|
||||
verifyZeroInteractions(uds2) || true
|
||||
when:
|
||||
MockHttpServletRequest request2 = new MockHttpServletRequest()
|
||||
MockHttpServletResponse response2 = new MockHttpServletResponse()
|
||||
MockFilterChain chain2 = new MockFilterChain()
|
||||
request2.servletPath = "/login"
|
||||
request2.requestURI = "/login"
|
||||
request2.method = 'POST'
|
||||
springSecurityFilterChain.doFilter(request2,response2,chain2)
|
||||
then:
|
||||
verify(uds2).loadUserByUsername(anyString()) || true
|
||||
verifyNoMoreInteractions(uds) || true
|
||||
}
|
||||
|
||||
def multipleAuthenticationManagersWorks () {
|
||||
xml.http(name: 'basic', pattern: '/basic/**', ) {
|
||||
'http-basic'()
|
||||
}
|
||||
xml.http(pattern: '/form/**') {
|
||||
'form-login'()
|
||||
}
|
||||
createAppContext()
|
||||
FilterChainProxy fcp = appContext.getBean(BeanIds.FILTER_CHAIN_PROXY)
|
||||
SecurityFilterChain basicChain = fcp.filterChains[0];
|
||||
def multipleAuthenticationManagersWorks () {
|
||||
xml.http(name: 'basic', pattern: '/basic/**', ) {
|
||||
'http-basic'()
|
||||
}
|
||||
xml.http(pattern: '/form/**') {
|
||||
'form-login'()
|
||||
}
|
||||
createAppContext()
|
||||
FilterChainProxy fcp = appContext.getBean(BeanIds.FILTER_CHAIN_PROXY)
|
||||
SecurityFilterChain basicChain = fcp.filterChains[0];
|
||||
|
||||
expect:
|
||||
Assert.assertSame (basicChain, appContext.getBean('basic'))
|
||||
}
|
||||
expect:
|
||||
Assert.assertSame (basicChain, appContext.getBean('basic'))
|
||||
}
|
||||
}
|
||||
|
||||
+112
-112
@@ -17,140 +17,140 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic
|
||||
|
||||
class PlaceHolderAndELConfigTests extends AbstractHttpConfigTests {
|
||||
|
||||
def setup() {
|
||||
// Add a PropertyPlaceholderConfigurer to the context for all the tests
|
||||
bean(PropertyPlaceholderConfigurer.class.name, PropertyPlaceholderConfigurer.class)
|
||||
}
|
||||
def setup() {
|
||||
// Add a PropertyPlaceholderConfigurer to the context for all the tests
|
||||
bean(PropertyPlaceholderConfigurer.class.name, PropertyPlaceholderConfigurer.class)
|
||||
}
|
||||
|
||||
def unsecuredPatternSupportsPlaceholderForPattern() {
|
||||
System.setProperty("pattern.nofilters", "/unprotected");
|
||||
def unsecuredPatternSupportsPlaceholderForPattern() {
|
||||
System.setProperty("pattern.nofilters", "/unprotected");
|
||||
|
||||
xml.http(pattern: '${pattern.nofilters}', security: 'none')
|
||||
httpAutoConfig() {
|
||||
interceptUrl('/**', 'ROLE_A')
|
||||
}
|
||||
createAppContext()
|
||||
xml.http(pattern: '${pattern.nofilters}', security: 'none')
|
||||
httpAutoConfig() {
|
||||
interceptUrl('/**', 'ROLE_A')
|
||||
}
|
||||
createAppContext()
|
||||
|
||||
List filters = getFilters("/unprotected");
|
||||
List filters = getFilters("/unprotected");
|
||||
|
||||
expect:
|
||||
filters.size() == 0
|
||||
}
|
||||
expect:
|
||||
filters.size() == 0
|
||||
}
|
||||
|
||||
// SEC-1201
|
||||
def interceptUrlsAndFormLoginSupportPropertyPlaceholders() {
|
||||
System.setProperty("secure.Url", "/Secure");
|
||||
System.setProperty("secure.role", "ROLE_A");
|
||||
System.setProperty("login.page", "/loginPage");
|
||||
System.setProperty("default.target", "/defaultTarget");
|
||||
System.setProperty("auth.failure", "/authFailure");
|
||||
// SEC-1201
|
||||
def interceptUrlsAndFormLoginSupportPropertyPlaceholders() {
|
||||
System.setProperty("secure.Url", "/Secure");
|
||||
System.setProperty("secure.role", "ROLE_A");
|
||||
System.setProperty("login.page", "/loginPage");
|
||||
System.setProperty("default.target", "/defaultTarget");
|
||||
System.setProperty("auth.failure", "/authFailure");
|
||||
|
||||
xml.http(pattern: '${login.page}', security: 'none')
|
||||
xml.http('use-expressions':false) {
|
||||
interceptUrl('${secure.Url}', '${secure.role}')
|
||||
'form-login'('login-page':'${login.page}', 'default-target-url': '${default.target}',
|
||||
'authentication-failure-url':'${auth.failure}');
|
||||
}
|
||||
createAppContext();
|
||||
xml.http(pattern: '${login.page}', security: 'none')
|
||||
xml.http('use-expressions':false) {
|
||||
interceptUrl('${secure.Url}', '${secure.role}')
|
||||
'form-login'('login-page':'${login.page}', 'default-target-url': '${default.target}',
|
||||
'authentication-failure-url':'${auth.failure}');
|
||||
}
|
||||
createAppContext();
|
||||
|
||||
expect:
|
||||
propertyValuesMatchPlaceholders()
|
||||
getFilters("/loginPage").size() == 0
|
||||
}
|
||||
expect:
|
||||
propertyValuesMatchPlaceholders()
|
||||
getFilters("/loginPage").size() == 0
|
||||
}
|
||||
|
||||
// SEC-1309
|
||||
def interceptUrlsAndFormLoginSupportEL() {
|
||||
System.setProperty("secure.url", "/Secure");
|
||||
System.setProperty("secure.role", "ROLE_A");
|
||||
System.setProperty("login.page", "/loginPage");
|
||||
System.setProperty("default.target", "/defaultTarget");
|
||||
System.setProperty("auth.failure", "/authFailure");
|
||||
// SEC-1309
|
||||
def interceptUrlsAndFormLoginSupportEL() {
|
||||
System.setProperty("secure.url", "/Secure");
|
||||
System.setProperty("secure.role", "ROLE_A");
|
||||
System.setProperty("login.page", "/loginPage");
|
||||
System.setProperty("default.target", "/defaultTarget");
|
||||
System.setProperty("auth.failure", "/authFailure");
|
||||
|
||||
xml.http('use-expressions':false) {
|
||||
interceptUrl("#{systemProperties['secure.url']}", "#{systemProperties['secure.role']}")
|
||||
'form-login'('login-page':"#{systemProperties['login.page']}", 'default-target-url': "#{systemProperties['default.target']}",
|
||||
'authentication-failure-url':"#{systemProperties['auth.failure']}");
|
||||
}
|
||||
createAppContext()
|
||||
xml.http('use-expressions':false) {
|
||||
interceptUrl("#{systemProperties['secure.url']}", "#{systemProperties['secure.role']}")
|
||||
'form-login'('login-page':"#{systemProperties['login.page']}", 'default-target-url': "#{systemProperties['default.target']}",
|
||||
'authentication-failure-url':"#{systemProperties['auth.failure']}");
|
||||
}
|
||||
createAppContext()
|
||||
|
||||
expect:
|
||||
propertyValuesMatchPlaceholders()
|
||||
}
|
||||
expect:
|
||||
propertyValuesMatchPlaceholders()
|
||||
}
|
||||
|
||||
private void propertyValuesMatchPlaceholders() {
|
||||
// Check the security attribute
|
||||
def fis = getFilter(FilterSecurityInterceptor);
|
||||
def fids = fis.getSecurityMetadataSource();
|
||||
Collection attrs = fids.getAttributes(createFilterinvocation("/secure", null));
|
||||
assert attrs.size() == 1
|
||||
assert attrs.contains(new SecurityConfig("ROLE_A"))
|
||||
private void propertyValuesMatchPlaceholders() {
|
||||
// Check the security attribute
|
||||
def fis = getFilter(FilterSecurityInterceptor);
|
||||
def fids = fis.getSecurityMetadataSource();
|
||||
Collection attrs = fids.getAttributes(createFilterinvocation("/secure", null));
|
||||
assert attrs.size() == 1
|
||||
assert attrs.contains(new SecurityConfig("ROLE_A"))
|
||||
|
||||
// Check the form login properties are set
|
||||
def apf = getFilter(UsernamePasswordAuthenticationFilter)
|
||||
assert FieldUtils.getFieldValue(apf, "successHandler.defaultTargetUrl") == '/defaultTarget'
|
||||
assert "/authFailure" == FieldUtils.getFieldValue(apf, "failureHandler.defaultFailureUrl")
|
||||
// Check the form login properties are set
|
||||
def apf = getFilter(UsernamePasswordAuthenticationFilter)
|
||||
assert FieldUtils.getFieldValue(apf, "successHandler.defaultTargetUrl") == '/defaultTarget'
|
||||
assert "/authFailure" == FieldUtils.getFieldValue(apf, "failureHandler.defaultFailureUrl")
|
||||
|
||||
def etf = getFilter(ExceptionTranslationFilter)
|
||||
assert "/loginPage"== etf.authenticationEntryPoint.loginFormUrl
|
||||
}
|
||||
def etf = getFilter(ExceptionTranslationFilter)
|
||||
assert "/loginPage"== etf.authenticationEntryPoint.loginFormUrl
|
||||
}
|
||||
|
||||
def portMappingsWorkWithPlaceholdersAndEL() {
|
||||
System.setProperty("http", "9080");
|
||||
System.setProperty("https", "9443");
|
||||
def portMappingsWorkWithPlaceholdersAndEL() {
|
||||
System.setProperty("http", "9080");
|
||||
System.setProperty("https", "9443");
|
||||
|
||||
httpAutoConfig {
|
||||
'port-mappings'() {
|
||||
'port-mapping'(http: '#{systemProperties.http}', https: '${https}')
|
||||
}
|
||||
}
|
||||
createAppContext();
|
||||
httpAutoConfig {
|
||||
'port-mappings'() {
|
||||
'port-mapping'(http: '#{systemProperties.http}', https: '${https}')
|
||||
}
|
||||
}
|
||||
createAppContext();
|
||||
|
||||
def pm = (appContext.getBeansOfType(PortMapperImpl).values() as List)[0];
|
||||
def pm = (appContext.getBeansOfType(PortMapperImpl).values() as List)[0];
|
||||
|
||||
expect:
|
||||
pm.getTranslatedPortMappings().size() == 1
|
||||
pm.lookupHttpPort(9443) == 9080
|
||||
pm.lookupHttpsPort(9080) == 9443
|
||||
}
|
||||
expect:
|
||||
pm.getTranslatedPortMappings().size() == 1
|
||||
pm.lookupHttpPort(9443) == 9080
|
||||
pm.lookupHttpsPort(9080) == 9443
|
||||
}
|
||||
|
||||
def requiresChannelSupportsPlaceholder() {
|
||||
System.setProperty("secure.url", "/secure");
|
||||
System.setProperty("required.channel", "https");
|
||||
def requiresChannelSupportsPlaceholder() {
|
||||
System.setProperty("secure.url", "/secure");
|
||||
System.setProperty("required.channel", "https");
|
||||
|
||||
httpAutoConfig {
|
||||
'intercept-url'(pattern: '${secure.url}', 'requires-channel': '${required.channel}')
|
||||
}
|
||||
createAppContext();
|
||||
List filters = getFilters("/secure");
|
||||
httpAutoConfig {
|
||||
'intercept-url'(pattern: '${secure.url}', 'requires-channel': '${required.channel}')
|
||||
}
|
||||
createAppContext();
|
||||
List filters = getFilters("/secure");
|
||||
|
||||
expect:
|
||||
filters.size() == AUTO_CONFIG_FILTERS + 1
|
||||
filters[0] instanceof ChannelProcessingFilter
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setServletPath("/secure");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
filters[0].doFilter(request, response, new MockFilterChain());
|
||||
response.getRedirectedUrl().startsWith("https")
|
||||
}
|
||||
expect:
|
||||
filters.size() == AUTO_CONFIG_FILTERS + 1
|
||||
filters[0] instanceof ChannelProcessingFilter
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setServletPath("/secure");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
filters[0].doFilter(request, response, new MockFilterChain());
|
||||
response.getRedirectedUrl().startsWith("https")
|
||||
}
|
||||
|
||||
def accessDeniedPageWorksWithPlaceholders() {
|
||||
System.setProperty("accessDenied", "/go-away");
|
||||
xml.http('auto-config': 'true') {
|
||||
'access-denied-handler'('error-page' : '${accessDenied}') {}
|
||||
}
|
||||
createAppContext();
|
||||
def accessDeniedPageWorksWithPlaceholders() {
|
||||
System.setProperty("accessDenied", "/go-away");
|
||||
xml.http('auto-config': 'true') {
|
||||
'access-denied-handler'('error-page' : '${accessDenied}') {}
|
||||
}
|
||||
createAppContext();
|
||||
|
||||
expect:
|
||||
FieldUtils.getFieldValue(getFilter(ExceptionTranslationFilter.class), "accessDeniedHandler.errorPage") == '/go-away'
|
||||
}
|
||||
expect:
|
||||
FieldUtils.getFieldValue(getFilter(ExceptionTranslationFilter.class), "accessDeniedHandler.errorPage") == '/go-away'
|
||||
}
|
||||
|
||||
def accessDeniedHandlerPageWorksWithEL() {
|
||||
httpAutoConfig {
|
||||
'access-denied-handler'('error-page': "#{'/go' + '-away'}")
|
||||
}
|
||||
createAppContext()
|
||||
def accessDeniedHandlerPageWorksWithEL() {
|
||||
httpAutoConfig {
|
||||
'access-denied-handler'('error-page': "#{'/go' + '-away'}")
|
||||
}
|
||||
createAppContext()
|
||||
|
||||
expect:
|
||||
getFilter(ExceptionTranslationFilter).accessDeniedHandler.errorPage == '/go-away'
|
||||
}
|
||||
expect:
|
||||
getFilter(ExceptionTranslationFilter).accessDeniedHandler.errorPage == '/go-away'
|
||||
}
|
||||
}
|
||||
|
||||
+217
-217
@@ -5,7 +5,7 @@
|
||||
* 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
|
||||
* 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,
|
||||
@@ -45,268 +45,268 @@ import org.springframework.security.web.authentication.rememberme.TokenBasedReme
|
||||
*/
|
||||
class RememberMeConfigTests extends AbstractHttpConfigTests {
|
||||
|
||||
def rememberMeServiceWorksWithTokenRepoRef() {
|
||||
httpAutoConfig () {
|
||||
'remember-me'('token-repository-ref': 'tokenRepo')
|
||||
}
|
||||
bean('tokenRepo', CustomTokenRepository.class.name)
|
||||
def rememberMeServiceWorksWithTokenRepoRef() {
|
||||
httpAutoConfig () {
|
||||
'remember-me'('token-repository-ref': 'tokenRepo')
|
||||
}
|
||||
bean('tokenRepo', CustomTokenRepository.class.name)
|
||||
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
|
||||
def rememberMeServices = rememberMeServices()
|
||||
def rememberMeServices = rememberMeServices()
|
||||
|
||||
expect:
|
||||
rememberMeServices instanceof PersistentTokenBasedRememberMeServices
|
||||
rememberMeServices.tokenRepository instanceof CustomTokenRepository
|
||||
FieldUtils.getFieldValue(rememberMeServices, "useSecureCookie") == null
|
||||
}
|
||||
expect:
|
||||
rememberMeServices instanceof PersistentTokenBasedRememberMeServices
|
||||
rememberMeServices.tokenRepository instanceof CustomTokenRepository
|
||||
FieldUtils.getFieldValue(rememberMeServices, "useSecureCookie") == null
|
||||
}
|
||||
|
||||
def rememberMeServiceWorksWithDataSourceRef() {
|
||||
httpAutoConfig () {
|
||||
'remember-me'('data-source-ref': 'ds')
|
||||
}
|
||||
bean('ds', TestDataSource.class.name, ['tokendb'])
|
||||
def rememberMeServiceWorksWithDataSourceRef() {
|
||||
httpAutoConfig () {
|
||||
'remember-me'('data-source-ref': 'ds')
|
||||
}
|
||||
bean('ds', TestDataSource.class.name, ['tokendb'])
|
||||
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
|
||||
def rememberMeServices = rememberMeServices()
|
||||
def rememberMeServices = rememberMeServices()
|
||||
|
||||
expect:
|
||||
rememberMeServices instanceof PersistentTokenBasedRememberMeServices
|
||||
rememberMeServices.tokenRepository instanceof JdbcTokenRepositoryImpl
|
||||
}
|
||||
expect:
|
||||
rememberMeServices instanceof PersistentTokenBasedRememberMeServices
|
||||
rememberMeServices.tokenRepository instanceof JdbcTokenRepositoryImpl
|
||||
}
|
||||
|
||||
def rememberMeServiceWorksWithAuthenticationSuccessHandlerRef() {
|
||||
httpAutoConfig () {
|
||||
'remember-me'('authentication-success-handler-ref': 'sh')
|
||||
}
|
||||
bean('sh', SimpleUrlAuthenticationSuccessHandler.class.name, ['/target'])
|
||||
def rememberMeServiceWorksWithAuthenticationSuccessHandlerRef() {
|
||||
httpAutoConfig () {
|
||||
'remember-me'('authentication-success-handler-ref': 'sh')
|
||||
}
|
||||
bean('sh', SimpleUrlAuthenticationSuccessHandler.class.name, ['/target'])
|
||||
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
|
||||
expect:
|
||||
getFilter(RememberMeAuthenticationFilter.class).successHandler instanceof SimpleUrlAuthenticationSuccessHandler
|
||||
}
|
||||
expect:
|
||||
getFilter(RememberMeAuthenticationFilter.class).successHandler instanceof SimpleUrlAuthenticationSuccessHandler
|
||||
}
|
||||
|
||||
def rememberMeServiceWorksWithExternalServicesImpl() {
|
||||
httpAutoConfig () {
|
||||
'remember-me'('key': "#{'our' + 'key'}", 'services-ref': 'rms')
|
||||
csrf(disabled:true)
|
||||
}
|
||||
xml.'b:bean'(id: 'rms', 'class': TokenBasedRememberMeServices.class.name) {
|
||||
'b:constructor-arg'(value: 'ourKey')
|
||||
'b:constructor-arg'(ref: 'us')
|
||||
'b:property'(name: 'tokenValiditySeconds', value: '5000')
|
||||
}
|
||||
def rememberMeServiceWorksWithExternalServicesImpl() {
|
||||
httpAutoConfig () {
|
||||
'remember-me'('key': "#{'our' + 'key'}", 'services-ref': 'rms')
|
||||
csrf(disabled:true)
|
||||
}
|
||||
xml.'b:bean'(id: 'rms', 'class': TokenBasedRememberMeServices.class.name) {
|
||||
'b:constructor-arg'(value: 'ourKey')
|
||||
'b:constructor-arg'(ref: 'us')
|
||||
'b:property'(name: 'tokenValiditySeconds', value: '5000')
|
||||
}
|
||||
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
|
||||
List logoutHandlers = FieldUtils.getFieldValue(getFilter(LogoutFilter.class), "handlers");
|
||||
Map ams = appContext.getBeansOfType(ProviderManager.class);
|
||||
ProviderManager am = (ams.values() as List).find { it instanceof ProviderManager && it.providers.size() == 2}
|
||||
RememberMeAuthenticationProvider rmp = am.providers.find { it instanceof RememberMeAuthenticationProvider}
|
||||
List logoutHandlers = FieldUtils.getFieldValue(getFilter(LogoutFilter.class), "handlers");
|
||||
Map ams = appContext.getBeansOfType(ProviderManager.class);
|
||||
ProviderManager am = (ams.values() as List).find { it instanceof ProviderManager && it.providers.size() == 2}
|
||||
RememberMeAuthenticationProvider rmp = am.providers.find { it instanceof RememberMeAuthenticationProvider}
|
||||
|
||||
expect:
|
||||
rmp != null
|
||||
5000 == FieldUtils.getFieldValue(rememberMeServices(), "tokenValiditySeconds")
|
||||
// SEC-909
|
||||
logoutHandlers.size() == 2
|
||||
logoutHandlers.get(1) == rememberMeServices()
|
||||
// SEC-1281
|
||||
rmp.key == "ourkey"
|
||||
}
|
||||
expect:
|
||||
rmp != null
|
||||
5000 == FieldUtils.getFieldValue(rememberMeServices(), "tokenValiditySeconds")
|
||||
// SEC-909
|
||||
logoutHandlers.size() == 2
|
||||
logoutHandlers.get(1) == rememberMeServices()
|
||||
// SEC-1281
|
||||
rmp.key == "ourkey"
|
||||
}
|
||||
|
||||
def rememberMeAddsLogoutHandlerToLogoutFilter() {
|
||||
httpAutoConfig () {
|
||||
'remember-me'()
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
def rememberMeAddsLogoutHandlerToLogoutFilter() {
|
||||
httpAutoConfig () {
|
||||
'remember-me'()
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
|
||||
def rememberMeServices = rememberMeServices()
|
||||
List logoutHandlers = getFilter(LogoutFilter.class).handlers
|
||||
def rememberMeServices = rememberMeServices()
|
||||
List logoutHandlers = getFilter(LogoutFilter.class).handlers
|
||||
|
||||
expect:
|
||||
rememberMeServices
|
||||
logoutHandlers.size() == 2
|
||||
logoutHandlers.get(0) instanceof SecurityContextLogoutHandler
|
||||
logoutHandlers.get(1) == rememberMeServices
|
||||
}
|
||||
expect:
|
||||
rememberMeServices
|
||||
logoutHandlers.size() == 2
|
||||
logoutHandlers.get(0) instanceof SecurityContextLogoutHandler
|
||||
logoutHandlers.get(1) == rememberMeServices
|
||||
}
|
||||
|
||||
def rememberMeTokenValidityIsParsedCorrectly() {
|
||||
httpAutoConfig () {
|
||||
'remember-me'('key': 'ourkey', 'token-validity-seconds':'10000')
|
||||
}
|
||||
def rememberMeTokenValidityIsParsedCorrectly() {
|
||||
httpAutoConfig () {
|
||||
'remember-me'('key': 'ourkey', 'token-validity-seconds':'10000')
|
||||
}
|
||||
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
|
||||
def rememberMeServices = rememberMeServices()
|
||||
def rememberMeFilter = getFilter(RememberMeAuthenticationFilter.class)
|
||||
def rememberMeServices = rememberMeServices()
|
||||
def rememberMeFilter = getFilter(RememberMeAuthenticationFilter.class)
|
||||
|
||||
expect:
|
||||
rememberMeFilter.authenticationManager
|
||||
rememberMeServices.key == 'ourkey'
|
||||
rememberMeServices.tokenValiditySeconds == 10000
|
||||
rememberMeServices.userDetailsService
|
||||
}
|
||||
expect:
|
||||
rememberMeFilter.authenticationManager
|
||||
rememberMeServices.key == 'ourkey'
|
||||
rememberMeServices.tokenValiditySeconds == 10000
|
||||
rememberMeServices.userDetailsService
|
||||
}
|
||||
|
||||
def 'Remember-me token validity allows negative value for non-persistent implementation'() {
|
||||
httpAutoConfig () {
|
||||
'remember-me'('key': 'ourkey', 'token-validity-seconds':'-1')
|
||||
}
|
||||
def 'Remember-me token validity allows negative value for non-persistent implementation'() {
|
||||
httpAutoConfig () {
|
||||
'remember-me'('key': 'ourkey', 'token-validity-seconds':'-1')
|
||||
}
|
||||
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
expect:
|
||||
rememberMeServices().tokenValiditySeconds == -1
|
||||
}
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
expect:
|
||||
rememberMeServices().tokenValiditySeconds == -1
|
||||
}
|
||||
|
||||
def 'remember-me@token-validity-seconds denies for persistent implementation'() {
|
||||
setup:
|
||||
httpAutoConfig () {
|
||||
'remember-me'('key': 'ourkey', 'token-validity-seconds':'-1', 'dataSource' : 'dataSource')
|
||||
}
|
||||
mockBean(DataSource)
|
||||
when:
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
then:
|
||||
thrown(FatalBeanException)
|
||||
}
|
||||
def 'remember-me@token-validity-seconds denies for persistent implementation'() {
|
||||
setup:
|
||||
httpAutoConfig () {
|
||||
'remember-me'('key': 'ourkey', 'token-validity-seconds':'-1', 'dataSource' : 'dataSource')
|
||||
}
|
||||
mockBean(DataSource)
|
||||
when:
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
then:
|
||||
thrown(FatalBeanException)
|
||||
}
|
||||
|
||||
def 'SEC-2165: remember-me@token-validity-seconds allows property placeholders'() {
|
||||
when:
|
||||
httpAutoConfig () {
|
||||
'remember-me'('key': 'ourkey', 'token-validity-seconds':'${security.rememberme.ttl}')
|
||||
}
|
||||
xml.'b:bean'(class: PropertyPlaceholderConfigurer.name) {
|
||||
'b:property'(name:'properties', value:'security.rememberme.ttl=30')
|
||||
}
|
||||
def 'SEC-2165: remember-me@token-validity-seconds allows property placeholders'() {
|
||||
when:
|
||||
httpAutoConfig () {
|
||||
'remember-me'('key': 'ourkey', 'token-validity-seconds':'${security.rememberme.ttl}')
|
||||
}
|
||||
xml.'b:bean'(class: PropertyPlaceholderConfigurer.name) {
|
||||
'b:property'(name:'properties', value:'security.rememberme.ttl=30')
|
||||
}
|
||||
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
then:
|
||||
rememberMeServices().tokenValiditySeconds == 30
|
||||
}
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
then:
|
||||
rememberMeServices().tokenValiditySeconds == 30
|
||||
}
|
||||
|
||||
def rememberMeSecureCookieAttributeIsSetCorrectly() {
|
||||
httpAutoConfig () {
|
||||
'remember-me'('key': 'ourkey', 'use-secure-cookie':'true')
|
||||
}
|
||||
def rememberMeSecureCookieAttributeIsSetCorrectly() {
|
||||
httpAutoConfig () {
|
||||
'remember-me'('key': 'ourkey', 'use-secure-cookie':'true')
|
||||
}
|
||||
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
expect:
|
||||
FieldUtils.getFieldValue(rememberMeServices(), "useSecureCookie")
|
||||
}
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
expect:
|
||||
FieldUtils.getFieldValue(rememberMeServices(), "useSecureCookie")
|
||||
}
|
||||
|
||||
// SEC-1827
|
||||
def rememberMeSecureCookieAttributeFalse() {
|
||||
httpAutoConfig () {
|
||||
'remember-me'('key': 'ourkey', 'use-secure-cookie':'false')
|
||||
}
|
||||
// SEC-1827
|
||||
def rememberMeSecureCookieAttributeFalse() {
|
||||
httpAutoConfig () {
|
||||
'remember-me'('key': 'ourkey', 'use-secure-cookie':'false')
|
||||
}
|
||||
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
expect: 'useSecureCookie is false'
|
||||
FieldUtils.getFieldValue(rememberMeServices(), "useSecureCookie") == Boolean.FALSE
|
||||
}
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
expect: 'useSecureCookie is false'
|
||||
FieldUtils.getFieldValue(rememberMeServices(), "useSecureCookie") == Boolean.FALSE
|
||||
}
|
||||
|
||||
def 'Negative token-validity is rejected with persistent implementation'() {
|
||||
when:
|
||||
httpAutoConfig () {
|
||||
'remember-me'('key': 'ourkey', 'token-validity-seconds':'-1', 'token-repository-ref': 'tokenRepo')
|
||||
}
|
||||
bean('tokenRepo', InMemoryTokenRepositoryImpl.class.name)
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
def 'Negative token-validity is rejected with persistent implementation'() {
|
||||
when:
|
||||
httpAutoConfig () {
|
||||
'remember-me'('key': 'ourkey', 'token-validity-seconds':'-1', 'token-repository-ref': 'tokenRepo')
|
||||
}
|
||||
bean('tokenRepo', InMemoryTokenRepositoryImpl.class.name)
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
|
||||
then:
|
||||
BeanDefinitionParsingException e = thrown()
|
||||
}
|
||||
then:
|
||||
BeanDefinitionParsingException e = thrown()
|
||||
}
|
||||
|
||||
def 'Custom user service is supported'() {
|
||||
when:
|
||||
httpAutoConfig () {
|
||||
'remember-me'('key': 'ourkey', 'token-validity-seconds':'-1', 'user-service-ref': 'userService')
|
||||
}
|
||||
bean('userService', MockUserDetailsService.class.name)
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
def 'Custom user service is supported'() {
|
||||
when:
|
||||
httpAutoConfig () {
|
||||
'remember-me'('key': 'ourkey', 'token-validity-seconds':'-1', 'user-service-ref': 'userService')
|
||||
}
|
||||
bean('userService', MockUserDetailsService.class.name)
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
|
||||
then: "Parses OK"
|
||||
notThrown BeanDefinitionParsingException
|
||||
}
|
||||
then: "Parses OK"
|
||||
notThrown BeanDefinitionParsingException
|
||||
}
|
||||
|
||||
// SEC-742
|
||||
def rememberMeWorksWithoutBasicProcessingFilter() {
|
||||
when:
|
||||
xml.http () {
|
||||
'form-login'('login-page': '/login.jsp', 'default-target-url': '/messageList.html' )
|
||||
logout('logout-success-url': '/login.jsp')
|
||||
anonymous(username: 'guest', 'granted-authority': 'guest')
|
||||
'remember-me'()
|
||||
}
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
// SEC-742
|
||||
def rememberMeWorksWithoutBasicProcessingFilter() {
|
||||
when:
|
||||
xml.http () {
|
||||
'form-login'('login-page': '/login.jsp', 'default-target-url': '/messageList.html' )
|
||||
logout('logout-success-url': '/login.jsp')
|
||||
anonymous(username: 'guest', 'granted-authority': 'guest')
|
||||
'remember-me'()
|
||||
}
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
|
||||
then: "Parses OK"
|
||||
notThrown BeanDefinitionParsingException
|
||||
}
|
||||
then: "Parses OK"
|
||||
notThrown BeanDefinitionParsingException
|
||||
}
|
||||
|
||||
def 'Default remember-me-parameter is correct'() {
|
||||
httpAutoConfig () {
|
||||
'remember-me'()
|
||||
}
|
||||
def 'Default remember-me-parameter is correct'() {
|
||||
httpAutoConfig () {
|
||||
'remember-me'()
|
||||
}
|
||||
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
expect:
|
||||
rememberMeServices().parameter == AbstractRememberMeServices.DEFAULT_PARAMETER
|
||||
}
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
expect:
|
||||
rememberMeServices().parameter == AbstractRememberMeServices.DEFAULT_PARAMETER
|
||||
}
|
||||
|
||||
// SEC-2119
|
||||
def 'Custom remember-me-parameter is supported'() {
|
||||
httpAutoConfig () {
|
||||
'remember-me'('remember-me-parameter': 'ourParam')
|
||||
}
|
||||
// SEC-2119
|
||||
def 'Custom remember-me-parameter is supported'() {
|
||||
httpAutoConfig () {
|
||||
'remember-me'('remember-me-parameter': 'ourParam')
|
||||
}
|
||||
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
expect:
|
||||
rememberMeServices().parameter == 'ourParam'
|
||||
}
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
expect:
|
||||
rememberMeServices().parameter == 'ourParam'
|
||||
}
|
||||
|
||||
def 'remember-me-parameter cannot be used together with services-ref'() {
|
||||
when:
|
||||
httpAutoConfig () {
|
||||
'remember-me'('remember-me-parameter': 'ourParam', 'services-ref': 'ourService')
|
||||
}
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
then:
|
||||
BeanDefinitionParsingException e = thrown()
|
||||
}
|
||||
def 'remember-me-parameter cannot be used together with services-ref'() {
|
||||
when:
|
||||
httpAutoConfig () {
|
||||
'remember-me'('remember-me-parameter': 'ourParam', 'services-ref': 'ourService')
|
||||
}
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
then:
|
||||
BeanDefinitionParsingException e = thrown()
|
||||
}
|
||||
|
||||
// SEC-2826
|
||||
def 'Custom remember-me-cookie is supported'() {
|
||||
httpAutoConfig () {
|
||||
'remember-me'('remember-me-cookie': 'ourCookie')
|
||||
}
|
||||
// SEC-2826
|
||||
def 'Custom remember-me-cookie is supported'() {
|
||||
httpAutoConfig () {
|
||||
'remember-me'('remember-me-cookie': 'ourCookie')
|
||||
}
|
||||
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
expect:
|
||||
rememberMeServices().cookieName == 'ourCookie'
|
||||
}
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
expect:
|
||||
rememberMeServices().cookieName == 'ourCookie'
|
||||
}
|
||||
|
||||
// SEC-2826
|
||||
def 'remember-me-cookie cannot be used together with services-ref'() {
|
||||
when:
|
||||
httpAutoConfig () {
|
||||
'remember-me'('remember-me-cookie': 'ourCookie', 'services-ref': 'ourService')
|
||||
}
|
||||
// SEC-2826
|
||||
def 'remember-me-cookie cannot be used together with services-ref'() {
|
||||
when:
|
||||
httpAutoConfig () {
|
||||
'remember-me'('remember-me-cookie': 'ourCookie', 'services-ref': 'ourService')
|
||||
}
|
||||
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
then:
|
||||
BeanDefinitionParsingException e = thrown()
|
||||
expect:
|
||||
e.message == 'Configuration problem: services-ref can\'t be used in combination with attributes token-repository-ref,data-source-ref, user-service-ref, token-validity-seconds, use-secure-cookie, remember-me-parameter or remember-me-cookie\nOffending resource: null'
|
||||
}
|
||||
createAppContext(AUTH_PROVIDER_XML)
|
||||
then:
|
||||
BeanDefinitionParsingException e = thrown()
|
||||
expect:
|
||||
e.message == 'Configuration problem: services-ref can\'t be used in combination with attributes token-repository-ref,data-source-ref, user-service-ref, token-validity-seconds, use-secure-cookie, remember-me-parameter or remember-me-cookie\nOffending resource: null'
|
||||
}
|
||||
|
||||
def rememberMeServices() {
|
||||
getFilter(RememberMeAuthenticationFilter.class).getRememberMeServices()
|
||||
}
|
||||
def rememberMeServices() {
|
||||
getFilter(RememberMeAuthenticationFilter.class).getRememberMeServices()
|
||||
}
|
||||
|
||||
static class CustomTokenRepository extends InMemoryTokenRepositoryImpl {
|
||||
static class CustomTokenRepository extends InMemoryTokenRepositoryImpl {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+319
-319
@@ -5,7 +5,7 @@
|
||||
* 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
|
||||
* 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,
|
||||
@@ -58,375 +58,375 @@ import org.springframework.security.web.session.SessionManagementFilter
|
||||
*/
|
||||
class SessionManagementConfigTests extends AbstractHttpConfigTests {
|
||||
|
||||
def settingCreateSessionToAlwaysSetsFilterPropertiesCorrectly() {
|
||||
httpCreateSession('always') { }
|
||||
createAppContext();
|
||||
def settingCreateSessionToAlwaysSetsFilterPropertiesCorrectly() {
|
||||
httpCreateSession('always') { }
|
||||
createAppContext();
|
||||
|
||||
def filter = getFilter(SecurityContextPersistenceFilter.class);
|
||||
def filter = getFilter(SecurityContextPersistenceFilter.class);
|
||||
|
||||
expect:
|
||||
filter.forceEagerSessionCreation
|
||||
filter.repo.allowSessionCreation
|
||||
!filter.repo.disableUrlRewriting
|
||||
}
|
||||
expect:
|
||||
filter.forceEagerSessionCreation
|
||||
filter.repo.allowSessionCreation
|
||||
!filter.repo.disableUrlRewriting
|
||||
}
|
||||
|
||||
def settingCreateSessionToNeverSetsFilterPropertiesCorrectly() {
|
||||
httpCreateSession('never') { }
|
||||
createAppContext();
|
||||
def settingCreateSessionToNeverSetsFilterPropertiesCorrectly() {
|
||||
httpCreateSession('never') { }
|
||||
createAppContext();
|
||||
|
||||
def filter = getFilter(SecurityContextPersistenceFilter.class);
|
||||
def filter = getFilter(SecurityContextPersistenceFilter.class);
|
||||
|
||||
expect:
|
||||
!filter.forceEagerSessionCreation
|
||||
!filter.repo.allowSessionCreation
|
||||
}
|
||||
expect:
|
||||
!filter.forceEagerSessionCreation
|
||||
!filter.repo.allowSessionCreation
|
||||
}
|
||||
|
||||
def settingCreateSessionToStatelessSetsFilterPropertiesCorrectly() {
|
||||
httpCreateSession('stateless') { }
|
||||
createAppContext();
|
||||
def settingCreateSessionToStatelessSetsFilterPropertiesCorrectly() {
|
||||
httpCreateSession('stateless') { }
|
||||
createAppContext();
|
||||
|
||||
def filter = getFilter(SecurityContextPersistenceFilter.class);
|
||||
def filter = getFilter(SecurityContextPersistenceFilter.class);
|
||||
|
||||
expect:
|
||||
!filter.forceEagerSessionCreation
|
||||
filter.repo instanceof NullSecurityContextRepository
|
||||
getFilter(SessionManagementFilter.class) == null
|
||||
getFilter(RequestCacheAwareFilter.class) == null
|
||||
}
|
||||
expect:
|
||||
!filter.forceEagerSessionCreation
|
||||
filter.repo instanceof NullSecurityContextRepository
|
||||
getFilter(SessionManagementFilter.class) == null
|
||||
getFilter(RequestCacheAwareFilter.class) == null
|
||||
}
|
||||
|
||||
def settingCreateSessionToIfRequiredDoesntCreateASessionForPublicInvocation() {
|
||||
httpCreateSession('ifRequired') { }
|
||||
createAppContext();
|
||||
def settingCreateSessionToIfRequiredDoesntCreateASessionForPublicInvocation() {
|
||||
httpCreateSession('ifRequired') { }
|
||||
createAppContext();
|
||||
|
||||
def filter = getFilter(SecurityContextPersistenceFilter.class);
|
||||
def filter = getFilter(SecurityContextPersistenceFilter.class);
|
||||
|
||||
expect:
|
||||
!filter.forceEagerSessionCreation
|
||||
filter.repo.allowSessionCreation
|
||||
}
|
||||
expect:
|
||||
!filter.forceEagerSessionCreation
|
||||
filter.repo.allowSessionCreation
|
||||
}
|
||||
|
||||
def 'SEC-1208: Session is not created when rejecting user due to max sessions exceeded'() {
|
||||
setup:
|
||||
httpCreateSession('never') {
|
||||
'session-management'() {
|
||||
'concurrency-control'('max-sessions':1,'error-if-maximum-exceeded':'true')
|
||||
}
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
SessionRegistry registry = appContext.getBean(SessionRegistry)
|
||||
registry.registerNewSession("1", new User("user","password",AuthorityUtils.createAuthorityList("ROLE_USER")))
|
||||
MockHttpServletRequest request = new MockHttpServletRequest()
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
String credentials = "user:password"
|
||||
request.addHeader("Authorization", "Basic " + credentials.bytes.encodeBase64())
|
||||
when: "exceed max authentication attempts"
|
||||
appContext.getBean(FilterChainProxy).doFilter(request, response, new MockFilterChain())
|
||||
then: "no new session is created"
|
||||
request.getSession(false) == null
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
}
|
||||
def 'SEC-1208: Session is not created when rejecting user due to max sessions exceeded'() {
|
||||
setup:
|
||||
httpCreateSession('never') {
|
||||
'session-management'() {
|
||||
'concurrency-control'('max-sessions':1,'error-if-maximum-exceeded':'true')
|
||||
}
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
SessionRegistry registry = appContext.getBean(SessionRegistry)
|
||||
registry.registerNewSession("1", new User("user","password",AuthorityUtils.createAuthorityList("ROLE_USER")))
|
||||
MockHttpServletRequest request = new MockHttpServletRequest()
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
String credentials = "user:password"
|
||||
request.addHeader("Authorization", "Basic " + credentials.bytes.encodeBase64())
|
||||
when: "exceed max authentication attempts"
|
||||
appContext.getBean(FilterChainProxy).doFilter(request, response, new MockFilterChain())
|
||||
then: "no new session is created"
|
||||
request.getSession(false) == null
|
||||
response.status == HttpServletResponse.SC_UNAUTHORIZED
|
||||
}
|
||||
|
||||
def 'SEC-2137: disable session fixation and enable concurrency control'() {
|
||||
setup: "context where session fixation is disabled and concurrency control is enabled"
|
||||
httpAutoConfig {
|
||||
'session-management'('session-fixation-protection':'none') {
|
||||
'concurrency-control'('max-sessions':'1','error-if-maximum-exceeded':'true')
|
||||
}
|
||||
}
|
||||
createAppContext()
|
||||
MockHttpServletRequest request = new MockHttpServletRequest()
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
String originalSessionId = request.session.id
|
||||
String credentials = "user:password"
|
||||
request.addHeader("Authorization", "Basic " + credentials.bytes.encodeBase64())
|
||||
when: "authenticate"
|
||||
appContext.getBean(FilterChainProxy).doFilter(request, response, new MockFilterChain())
|
||||
then: "session invalidate is not called"
|
||||
request.session.id == originalSessionId
|
||||
}
|
||||
def 'SEC-2137: disable session fixation and enable concurrency control'() {
|
||||
setup: "context where session fixation is disabled and concurrency control is enabled"
|
||||
httpAutoConfig {
|
||||
'session-management'('session-fixation-protection':'none') {
|
||||
'concurrency-control'('max-sessions':'1','error-if-maximum-exceeded':'true')
|
||||
}
|
||||
}
|
||||
createAppContext()
|
||||
MockHttpServletRequest request = new MockHttpServletRequest()
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
String originalSessionId = request.session.id
|
||||
String credentials = "user:password"
|
||||
request.addHeader("Authorization", "Basic " + credentials.bytes.encodeBase64())
|
||||
when: "authenticate"
|
||||
appContext.getBean(FilterChainProxy).doFilter(request, response, new MockFilterChain())
|
||||
then: "session invalidate is not called"
|
||||
request.session.id == originalSessionId
|
||||
}
|
||||
|
||||
def httpCreateSession(String create, Closure c) {
|
||||
xml.http(['auto-config': 'true', 'create-session': create], c)
|
||||
}
|
||||
def httpCreateSession(String create, Closure c) {
|
||||
xml.http(['auto-config': 'true', 'create-session': create], c)
|
||||
}
|
||||
|
||||
def concurrentSessionSupportAddsFilterAndExpectedBeans() {
|
||||
when:
|
||||
httpAutoConfig {
|
||||
'session-management'() {
|
||||
'concurrency-control'('session-registry-alias':'sr', 'expired-url': '/expired')
|
||||
}
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext();
|
||||
List filters = getFilters("/someurl");
|
||||
def concurrentSessionFilter = filters.get(1)
|
||||
def concurrentSessionSupportAddsFilterAndExpectedBeans() {
|
||||
when:
|
||||
httpAutoConfig {
|
||||
'session-management'() {
|
||||
'concurrency-control'('session-registry-alias':'sr', 'expired-url': '/expired')
|
||||
}
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext();
|
||||
List filters = getFilters("/someurl");
|
||||
def concurrentSessionFilter = filters.get(1)
|
||||
|
||||
then:
|
||||
concurrentSessionFilter instanceof ConcurrentSessionFilter
|
||||
concurrentSessionFilter.expiredUrl == '/expired'
|
||||
appContext.getBean("sr") != null
|
||||
getFilter(SessionManagementFilter.class) != null
|
||||
sessionRegistryIsValid();
|
||||
then:
|
||||
concurrentSessionFilter instanceof ConcurrentSessionFilter
|
||||
concurrentSessionFilter.expiredUrl == '/expired'
|
||||
appContext.getBean("sr") != null
|
||||
getFilter(SessionManagementFilter.class) != null
|
||||
sessionRegistryIsValid();
|
||||
|
||||
concurrentSessionFilter.handlers.size() == 1
|
||||
def logoutHandler = concurrentSessionFilter.handlers[0]
|
||||
logoutHandler instanceof SecurityContextLogoutHandler
|
||||
logoutHandler.invalidateHttpSession
|
||||
concurrentSessionFilter.handlers.size() == 1
|
||||
def logoutHandler = concurrentSessionFilter.handlers[0]
|
||||
logoutHandler instanceof SecurityContextLogoutHandler
|
||||
logoutHandler.invalidateHttpSession
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
def 'concurrency-control adds custom logout handlers'() {
|
||||
when: 'Custom logout and remember-me'
|
||||
httpAutoConfig {
|
||||
'session-management'() {
|
||||
'concurrency-control'()
|
||||
}
|
||||
'logout'('invalidate-session': false, 'delete-cookies': 'testCookie')
|
||||
'remember-me'()
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
def 'concurrency-control adds custom logout handlers'() {
|
||||
when: 'Custom logout and remember-me'
|
||||
httpAutoConfig {
|
||||
'session-management'() {
|
||||
'concurrency-control'()
|
||||
}
|
||||
'logout'('invalidate-session': false, 'delete-cookies': 'testCookie')
|
||||
'remember-me'()
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
|
||||
List filters = getFilters("/someurl")
|
||||
ConcurrentSessionFilter concurrentSessionFilter = filters.get(1)
|
||||
def logoutHandlers = concurrentSessionFilter.handlers
|
||||
List filters = getFilters("/someurl")
|
||||
ConcurrentSessionFilter concurrentSessionFilter = filters.get(1)
|
||||
def logoutHandlers = concurrentSessionFilter.handlers
|
||||
|
||||
then: 'ConcurrentSessionFilter contains the customized LogoutHandlers'
|
||||
logoutHandlers.size() == 3
|
||||
def securityCtxlogoutHandler = logoutHandlers.find { it instanceof SecurityContextLogoutHandler }
|
||||
securityCtxlogoutHandler.invalidateHttpSession == false
|
||||
def cookieClearingLogoutHandler = logoutHandlers.find { it instanceof CookieClearingLogoutHandler }
|
||||
cookieClearingLogoutHandler.cookiesToClear == ['testCookie']
|
||||
def remembermeLogoutHandler = logoutHandlers.find { it instanceof RememberMeServices }
|
||||
remembermeLogoutHandler == getFilter(RememberMeAuthenticationFilter.class).rememberMeServices
|
||||
}
|
||||
then: 'ConcurrentSessionFilter contains the customized LogoutHandlers'
|
||||
logoutHandlers.size() == 3
|
||||
def securityCtxlogoutHandler = logoutHandlers.find { it instanceof SecurityContextLogoutHandler }
|
||||
securityCtxlogoutHandler.invalidateHttpSession == false
|
||||
def cookieClearingLogoutHandler = logoutHandlers.find { it instanceof CookieClearingLogoutHandler }
|
||||
cookieClearingLogoutHandler.cookiesToClear == ['testCookie']
|
||||
def remembermeLogoutHandler = logoutHandlers.find { it instanceof RememberMeServices }
|
||||
remembermeLogoutHandler == getFilter(RememberMeAuthenticationFilter.class).rememberMeServices
|
||||
}
|
||||
|
||||
def 'concurrency-control with remember-me and no LogoutFilter contains SecurityContextLogoutHandler and RememberMeServices as LogoutHandlers'() {
|
||||
when: 'RememberMe and No LogoutFilter'
|
||||
xml.http(['entry-point-ref': 'entryPoint'], {
|
||||
'session-management'() {
|
||||
'concurrency-control'()
|
||||
}
|
||||
'remember-me'()
|
||||
csrf(disabled:true)
|
||||
})
|
||||
bean('entryPoint', 'org.springframework.security.web.authentication.Http403ForbiddenEntryPoint')
|
||||
createAppContext()
|
||||
def 'concurrency-control with remember-me and no LogoutFilter contains SecurityContextLogoutHandler and RememberMeServices as LogoutHandlers'() {
|
||||
when: 'RememberMe and No LogoutFilter'
|
||||
xml.http(['entry-point-ref': 'entryPoint'], {
|
||||
'session-management'() {
|
||||
'concurrency-control'()
|
||||
}
|
||||
'remember-me'()
|
||||
csrf(disabled:true)
|
||||
})
|
||||
bean('entryPoint', 'org.springframework.security.web.authentication.Http403ForbiddenEntryPoint')
|
||||
createAppContext()
|
||||
|
||||
List filters = getFilters("/someurl")
|
||||
ConcurrentSessionFilter concurrentSessionFilter = filters.get(1)
|
||||
def logoutHandlers = concurrentSessionFilter.handlers
|
||||
List filters = getFilters("/someurl")
|
||||
ConcurrentSessionFilter concurrentSessionFilter = filters.get(1)
|
||||
def logoutHandlers = concurrentSessionFilter.handlers
|
||||
|
||||
then: 'SecurityContextLogoutHandler and RememberMeServices are in ConcurrentSessionFilter logoutHandlers'
|
||||
!filters.find { it instanceof LogoutFilter }
|
||||
logoutHandlers.size() == 2
|
||||
def securityCtxlogoutHandler = logoutHandlers.find { it instanceof SecurityContextLogoutHandler }
|
||||
securityCtxlogoutHandler.invalidateHttpSession == true
|
||||
logoutHandlers.find { it instanceof RememberMeServices } == getFilter(RememberMeAuthenticationFilter).rememberMeServices
|
||||
}
|
||||
then: 'SecurityContextLogoutHandler and RememberMeServices are in ConcurrentSessionFilter logoutHandlers'
|
||||
!filters.find { it instanceof LogoutFilter }
|
||||
logoutHandlers.size() == 2
|
||||
def securityCtxlogoutHandler = logoutHandlers.find { it instanceof SecurityContextLogoutHandler }
|
||||
securityCtxlogoutHandler.invalidateHttpSession == true
|
||||
logoutHandlers.find { it instanceof RememberMeServices } == getFilter(RememberMeAuthenticationFilter).rememberMeServices
|
||||
}
|
||||
|
||||
def 'concurrency-control with no remember-me or LogoutFilter contains SecurityContextLogoutHandler as LogoutHandlers'() {
|
||||
when: 'No Logout Filter or RememberMe'
|
||||
xml.http(['entry-point-ref': 'entryPoint'], {
|
||||
'session-management'() {
|
||||
'concurrency-control'()
|
||||
}
|
||||
})
|
||||
bean('entryPoint', 'org.springframework.security.web.authentication.Http403ForbiddenEntryPoint')
|
||||
createAppContext()
|
||||
def 'concurrency-control with no remember-me or LogoutFilter contains SecurityContextLogoutHandler as LogoutHandlers'() {
|
||||
when: 'No Logout Filter or RememberMe'
|
||||
xml.http(['entry-point-ref': 'entryPoint'], {
|
||||
'session-management'() {
|
||||
'concurrency-control'()
|
||||
}
|
||||
})
|
||||
bean('entryPoint', 'org.springframework.security.web.authentication.Http403ForbiddenEntryPoint')
|
||||
createAppContext()
|
||||
|
||||
List filters = getFilters("/someurl")
|
||||
ConcurrentSessionFilter concurrentSessionFilter = filters.get(1)
|
||||
def logoutHandlers = concurrentSessionFilter.handlers
|
||||
List filters = getFilters("/someurl")
|
||||
ConcurrentSessionFilter concurrentSessionFilter = filters.get(1)
|
||||
def logoutHandlers = concurrentSessionFilter.handlers
|
||||
|
||||
then: 'Only SecurityContextLogoutHandler is found in ConcurrentSessionFilter logoutHandlers'
|
||||
!filters.find { it instanceof LogoutFilter }
|
||||
logoutHandlers.size() == 1
|
||||
def securityCtxlogoutHandler = logoutHandlers.find { it instanceof SecurityContextLogoutHandler }
|
||||
securityCtxlogoutHandler.invalidateHttpSession == true
|
||||
}
|
||||
then: 'Only SecurityContextLogoutHandler is found in ConcurrentSessionFilter logoutHandlers'
|
||||
!filters.find { it instanceof LogoutFilter }
|
||||
logoutHandlers.size() == 1
|
||||
def securityCtxlogoutHandler = logoutHandlers.find { it instanceof SecurityContextLogoutHandler }
|
||||
securityCtxlogoutHandler.invalidateHttpSession == true
|
||||
}
|
||||
|
||||
def 'SEC-2057: ConcurrentSessionFilter is after SecurityContextPersistenceFilter'() {
|
||||
httpAutoConfig {
|
||||
'session-management'() {
|
||||
'concurrency-control'()
|
||||
}
|
||||
}
|
||||
createAppContext()
|
||||
List filters = getFilters("/someurl")
|
||||
def 'SEC-2057: ConcurrentSessionFilter is after SecurityContextPersistenceFilter'() {
|
||||
httpAutoConfig {
|
||||
'session-management'() {
|
||||
'concurrency-control'()
|
||||
}
|
||||
}
|
||||
createAppContext()
|
||||
List filters = getFilters("/someurl")
|
||||
|
||||
expect:
|
||||
filters.get(0) instanceof SecurityContextPersistenceFilter
|
||||
filters.get(1) instanceof ConcurrentSessionFilter
|
||||
}
|
||||
expect:
|
||||
filters.get(0) instanceof SecurityContextPersistenceFilter
|
||||
filters.get(1) instanceof ConcurrentSessionFilter
|
||||
}
|
||||
|
||||
def 'concurrency-control handles default expired-url as null'() {
|
||||
httpAutoConfig {
|
||||
'session-management'() {
|
||||
'concurrency-control'('session-registry-alias':'sr')
|
||||
}
|
||||
}
|
||||
createAppContext();
|
||||
List filters = getFilters("/someurl");
|
||||
def 'concurrency-control handles default expired-url as null'() {
|
||||
httpAutoConfig {
|
||||
'session-management'() {
|
||||
'concurrency-control'('session-registry-alias':'sr')
|
||||
}
|
||||
}
|
||||
createAppContext();
|
||||
List filters = getFilters("/someurl");
|
||||
|
||||
expect:
|
||||
filters.get(1).expiredUrl == null
|
||||
}
|
||||
expect:
|
||||
filters.get(1).expiredUrl == null
|
||||
}
|
||||
|
||||
def externalSessionStrategyIsSupported() {
|
||||
setup:
|
||||
httpAutoConfig {
|
||||
'session-management'('session-authentication-strategy-ref':'ss')
|
||||
csrf(disabled:true)
|
||||
}
|
||||
mockBean(SessionAuthenticationStrategy,'ss')
|
||||
createAppContext()
|
||||
def externalSessionStrategyIsSupported() {
|
||||
setup:
|
||||
httpAutoConfig {
|
||||
'session-management'('session-authentication-strategy-ref':'ss')
|
||||
csrf(disabled:true)
|
||||
}
|
||||
mockBean(SessionAuthenticationStrategy,'ss')
|
||||
createAppContext()
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.getSession();
|
||||
request.servletPath = "/login"
|
||||
request.setMethod("POST");
|
||||
request.setParameter("username", "user");
|
||||
request.setParameter("password", "password");
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.getSession();
|
||||
request.servletPath = "/login"
|
||||
request.setMethod("POST");
|
||||
request.setParameter("username", "user");
|
||||
request.setParameter("password", "password");
|
||||
|
||||
SessionAuthenticationStrategy sessionAuthStrategy = appContext.getBean('ss',SessionAuthenticationStrategy)
|
||||
FilterChainProxy springSecurityFilterChain = appContext.getBean(FilterChainProxy)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,new MockHttpServletResponse(), new MockFilterChain())
|
||||
then: "CustomSessionAuthenticationStrategy has seen the request (although REQUEST is a wrapped request)"
|
||||
verify(sessionAuthStrategy).onAuthentication(any(Authentication), any(HttpServletRequest), any(HttpServletResponse))
|
||||
}
|
||||
SessionAuthenticationStrategy sessionAuthStrategy = appContext.getBean('ss',SessionAuthenticationStrategy)
|
||||
FilterChainProxy springSecurityFilterChain = appContext.getBean(FilterChainProxy)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,new MockHttpServletResponse(), new MockFilterChain())
|
||||
then: "CustomSessionAuthenticationStrategy has seen the request (although REQUEST is a wrapped request)"
|
||||
verify(sessionAuthStrategy).onAuthentication(any(Authentication), any(HttpServletRequest), any(HttpServletResponse))
|
||||
}
|
||||
|
||||
def externalSessionRegistryBeanIsConfiguredCorrectly() {
|
||||
httpAutoConfig {
|
||||
'session-management'() {
|
||||
'concurrency-control'('session-registry-ref':'sr')
|
||||
}
|
||||
csrf(disabled:true)
|
||||
}
|
||||
bean('sr', SessionRegistryImpl.class.name)
|
||||
createAppContext();
|
||||
def externalSessionRegistryBeanIsConfiguredCorrectly() {
|
||||
httpAutoConfig {
|
||||
'session-management'() {
|
||||
'concurrency-control'('session-registry-ref':'sr')
|
||||
}
|
||||
csrf(disabled:true)
|
||||
}
|
||||
bean('sr', SessionRegistryImpl.class.name)
|
||||
createAppContext();
|
||||
|
||||
expect:
|
||||
sessionRegistryIsValid();
|
||||
}
|
||||
expect:
|
||||
sessionRegistryIsValid();
|
||||
}
|
||||
|
||||
def sessionRegistryIsValid() {
|
||||
Object sessionRegistry = appContext.getBean("sr");
|
||||
Object sessionRegistryFromConcurrencyFilter = FieldUtils.getFieldValue(
|
||||
getFilter(ConcurrentSessionFilter.class), "sessionRegistry");
|
||||
Object sessionRegistryFromFormLoginFilter = FieldUtils.getFieldValue(getFilter(UsernamePasswordAuthenticationFilter),"sessionStrategy").delegateStrategies[0].sessionRegistry
|
||||
Object sessionRegistryFromMgmtFilter = FieldUtils.getFieldValue(getFilter(SessionManagementFilter),"sessionAuthenticationStrategy").delegateStrategies[0].sessionRegistry
|
||||
def sessionRegistryIsValid() {
|
||||
Object sessionRegistry = appContext.getBean("sr");
|
||||
Object sessionRegistryFromConcurrencyFilter = FieldUtils.getFieldValue(
|
||||
getFilter(ConcurrentSessionFilter.class), "sessionRegistry");
|
||||
Object sessionRegistryFromFormLoginFilter = FieldUtils.getFieldValue(getFilter(UsernamePasswordAuthenticationFilter),"sessionStrategy").delegateStrategies[0].sessionRegistry
|
||||
Object sessionRegistryFromMgmtFilter = FieldUtils.getFieldValue(getFilter(SessionManagementFilter),"sessionAuthenticationStrategy").delegateStrategies[0].sessionRegistry
|
||||
|
||||
assertSame(sessionRegistry, sessionRegistryFromConcurrencyFilter);
|
||||
assertSame(sessionRegistry, sessionRegistryFromMgmtFilter);
|
||||
// SEC-1143
|
||||
assertSame(sessionRegistry, sessionRegistryFromFormLoginFilter);
|
||||
true;
|
||||
}
|
||||
assertSame(sessionRegistry, sessionRegistryFromConcurrencyFilter);
|
||||
assertSame(sessionRegistry, sessionRegistryFromMgmtFilter);
|
||||
// SEC-1143
|
||||
assertSame(sessionRegistry, sessionRegistryFromFormLoginFilter);
|
||||
true;
|
||||
}
|
||||
|
||||
def concurrentSessionMaxSessionsIsCorrectlyConfigured() {
|
||||
setup:
|
||||
httpAutoConfig {
|
||||
'session-management'('session-authentication-error-url':'/max-exceeded') {
|
||||
'concurrency-control'('max-sessions': '2', 'error-if-maximum-exceeded':'true')
|
||||
}
|
||||
}
|
||||
createAppContext();
|
||||
def concurrentSessionMaxSessionsIsCorrectlyConfigured() {
|
||||
setup:
|
||||
httpAutoConfig {
|
||||
'session-management'('session-authentication-error-url':'/max-exceeded') {
|
||||
'concurrency-control'('max-sessions': '2', 'error-if-maximum-exceeded':'true')
|
||||
}
|
||||
}
|
||||
createAppContext();
|
||||
|
||||
def seshFilter = getFilter(SessionManagementFilter.class);
|
||||
def auth = new UsernamePasswordAuthenticationToken("bob", "pass");
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
MockHttpServletResponse mockResponse = new MockHttpServletResponse();
|
||||
def response = new SaveContextOnUpdateOrErrorResponseWrapper(mockResponse, false) {
|
||||
protected void saveContext(SecurityContext context) {
|
||||
}
|
||||
};
|
||||
when: "First session is established"
|
||||
seshFilter.doFilter(new MockHttpServletRequest(), response, new MockFilterChain());
|
||||
then: "ok"
|
||||
mockResponse.redirectedUrl == null
|
||||
when: "Second session is established"
|
||||
seshFilter.doFilter(new MockHttpServletRequest(), response, new MockFilterChain());
|
||||
then: "ok"
|
||||
mockResponse.redirectedUrl == null
|
||||
when: "Third session is established"
|
||||
seshFilter.doFilter(new MockHttpServletRequest(), response, new MockFilterChain());
|
||||
then: "Rejected"
|
||||
mockResponse.redirectedUrl == "/max-exceeded";
|
||||
}
|
||||
def seshFilter = getFilter(SessionManagementFilter.class);
|
||||
def auth = new UsernamePasswordAuthenticationToken("bob", "pass");
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
MockHttpServletResponse mockResponse = new MockHttpServletResponse();
|
||||
def response = new SaveContextOnUpdateOrErrorResponseWrapper(mockResponse, false) {
|
||||
protected void saveContext(SecurityContext context) {
|
||||
}
|
||||
};
|
||||
when: "First session is established"
|
||||
seshFilter.doFilter(new MockHttpServletRequest(), response, new MockFilterChain());
|
||||
then: "ok"
|
||||
mockResponse.redirectedUrl == null
|
||||
when: "Second session is established"
|
||||
seshFilter.doFilter(new MockHttpServletRequest(), response, new MockFilterChain());
|
||||
then: "ok"
|
||||
mockResponse.redirectedUrl == null
|
||||
when: "Third session is established"
|
||||
seshFilter.doFilter(new MockHttpServletRequest(), response, new MockFilterChain());
|
||||
then: "Rejected"
|
||||
mockResponse.redirectedUrl == "/max-exceeded";
|
||||
}
|
||||
|
||||
def disablingSessionProtectionRemovesSessionManagementFilterIfNoInvalidSessionUrlSet() {
|
||||
httpAutoConfig {
|
||||
'session-management'('session-fixation-protection': 'none')
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
def disablingSessionProtectionRemovesSessionManagementFilterIfNoInvalidSessionUrlSet() {
|
||||
httpAutoConfig {
|
||||
'session-management'('session-fixation-protection': 'none')
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
|
||||
expect:
|
||||
!(getFilters("/someurl").find { it instanceof SessionManagementFilter})
|
||||
}
|
||||
expect:
|
||||
!(getFilters("/someurl").find { it instanceof SessionManagementFilter})
|
||||
}
|
||||
|
||||
def 'session-fixation-protection=none'() {
|
||||
setup:
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(method:'POST')
|
||||
request.session.id = '123'
|
||||
request.setParameter('username', 'user')
|
||||
request.setParameter('password', 'password')
|
||||
request.servletPath = '/login'
|
||||
def 'session-fixation-protection=none'() {
|
||||
setup:
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(method:'POST')
|
||||
request.session.id = '123'
|
||||
request.setParameter('username', 'user')
|
||||
request.setParameter('password', 'password')
|
||||
request.servletPath = '/login'
|
||||
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
httpAutoConfig {
|
||||
'session-management'('session-fixation-protection': 'none')
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
request.session.id = '123'
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
httpAutoConfig {
|
||||
'session-management'('session-fixation-protection': 'none')
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
request.session.id = '123'
|
||||
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response, chain)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response, chain)
|
||||
|
||||
then:
|
||||
request.session.id == '123'
|
||||
}
|
||||
then:
|
||||
request.session.id == '123'
|
||||
}
|
||||
|
||||
def 'session-fixation-protection=migrateSession'() {
|
||||
setup:
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(method:'POST')
|
||||
request.session.id = '123'
|
||||
request.setParameter('username', 'user')
|
||||
request.setParameter('password', 'password')
|
||||
request.servletPath = '/login'
|
||||
def 'session-fixation-protection=migrateSession'() {
|
||||
setup:
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(method:'POST')
|
||||
request.session.id = '123'
|
||||
request.setParameter('username', 'user')
|
||||
request.setParameter('password', 'password')
|
||||
request.servletPath = '/login'
|
||||
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
httpAutoConfig {
|
||||
'session-management'('session-fixation-protection': 'migrateSession')
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
request.session.id = '123'
|
||||
MockHttpServletResponse response = new MockHttpServletResponse()
|
||||
MockFilterChain chain = new MockFilterChain()
|
||||
httpAutoConfig {
|
||||
'session-management'('session-fixation-protection': 'migrateSession')
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
request.session.id = '123'
|
||||
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response, chain)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response, chain)
|
||||
|
||||
then:
|
||||
request.session.id != '123'
|
||||
}
|
||||
then:
|
||||
request.session.id != '123'
|
||||
}
|
||||
|
||||
def disablingSessionProtectionRetainsSessionManagementFilterInvalidSessionUrlSet() {
|
||||
httpAutoConfig {
|
||||
'session-management'('session-fixation-protection': 'none', 'invalid-session-url': '/timeoutUrl')
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
def filter = getFilters("/someurl")[10]
|
||||
def disablingSessionProtectionRetainsSessionManagementFilterInvalidSessionUrlSet() {
|
||||
httpAutoConfig {
|
||||
'session-management'('session-fixation-protection': 'none', 'invalid-session-url': '/timeoutUrl')
|
||||
csrf(disabled:true)
|
||||
}
|
||||
createAppContext()
|
||||
def filter = getFilters("/someurl")[10]
|
||||
|
||||
expect:
|
||||
filter instanceof SessionManagementFilter
|
||||
filter.invalidSessionStrategy.destinationUrl == '/timeoutUrl'
|
||||
}
|
||||
expect:
|
||||
filter instanceof SessionManagementFilter
|
||||
filter.invalidSessionStrategy.destinationUrl == '/timeoutUrl'
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user