Various NamespaceHttp*Tests groovy->java
Issue: gh-4939
This commit is contained in:
@@ -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));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user