parent
b1195e7789
commit
cf0c5f9026
|
@ -1,197 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.FilterChain
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.security.access.AccessDecisionManager
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.access.ConfigAttribute
|
||||
import org.springframework.security.authentication.AnonymousAuthenticationToken
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.BaseSpringSpec
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.BaseWebConfig;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint
|
||||
import org.springframework.security.web.FilterInvocation
|
||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
|
||||
import org.springframework.security.web.access.ExceptionTranslationFilter
|
||||
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor
|
||||
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
|
||||
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
||||
import org.springframework.security.web.context.NullSecurityContextRepository;
|
||||
import org.springframework.security.web.context.SecurityContextPersistenceFilter
|
||||
import org.springframework.security.web.jaasapi.JaasApiIntegrationFilter;
|
||||
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher
|
||||
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher
|
||||
import org.springframework.web.filter.OncePerRequestFilter
|
||||
|
||||
import spock.lang.Ignore;
|
||||
|
||||
/**
|
||||
* Tests to verify that all the functionality of <anonymous> attributes is present
|
||||
*
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
public class NamespaceHttpCustomFilterTests extends BaseSpringSpec {
|
||||
def "http/custom-filter@before"() {
|
||||
when:
|
||||
loadConfig(CustomFilterBeforeConfig)
|
||||
then:
|
||||
filterChain().filters[0].class == CustomFilter
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CustomFilterBeforeConfig extends BaseWebConfig {
|
||||
CustomFilterBeforeConfig() {
|
||||
// do not add the default filters to make testing easier
|
||||
super(true)
|
||||
}
|
||||
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.addFilterBefore(new CustomFilter(), UsernamePasswordAuthenticationFilter.class)
|
||||
.formLogin()
|
||||
}
|
||||
}
|
||||
|
||||
def "http/custom-filter@after"() {
|
||||
when:
|
||||
loadConfig(CustomFilterAfterConfig)
|
||||
then:
|
||||
filterChain().filters[1].class == CustomFilter
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CustomFilterAfterConfig extends BaseWebConfig {
|
||||
CustomFilterAfterConfig() {
|
||||
// do not add the default filters to make testing easier
|
||||
super(true)
|
||||
}
|
||||
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.addFilterAfter(new CustomFilter(), UsernamePasswordAuthenticationFilter.class)
|
||||
.formLogin()
|
||||
}
|
||||
}
|
||||
|
||||
def "http/custom-filter@position"() {
|
||||
when:
|
||||
loadConfig(CustomFilterPositionConfig)
|
||||
then:
|
||||
filterChain().filters.collect { it.class } == [CustomFilter]
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CustomFilterPositionConfig extends BaseWebConfig {
|
||||
CustomFilterPositionConfig() {
|
||||
// do not add the default filters to make testing easier
|
||||
super(true)
|
||||
}
|
||||
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
// this works so long as the CustomFilter extends one of the standard filters
|
||||
// if not, use addFilterBefore or addFilterAfter
|
||||
.addFilter(new CustomFilter())
|
||||
}
|
||||
}
|
||||
|
||||
def "http/custom-filter@position at"() {
|
||||
when:
|
||||
loadConfig(CustomFilterPositionAtConfig)
|
||||
then:
|
||||
filterChain().filters.collect { it.class } == [OtherCustomFilter]
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CustomFilterPositionAtConfig extends BaseWebConfig {
|
||||
CustomFilterPositionAtConfig() {
|
||||
// do not add the default filters to make testing easier
|
||||
super(true)
|
||||
}
|
||||
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.addFilterAt(new OtherCustomFilter(), UsernamePasswordAuthenticationFilter.class)
|
||||
}
|
||||
}
|
||||
|
||||
def "http/custom-filter no AuthenticationManager in HttpSecurity"() {
|
||||
when:
|
||||
loadConfig(NoAuthenticationManagerInHtppConfigurationConfig)
|
||||
then:
|
||||
filterChain().filters[0].class == CustomFilter
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class NoAuthenticationManagerInHtppConfigurationConfig extends WebSecurityConfigurerAdapter {
|
||||
NoAuthenticationManagerInHtppConfigurationConfig() {
|
||||
super(true)
|
||||
}
|
||||
|
||||
protected AuthenticationManager authenticationManager()
|
||||
throws Exception {
|
||||
return new CustomAuthenticationManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.addFilterBefore(new CustomFilter(), UsernamePasswordAuthenticationFilter.class)
|
||||
}
|
||||
}
|
||||
|
||||
static class CustomFilter extends UsernamePasswordAuthenticationFilter {}
|
||||
static class OtherCustomFilter extends OncePerRequestFilter {
|
||||
protected void doFilterInternal(
|
||||
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
filterChain.doFilter(request,response);
|
||||
}
|
||||
}
|
||||
|
||||
static class CustomAuthenticationManager implements AuthenticationManager {
|
||||
public Authentication authenticate(Authentication authentication)
|
||||
throws AuthenticationException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,134 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest
|
||||
import javax.servlet.http.HttpServletResponse
|
||||
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.mock.web.MockFilterChain
|
||||
import org.springframework.mock.web.MockHttpServletRequest
|
||||
import org.springframework.mock.web.MockHttpServletResponse
|
||||
import org.springframework.security.config.annotation.BaseSpringSpec
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.BaseWebConfig
|
||||
import org.springframework.security.web.FilterChainProxy
|
||||
import org.springframework.security.web.firewall.DefaultHttpFirewall
|
||||
import org.springframework.security.web.firewall.FirewalledRequest
|
||||
import org.springframework.security.web.firewall.RequestRejectedException
|
||||
|
||||
/**
|
||||
* Tests to verify that all the functionality of <http-firewall> attributes is present
|
||||
*
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
public class NamespaceHttpFirewallTests extends BaseSpringSpec {
|
||||
FilterChainProxy springSecurityFilterChain
|
||||
MockHttpServletRequest request
|
||||
MockHttpServletResponse response
|
||||
MockFilterChain chain
|
||||
|
||||
def setup() {
|
||||
request = new MockHttpServletRequest("GET", "")
|
||||
response = new MockHttpServletResponse()
|
||||
chain = new MockFilterChain()
|
||||
}
|
||||
|
||||
def "http-firewall"() {
|
||||
setup:
|
||||
loadConfig(HttpFirewallConfig)
|
||||
springSecurityFilterChain = context.getBean(FilterChainProxy)
|
||||
request.setPathInfo("/public/../private/")
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "the default firewall is used"
|
||||
thrown(RequestRejectedException)
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class HttpFirewallConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
}
|
||||
}
|
||||
|
||||
def "http-firewall@ref"() {
|
||||
setup:
|
||||
loadConfig(CustomHttpFirewallConfig)
|
||||
springSecurityFilterChain = context.getBean(FilterChainProxy)
|
||||
request.setParameter("deny", "true")
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "the custom firewall is used"
|
||||
thrown(RequestRejectedException)
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CustomHttpFirewallConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) { }
|
||||
|
||||
@Override
|
||||
public void configure(WebSecurity builder) throws Exception {
|
||||
builder
|
||||
.httpFirewall(new CustomHttpFirewall())
|
||||
}
|
||||
}
|
||||
|
||||
def "http-firewall bean"() {
|
||||
setup:
|
||||
loadConfig(CustomHttpFirewallBeanConfig)
|
||||
springSecurityFilterChain = context.getBean(FilterChainProxy)
|
||||
request.setParameter("deny", "true")
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "the custom firewall is used"
|
||||
thrown(RequestRejectedException)
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CustomHttpFirewallBeanConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) { }
|
||||
|
||||
@Bean
|
||||
CustomHttpFirewall firewall() {
|
||||
return new CustomHttpFirewall();
|
||||
}
|
||||
}
|
||||
|
||||
static class CustomHttpFirewall extends DefaultHttpFirewall {
|
||||
|
||||
@Override
|
||||
public FirewalledRequest getFirewalledRequest(HttpServletRequest request)
|
||||
throws RequestRejectedException {
|
||||
if(request.getParameter("deny")) {
|
||||
throw new RequestRejectedException("custom rejection")
|
||||
}
|
||||
return super.getFirewalledRequest(request)
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpServletResponse getFirewalledResponse(
|
||||
HttpServletResponse response) {
|
||||
return super.getFirewalledRequest(response)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,170 +0,0 @@
|
|||
|
||||
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers
|
||||
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.mock.web.MockFilterChain
|
||||
import org.springframework.mock.web.MockHttpServletRequest
|
||||
import org.springframework.mock.web.MockHttpServletResponse
|
||||
import org.springframework.security.config.annotation.BaseSpringSpec
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.BaseWebConfig
|
||||
import org.springframework.security.web.FilterChainProxy
|
||||
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource
|
||||
|
||||
/**
|
||||
* Tests to verify that all the functionality of <anonymous> attributes is present
|
||||
*
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
public class NamespaceHttpFormLoginTests extends BaseSpringSpec {
|
||||
FilterChainProxy springSecurityFilterChain
|
||||
|
||||
def "http/form-login"() {
|
||||
setup:
|
||||
loadConfig(FormLoginConfig)
|
||||
springSecurityFilterChain = context.getBean(FilterChainProxy)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getRedirectedUrl() == "http://localhost/login"
|
||||
when: "fail to log in"
|
||||
super.setup()
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to login error page"
|
||||
response.getRedirectedUrl() == "/login?error"
|
||||
when: "login success"
|
||||
super.setup()
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
request.parameters.username = ["user"] as String[]
|
||||
request.parameters.password = ["password"] as String[]
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to default succes page"
|
||||
response.getRedirectedUrl() == "/"
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class FormLoginConfig extends BaseWebConfig {
|
||||
|
||||
@Override
|
||||
public void configure(WebSecurity web) throws Exception {
|
||||
web
|
||||
.ignoring()
|
||||
.antMatchers("/resources/**");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
}
|
||||
}
|
||||
|
||||
def "http/form-login custom"() {
|
||||
setup:
|
||||
loadConfig(FormLoginCustomConfig)
|
||||
springSecurityFilterChain = context.getBean(FilterChainProxy)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getRedirectedUrl() == "http://localhost/authentication/login"
|
||||
when: "fail to log in"
|
||||
super.setup()
|
||||
request.servletPath = "/authentication/login/process"
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to login error page"
|
||||
response.getRedirectedUrl() == "/authentication/login?failed"
|
||||
when: "login success"
|
||||
super.setup()
|
||||
request.servletPath = "/authentication/login/process"
|
||||
request.method = "POST"
|
||||
request.parameters.username = ["user"] as String[]
|
||||
request.parameters.password = ["password"] as String[]
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to default succes page"
|
||||
response.getRedirectedUrl() == "/default"
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class FormLoginCustomConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
boolean alwaysUseDefaultSuccess = true;
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
.usernameParameter("username") // form-login@username-parameter
|
||||
.passwordParameter("password") // form-login@password-parameter
|
||||
.loginPage("/authentication/login") // form-login@login-page
|
||||
.failureUrl("/authentication/login?failed") // form-login@authentication-failure-url
|
||||
.loginProcessingUrl("/authentication/login/process") // form-login@login-processing-url
|
||||
.defaultSuccessUrl("/default", alwaysUseDefaultSuccess) // form-login@default-target-url / form-login@always-use-default-target
|
||||
}
|
||||
}
|
||||
|
||||
def "http/form-login custom refs"() {
|
||||
when:
|
||||
loadConfig(FormLoginCustomRefsConfig)
|
||||
springSecurityFilterChain = context.getBean(FilterChainProxy)
|
||||
then: "CustomWebAuthenticationDetailsSource is used"
|
||||
findFilter(UsernamePasswordAuthenticationFilter).authenticationDetailsSource.class == CustomWebAuthenticationDetailsSource
|
||||
when: "fail to log in"
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to login error page"
|
||||
response.getRedirectedUrl() == "/custom/failure"
|
||||
when: "login success"
|
||||
super.setup()
|
||||
request.servletPath = "/login"
|
||||
request.method = "POST"
|
||||
request.parameters.username = ["user"] as String[]
|
||||
request.parameters.password = ["password"] as String[]
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to default succes page"
|
||||
response.getRedirectedUrl() == "/custom/targetUrl"
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class FormLoginCustomRefsConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.loginPage("/login")
|
||||
.failureHandler(new SimpleUrlAuthenticationFailureHandler("/custom/failure")) // form-login@authentication-failure-handler-ref
|
||||
.successHandler(new SavedRequestAwareAuthenticationSuccessHandler( defaultTargetUrl : "/custom/targetUrl" )) // form-login@authentication-success-handler-ref
|
||||
.authenticationDetailsSource(new CustomWebAuthenticationDetailsSource()) // form-login@authentication-details-source-ref
|
||||
.and();
|
||||
}
|
||||
}
|
||||
|
||||
static class CustomWebAuthenticationDetailsSource extends WebAuthenticationDetailsSource {}
|
||||
}
|
|
@ -1,267 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.security.config.annotation.BaseSpringSpec
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.BaseWebConfig
|
||||
import org.springframework.security.web.header.writers.CacheControlHeadersWriter
|
||||
import org.springframework.security.web.header.writers.HstsHeaderWriter
|
||||
import org.springframework.security.web.header.writers.StaticHeadersWriter
|
||||
import org.springframework.security.web.header.writers.XContentTypeOptionsHeaderWriter
|
||||
import org.springframework.security.web.header.writers.XXssProtectionHeaderWriter
|
||||
import org.springframework.security.web.header.writers.frameoptions.StaticAllowFromStrategy
|
||||
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter
|
||||
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter.XFrameOptionsMode
|
||||
import org.springframework.security.web.util.matcher.AnyRequestMatcher
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
|
||||
/**
|
||||
* Tests to verify that all the functionality of <headers> attributes is present
|
||||
*
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
public class NamespaceHttpHeadersTests extends BaseSpringSpec {
|
||||
|
||||
def "http/headers"() {
|
||||
setup:
|
||||
loadConfig(HeadersDefaultConfig)
|
||||
request.secure = true
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['X-Content-Type-Options':'nosniff',
|
||||
'X-Frame-Options':'DENY',
|
||||
'Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains',
|
||||
'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
|
||||
'Pragma':'no-cache',
|
||||
'Expires' : '0',
|
||||
'X-XSS-Protection' : '1; mode=block']
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class HeadersDefaultConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.headers()
|
||||
}
|
||||
}
|
||||
|
||||
def "http/headers/cache-control"() {
|
||||
setup:
|
||||
loadConfig(HeadersCacheControlConfig)
|
||||
request.secure = true
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
|
||||
'Expires' : '0',
|
||||
'Pragma':'no-cache']
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class HeadersCacheControlConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.headers()
|
||||
.defaultsDisabled()
|
||||
.cacheControl()
|
||||
}
|
||||
}
|
||||
|
||||
def "http/headers/hsts"() {
|
||||
setup:
|
||||
loadConfig(HstsConfig)
|
||||
request.secure = true
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains']
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class HstsConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.headers()
|
||||
.defaultsDisabled()
|
||||
.httpStrictTransportSecurity()
|
||||
}
|
||||
}
|
||||
|
||||
def "http/headers/hsts custom"() {
|
||||
setup:
|
||||
loadConfig(HstsCustomConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['Strict-Transport-Security': 'max-age=15768000']
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class HstsCustomConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.headers()
|
||||
// hsts@request-matcher-ref, hsts@max-age-seconds, hsts@include-subdomains
|
||||
.defaultsDisabled()
|
||||
.httpStrictTransportSecurity()
|
||||
.requestMatcher(AnyRequestMatcher.INSTANCE)
|
||||
.maxAgeInSeconds(15768000)
|
||||
.includeSubDomains(false)
|
||||
}
|
||||
}
|
||||
|
||||
def "http/headers/frame-options@policy=SAMEORIGIN"() {
|
||||
setup:
|
||||
loadConfig(FrameOptionsSameOriginConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['X-Frame-Options': 'SAMEORIGIN']
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class FrameOptionsSameOriginConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.headers()
|
||||
// frame-options@policy=SAMEORIGIN
|
||||
.defaultsDisabled()
|
||||
.frameOptions()
|
||||
.sameOrigin()
|
||||
}
|
||||
}
|
||||
|
||||
// frame-options@strategy, frame-options@value, frame-options@parameter are not provided instead use frame-options@ref
|
||||
|
||||
def "http/headers/frame-options"() {
|
||||
setup:
|
||||
loadConfig(FrameOptionsAllowFromConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['X-Frame-Options': 'ALLOW-FROM https://example.com']
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class FrameOptionsAllowFromConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.headers()
|
||||
// frame-options@ref
|
||||
.defaultsDisabled()
|
||||
.addHeaderWriter(new XFrameOptionsHeaderWriter(new StaticAllowFromStrategy(new URI("https://example.com"))))
|
||||
}
|
||||
}
|
||||
|
||||
def "http/headers/xss-protection"() {
|
||||
setup:
|
||||
loadConfig(XssProtectionConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['X-XSS-Protection': '1; mode=block']
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class XssProtectionConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.headers()
|
||||
// xss-protection
|
||||
.defaultsDisabled()
|
||||
.xssProtection()
|
||||
}
|
||||
}
|
||||
|
||||
def "http/headers/xss-protection custom"() {
|
||||
setup:
|
||||
loadConfig(XssProtectionCustomConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['X-XSS-Protection': '1']
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class XssProtectionCustomConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.headers()
|
||||
// xss-protection@enabled and xss-protection@block
|
||||
.defaultsDisabled()
|
||||
.xssProtection()
|
||||
.xssProtectionEnabled(true)
|
||||
.block(false)
|
||||
}
|
||||
}
|
||||
|
||||
def "http/headers/content-type-options"() {
|
||||
setup:
|
||||
loadConfig(ContentTypeOptionsConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['X-Content-Type-Options': 'nosniff']
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class ContentTypeOptionsConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.headers()
|
||||
// content-type-options
|
||||
.defaultsDisabled()
|
||||
.contentTypeOptions()
|
||||
}
|
||||
}
|
||||
|
||||
// header@name / header@value are not provided instead use header@ref
|
||||
|
||||
def "http/headers/header@ref"() {
|
||||
setup:
|
||||
loadConfig(HeaderRefConfig)
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
responseHeaders == ['customHeaderName': 'customHeaderValue']
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class HeaderRefConfig extends BaseWebConfig {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) {
|
||||
http
|
||||
.headers()
|
||||
.defaultsDisabled()
|
||||
.addHeaderWriter(new StaticHeadersWriter("customHeaderName", "customHeaderValue"))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,169 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers
|
||||
|
||||
import javax.servlet.http.HttpServletResponse
|
||||
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.mock.web.MockFilterChain
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
|
||||
import org.springframework.security.config.annotation.BaseSpringSpec
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.context.SecurityContextImpl
|
||||
import org.springframework.security.web.FilterChainProxy
|
||||
import org.springframework.security.web.context.HttpRequestResponseHolder
|
||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository
|
||||
|
||||
/**
|
||||
* Tests to verify that all the functionality of <intercept-url> attributes is present
|
||||
*
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
public class NamespaceHttpInterceptUrlTests extends BaseSpringSpec {
|
||||
|
||||
def "http/intercept-url denied when not logged in"() {
|
||||
setup:
|
||||
loadConfig(HttpInterceptUrlConfig)
|
||||
request.servletPath == "/users"
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
}
|
||||
|
||||
def "http/intercept-url denied when logged in"() {
|
||||
setup:
|
||||
loadConfig(HttpInterceptUrlConfig)
|
||||
login()
|
||||
request.setServletPath("/users")
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
}
|
||||
|
||||
def "http/intercept-url allowed when logged in"() {
|
||||
setup:
|
||||
loadConfig(HttpInterceptUrlConfig)
|
||||
login("admin","ROLE_ADMIN")
|
||||
request.setServletPath("/users")
|
||||
when:
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
!response.isCommitted()
|
||||
}
|
||||
|
||||
def "http/intercept-url@method=POST"() {
|
||||
setup:
|
||||
loadConfig(HttpInterceptUrlConfig)
|
||||
when:
|
||||
login()
|
||||
request.setServletPath("/admin/post")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
!response.isCommitted()
|
||||
when:
|
||||
super.setup()
|
||||
login()
|
||||
request.setServletPath("/admin/post")
|
||||
request.setMethod("POST")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_FORBIDDEN
|
||||
when:
|
||||
super.setup()
|
||||
login("admin","ROLE_ADMIN")
|
||||
request.setServletPath("/admin/post")
|
||||
request.setMethod("POST")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == HttpServletResponse.SC_OK
|
||||
!response.committed
|
||||
}
|
||||
|
||||
def "http/intercept-url@requires-channel"() {
|
||||
setup:
|
||||
loadConfig(HttpInterceptUrlConfig)
|
||||
when:
|
||||
request.setServletPath("/login")
|
||||
request.setRequestURI("/login")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "https://localhost/login"
|
||||
when:
|
||||
super.setup()
|
||||
request.setServletPath("/secured/a")
|
||||
request.setRequestURI("/secured/a")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "https://localhost/secured/a"
|
||||
when:
|
||||
super.setup()
|
||||
request.setSecure(true)
|
||||
request.setScheme("https")
|
||||
request.setServletPath("/user")
|
||||
request.setRequestURI("/user")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "http://localhost/user"
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class HttpInterceptUrlConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
// the line below is similar to intercept-url@pattern:
|
||||
// <intercept-url pattern="/users**" access="hasRole('ROLE_ADMIN')"/>
|
||||
// <intercept-url pattern="/sessions/**" access="hasRole('ROLE_ADMIN')"/>
|
||||
.antMatchers("/users**","/sessions/**").hasRole("ADMIN")
|
||||
// the line below is similar to intercept-url@method:
|
||||
// <intercept-url pattern="/admin/post" access="hasRole('ROLE_ADMIN')" method="POST"/>
|
||||
// <intercept-url pattern="/admin/another-post/**" access="hasRole('ROLE_ADMIN')" method="POST"/>
|
||||
.antMatchers(HttpMethod.POST, "/admin/post","/admin/another-post/**").hasRole("ADMIN")
|
||||
.antMatchers("/signup").permitAll()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.requiresChannel()
|
||||
// NOTE: channel security is configured separately of authorization (i.e. intercept-url@access
|
||||
// the line below is similar to intercept-url@requires-channel="https":
|
||||
// <intercept-url pattern="/login" requires-channel="https"/>
|
||||
// <intercept-url pattern="/secured/**" requires-channel="https"/>
|
||||
.antMatchers("/login","/secured/**").requiresSecure()
|
||||
// the line below is similar to intercept-url@requires-channel="http":
|
||||
// <intercept-url pattern="/**" requires-channel="http"/>
|
||||
.anyRequest().requiresInsecure()
|
||||
}
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER").and()
|
||||
.withUser("admin").password("password").roles("USER", "ADMIN")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,142 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.mock.web.MockFilterChain
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse
|
||||
import org.springframework.security.access.AccessDecisionManager
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.access.ConfigAttribute
|
||||
import org.springframework.security.authentication.AnonymousAuthenticationToken
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.BaseSpringSpec
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint
|
||||
import org.springframework.security.web.FilterChainProxy
|
||||
import org.springframework.security.web.FilterInvocation
|
||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
|
||||
import org.springframework.security.web.access.ExceptionTranslationFilter
|
||||
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor
|
||||
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource
|
||||
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider;
|
||||
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
|
||||
import org.springframework.security.web.authentication.preauth.PreAuthenticatedGrantedAuthoritiesUserDetailsService;
|
||||
import org.springframework.security.web.authentication.preauth.j2ee.J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource;
|
||||
import org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
||||
import org.springframework.security.web.context.NullSecurityContextRepository;
|
||||
import org.springframework.security.web.context.SecurityContextPersistenceFilter
|
||||
import org.springframework.security.web.jaasapi.JaasApiIntegrationFilter;
|
||||
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher
|
||||
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
/**
|
||||
* Tests to verify that all the functionality of <jee> attributes is present
|
||||
*
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
public class NamespaceHttpJeeTests extends BaseSpringSpec {
|
||||
|
||||
def "http/jee@mappable-roles"() {
|
||||
when:
|
||||
loadConfig(JeeMappableRolesConfig)
|
||||
J2eePreAuthenticatedProcessingFilter filter = findFilter(J2eePreAuthenticatedProcessingFilter)
|
||||
AuthenticationManager authenticationManager = ReflectionTestUtils.getField(filter,"authenticationManager")
|
||||
then:
|
||||
authenticationManager
|
||||
filter.authenticationDetailsSource.class == J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource
|
||||
filter.authenticationDetailsSource.j2eeMappableRoles == ["ROLE_USER", "ROLE_ADMIN"] as Set
|
||||
authenticationManager.providers.find { it instanceof PreAuthenticatedAuthenticationProvider }.preAuthenticatedUserDetailsService.class == PreAuthenticatedGrantedAuthoritiesUserDetailsService
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
public static class JeeMappableRolesConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.jee()
|
||||
.mappableRoles("USER","ADMIN");
|
||||
}
|
||||
}
|
||||
|
||||
def "http/jee@user-service-ref"() {
|
||||
when:
|
||||
loadConfig(JeeUserServiceRefConfig)
|
||||
J2eePreAuthenticatedProcessingFilter filter = findFilter(J2eePreAuthenticatedProcessingFilter)
|
||||
AuthenticationManager authenticationManager = ReflectionTestUtils.getField(filter,"authenticationManager")
|
||||
then:
|
||||
authenticationManager
|
||||
filter.authenticationDetailsSource.class == J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource
|
||||
filter.authenticationDetailsSource.j2eeMappableRoles == ["ROLE_USER", "ROLE_ADMIN"] as Set
|
||||
authenticationManager.providers.find { it instanceof PreAuthenticatedAuthenticationProvider }.preAuthenticatedUserDetailsService.class == CustomUserService
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
public static class JeeUserServiceRefConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.jee()
|
||||
.mappableAuthorities("ROLE_USER","ROLE_ADMIN")
|
||||
.authenticatedUserDetailsService(new CustomUserService());
|
||||
}
|
||||
}
|
||||
|
||||
static class CustomUserService implements AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> {
|
||||
public UserDetails loadUserDetails(
|
||||
PreAuthenticatedAuthenticationToken token)
|
||||
throws UsernameNotFoundException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,115 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers
|
||||
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.mock.web.MockFilterChain
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
|
||||
import org.springframework.security.config.annotation.BaseSpringSpec
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.context.SecurityContextImpl
|
||||
import org.springframework.security.web.FilterChainProxy
|
||||
import org.springframework.security.web.context.HttpRequestResponseHolder
|
||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository
|
||||
|
||||
/**
|
||||
* Tests to verify that all the functionality of <port-mappings> attributes is present
|
||||
*
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
public class NamespaceHttpPortMappingsTests extends BaseSpringSpec {
|
||||
FilterChainProxy springSecurityFilterChain
|
||||
MockHttpServletRequest request
|
||||
MockHttpServletResponse response
|
||||
MockFilterChain chain
|
||||
|
||||
def setup() {
|
||||
request = new MockHttpServletRequest("GET", "")
|
||||
request.setMethod("GET")
|
||||
response = new MockHttpServletResponse()
|
||||
chain = new MockFilterChain()
|
||||
}
|
||||
|
||||
def "http/port-mapper works with http/intercept-url@requires-channel"() {
|
||||
setup:
|
||||
loadConfig(HttpInterceptUrlWithPortMapperConfig)
|
||||
springSecurityFilterChain = context.getBean(FilterChainProxy)
|
||||
when:
|
||||
request.setServletPath("/login")
|
||||
request.setRequestURI("/login")
|
||||
request.setServerPort(9080);
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "https://localhost:9443/login"
|
||||
when:
|
||||
setup()
|
||||
request.setServletPath("/secured/a")
|
||||
request.setRequestURI("/secured/a")
|
||||
request.setServerPort(9080);
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "https://localhost:9443/secured/a"
|
||||
when:
|
||||
setup()
|
||||
request.setSecure(true)
|
||||
request.setScheme("https")
|
||||
request.setServerPort(9443);
|
||||
request.setServletPath("/user")
|
||||
request.setRequestURI("/user")
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.redirectedUrl == "http://localhost:9080/user"
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class HttpInterceptUrlWithPortMapperConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.portMapper()
|
||||
.http(9080).mapsTo(9443)
|
||||
.and()
|
||||
.requiresChannel()
|
||||
.antMatchers("/login","/secured/**").requiresSecure()
|
||||
.anyRequest().requiresInsecure()
|
||||
}
|
||||
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER").and()
|
||||
.withUser("admin").password("password").roles("USER", "ADMIN")
|
||||
}
|
||||
}
|
||||
|
||||
def login(String username="user", String role="ROLE_USER") {
|
||||
HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository()
|
||||
HttpRequestResponseHolder requestResponseHolder = new HttpRequestResponseHolder(request, response)
|
||||
repo.loadContext(requestResponseHolder)
|
||||
repo.saveContext(new SecurityContextImpl(authentication: new UsernamePasswordAuthenticationToken(username, null, AuthorityUtils.createAuthorityList(role))), requestResponseHolder.request, requestResponseHolder.response)
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.config.annotation.BaseSpringSpec;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.BaseWebConfig;
|
||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
import org.springframework.security.web.access.ExceptionTranslationFilter;
|
||||
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
|
||||
import org.springframework.security.web.savedrequest.RequestCache;
|
||||
|
||||
/**
|
||||
* Tests to verify that all the functionality of <request-cache> attributes is present
|
||||
*
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
public class NamespaceHttpRequestCacheTests extends BaseSpringSpec {
|
||||
def "http/request-cache@ref"() {
|
||||
setup:
|
||||
RequestCacheRefConfig.REQUEST_CACHE = Mock(RequestCache)
|
||||
when:
|
||||
loadConfig(RequestCacheRefConfig)
|
||||
then:
|
||||
findFilter(ExceptionTranslationFilter).requestCache == RequestCacheRefConfig.REQUEST_CACHE
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class RequestCacheRefConfig extends BaseWebConfig {
|
||||
static RequestCache REQUEST_CACHE
|
||||
protected void configure(HttpSecurity http) {
|
||||
http.
|
||||
requestCache()
|
||||
.requestCache(REQUEST_CACHE)
|
||||
}
|
||||
}
|
||||
|
||||
def "http/request-cache@ref defaults to HttpSessionRequestCache"() {
|
||||
when:
|
||||
loadConfig(DefaultRequestCacheRefConfig)
|
||||
then:
|
||||
findFilter(ExceptionTranslationFilter).requestCache.class == HttpSessionRequestCache
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class DefaultRequestCacheRefConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.config.annotation.BaseSpringSpec;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.BaseWebConfig;
|
||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
import org.springframework.security.web.access.ExceptionTranslationFilter;
|
||||
|
||||
/**
|
||||
* Tests to verify that all the functionality of <access-denied-handler> attributes is present
|
||||
*
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
public class NamespaceHttpServerAccessDeniedHandlerTests extends BaseSpringSpec {
|
||||
def "http/access-denied-handler@error-page"() {
|
||||
when:
|
||||
loadConfig(AccessDeniedPageConfig)
|
||||
then:
|
||||
findFilter(ExceptionTranslationFilter).accessDeniedHandler.errorPage == "/AccessDeniedPageConfig"
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class AccessDeniedPageConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
http.
|
||||
exceptionHandling()
|
||||
.accessDeniedPage("/AccessDeniedPageConfig")
|
||||
}
|
||||
}
|
||||
|
||||
def "http/access-denied-handler@ref"() {
|
||||
when:
|
||||
loadConfig(AccessDeniedHandlerRefConfig)
|
||||
then:
|
||||
findFilter(ExceptionTranslationFilter).accessDeniedHandler.class == AccessDeniedHandlerRefConfig.CustomAccessDeniedHandler
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class AccessDeniedHandlerRefConfig extends BaseWebConfig {
|
||||
protected void configure(HttpSecurity http) {
|
||||
CustomAccessDeniedHandler accessDeniedHandler = new CustomAccessDeniedHandler()
|
||||
http.
|
||||
exceptionHandling()
|
||||
.accessDeniedHandler(accessDeniedHandler)
|
||||
}
|
||||
|
||||
static class CustomAccessDeniedHandler implements AccessDeniedHandler {
|
||||
public void handle(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
AccessDeniedException accessDeniedException)
|
||||
throws IOException, ServletException {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.assertj.core.api.ListAssert;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.test.SpringTestRule;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests to verify that all the functionality of <custom-filter> attributes is present
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Josh Cummings
|
||||
*
|
||||
*/
|
||||
public class NamespaceHttpCustomFilterTests {
|
||||
|
||||
@Rule
|
||||
public final SpringTestRule spring = new SpringTestRule();
|
||||
|
||||
@Test
|
||||
public void getFiltersWhenFilterAddedBeforeThenBehaviorMatchesNamespace() {
|
||||
this.spring.register(CustomFilterBeforeConfig.class, UserDetailsServiceConfig.class).autowire();
|
||||
assertThatFilters().containsSubsequence(CustomFilter.class, UsernamePasswordAuthenticationFilter.class);
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CustomFilterBeforeConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.addFilterBefore(new CustomFilter(), UsernamePasswordAuthenticationFilter.class)
|
||||
.formLogin();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFiltersWhenFilterAddedAfterThenBehaviorMatchesNamespace() {
|
||||
this.spring.register(CustomFilterAfterConfig.class, UserDetailsServiceConfig.class).autowire();
|
||||
assertThatFilters().containsSubsequence(UsernamePasswordAuthenticationFilter.class, CustomFilter.class);
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CustomFilterAfterConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.addFilterAfter(new CustomFilter(), UsernamePasswordAuthenticationFilter.class)
|
||||
.formLogin();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFiltersWhenFilterAddedThenBehaviorMatchesNamespace() {
|
||||
this.spring.register(CustomFilterPositionConfig.class, UserDetailsServiceConfig.class).autowire();
|
||||
assertThatFilters().containsExactly(CustomFilter.class);
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CustomFilterPositionConfig extends WebSecurityConfigurerAdapter {
|
||||
CustomFilterPositionConfig() {
|
||||
// do not add the default filters to make testing easier
|
||||
super(true);
|
||||
}
|
||||
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
// this works so long as the CustomFilter extends one of the standard filters
|
||||
// if not, use addFilterBefore or addFilterAfter
|
||||
.addFilter(new CustomFilter());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void getFiltersWhenFilterAddedAtPositionThenBehaviorMatchesNamespace() {
|
||||
this.spring.register(CustomFilterPositionAtConfig.class, UserDetailsServiceConfig.class).autowire();
|
||||
assertThatFilters().containsExactly(OtherCustomFilter.class);
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CustomFilterPositionAtConfig extends WebSecurityConfigurerAdapter {
|
||||
CustomFilterPositionAtConfig() {
|
||||
// do not add the default filters to make testing easier
|
||||
super(true);
|
||||
}
|
||||
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.addFilterAt(new OtherCustomFilter(), UsernamePasswordAuthenticationFilter.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFiltersWhenCustomAuthenticationManagerThenBehaviorMatchesNamespace() {
|
||||
this.spring.register(NoAuthenticationManagerInHttpConfigurationConfig.class).autowire();
|
||||
assertThatFilters().startsWith(CustomFilter.class);
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class NoAuthenticationManagerInHttpConfigurationConfig extends WebSecurityConfigurerAdapter {
|
||||
NoAuthenticationManagerInHttpConfigurationConfig() {
|
||||
super(true);
|
||||
}
|
||||
|
||||
protected AuthenticationManager authenticationManager()
|
||||
throws Exception {
|
||||
return new CustomAuthenticationManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.addFilterBefore(new CustomFilter(), UsernamePasswordAuthenticationFilter.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class UserDetailsServiceConfig {
|
||||
@Bean
|
||||
public UserDetailsService userDetailsService() {
|
||||
return new InMemoryUserDetailsManager(
|
||||
User.withDefaultPasswordEncoder()
|
||||
.username("user")
|
||||
.password("password")
|
||||
.roles("USER")
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
static class CustomFilter extends UsernamePasswordAuthenticationFilter {}
|
||||
static class OtherCustomFilter extends OncePerRequestFilter {
|
||||
protected void doFilterInternal(
|
||||
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
static class CustomAuthenticationManager implements AuthenticationManager {
|
||||
public Authentication authenticate(Authentication authentication)
|
||||
throws AuthenticationException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private ListAssert<Class<?>> assertThatFilters() {
|
||||
FilterChainProxy filterChain = this.spring.getContext().getBean(FilterChainProxy.class);
|
||||
List<Class<?>> filters = filterChain.getFilters("/").stream()
|
||||
.map(Object::getClass).collect(Collectors.toList());
|
||||
return assertThat(filters);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.test.SpringTestRule;
|
||||
import org.springframework.security.web.firewall.DefaultHttpFirewall;
|
||||
import org.springframework.security.web.firewall.FirewalledRequest;
|
||||
import org.springframework.security.web.firewall.HttpFirewall;
|
||||
import org.springframework.security.web.firewall.RequestRejectedException;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatCode;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
|
||||
/**
|
||||
* Tests to verify that all the functionality of <http-firewall> attributes is present
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Josh Cummings
|
||||
*/
|
||||
public class NamespaceHttpFirewallTests {
|
||||
|
||||
@Rule
|
||||
public final SpringTestRule rule = new SpringTestRule();
|
||||
|
||||
@Autowired
|
||||
MockMvc mvc;
|
||||
|
||||
@Test
|
||||
public void requestWhenPathContainsDoubleDotsThenBehaviorMatchesNamespace() throws Exception {
|
||||
this.rule.register(HttpFirewallConfig.class).autowire();
|
||||
assertThatCode(() -> this.mvc.perform(get("/public/../private/")))
|
||||
.isInstanceOf(RequestRejectedException.class);
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class HttpFirewallConfig {}
|
||||
|
||||
@Test
|
||||
public void requestWithCustomFirewallThenBehaviorMatchesNamespace() {
|
||||
this.rule.register(CustomHttpFirewallConfig.class).autowire();
|
||||
assertThatCode(() -> this.mvc.perform(get("/").param("deny", "true")))
|
||||
.isInstanceOf(RequestRejectedException.class);
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CustomHttpFirewallConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
public void configure(WebSecurity web) throws Exception {
|
||||
web
|
||||
.httpFirewall(new CustomHttpFirewall());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWithCustomFirewallBeanThenBehaviorMatchesNamespace() {
|
||||
this.rule.register(CustomHttpFirewallBeanConfig.class).autowire();
|
||||
assertThatCode(() -> this.mvc.perform(get("/").param("deny", "true")))
|
||||
.isInstanceOf(RequestRejectedException.class);
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CustomHttpFirewallBeanConfig {
|
||||
@Bean
|
||||
HttpFirewall firewall() {
|
||||
return new CustomHttpFirewall();
|
||||
}
|
||||
}
|
||||
|
||||
static class CustomHttpFirewall extends DefaultHttpFirewall {
|
||||
|
||||
@Override
|
||||
public FirewalledRequest getFirewalledRequest(HttpServletRequest request)
|
||||
throws RequestRejectedException {
|
||||
if (request.getParameter("deny") != null) {
|
||||
throw new RequestRejectedException("custom rejection");
|
||||
}
|
||||
return super.getFirewalledRequest(request);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.test.SpringTestRule;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
|
||||
|
||||
/**
|
||||
* Tests to verify that all the functionality of <form-login> attributes is present
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Josh Cummings
|
||||
*
|
||||
*/
|
||||
public class NamespaceHttpFormLoginTests {
|
||||
|
||||
@Rule
|
||||
public final SpringTestRule spring = new SpringTestRule();
|
||||
|
||||
@Autowired
|
||||
MockMvc mvc;
|
||||
|
||||
|
||||
@Test
|
||||
public void formLoginWhenDefaultConfigurationThenMatchesNamespace() throws Exception {
|
||||
this.spring.register(FormLoginConfig.class, UserDetailsServiceConfig.class).autowire();
|
||||
|
||||
this.mvc.perform(get("/"))
|
||||
.andExpect(redirectedUrl("http://localhost/login"));
|
||||
|
||||
this.mvc.perform(post("/login")
|
||||
.with(csrf()))
|
||||
.andExpect(redirectedUrl("/login?error"));
|
||||
|
||||
this.mvc.perform(post("/login")
|
||||
.param("username", "user")
|
||||
.param("password", "password")
|
||||
.with(csrf()))
|
||||
.andExpect(redirectedUrl("/"));
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class FormLoginConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
public void configure(WebSecurity web) throws Exception {
|
||||
web
|
||||
.ignoring()
|
||||
.antMatchers("/resources/**");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void formLoginWithCustomEndpointsThenBehaviorMatchesNamespace() throws Exception {
|
||||
this.spring.register(FormLoginCustomConfig.class, UserDetailsServiceConfig.class).autowire();
|
||||
|
||||
this.mvc.perform(get("/"))
|
||||
.andExpect(redirectedUrl("http://localhost/authentication/login"));
|
||||
|
||||
this.mvc.perform(post("/authentication/login/process")
|
||||
.with(csrf()))
|
||||
.andExpect(redirectedUrl("/authentication/login?failed"));
|
||||
|
||||
this.mvc.perform(post("/authentication/login/process")
|
||||
.param("username", "user")
|
||||
.param("password", "password")
|
||||
.with(csrf()))
|
||||
.andExpect(redirectedUrl("/default"));
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class FormLoginCustomConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
boolean alwaysUseDefaultSuccess = true;
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
.usernameParameter("username") // form-login@username-parameter
|
||||
.passwordParameter("password") // form-login@password-parameter
|
||||
.loginPage("/authentication/login") // form-login@login-page
|
||||
.failureUrl("/authentication/login?failed") // form-login@authentication-failure-url
|
||||
.loginProcessingUrl("/authentication/login/process") // form-login@login-processing-url
|
||||
.defaultSuccessUrl("/default", alwaysUseDefaultSuccess); // form-login@default-target-url / form-login@always-use-default-target
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void formLoginWithCustomHandlersThenBehaviorMatchesNamespace() throws Exception {
|
||||
this.spring.register(FormLoginCustomRefsConfig.class, UserDetailsServiceConfig.class).autowire();
|
||||
|
||||
this.mvc.perform(get("/"))
|
||||
.andExpect(redirectedUrl("http://localhost/login"));
|
||||
|
||||
this.mvc.perform(post("/login")
|
||||
.with(csrf()))
|
||||
.andExpect(redirectedUrl("/custom/failure"));
|
||||
verifyBean(WebAuthenticationDetailsSource.class).buildDetails(any(HttpServletRequest.class));
|
||||
|
||||
this.mvc.perform(post("/login")
|
||||
.param("username", "user")
|
||||
.param("password", "password")
|
||||
.with(csrf()))
|
||||
.andExpect(redirectedUrl("/custom/targetUrl"));
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class FormLoginCustomRefsConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
SavedRequestAwareAuthenticationSuccessHandler successHandler =
|
||||
new SavedRequestAwareAuthenticationSuccessHandler();
|
||||
successHandler.setDefaultTargetUrl("/custom/targetUrl");
|
||||
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.formLogin()
|
||||
.loginPage("/login")
|
||||
.failureHandler(new SimpleUrlAuthenticationFailureHandler("/custom/failure")) // form-login@authentication-failure-handler-ref
|
||||
.successHandler(successHandler) // form-login@authentication-success-handler-ref
|
||||
.authenticationDetailsSource(authenticationDetailsSource()) // form-login@authentication-details-source-ref
|
||||
.and();
|
||||
}
|
||||
|
||||
@Bean
|
||||
WebAuthenticationDetailsSource authenticationDetailsSource() {
|
||||
return spy(WebAuthenticationDetailsSource.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class UserDetailsServiceConfig {
|
||||
@Bean
|
||||
public UserDetailsService userDetailsService() {
|
||||
return new InMemoryUserDetailsManager(
|
||||
User.withDefaultPasswordEncoder()
|
||||
.username("user")
|
||||
.password("password")
|
||||
.roles("USER")
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T verifyBean(Class<T> beanClass) {
|
||||
return verify(this.spring.getContext().getBean(beanClass));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,293 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.test.SpringTestRule;
|
||||
import org.springframework.security.web.header.writers.StaticHeadersWriter;
|
||||
import org.springframework.security.web.header.writers.frameoptions.StaticAllowFromStrategy;
|
||||
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter;
|
||||
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.ResultMatcher;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
|
||||
|
||||
/**
|
||||
* Tests to verify that all the functionality of <headers> attributes is present
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Josh Cummings
|
||||
*
|
||||
*/
|
||||
public class NamespaceHttpHeadersTests {
|
||||
static final Map<String, String> defaultHeaders = new LinkedHashMap<>();
|
||||
|
||||
static {
|
||||
defaultHeaders.put("X-Content-Type-Options", "nosniff");
|
||||
defaultHeaders.put("X-Frame-Options", "DENY");
|
||||
defaultHeaders.put("Strict-Transport-Security", "max-age=31536000 ; includeSubDomains");
|
||||
defaultHeaders.put("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate");
|
||||
defaultHeaders.put("Expires", "0");
|
||||
defaultHeaders.put("Pragma", "no-cache");
|
||||
defaultHeaders.put("X-XSS-Protection", "1; mode=block");
|
||||
}
|
||||
|
||||
@Rule
|
||||
public final SpringTestRule spring = new SpringTestRule();
|
||||
|
||||
@Autowired
|
||||
MockMvc mvc;
|
||||
|
||||
@Test
|
||||
public void secureRequestWhenDefaultConfigThenBehaviorMatchesNamespace() throws Exception {
|
||||
this.spring.register(HeadersDefaultConfig.class).autowire();
|
||||
|
||||
this.mvc.perform(get("/").secure(true))
|
||||
.andExpect(includesDefaults());
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class HeadersDefaultConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.headers();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void secureRequestWhenCacheControlOnlyThenBehaviorMatchesNamespace() throws Exception {
|
||||
this.spring.register(HeadersCacheControlConfig.class).autowire();
|
||||
|
||||
this.mvc.perform(get("/").secure(true))
|
||||
.andExpect(includes("Cache-Control", "Expires", "Pragma"));
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class HeadersCacheControlConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.headers()
|
||||
.defaultsDisabled()
|
||||
.cacheControl();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void secureRequestWhenHstsOnlyThenBehaviorMatchesNamespace() throws Exception {
|
||||
this.spring.register(HstsConfig.class).autowire();
|
||||
|
||||
this.mvc.perform(get("/").secure(true))
|
||||
.andExpect(includes("Strict-Transport-Security"));
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class HstsConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.headers()
|
||||
.defaultsDisabled()
|
||||
.httpStrictTransportSecurity();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenHstsCustomThenBehaviorMatchesNamespace() throws Exception {
|
||||
this.spring.register(HstsCustomConfig.class).autowire();
|
||||
|
||||
this.mvc.perform(get("/"))
|
||||
.andExpect(includes(Collections.singletonMap("Strict-Transport-Security", "max-age=15768000")));
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class HstsCustomConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.headers()
|
||||
// hsts@request-matcher-ref, hsts@max-age-seconds, hsts@include-subdomains
|
||||
.defaultsDisabled()
|
||||
.httpStrictTransportSecurity()
|
||||
.requestMatcher(AnyRequestMatcher.INSTANCE)
|
||||
.maxAgeInSeconds(15768000)
|
||||
.includeSubDomains(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenFrameOptionsSameOriginThenBehaviorMatchesNamespace() throws Exception {
|
||||
this.spring.register(FrameOptionsSameOriginConfig.class).autowire();
|
||||
|
||||
this.mvc.perform(get("/"))
|
||||
.andExpect(includes(Collections.singletonMap("X-Frame-Options", "SAMEORIGIN")));
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class FrameOptionsSameOriginConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.headers()
|
||||
// frame-options@policy=SAMEORIGIN
|
||||
.defaultsDisabled()
|
||||
.frameOptions()
|
||||
.sameOrigin();
|
||||
}
|
||||
}
|
||||
|
||||
// frame-options@strategy, frame-options@value, frame-options@parameter are not provided instead use frame-options@ref
|
||||
|
||||
@Test
|
||||
public void requestWhenFrameOptionsAllowFromThenBehaviorMatchesNamespace() throws Exception {
|
||||
this.spring.register(FrameOptionsAllowFromConfig.class).autowire();
|
||||
|
||||
this.mvc.perform(get("/"))
|
||||
.andExpect(includes(Collections.singletonMap("X-Frame-Options", "ALLOW-FROM https://example.com")));
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class FrameOptionsAllowFromConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.headers()
|
||||
// frame-options@ref
|
||||
.defaultsDisabled()
|
||||
.addHeaderWriter(new XFrameOptionsHeaderWriter(
|
||||
new StaticAllowFromStrategy(URI.create("https://example.com"))));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenXssOnlyThenBehaviorMatchesNamespace() throws Exception {
|
||||
this.spring.register(XssProtectionConfig.class).autowire();
|
||||
|
||||
this.mvc.perform(get("/"))
|
||||
.andExpect(includes("X-XSS-Protection"));
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class XssProtectionConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.headers()
|
||||
// xss-protection
|
||||
.defaultsDisabled()
|
||||
.xssProtection();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenXssCustomThenBehaviorMatchesNamespace() throws Exception {
|
||||
this.spring.register(XssProtectionCustomConfig.class).autowire();
|
||||
|
||||
this.mvc.perform(get("/"))
|
||||
.andExpect(includes(Collections.singletonMap("X-XSS-Protection", "1")));
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class XssProtectionCustomConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.headers()
|
||||
// xss-protection@enabled and xss-protection@block
|
||||
.defaultsDisabled()
|
||||
.xssProtection()
|
||||
.xssProtectionEnabled(true)
|
||||
.block(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenXContentTypeOptionsOnlyThenBehaviorMatchesNamespace() throws Exception {
|
||||
this.spring.register(ContentTypeOptionsConfig.class).autowire();
|
||||
|
||||
this.mvc.perform(get("/"))
|
||||
.andExpect(includes("X-Content-Type-Options"));
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class ContentTypeOptionsConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.headers()
|
||||
// content-type-options
|
||||
.defaultsDisabled()
|
||||
.contentTypeOptions();
|
||||
}
|
||||
}
|
||||
|
||||
// header@name / header@value are not provided instead use header@ref
|
||||
|
||||
@Test
|
||||
public void requestWhenCustomHeaderOnlyThenBehaviorMatchesNamespace() throws Exception {
|
||||
this.spring.register(HeaderRefConfig.class).autowire();
|
||||
|
||||
this.mvc.perform(get("/"))
|
||||
.andExpect(includes(Collections.singletonMap("customHeaderName", "customHeaderValue")));
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class HeaderRefConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.headers()
|
||||
.defaultsDisabled()
|
||||
.addHeaderWriter(new StaticHeadersWriter("customHeaderName", "customHeaderValue"));
|
||||
}
|
||||
}
|
||||
|
||||
private static ResultMatcher includesDefaults() {
|
||||
return includes(defaultHeaders);
|
||||
}
|
||||
|
||||
private static ResultMatcher includes(String... headerNames) {
|
||||
return includes(defaultHeaders, headerNames);
|
||||
}
|
||||
|
||||
private static ResultMatcher includes(Map<String, String> headers) {
|
||||
return includes(headers, headers.keySet().toArray(new String[headers.size()]));
|
||||
}
|
||||
|
||||
private static ResultMatcher includes(Map<String, String> headers, String... headerNames) {
|
||||
return result -> {
|
||||
assertThat(result.getResponse().getHeaderNames()).hasSameSizeAs(headerNames);
|
||||
for (String headerName : headerNames) {
|
||||
header().string(headerName, headers.get(headerName)).match(result);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.test.SpringTestRule;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* Tests to verify that all the functionality of <intercept-url> attributes is present
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Josh Cummings
|
||||
*
|
||||
*/
|
||||
public class NamespaceHttpInterceptUrlTests {
|
||||
|
||||
@Rule
|
||||
public final SpringTestRule spring = new SpringTestRule();
|
||||
|
||||
@Autowired
|
||||
MockMvc mvc;
|
||||
|
||||
@Test
|
||||
public void unauthenticatedRequestWhenUrlRequiresAuthenticationThenBehaviorMatchesNamespace() throws Exception {
|
||||
this.spring.register(HttpInterceptUrlConfig.class).autowire();
|
||||
|
||||
this.mvc.perform(get("/users"))
|
||||
.andExpect(status().isForbidden());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticatedRequestWhenUrlRequiresElevatedPrivilegesThenBehaviorMatchesNamespace() throws Exception {
|
||||
this.spring.register(HttpInterceptUrlConfig.class).autowire();
|
||||
|
||||
|
||||
this.mvc.perform(get("/users")
|
||||
.with(authentication(user("ROLE_USER"))))
|
||||
.andExpect(status().isForbidden());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticatedRequestWhenAuthorizedThenBehaviorMatchesNamespace() throws Exception {
|
||||
this.spring.register(HttpInterceptUrlConfig.class, BaseController.class).autowire();
|
||||
|
||||
this.mvc.perform(get("/users")
|
||||
.with(authentication(user("ROLE_ADMIN"))))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenMappedByPostInterceptUrlThenBehaviorMatchesNamespace() throws Exception {
|
||||
this.spring.register(HttpInterceptUrlConfig.class, BaseController.class).autowire();
|
||||
|
||||
this.mvc.perform(get("/admin/post")
|
||||
.with(authentication(user("ROLE_USER"))))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
this.mvc.perform(post("/admin/post")
|
||||
.with(authentication(user("ROLE_USER"))))
|
||||
.andExpect(status().isForbidden());
|
||||
|
||||
this.mvc.perform(post("/admin/post")
|
||||
.with(csrf())
|
||||
.with(authentication(user("ROLE_ADMIN"))))
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenRequiresChannelThenBehaviorMatchesNamespace() throws Exception {
|
||||
this.spring.register(HttpInterceptUrlConfig.class).autowire();
|
||||
|
||||
this.mvc.perform(get("/login"))
|
||||
.andExpect(redirectedUrl("https://localhost/login"));
|
||||
|
||||
this.mvc.perform(get("/secured/a"))
|
||||
.andExpect(redirectedUrl("https://localhost/secured/a"));
|
||||
|
||||
this.mvc.perform(get("https://localhost/user"))
|
||||
.andExpect(redirectedUrl("http://localhost/user"));
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class HttpInterceptUrlConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
// the line below is similar to intercept-url@pattern:
|
||||
// <intercept-url pattern="/users**" access="hasRole('ROLE_ADMIN')"/>
|
||||
// <intercept-url pattern="/sessions/**" access="hasRole('ROLE_ADMIN')"/>
|
||||
.antMatchers("/users**", "/sessions/**").hasRole("ADMIN")
|
||||
// the line below is similar to intercept-url@method:
|
||||
// <intercept-url pattern="/admin/post" access="hasRole('ROLE_ADMIN')" method="POST"/>
|
||||
// <intercept-url pattern="/admin/another-post/**" access="hasRole('ROLE_ADMIN')" method="POST"/>
|
||||
.antMatchers(HttpMethod.POST, "/admin/post", "/admin/another-post/**").hasRole("ADMIN")
|
||||
.antMatchers("/signup").permitAll()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.requiresChannel()
|
||||
// NOTE: channel security is configured separately of authorization (i.e. intercept-url@access
|
||||
// the line below is similar to intercept-url@requires-channel="https":
|
||||
// <intercept-url pattern="/login" requires-channel="https"/>
|
||||
// <intercept-url pattern="/secured/**" requires-channel="https"/>
|
||||
.antMatchers("/login", "/secured/**").requiresSecure()
|
||||
// the line below is similar to intercept-url@requires-channel="http":
|
||||
// <intercept-url pattern="/**" requires-channel="http"/>
|
||||
.anyRequest().requiresInsecure();
|
||||
}
|
||||
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER").and()
|
||||
.withUser("admin").password("password").roles("USER", "ADMIN");
|
||||
}
|
||||
}
|
||||
|
||||
@RestController
|
||||
static class BaseController {
|
||||
@GetMapping("/users")
|
||||
public String users() {
|
||||
return "ok";
|
||||
}
|
||||
|
||||
@GetMapping("/sessions")
|
||||
public String sessions() {
|
||||
return "sessions";
|
||||
}
|
||||
|
||||
@RequestMapping("/admin/post")
|
||||
public String adminPost() {
|
||||
return "adminPost";
|
||||
}
|
||||
|
||||
@GetMapping("/admin/another-post")
|
||||
public String adminAnotherPost() {
|
||||
return "adminAnotherPost";
|
||||
}
|
||||
|
||||
@GetMapping("/signup")
|
||||
public String signup() {
|
||||
return "signup";
|
||||
}
|
||||
}
|
||||
|
||||
private static Authentication user(String role) {
|
||||
return new UsernamePasswordAuthenticationToken("user", null, AuthorityUtils.createAuthorityList(role));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.test.SpringTestRule;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* Tests to verify that all the functionality of <jee> attributes is present
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Josh Cummings
|
||||
*
|
||||
*/
|
||||
public class NamespaceHttpJeeTests {
|
||||
|
||||
@Rule
|
||||
public final SpringTestRule spring = new SpringTestRule();
|
||||
|
||||
@Autowired
|
||||
MockMvc mvc;
|
||||
|
||||
@Test
|
||||
public void requestWhenJeeUserThenBehaviorDiffersFromNamespaceForRoleNames() throws Exception {
|
||||
this.spring.register(JeeMappableRolesConfig.class, BaseController.class).autowire();
|
||||
|
||||
Principal user = mock(Principal.class);
|
||||
when(user.getName()).thenReturn("joe");
|
||||
|
||||
this.mvc.perform(get("/roles")
|
||||
.principal(user)
|
||||
.with(request -> {
|
||||
request.addUserRole("ROLE_admin");
|
||||
request.addUserRole("ROLE_user");
|
||||
request.addUserRole("ROLE_unmapped");
|
||||
return request;
|
||||
}))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().string("ROLE_admin,ROLE_user"));
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
public static class JeeMappableRolesConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("user")
|
||||
.and()
|
||||
.jee()
|
||||
.mappableRoles("user", "admin");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenCustomAuthenticatedUserDetailsServiceThenBehaviorMatchesNamespace() throws Exception {
|
||||
this.spring.register(JeeUserServiceRefConfig.class, BaseController.class).autowire();
|
||||
|
||||
Principal user = mock(Principal.class);
|
||||
when(user.getName()).thenReturn("joe");
|
||||
|
||||
User result = new User(user.getName(), "N/A", true, true, true, true,
|
||||
AuthorityUtils.createAuthorityList("ROLE_user"));
|
||||
|
||||
when(bean(AuthenticationUserDetailsService.class).loadUserDetails(any()))
|
||||
.thenReturn(result);
|
||||
|
||||
this.mvc.perform(get("/roles")
|
||||
.principal(user))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().string("ROLE_user"));
|
||||
|
||||
verifyBean(AuthenticationUserDetailsService.class).loadUserDetails(any());
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
public static class JeeUserServiceRefConfig extends WebSecurityConfigurerAdapter {
|
||||
private final AuthenticationUserDetailsService authenticationUserDetailsService =
|
||||
mock(AuthenticationUserDetailsService.class);
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("user")
|
||||
.and()
|
||||
.jee()
|
||||
.mappableAuthorities("ROLE_user", "ROLE_admin")
|
||||
.authenticatedUserDetailsService(this.authenticationUserDetailsService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuthenticationUserDetailsService authenticationUserDetailsService() {
|
||||
return this.authenticationUserDetailsService;
|
||||
}
|
||||
}
|
||||
|
||||
@RestController
|
||||
static class BaseController {
|
||||
@GetMapping("/authenticated")
|
||||
public String authenticated(Authentication authentication) {
|
||||
return authentication.getName();
|
||||
}
|
||||
|
||||
@GetMapping("/roles")
|
||||
public String roles(Authentication authentication) {
|
||||
return authentication.getAuthorities().stream()
|
||||
.map(Object::toString).collect(Collectors.joining(","));
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T bean(Class<T> beanClass) {
|
||||
return this.spring.getContext().getBean(beanClass);
|
||||
}
|
||||
|
||||
private <T> T verifyBean(Class<T> beanClass) {
|
||||
return verify(this.spring.getContext().getBean(beanClass));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.test.SpringTestRule;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
|
||||
|
||||
/**
|
||||
* Tests to verify that all the functionality of <port-mappings> attributes is present
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Josh Cummings
|
||||
*
|
||||
*/
|
||||
public class NamespaceHttpPortMappingsTests {
|
||||
|
||||
@Rule
|
||||
public final SpringTestRule spring = new SpringTestRule();
|
||||
|
||||
@Autowired
|
||||
MockMvc mvc;
|
||||
|
||||
@Test
|
||||
public void portMappingWhenRequestRequiresChannelThenBehaviorMatchesNamespace() throws Exception {
|
||||
this.spring.register(HttpInterceptUrlWithPortMapperConfig.class).autowire();
|
||||
|
||||
this.mvc.perform(get("http://localhost:9080/login"))
|
||||
.andExpect(redirectedUrl("https://localhost:9443/login"));
|
||||
|
||||
this.mvc.perform(get("http://localhost:9080/secured/a"))
|
||||
.andExpect(redirectedUrl("https://localhost:9443/secured/a"));
|
||||
|
||||
this.mvc.perform(get("https://localhost:9443/user"))
|
||||
.andExpect(redirectedUrl("http://localhost:9080/user"));
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class HttpInterceptUrlWithPortMapperConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().hasRole("USER")
|
||||
.and()
|
||||
.portMapper()
|
||||
.http(9080).mapsTo(9443)
|
||||
.and()
|
||||
.requiresChannel()
|
||||
.antMatchers("/login", "/secured/**").requiresSecure()
|
||||
.anyRequest().requiresInsecure();
|
||||
}
|
||||
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER").and()
|
||||
.withUser("admin").password("password").roles("USER", "ADMIN");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.test.SpringTestRule;
|
||||
import org.springframework.security.core.userdetails.PasswordEncodedUser;
|
||||
import org.springframework.security.web.savedrequest.RequestCache;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* Tests to verify that all the functionality of <request-cache> attributes is present
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Josh Cummings
|
||||
*
|
||||
*/
|
||||
public class NamespaceHttpRequestCacheTests {
|
||||
|
||||
@Rule
|
||||
public final SpringTestRule spring = new SpringTestRule();
|
||||
|
||||
@Autowired
|
||||
MockMvc mvc;
|
||||
|
||||
@Test
|
||||
public void requestWhenCustomRequestCacheThenBehaviorMatchesNamespace() throws Exception {
|
||||
this.spring.register(RequestCacheRefConfig.class).autowire();
|
||||
this.mvc.perform(get("/"))
|
||||
.andExpect(status().isForbidden());
|
||||
verifyBean(RequestCache.class).saveRequest(any(HttpServletRequest.class), any(HttpServletResponse.class));
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class RequestCacheRefConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.requestCache()
|
||||
.requestCache(requestCache());
|
||||
}
|
||||
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser(PasswordEncodedUser.user())
|
||||
.withUser(PasswordEncodedUser.admin());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RequestCache requestCache() {
|
||||
return mock(RequestCache.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenDefaultConfigurationThenUsesHttpSessionRequestCache() throws Exception {
|
||||
this.spring.register(DefaultRequestCacheRefConfig.class).autowire();
|
||||
|
||||
MvcResult result = this.mvc.perform(get("/"))
|
||||
.andExpect(status().isForbidden())
|
||||
.andReturn();
|
||||
|
||||
HttpSession session = result.getRequest().getSession(false);
|
||||
assertThat(session).isNotNull();
|
||||
assertThat(session.getAttribute("SPRING_SECURITY_SAVED_REQUEST")).isNotNull();
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class DefaultRequestCacheRefConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated();
|
||||
}
|
||||
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser(PasswordEncodedUser.user())
|
||||
.withUser(PasswordEncodedUser.admin());
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T verifyBean(Class<T> beanClass) {
|
||||
return verify(this.spring.getContext().getBean(beanClass));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.test.SpringTestRule;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* Tests to verify that all the functionality of <access-denied-handler> attributes is present
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Josh Cummings
|
||||
*
|
||||
*/
|
||||
public class NamespaceHttpServerAccessDeniedHandlerTests {
|
||||
|
||||
@Rule
|
||||
public final SpringTestRule spring = new SpringTestRule();
|
||||
|
||||
@Autowired
|
||||
MockMvc mvc;
|
||||
|
||||
@Test
|
||||
public void requestWhenCustomAccessDeniedPageThenBehaviorMatchesNamespace() throws Exception {
|
||||
this.spring.register(AccessDeniedPageConfig.class).autowire();
|
||||
this.mvc.perform(get("/")
|
||||
.with(authentication(user())))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(forwardedUrl("/AccessDeniedPageConfig"));
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class AccessDeniedPageConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().denyAll()
|
||||
.and()
|
||||
.exceptionHandling()
|
||||
.accessDeniedPage("/AccessDeniedPageConfig");
|
||||
}
|
||||
}
|
||||
|
||||
private static Authentication user() {
|
||||
return new UsernamePasswordAuthenticationToken("user", null, AuthorityUtils.NO_AUTHORITIES);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenCustomAccessDeniedHandlerThenBehaviorMatchesNamespace() throws Exception {
|
||||
this.spring.register(AccessDeniedHandlerRefConfig.class).autowire();
|
||||
this.mvc.perform(get("/")
|
||||
.with(authentication(user())));
|
||||
verifyBean(AccessDeniedHandler.class)
|
||||
.handle(any(HttpServletRequest.class), any(HttpServletResponse.class), any(AccessDeniedException.class));
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class AccessDeniedHandlerRefConfig extends WebSecurityConfigurerAdapter {
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().denyAll()
|
||||
.and()
|
||||
.exceptionHandling()
|
||||
.accessDeniedHandler(accessDeniedHandler());
|
||||
}
|
||||
|
||||
@Bean
|
||||
AccessDeniedHandler accessDeniedHandler() {
|
||||
return mock(AccessDeniedHandler.class);
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T verifyBean(Class<T> beanClass) {
|
||||
return verify(this.spring.getContext().getBean(beanClass));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue