Adapt to Spring Security changes

Closes gh-32604
This commit is contained in:
Madhura Bhave 2022-10-07 15:23:31 -07:00
parent 2e74878ba4
commit ce3c933f77
58 changed files with 497 additions and 361 deletions

View File

@ -34,6 +34,10 @@ import org.springframework.core.annotation.Order;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.context.DelegatingSecurityContextRepository;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.security.web.context.RequestAttributeSecurityContextRepository;
import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.util.ClassUtils;
/**
@ -67,6 +71,8 @@ public class ManagementWebSecurityAutoConfiguration {
}
http.formLogin(Customizer.withDefaults());
http.httpBasic(Customizer.withDefaults());
http.setSharedObject(SecurityContextRepository.class, new DelegatingSecurityContextRepository(
new RequestAttributeSecurityContextRepository(), new HttpSessionSecurityContextRepository()));
return http.build();
}

View File

@ -32,8 +32,8 @@ import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.event.AbstractAuthorizationEvent;
import org.springframework.security.authentication.event.AbstractAuthenticationEvent;
import org.springframework.security.authorization.event.AuthorizationEvent;
import static org.assertj.core.api.Assertions.assertThat;
@ -149,7 +149,7 @@ class AuditAutoConfigurationTests {
}
@Override
public void onApplicationEvent(AbstractAuthorizationEvent event) {
public void onApplicationEvent(AuthorizationEvent event) {
}
}

View File

@ -45,6 +45,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.test.web.reactive.server.WebTestClient;
/**
@ -177,22 +178,15 @@ abstract class AbstractEndpointRequestIntegrationTests {
static class SecurityConfiguration {
@Bean
@SuppressWarnings("deprecation")
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter webSecurityConfigurerAdapter() {
return new org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter() {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((requests) -> {
requests.requestMatchers(EndpointRequest.toLinks()).permitAll();
requests.requestMatchers(EndpointRequest.to(TestEndpoint1.class)).permitAll();
requests.requestMatchers(EndpointRequest.toAnyEndpoint()).authenticated();
requests.anyRequest().hasRole("ADMIN");
});
http.httpBasic();
}
};
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((requests) -> {
requests.requestMatchers(EndpointRequest.toLinks()).permitAll();
requests.requestMatchers(EndpointRequest.to(TestEndpoint1.class)).permitAll();
requests.requestMatchers(EndpointRequest.toAnyEndpoint()).authenticated();
requests.anyRequest().hasRole("ADMIN");
});
http.httpBasic();
return http.build();
}
}

View File

@ -172,18 +172,17 @@ class ManagementWebSecurityAutoConfigurationTests {
}
@Configuration(proxyBeanMethods = false)
@SuppressWarnings("deprecation")
static class CustomSecurityConfiguration
extends org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter {
static class CustomSecurityConfiguration {
@Override
protected void configure(HttpSecurity http) throws Exception {
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((requests) -> {
requests.antMatchers("/foo").permitAll();
requests.requestMatchers(new AntPathRequestMatcher("/foo")).permitAll();
requests.anyRequest().authenticated();
});
http.formLogin(Customizer.withDefaults());
http.httpBasic();
return http.build();
}
}
@ -193,8 +192,8 @@ class ManagementWebSecurityAutoConfigurationTests {
@Bean
SecurityFilterChain testSecurityFilterChain(HttpSecurity http) throws Exception {
return http.antMatcher("/**").authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated())
.build();
return http.securityMatcher("/**")
.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated()).build();
}
}
@ -205,8 +204,10 @@ class ManagementWebSecurityAutoConfigurationTests {
@Bean
@Order(SecurityProperties.BASIC_AUTH_ORDER - 1)
SecurityFilterChain testRemoteDevToolsSecurityFilterChain(HttpSecurity http) throws Exception {
return http.requestMatcher(new AntPathRequestMatcher("/**")).authorizeHttpRequests().anyRequest()
.anonymous().and().csrf().disable().build();
http.securityMatcher(new AntPathRequestMatcher("/**"));
http.authorizeHttpRequests().anyRequest().anonymous();
http.csrf().disable();
return http.build();
}
}

View File

@ -20,7 +20,6 @@ import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.security.Principal;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Supplier;
@ -55,9 +54,7 @@ import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.access.vote.RoleVoter;
import org.springframework.security.authorization.AuthorityAuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.util.AntPathMatcher;
@ -469,7 +466,7 @@ public abstract class AbstractWebFluxEndpointHandlerMapping extends RequestMappi
private static final class ReactiveSecurityContext implements SecurityContext {
private final RoleVoter roleVoter = new RoleVoter();
private static final String ROLE_PREFIX = "ROLE_";
private final Authentication authentication;
@ -477,6 +474,10 @@ public abstract class AbstractWebFluxEndpointHandlerMapping extends RequestMappi
this.authentication = authentication;
}
private Authentication getAuthentication() {
return this.authentication;
}
@Override
public Principal getPrincipal() {
return this.authentication;
@ -484,11 +485,9 @@ public abstract class AbstractWebFluxEndpointHandlerMapping extends RequestMappi
@Override
public boolean isUserInRole(String role) {
if (!role.startsWith(this.roleVoter.getRolePrefix())) {
role = this.roleVoter.getRolePrefix() + role;
}
return this.roleVoter.vote(this.authentication, null,
Collections.singletonList(new SecurityConfig(role))) == AccessDecisionVoter.ACCESS_GRANTED;
String authority = (!role.startsWith(ROLE_PREFIX)) ? ROLE_PREFIX + role : role;
return AuthorityAuthorizationManager.hasAuthority(authority).check(this::getAuthentication, null)
.isGranted();
}
}

View File

@ -21,18 +21,21 @@ import org.springframework.boot.actuate.audit.listener.AuditApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.ApplicationListener;
import org.springframework.security.access.event.AbstractAuthorizationEvent;
import org.springframework.security.authorization.event.AuthorizationDeniedEvent;
import org.springframework.security.authorization.event.AuthorizationEvent;
import org.springframework.security.authorization.event.AuthorizationGrantedEvent;
/**
* Abstract {@link ApplicationListener} to expose Spring Security
* {@link AbstractAuthorizationEvent authorization events} as {@link AuditEvent}s.
* {@link AuthorizationDeniedEvent authorization denied} and
* {@link AuthorizationGrantedEvent authorization granted} events as {@link AuditEvent}s.
*
* @author Dave Syer
* @author Vedran Pavic
* @since 1.3.0
*/
public abstract class AbstractAuthorizationAuditListener
implements ApplicationListener<AbstractAuthorizationEvent>, ApplicationEventPublisherAware {
implements ApplicationListener<AuthorizationEvent>, ApplicationEventPublisherAware {
private ApplicationEventPublisher publisher;

View File

@ -17,6 +17,7 @@
package org.springframework.boot.actuate.security;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.boot.actuate.audit.AuditEvent;
@ -75,7 +76,7 @@ public class AuthenticationAuditListener extends AbstractAuthenticationAuditList
}
private void onAuthenticationFailureEvent(AbstractAuthenticationFailureEvent event) {
Map<String, Object> data = new HashMap<>();
Map<String, Object> data = new LinkedHashMap<>();
data.put("type", event.getException().getClass().getName());
data.put("message", event.getException().getMessage());
if (event.getAuthentication().getDetails() != null) {
@ -85,7 +86,7 @@ public class AuthenticationAuditListener extends AbstractAuthenticationAuditList
}
private void onAuthenticationSuccessEvent(AuthenticationSuccessEvent event) {
Map<String, Object> data = new HashMap<>();
Map<String, Object> data = new LinkedHashMap<>();
if (event.getAuthentication().getDetails() != null) {
data.put("details", event.getAuthentication().getDetails());
}

View File

@ -16,13 +16,14 @@
package org.springframework.boot.actuate.security;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Supplier;
import org.springframework.boot.actuate.audit.AuditEvent;
import org.springframework.security.access.event.AbstractAuthorizationEvent;
import org.springframework.security.access.event.AuthenticationCredentialsNotFoundEvent;
import org.springframework.security.access.event.AuthorizationFailureEvent;
import org.springframework.security.authorization.event.AuthorizationDeniedEvent;
import org.springframework.security.authorization.event.AuthorizationEvent;
import org.springframework.security.core.Authentication;
/**
* Default implementation of {@link AbstractAuthorizationAuditListener}.
@ -39,30 +40,38 @@ public class AuthorizationAuditListener extends AbstractAuthorizationAuditListen
public static final String AUTHORIZATION_FAILURE = "AUTHORIZATION_FAILURE";
@Override
public void onApplicationEvent(AbstractAuthorizationEvent event) {
if (event instanceof AuthenticationCredentialsNotFoundEvent credentialsNotFoundEvent) {
onAuthenticationCredentialsNotFoundEvent(credentialsNotFoundEvent);
}
else if (event instanceof AuthorizationFailureEvent authorizationFailureEvent) {
onAuthorizationFailureEvent(authorizationFailureEvent);
public void onApplicationEvent(AuthorizationEvent event) {
if (event instanceof AuthorizationDeniedEvent<?> authorizationDeniedEvent) {
onAuthorizationDeniedEvent(authorizationDeniedEvent);
}
}
private void onAuthenticationCredentialsNotFoundEvent(AuthenticationCredentialsNotFoundEvent event) {
Map<String, Object> data = new HashMap<>();
data.put("type", event.getCredentialsNotFoundException().getClass().getName());
data.put("message", event.getCredentialsNotFoundException().getMessage());
publish(new AuditEvent("<unknown>", AuthenticationAuditListener.AUTHENTICATION_FAILURE, data));
private void onAuthorizationDeniedEvent(AuthorizationDeniedEvent<?> event) {
String name = getName(event.getAuthentication());
Map<String, Object> data = new LinkedHashMap<>();
Object details = getDetails(event.getAuthentication());
if (details != null) {
data.put("details", details);
}
publish(new AuditEvent(name, AUTHORIZATION_FAILURE, data));
}
private void onAuthorizationFailureEvent(AuthorizationFailureEvent event) {
Map<String, Object> data = new HashMap<>();
data.put("type", event.getAccessDeniedException().getClass().getName());
data.put("message", event.getAccessDeniedException().getMessage());
if (event.getAuthentication().getDetails() != null) {
data.put("details", event.getAuthentication().getDetails());
private String getName(Supplier<Authentication> authentication) {
try {
return authentication.get().getName();
}
catch (Exception ex) {
return "<unknown>";
}
}
private Object getDetails(Supplier<Authentication> authentication) {
try {
return authentication.get().getDetails();
}
catch (Exception ex) {
return null;
}
publish(new AuditEvent(event.getAuthentication().getName(), AUTHORIZATION_FAILURE, data));
}
}

View File

@ -16,21 +16,17 @@
package org.springframework.boot.actuate.security;
import java.util.Collections;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.boot.actuate.audit.AuditEvent;
import org.springframework.boot.actuate.audit.listener.AuditApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.access.event.AbstractAuthorizationEvent;
import org.springframework.security.access.event.AuthenticationCredentialsNotFoundEvent;
import org.springframework.security.access.event.AuthorizationFailureEvent;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.event.AuthorizationDeniedEvent;
import org.springframework.security.authorization.event.AuthorizationEvent;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.then;
@ -51,35 +47,48 @@ class AuthorizationAuditListenerTests {
}
@Test
void testAuthenticationCredentialsNotFound() {
AuditApplicationEvent event = handleAuthorizationEvent(
new AuthenticationCredentialsNotFoundEvent(this, Collections.singletonList(new SecurityConfig("USER")),
new AuthenticationCredentialsNotFoundException("Bad user")));
assertThat(event.getAuditEvent().getType()).isEqualTo(AuthenticationAuditListener.AUTHENTICATION_FAILURE);
}
@Test
void testAuthorizationFailure() {
AuditApplicationEvent event = handleAuthorizationEvent(new AuthorizationFailureEvent(this,
Collections.singletonList(new SecurityConfig("USER")),
new UsernamePasswordAuthenticationToken("user", "password"), new AccessDeniedException("Bad user")));
assertThat(event.getAuditEvent().getType()).isEqualTo(AuthorizationAuditListener.AUTHORIZATION_FAILURE);
}
@Test
void testDetailsAreIncludedInAuditEvent() {
Object details = new Object();
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken("user",
void authorizationDeniedEvent() {
AuthorizationDecision decision = new AuthorizationDecision(false);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken("spring",
"password");
authentication.setDetails(details);
AuditApplicationEvent event = handleAuthorizationEvent(
new AuthorizationFailureEvent(this, Collections.singletonList(new SecurityConfig("USER")),
authentication, new AccessDeniedException("Bad user")));
assertThat(event.getAuditEvent().getType()).isEqualTo(AuthorizationAuditListener.AUTHORIZATION_FAILURE);
assertThat(event.getAuditEvent().getData()).containsEntry("details", details);
authentication.setDetails("details");
AuthorizationDeniedEvent<?> authorizationEvent = new AuthorizationDeniedEvent<>(() -> authentication, "",
decision);
AuditEvent auditEvent = handleAuthorizationEvent(authorizationEvent).getAuditEvent();
assertThat(auditEvent.getPrincipal()).isEqualTo("spring");
assertThat(auditEvent.getType()).isEqualTo(AuthorizationAuditListener.AUTHORIZATION_FAILURE);
assertThat(auditEvent.getData()).containsEntry("details", "details");
}
private AuditApplicationEvent handleAuthorizationEvent(AbstractAuthorizationEvent event) {
@Test
void authorizationDeniedEventWhenAuthenticationIsNotAvailable() {
AuthorizationDecision decision = new AuthorizationDecision(false);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken("spring",
"password");
authentication.setDetails("details");
AuthorizationDeniedEvent<?> authorizationEvent = new AuthorizationDeniedEvent<>(() -> {
throw new RuntimeException("No authentication");
}, "", decision);
AuditEvent auditEvent = handleAuthorizationEvent(authorizationEvent).getAuditEvent();
assertThat(auditEvent.getPrincipal()).isEqualTo("<unknown>");
assertThat(auditEvent.getType()).isEqualTo(AuthorizationAuditListener.AUTHORIZATION_FAILURE);
assertThat(auditEvent.getData()).doesNotContainKey("details");
}
@Test
void authorizationDeniedEventWhenAuthenticationDoesNotHaveDetails() {
AuthorizationDecision decision = new AuthorizationDecision(false);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken("spring",
"password");
AuthorizationDeniedEvent<?> authorizationEvent = new AuthorizationDeniedEvent<>(() -> authentication, "",
decision);
AuditEvent auditEvent = handleAuthorizationEvent(authorizationEvent).getAuditEvent();
assertThat(auditEvent.getPrincipal()).isEqualTo("spring");
assertThat(auditEvent.getType()).isEqualTo(AuthorizationAuditListener.AUTHORIZATION_FAILURE);
assertThat(auditEvent.getData()).doesNotContainKey("details");
}
private AuditApplicationEvent handleAuthorizationEvent(AuthorizationEvent event) {
ArgumentCaptor<AuditApplicationEvent> eventCaptor = ArgumentCaptor.forClass(AuditApplicationEvent.class);
this.listener.onApplicationEvent(event);
then(this.publisher).should().publishEvent(eventCaptor.capture());

View File

@ -40,10 +40,7 @@ class DefaultWebSecurityCondition extends AllNestedConditions {
}
@ConditionalOnMissingBean({
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.class,
SecurityFilterChain.class })
@SuppressWarnings("deprecation")
@ConditionalOnMissingBean({ SecurityFilterChain.class })
static class Beans {
}

View File

@ -20,7 +20,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken;
import org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenIntrospector;
/**

View File

@ -25,7 +25,7 @@ import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfi
import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Import;
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken;
/**
* {@link EnableAutoConfiguration Auto-configuration} for OAuth2 resource server support.

View File

@ -29,6 +29,10 @@ import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.context.DelegatingSecurityContextRepository;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.security.web.context.RequestAttributeSecurityContextRepository;
import org.springframework.security.web.context.SecurityContextRepository;
/**
* {@link Configuration @Configuration} class securing servlet applications.
@ -57,6 +61,8 @@ class SpringBootWebSecurityConfiguration {
http.authorizeHttpRequests().anyRequest().authenticated();
http.formLogin();
http.httpBasic();
http.setSharedObject(SecurityContextRepository.class, new DelegatingSecurityContextRepository(
new RequestAttributeSecurityContextRepository(), new HttpSessionSecurityContextRepository()));
return http.build();
}

View File

@ -30,7 +30,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationManagerResolver;
import org.springframework.security.authentication.AuthenticationProvider;
@ -72,7 +71,6 @@ public class UserDetailsServiceAutoConfiguration {
private static final Log logger = LogFactory.getLog(UserDetailsServiceAutoConfiguration.class);
@Bean
@Lazy
public InMemoryUserDetailsManager inMemoryUserDetailsManager(SecurityProperties properties,
ObjectProvider<PasswordEncoder> passwordEncoder) {
SecurityProperties.User user = properties.getUser();

View File

@ -32,7 +32,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Import;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.web.bind.annotation.RequestMapping;
import static org.assertj.core.api.Assertions.assertThat;
@ -166,7 +166,7 @@ class AopAutoConfigurationTests {
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableMethodSecurity(prePostEnabled = true)
@Configuration(proxyBeanMethods = false)
static class EnableGlobalMethodSecurityConfiguration {

View File

@ -38,7 +38,7 @@ import org.springframework.graphql.execution.SecurityDataFetcherExceptionResolve
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
@ -151,7 +151,7 @@ class GraphQlWebMvcSecurityAutoConfigurationTests {
@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableMethodSecurity(prePostEnabled = true)
@SuppressWarnings("deprecation")
static class SecurityConfig {

View File

@ -22,9 +22,11 @@ import java.util.List;
import jakarta.servlet.Filter;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -56,7 +58,7 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
class OAuth2WebSecurityConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner();
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner();
@Test
void securityConfigurerConfiguresOAuth2Login() {
@ -113,21 +115,10 @@ class OAuth2WebSecurityConfigurationTests {
.run((context) -> assertThat(context).hasSingleBean(OAuth2AuthorizedClientRepository.class));
}
@Test
void securityFilterChainConfigBacksOffWhenOtherWebSecurityAdapterPresent() {
this.contextRunner
.withUserConfiguration(TestWebSecurityConfigurerConfig.class, OAuth2WebSecurityConfiguration.class)
.run((context) -> {
assertThat(getFilters(context, OAuth2LoginAuthenticationFilter.class)).isEmpty();
assertThat(getFilters(context, OAuth2AuthorizationCodeGrantFilter.class)).isEmpty();
assertThat(context).getBean(OAuth2AuthorizedClientService.class).isNotNull();
});
}
@Test
void securityFilterChainConfigBacksOffWhenOtherSecurityFilterChainBeanPresent() {
this.contextRunner
.withUserConfiguration(TestSecurityFilterChainConfig.class, OAuth2WebSecurityConfiguration.class)
this.contextRunner.withConfiguration(AutoConfigurations.of(WebMvcAutoConfiguration.class))
.withUserConfiguration(TestSecurityFilterChainConfiguration.class, OAuth2WebSecurityConfiguration.class)
.run((context) -> {
assertThat(getFilters(context, OAuth2LoginAuthenticationFilter.class)).isEmpty();
assertThat(getFilters(context, OAuth2AuthorizationCodeGrantFilter.class)).isEmpty();
@ -164,7 +155,7 @@ class OAuth2WebSecurityConfigurationTests {
});
}
private List<Filter> getFilters(AssertableApplicationContext context, Class<? extends Filter> filter) {
private List<Filter> getFilters(AssertableWebApplicationContext context, Class<? extends Filter> filter) {
FilterChainProxy filterChain = (FilterChainProxy) context.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN);
List<SecurityFilterChain> filterChains = filterChain.getFilterChains();
List<Filter> filters = filterChains.get(0).getFilters();
@ -228,20 +219,12 @@ class OAuth2WebSecurityConfigurationTests {
@Configuration(proxyBeanMethods = false)
@Import(ClientRegistrationRepositoryConfiguration.class)
@SuppressWarnings("deprecation")
static class TestWebSecurityConfigurerConfig
extends org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter {
}
@Configuration(proxyBeanMethods = false)
@Import(ClientRegistrationRepositoryConfiguration.class)
static class TestSecurityFilterChainConfig {
static class TestSecurityFilterChainConfiguration {
@Bean
SecurityFilterChain testSecurityFilterChain(HttpSecurity http) throws Exception {
return http.antMatcher("/**").authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated())
.build();
return http.securityMatcher("/**")
.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated()).build();
}

View File

@ -60,7 +60,7 @@ import org.springframework.security.oauth2.jwt.JwtTimestampValidator;
import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder;
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
import org.springframework.security.oauth2.jwt.SupplierReactiveJwtDecoder;
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken;
import org.springframework.security.oauth2.server.resource.authentication.JwtReactiveAuthenticationManager;
import org.springframework.security.oauth2.server.resource.authentication.OpaqueTokenReactiveAuthenticationManager;
import org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenIntrospector;

View File

@ -37,6 +37,7 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
@ -57,10 +58,10 @@ import org.springframework.security.oauth2.jwt.JwtIssuerValidator;
import org.springframework.security.oauth2.jwt.JwtTimestampValidator;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.oauth2.jwt.SupplierJwtDecoder;
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider;
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter;
import org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.test.util.ReflectionTestUtils;
@ -579,7 +580,7 @@ class OAuth2ResourceServerAutoConfigurationTests {
@Test
void jwtSecurityConfigurerBacksOffWhenSecurityFilterChainBeanIsPresent() {
this.contextRunner
this.contextRunner.withConfiguration(AutoConfigurations.of(WebMvcAutoConfiguration.class))
.withPropertyValues("spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com")
.withUserConfiguration(JwtDecoderConfig.class, TestSecurityFilterChainConfig.class)
.run((context) -> assertThat(context).hasSingleBean(SecurityFilterChain.class));
@ -587,7 +588,8 @@ class OAuth2ResourceServerAutoConfigurationTests {
@Test
void opaqueTokenSecurityConfigurerBacksOffWhenSecurityFilterChainBeanIsPresent() {
this.contextRunner.withUserConfiguration(TestSecurityFilterChainConfig.class)
this.contextRunner.withConfiguration(AutoConfigurations.of(WebMvcAutoConfiguration.class))
.withUserConfiguration(TestSecurityFilterChainConfig.class)
.withPropertyValues(
"spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=https://check-token.com",
"spring.security.oauth2.resourceserver.opaquetoken.client-id=my-client-id",
@ -692,8 +694,9 @@ class OAuth2ResourceServerAutoConfigurationTests {
@Bean
SecurityFilterChain testSecurityFilterChain(HttpSecurity http) throws Exception {
return http.antMatcher("/**").authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated())
.build();
http.securityMatcher("/**");
http.authorizeHttpRequests().anyRequest().authenticated();
return http.build();
}
}

View File

@ -27,6 +27,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
@ -41,7 +42,7 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding;
import org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter;
import org.springframework.security.saml2.provider.service.web.authentication.Saml2WebSsoAuthenticationFilter;
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestFilter;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.SecurityFilterChain;
@ -205,17 +206,10 @@ class Saml2RelyingPartyAutoConfigurationTests {
.run((context) -> assertThat(hasFilter(context, Saml2WebSsoAuthenticationFilter.class)).isTrue());
}
@Test
void samlLoginShouldBackOffWhenAWebSecurityConfigurerAdapterIsDefined() {
this.contextRunner.withUserConfiguration(WebSecurityConfigurerAdapterConfiguration.class)
.withPropertyValues(getPropertyValues())
.run((context) -> assertThat(hasFilter(context, Saml2WebSsoAuthenticationFilter.class)).isFalse());
}
@Test
void samlLoginShouldBackOffWhenASecurityFilterChainBeanIsPresent() {
this.contextRunner.withUserConfiguration(TestSecurityFilterChainConfig.class)
.withPropertyValues(getPropertyValues())
this.contextRunner.withConfiguration(AutoConfigurations.of(WebMvcAutoConfiguration.class))
.withUserConfiguration(TestSecurityFilterChainConfig.class).withPropertyValues(getPropertyValues())
.run((context) -> assertThat(hasFilter(context, Saml2WebSsoAuthenticationFilter.class)).isFalse());
}
@ -303,26 +297,13 @@ class Saml2RelyingPartyAutoConfigurationTests {
}
@Configuration(proxyBeanMethods = false)
static class WebSecurityConfigurerAdapterConfiguration {
@Bean
@SuppressWarnings("deprecation")
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter webSecurityConfigurerAdapter() {
return new org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter() {
};
}
}
@Configuration(proxyBeanMethods = false)
static class TestSecurityFilterChainConfig {
@Bean
SecurityFilterChain testSecurityFilterChain(HttpSecurity http) throws Exception {
return http.antMatcher("/**").authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated())
.build();
return http.securityMatcher("/**")
.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated()).build();
}
}

View File

@ -28,6 +28,7 @@ import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoCon
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.test.City;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConfigurationPropertiesBinding;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@ -45,7 +46,6 @@ import org.springframework.security.authentication.AuthenticationEventPublisher;
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
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.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension;
@ -89,30 +89,11 @@ class SecurityAutoConfigurationTests {
@Test
void securityConfigurerBacksOffWhenOtherSecurityFilterChainBeanPresent() {
this.contextRunner.withUserConfiguration(TestSecurityFilterChainConfig.class).run((context) -> {
assertThat(context.getBeansOfType(SecurityFilterChain.class).size()).isEqualTo(1);
assertThat(context.containsBean("testSecurityFilterChain")).isTrue();
});
}
@Test
@SuppressWarnings("deprecation")
void securityConfigurerBacksOffWhenOtherWebSecurityAdapterBeanPresent() {
this.contextRunner.withUserConfiguration(WebSecurity.class).run((context) -> {
assertThat(context.getBeansOfType(
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.class)
.size()).isEqualTo(1);
assertThat(context.containsBean("securityAutoConfigurationTests.WebSecurity")).isTrue();
});
}
@Test
void testDefaultFilterOrderWithSecurityAdapter() {
this.contextRunner
.withConfiguration(AutoConfigurations.of(WebSecurity.class, SecurityFilterAutoConfiguration.class))
.run((context) -> assertThat(
context.getBean("securityFilterChainRegistration", DelegatingFilterProxyRegistrationBean.class)
.getOrder()).isEqualTo(OrderedFilter.REQUEST_WRAPPER_FILTER_MAX_ORDER - 100));
this.contextRunner.withConfiguration(AutoConfigurations.of(WebMvcAutoConfiguration.class))
.withUserConfiguration(TestSecurityFilterChainConfig.class).run((context) -> {
assertThat(context.getBeansOfType(SecurityFilterChain.class).size()).isEqualTo(1);
assertThat(context.containsBean("testSecurityFilterChain")).isTrue();
});
}
@Test
@ -255,21 +236,13 @@ class SecurityAutoConfigurationTests {
}
@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
@SuppressWarnings("deprecation")
static class WebSecurity
extends org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter {
}
@Configuration(proxyBeanMethods = false)
static class TestSecurityFilterChainConfig {
@Bean
SecurityFilterChain testSecurityFilterChain(HttpSecurity http) throws Exception {
return http.antMatcher("/**").authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated())
.build();
return http.securityMatcher("/**")
.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated()).build();
}
@ -281,7 +254,7 @@ class SecurityAutoConfigurationTests {
@Bean
@ConfigurationPropertiesBinding
Converter<String, TargetType> targetTypeConverter() {
return new Converter<String, TargetType>() {
return new Converter<>() {
@Override
public TargetType convert(String input) {

View File

@ -22,7 +22,6 @@ import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfigurationTests.WebSecurity;
import org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfigurationEarlyInitializationTests.ConverterBean;
import org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfigurationEarlyInitializationTests.DeserializerBean;
import org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfigurationEarlyInitializationTests.ExampleController;
@ -53,7 +52,7 @@ class SecurityFilterAutoConfigurationTests {
@Configuration(proxyBeanMethods = false)
@Import({ DeserializerBean.class, JacksonModuleBean.class, ExampleController.class, ConverterBean.class })
@ImportAutoConfiguration({ WebMvcAutoConfiguration.class, JacksonAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class, DispatcherServletAutoConfiguration.class, WebSecurity.class,
HttpMessageConvertersAutoConfiguration.class, DispatcherServletAutoConfiguration.class,
SecurityFilterAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })
static class Config {

View File

@ -36,7 +36,6 @@ import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.TestingAuthenticationProvider;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
@ -164,12 +163,6 @@ class UserDetailsServiceAutoConfigurationTests {
.run(((context) -> assertThat(context).doesNotHaveBean(InMemoryUserDetailsManager.class)));
}
@Test
void generatedPasswordShouldNotBePrintedIfAuthenticationManagerBuilderIsUsed(CapturedOutput output) {
this.contextRunner.withUserConfiguration(TestConfigWithAuthenticationManagerBuilder.class)
.run(((context) -> assertThat(output).doesNotContain("Using generated security password: ")));
}
private void testPasswordEncoding(Class<?> configClass, String providedPassword, String expectedPassword) {
this.contextRunner.withUserConfiguration(configClass)
.withPropertyValues("spring.security.user.password=" + providedPassword).run(((context) -> {
@ -264,24 +257,6 @@ class UserDetailsServiceAutoConfigurationTests {
}
@Configuration(proxyBeanMethods = false)
@Import(TestSecurityConfiguration.class)
static class TestConfigWithAuthenticationManagerBuilder {
@Bean
@SuppressWarnings("deprecation")
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter webSecurityConfigurerAdapter() {
return new org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter() {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("hero").password("{noop}hero").roles("HERO", "USER").and()
.withUser("user").password("{noop}user").roles("USER");
}
};
}
}
@Configuration(proxyBeanMethods = false)
static class TestAuthenticationManagerResolverConfiguration {

View File

@ -1497,7 +1497,7 @@ bom {
]
}
}
library("Spring Security", "6.0.0-M7") {
library("Spring Security", "6.0.0-SNAPSHOT") {
group("org.springframework.security") {
imports = [
"spring-security-bom"

View File

@ -17,7 +17,6 @@
package org.springframework.boot.devtools.autoconfigure;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.context.annotation.Bean;
@ -47,11 +46,10 @@ class RemoteDevtoolsSecurityConfiguration {
@Bean
@Order(SecurityProperties.BASIC_AUTH_ORDER - 1)
@ConditionalOnMissingBean(org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.class)
@SuppressWarnings("deprecation")
SecurityFilterChain devtoolsSecurityFilterChain(HttpSecurity http) throws Exception {
http.requestMatcher(new AntPathRequestMatcher(this.url)).authorizeHttpRequests().anyRequest().anonymous().and()
.csrf().disable();
http.securityMatcher(new AntPathRequestMatcher(this.url));
http.authorizeHttpRequests().anyRequest().anonymous();
http.csrf().disable();
return http.build();
}

View File

@ -44,7 +44,6 @@ import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockServletContext;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
@ -183,25 +182,6 @@ class RemoteDevToolsAutoConfigurationTests {
mockMvc.perform(MockMvcRequestBuilders.get("/my-path")).andExpect(status().isUnauthorized());
}
@Test
void securityConfigurationWhenWebSecurityConfigurerAdapterIsFound2() throws Exception {
this.context = getContext(() -> {
AnnotationConfigServletWebApplicationContext context = new AnnotationConfigServletWebApplicationContext();
context.setServletContext(new MockServletContext());
context.register(Config.class, PropertyPlaceholderAutoConfiguration.class,
TestWebSecurityConfigurerAdapter.class);
TestPropertyValues.of("spring.devtools.remote.secret:supersecret").applyTo(context);
context.refresh();
return context;
});
DispatcherFilter filter = this.context.getBean(DispatcherFilter.class);
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context).apply(springSecurity()).addFilter(filter)
.build();
mockMvc.perform(MockMvcRequestBuilders.get(DEFAULT_CONTEXT_PATH + "/restart").header(DEFAULT_SECRET_HEADER_NAME,
"supersecret")).andExpect(status().isOk());
assertRestartInvoked(true);
}
@Test
void disableRestart() throws Exception {
this.context = getContext(() -> loadContext("spring.devtools.remote.secret:supersecret",
@ -270,18 +250,6 @@ class RemoteDevToolsAutoConfigurationTests {
}
@Configuration(proxyBeanMethods = false)
@SuppressWarnings("deprecation")
static class TestWebSecurityConfigurerAdapter
extends org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/foo/**").authorizeHttpRequests().anyRequest().authenticated().and().httpBasic();
}
}
/**
* Mock {@link HttpRestartServer} implementation.
*/

View File

@ -212,8 +212,8 @@ You can use the configprop:management.endpoints.web.exposure.include[] property
NOTE: Before setting the `management.endpoints.web.exposure.include`, ensure that the exposed actuators do not contain sensitive information, are secured by placing them behind a firewall, or are secured by something like Spring Security.
If Spring Security is on the classpath and no other `WebSecurityConfigurerAdapter` or `SecurityFilterChain` bean is present, all actuators other than `/health` are secured by Spring Boot auto-configuration.
If you define a custom `WebSecurityConfigurerAdapter` or `SecurityFilterChain` bean, Spring Boot auto-configuration backs off and lets you fully control the actuator access rules.
If Spring Security is on the classpath and no other `SecurityFilterChain` bean is present, all actuators other than `/health` are secured by Spring Boot auto-configuration.
If you define a custom `SecurityFilterChain` bean, Spring Boot auto-configuration backs off and lets you fully control the actuator access rules.
If you wish to configure custom security for HTTP endpoints (for example, to allow only users with a certain role to access them), Spring Boot provides some convenient `RequestMatcher` objects that you can use in combination with Spring Security.

View File

@ -8,7 +8,7 @@ For more about Spring Security, see the {spring-security}[Spring Security projec
[[howto.security.switch-off-spring-boot-configuration]]
=== Switch off the Spring Boot Security Configuration
If you define a `@Configuration` with a `WebSecurityConfigurerAdapter` or a `SecurityFilterChain` bean in your application, it switches off the default webapp security settings in Spring Boot.
If you define a `@Configuration` with a `SecurityFilterChain` bean in your application, it switches off the default webapp security settings in Spring Boot.

View File

@ -38,7 +38,7 @@ To switch off the default web application security configuration completely or t
To also switch off the `UserDetailsService` configuration, you can add a bean of type `UserDetailsService`, `AuthenticationProvider`, or `AuthenticationManager`.
Access rules can be overridden by adding a custom `SecurityFilterChain` or `WebSecurityConfigurerAdapter` bean.
Access rules can be overridden by adding a custom `SecurityFilterChain` bean.
Spring Boot provides convenience methods that can be used to override access rules for actuator endpoints and static resources.
`EndpointRequest` can be used to create a `RequestMatcher` that is based on the configprop:management.endpoints.web.base-path[] property.
`PathRequest` can be used to create a `RequestMatcher` for resources in commonly used locations.

View File

@ -27,7 +27,7 @@ public class MySecurityConfiguration {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.requestMatcher(EndpointRequest.toAnyEndpoint());
http.securityMatcher(EndpointRequest.toAnyEndpoint());
http.authorizeHttpRequests((requests) -> requests.anyRequest().permitAll());
return http.build();
}

View File

@ -29,7 +29,7 @@ public class MySecurityConfiguration {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.requestMatcher(EndpointRequest.toAnyEndpoint());
http.securityMatcher(EndpointRequest.toAnyEndpoint());
http.authorizeHttpRequests((requests) -> requests.anyRequest().hasRole("ENDPOINT_ADMIN"));
http.httpBasic(withDefaults());
return http.build();

View File

@ -33,7 +33,7 @@ public class DevProfileSecurityConfiguration {
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
SecurityFilterChain h2ConsoleSecurityFilterChain(HttpSecurity http) throws Exception {
http.requestMatcher(PathRequest.toH2Console());
http.securityMatcher(PathRequest.toH2Console());
http.authorizeHttpRequests(yourCustomAuthorization());
http.csrf((csrf) -> csrf.disable());
http.headers((headers) -> headers.frameOptions().sameOrigin());

View File

@ -27,7 +27,7 @@ class MySecurityConfiguration {
@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests {
http.securityMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests {
requests -> requests.anyRequest().permitAll() }
return http.build()
}

View File

@ -27,7 +27,7 @@ class MySecurityConfiguration {
@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests { requests ->
http.securityMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests { requests ->
requests.anyRequest().hasRole("ENDPOINT_ADMIN")
}
http.httpBasic()

View File

@ -60,7 +60,6 @@ class WebMvcTypeExcludeFilterTests {
assertThat(excludes(filter, ExampleMessageConverter.class)).isFalse();
assertThat(excludes(filter, ExampleService.class)).isTrue();
assertThat(excludes(filter, ExampleRepository.class)).isTrue();
assertThat(excludes(filter, ExampleWebSecurityConfigurer.class)).isFalse();
assertThat(excludes(filter, SecurityFilterChain.class)).isFalse();
assertThat(excludes(filter, ExampleHandlerInterceptor.class)).isFalse();
assertThat(excludes(filter, ExampleModule.class)).isFalse();
@ -78,7 +77,6 @@ class WebMvcTypeExcludeFilterTests {
assertThat(excludes(filter, ExampleMessageConverter.class)).isFalse();
assertThat(excludes(filter, ExampleService.class)).isTrue();
assertThat(excludes(filter, ExampleRepository.class)).isTrue();
assertThat(excludes(filter, ExampleWebSecurityConfigurer.class)).isFalse();
assertThat(excludes(filter, SecurityFilterChain.class)).isFalse();
assertThat(excludes(filter, ExampleHandlerInterceptor.class)).isFalse();
assertThat(excludes(filter, ExampleModule.class)).isFalse();
@ -96,7 +94,6 @@ class WebMvcTypeExcludeFilterTests {
assertThat(excludes(filter, ExampleMessageConverter.class)).isTrue();
assertThat(excludes(filter, ExampleService.class)).isTrue();
assertThat(excludes(filter, ExampleRepository.class)).isTrue();
assertThat(excludes(filter, ExampleWebSecurityConfigurer.class)).isTrue();
assertThat(excludes(filter, SecurityFilterChain.class)).isTrue();
assertThat(excludes(filter, ExampleHandlerInterceptor.class)).isTrue();
assertThat(excludes(filter, ExampleModule.class)).isTrue();
@ -130,7 +127,6 @@ class WebMvcTypeExcludeFilterTests {
assertThat(excludes(filter, ExampleMessageConverter.class)).isFalse();
assertThat(excludes(filter, ExampleService.class)).isTrue();
assertThat(excludes(filter, ExampleRepository.class)).isTrue();
assertThat(excludes(filter, ExampleWebSecurityConfigurer.class)).isFalse();
assertThat(excludes(filter, SecurityFilterChain.class)).isFalse();
assertThat(excludes(filter, ExampleHandlerInterceptor.class)).isFalse();
assertThat(excludes(filter, ExampleModule.class)).isFalse();
@ -204,12 +200,6 @@ class WebMvcTypeExcludeFilterTests {
}
@SuppressWarnings("deprecation")
static class ExampleWebSecurityConfigurer
extends org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter {
}
static class ExampleHandlerInterceptor implements HandlerInterceptor {
}

View File

@ -54,7 +54,7 @@ public class EncodePasswordCommand extends OptionParsingCommand {
Map<String, Supplier<PasswordEncoder>> encoders = new LinkedHashMap<>();
encoders.put("default", PasswordEncoderFactories::createDelegatingPasswordEncoder);
encoders.put("bcrypt", BCryptPasswordEncoder::new);
encoders.put("pbkdf2", Pbkdf2PasswordEncoder::new);
encoders.put("pbkdf2", Pbkdf2PasswordEncoder::defaultsForSpringSecurity_v5_8);
ENCODERS = Collections.unmodifiableMap(encoders);
}

View File

@ -83,7 +83,8 @@ class EncodePasswordCommandTests {
ExitStatus status = command.run("-a", "pbkdf2", "boot");
then(this.log).should().info(this.message.capture());
assertThat(this.message.getValue()).doesNotStartWith("{");
assertThat(new Pbkdf2PasswordEncoder().matches("boot", this.message.getValue())).isTrue();
assertThat(Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_8().matches("boot", this.message.getValue()))
.isTrue();
assertThat(status).isEqualTo(ExitStatus.OK);
}

View File

@ -56,14 +56,14 @@ public class SecurityConfiguration {
@Bean
SecurityFilterChain configure(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((requests) -> {
requests.mvcMatchers("/actuator/beans").hasRole("BEANS");
requests.requestMatchers("/actuator/beans").hasRole("BEANS");
requests.requestMatchers(EndpointRequest.to("health")).permitAll();
requests.requestMatchers(EndpointRequest.toAnyEndpoint().excluding(MappingsEndpoint.class))
.hasRole("ACTUATOR");
requests.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll();
requests.antMatchers("/foo").permitAll();
requests.antMatchers("/error").permitAll();
requests.antMatchers("/**").hasRole("USER");
requests.requestMatchers("/foo").permitAll();
requests.requestMatchers("/error").permitAll();
requests.requestMatchers("/**").hasRole("USER");
});
http.cors(Customizer.withDefaults());
http.httpBasic();

View File

@ -128,7 +128,8 @@ abstract class AbstractSampleActuatorCustomSecurityTests {
@Test
void secureServletEndpointWithAnonymous() {
ResponseEntity<String> entity = restTemplate().getForEntity("/actuator/se1", String.class);
ResponseEntity<String> entity = restTemplate().getForEntity(getManagementPath() + "/actuator/se1",
String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
entity = restTemplate().getForEntity(getManagementPath() + "/actuator/se1/list", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);

View File

@ -18,7 +18,7 @@ package smoketest.graphql;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
@ -30,7 +30,7 @@ import static org.springframework.security.config.Customizer.withDefaults;
@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
@Bean

View File

@ -40,15 +40,14 @@ public class SecurityConfiguration {
@Bean
SecurityFilterChain configure(HttpSecurity http) throws Exception {
// @formatter:off
http.authorizeHttpRequests()
.requestMatchers(EndpointRequest.to("health")).permitAll()
.requestMatchers(EndpointRequest.toAnyEndpoint().excluding(MappingsEndpoint.class)).hasRole("ACTUATOR")
.antMatchers("/**").hasRole("USER")
.and()
.httpBasic();
http.authorizeHttpRequests((requests) -> {
requests.requestMatchers(EndpointRequest.to("health")).permitAll();
requests.requestMatchers(EndpointRequest.toAnyEndpoint().excluding(MappingsEndpoint.class))
.hasRole("ACTUATOR");
requests.requestMatchers("/**").hasRole("USER");
});
http.httpBasic();
return http.build();
// @formatter:on
}
}

View File

@ -22,13 +22,13 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
@EnableAutoConfiguration
@ComponentScan
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
@EnableMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class SampleSecureApplication implements CommandLineRunner {
@Autowired

View File

@ -26,6 +26,7 @@ import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import static org.assertj.core.api.Assertions.assertThat;
@ -62,7 +63,8 @@ class SampleSecureApplicationTests {
@Test
void authenticated() {
SecurityContextHolder.getContext().setAuthentication(this.authentication);
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("user", "N/A",
AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER")));
assertThat("Hello Security").isEqualTo(this.service.secure());
}

View File

@ -0,0 +1,47 @@
/*
* Copyright 2012-2022 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 smoketest.session.hazelcast;
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.boot.actuate.health.HealthEndpoint;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
/**
* Security configuration.
*
* @author Madhura Bhave
*/
@Configuration(proxyBeanMethods = false)
class SecurityConfiguration {
@Bean
SecurityFilterChain managementSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((requests) -> {
requests.requestMatchers(EndpointRequest.to(HealthEndpoint.class)).permitAll();
requests.anyRequest().authenticated();
});
http.formLogin(Customizer.withDefaults());
http.httpBasic(Customizer.withDefaults());
http.csrf().disable();
return http.build();
}
}

View File

@ -18,6 +18,7 @@ package smoketest.session.hazelcast;
import java.net.URI;
import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@ -27,11 +28,15 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import static org.assertj.core.api.Assertions.assertThat;
@ -50,10 +55,7 @@ class SampleSessionHazelcastApplicationTests {
@Test
@SuppressWarnings("unchecked")
void sessionsEndpointShouldReturnUserSession() {
URI uri = URI.create("/");
ResponseEntity<String> firstResponse = performRequest(uri, null);
String cookie = firstResponse.getHeaders().getFirst("Set-Cookie");
performRequest(uri, cookie).getBody();
performLogin();
ResponseEntity<Map<String, Object>> entity = getSessions();
assertThat(entity).isNotNull();
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
@ -61,29 +63,21 @@ class SampleSessionHazelcastApplicationTests {
assertThat(sessions.size()).isEqualTo(1);
}
private ResponseEntity<String> performRequest(URI uri, String cookie) {
HttpHeaders headers = getHeaders(cookie);
RequestEntity<Object> request = new RequestEntity<>(headers, HttpMethod.GET, uri);
return this.restTemplate.exchange(request, String.class);
}
private HttpHeaders getHeaders(String cookie) {
private String performLogin() {
HttpHeaders headers = new HttpHeaders();
if (cookie != null) {
headers.set("Cookie", cookie);
}
else {
headers.set("Authorization", getBasicAuth());
}
return headers;
}
private String getBasicAuth() {
return "Basic " + Base64.getEncoder().encodeToString("user:password".getBytes());
headers.setAccept(Collections.singletonList(MediaType.TEXT_HTML));
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
form.set("username", "user");
form.set("password", "password");
ResponseEntity<String> entity = this.restTemplate.exchange("/login", HttpMethod.POST,
new HttpEntity<>(form, headers), String.class);
return entity.getHeaders().getFirst("Set-Cookie");
}
private ResponseEntity<Map<String, Object>> getSessions() {
HttpHeaders headers = getHeaders(null);
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", getBasicAuth());
RequestEntity<Object> request = new RequestEntity<>(headers, HttpMethod.GET,
URI.create("/actuator/sessions?username=user"));
ParameterizedTypeReference<Map<String, Object>> stringObjectMap = new ParameterizedTypeReference<Map<String, Object>>() {
@ -91,4 +85,8 @@ class SampleSessionHazelcastApplicationTests {
return this.restTemplate.exchange(request, stringObjectMap);
}
private String getBasicAuth() {
return "Basic " + Base64.getEncoder().encodeToString("user:password".getBytes());
}
}

View File

@ -0,0 +1,47 @@
/*
* Copyright 2012-2022 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 smoketest.session;
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.boot.actuate.health.HealthEndpoint;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
/**
* Security configuration.
*
* @author Madhura Bhave
*/
@Configuration(proxyBeanMethods = false)
class SecurityConfiguration {
@Bean
SecurityFilterChain managementSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((requests) -> {
requests.requestMatchers(EndpointRequest.to(HealthEndpoint.class)).permitAll();
requests.anyRequest().authenticated();
});
http.formLogin(Customizer.withDefaults());
http.httpBasic(Customizer.withDefaults());
http.csrf().disable();
return http.build();
}
}

View File

@ -18,6 +18,7 @@ package smoketest.session;
import java.net.URI;
import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@ -27,11 +28,15 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import static org.assertj.core.api.Assertions.assertThat;
@ -53,9 +58,8 @@ class SampleSessionJdbcApplicationTests {
@Test
void sessionExpiry() throws Exception {
ResponseEntity<String> firstResponse = performRequest(ROOT_URI, null);
String sessionId1 = firstResponse.getBody();
String cookie = firstResponse.getHeaders().getFirst("Set-Cookie");
String cookie = performLogin();
String sessionId1 = performRequest(ROOT_URI, cookie).getBody();
String sessionId2 = performRequest(ROOT_URI, cookie).getBody();
assertThat(sessionId1).isEqualTo(sessionId2);
Thread.sleep(2100);
@ -63,10 +67,22 @@ class SampleSessionJdbcApplicationTests {
assertThat(loginPage).containsIgnoringCase("login");
}
private String performLogin() {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.TEXT_HTML));
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
form.set("username", "user");
form.set("password", "password");
ResponseEntity<String> entity = this.restTemplate.exchange("/login", HttpMethod.POST,
new HttpEntity<>(form, headers), String.class);
return entity.getHeaders().getFirst("Set-Cookie");
}
@Test
@SuppressWarnings("unchecked")
void sessionsEndpointShouldReturnUserSession() {
performRequest(ROOT_URI, null);
performLogin();
ResponseEntity<Map<String, Object>> response = getSessions();
assertThat(response).isNotNull();
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);

View File

@ -0,0 +1,47 @@
/*
* Copyright 2012-2022 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 smoketest.session.mongodb;
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.boot.actuate.health.HealthEndpoint;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
/**
* Security configuration.
*
* @author Madhura Bhave
*/
@Configuration(proxyBeanMethods = false)
class SecurityConfiguration {
@Bean
SecurityFilterChain managementSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((requests) -> {
requests.requestMatchers(EndpointRequest.to(HealthEndpoint.class)).permitAll();
requests.anyRequest().authenticated();
});
http.formLogin(Customizer.withDefaults());
http.httpBasic(Customizer.withDefaults());
http.csrf().disable();
return http.build();
}
}

View File

@ -18,6 +18,7 @@ package smoketest.session.mongodb;
import java.net.URI;
import java.time.Duration;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@ -32,13 +33,17 @@ import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.boot.testsupport.testcontainers.DockerImageNames;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import static org.assertj.core.api.Assertions.assertThat;
@ -69,7 +74,7 @@ public class SampleSessionMongoApplicationTests {
@Test
@SuppressWarnings("unchecked")
void sessionsEndpointShouldReturnUserSessions() {
createSession(URI.create("/"));
performLogin();
ResponseEntity<Map<String, Object>> response = getSessions();
assertThat(response).isNotNull();
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
@ -86,9 +91,16 @@ public class SampleSessionMongoApplicationTests {
assertThat(entity.getBody()).contains("maxWireVersion");
}
private void createSession(URI uri) {
RequestEntity<Object> request = getRequestEntity(uri);
this.restTemplate.exchange(request, String.class);
private String performLogin() {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.TEXT_HTML));
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
form.set("username", "user");
form.set("password", "password");
ResponseEntity<String> entity = this.restTemplate.exchange("/login", HttpMethod.POST,
new HttpEntity<>(form, headers), String.class);
return entity.getHeaders().getFirst("Set-Cookie");
}
private RequestEntity<Object> getRequestEntity(URI uri) {

View File

@ -0,0 +1,47 @@
/*
* Copyright 2012-2022 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 smoketest.session.redis;
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.boot.actuate.health.HealthEndpoint;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
/**
* Security configuration.
*
* @author Madhura Bhave
*/
@Configuration(proxyBeanMethods = false)
class SecurityConfiguration {
@Bean
SecurityFilterChain managementSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((requests) -> {
requests.requestMatchers(EndpointRequest.to(HealthEndpoint.class)).permitAll();
requests.anyRequest().authenticated();
});
http.formLogin(Customizer.withDefaults());
http.httpBasic(Customizer.withDefaults());
http.csrf().disable();
return http.build();
}
}

View File

@ -17,6 +17,7 @@
package smoketest.session.redis;
import java.net.URI;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@ -29,13 +30,17 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.testsupport.testcontainers.RedisContainer;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import static org.assertj.core.api.Assertions.assertThat;
@ -63,7 +68,7 @@ public class SampleSessionRedisApplicationTests {
@Test
@SuppressWarnings("unchecked")
void sessionsEndpointShouldReturnUserSessions() {
createSession(URI.create("/"));
performLogin();
ResponseEntity<Map<String, Object>> response = this.getSessions();
assertThat(response).isNotNull();
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
@ -71,9 +76,16 @@ public class SampleSessionRedisApplicationTests {
assertThat(sessions.size()).isEqualTo(1);
}
private void createSession(URI uri) {
RequestEntity<Object> request = getRequestEntity(uri);
this.restTemplate.exchange(request, String.class);
private String performLogin() {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.TEXT_HTML));
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
form.set("username", "user");
form.set("password", "password");
ResponseEntity<String> entity = this.restTemplate.exchange("/login", HttpMethod.POST,
new HttpEntity<>(form, headers), String.class);
return entity.getHeaders().getFirst("Set-Cookie");
}
private RequestEntity<Object> getRequestEntity(URI uri) {

View File

@ -24,18 +24,20 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.context.RequestAttributeSecurityContextRepository;
import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@SpringBootApplication
@EnableGlobalMethodSecurity(securedEnabled = true)
@EnableMethodSecurity(securedEnabled = true)
public class SampleMethodSecurityApplication implements WebMvcConfigurer {
@Override
@ -69,8 +71,8 @@ public class SampleMethodSecurityApplication implements WebMvcConfigurer {
@Bean
SecurityFilterChain configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeHttpRequests(
(requests) -> requests.anyRequest().fullyAuthenticated().shouldFilterAllDispatcherTypes(false));
http.authorizeHttpRequests((requests) -> requests.anyRequest().fullyAuthenticated());
http.httpBasic();
http.formLogin((form) -> form.loginPage("/login").permitAll());
http.exceptionHandling((exceptions) -> exceptions.accessDeniedPage("/access"));
return http.build();
@ -85,10 +87,10 @@ public class SampleMethodSecurityApplication implements WebMvcConfigurer {
@Bean
SecurityFilterChain actuatorSecurity(HttpSecurity http) throws Exception {
http.csrf().disable();
http.requestMatcher(EndpointRequest.toAnyEndpoint());
http.authorizeHttpRequests(
(requests) -> requests.anyRequest().authenticated().shouldFilterAllDispatcherTypes(false));
http.securityMatcher(EndpointRequest.toAnyEndpoint());
http.authorizeHttpRequests((requests) -> requests.anyRequest().authenticated());
http.httpBasic();
http.setSharedObject(SecurityContextRepository.class, new RequestAttributeSecurityContextRepository());
return http.build();
}

View File

@ -21,6 +21,8 @@ import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.context.RequestAttributeSecurityContextRepository;
import org.springframework.security.web.context.SecurityContextRepository;
/**
* Tests to ensure that the error page with a custom servlet path is accessible only to
@ -45,10 +47,11 @@ class CustomServletPathErrorPageTests extends AbstractErrorPageTests {
@Bean
SecurityFilterChain configure(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((requests) -> {
requests.antMatchers("/custom/servlet/path/public/**").permitAll();
requests.requestMatchers("/public/**").permitAll();
requests.anyRequest().fullyAuthenticated();
});
http.httpBasic();
http.setSharedObject(SecurityContextRepository.class, new RequestAttributeSecurityContextRepository());
http.formLogin((form) -> form.loginPage("/custom/servlet/path/login").permitAll());
return http.build();
}

View File

@ -20,6 +20,8 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.context.RequestAttributeSecurityContextRepository;
import org.springframework.security.web.context.SecurityContextRepository;
/**
* Tests for error page that permits access to all with a custom servlet path.
@ -44,10 +46,11 @@ class CustomServletPathUnauthenticatedErrorPageTests extends AbstractUnauthentic
@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((requests) -> {
requests.antMatchers("/custom/servlet/path/error").permitAll();
requests.antMatchers("/custom/servlet/path/public/**").permitAll();
requests.requestMatchers("/error").permitAll();
requests.requestMatchers("/public/**").permitAll();
requests.anyRequest().authenticated();
});
http.setSharedObject(SecurityContextRepository.class, new RequestAttributeSecurityContextRepository());
http.httpBasic();
return http.build();
}

View File

@ -21,6 +21,8 @@ import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.context.RequestAttributeSecurityContextRepository;
import org.springframework.security.web.context.SecurityContextRepository;
/**
* Tests to ensure that the error page is accessible only to authorized users.
@ -44,9 +46,10 @@ class ErrorPageTests extends AbstractErrorPageTests {
@Bean
SecurityFilterChain configure(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((requests) -> {
requests.antMatchers("/public/**").permitAll();
requests.requestMatchers("/public/**").permitAll();
requests.anyRequest().fullyAuthenticated();
});
http.setSharedObject(SecurityContextRepository.class, new RequestAttributeSecurityContextRepository());
http.httpBasic();
http.formLogin((form) -> form.loginPage("/login").permitAll());
return http.build();

View File

@ -46,7 +46,7 @@ class NoSessionErrorPageTests extends AbstractErrorPageTests {
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http.sessionManagement((session) -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests((requests) -> {
requests.antMatchers("/public/**").permitAll();
requests.requestMatchers("/public/**").permitAll();
requests.anyRequest().authenticated();
});
http.httpBasic();

View File

@ -96,7 +96,7 @@ class SampleWebSecureApplicationTests {
SecurityFilterChain configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeHttpRequests((requests) -> {
requests.antMatchers("/public/**").permitAll();
requests.requestMatchers("/public/**").permitAll();
requests.anyRequest().fullyAuthenticated();
});
http.httpBasic();

View File

@ -21,6 +21,8 @@ import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.context.RequestAttributeSecurityContextRepository;
import org.springframework.security.web.context.SecurityContextRepository;
/**
* Tests for error page that permits access to all.
@ -44,10 +46,11 @@ class UnauthenticatedErrorPageTests extends AbstractUnauthenticatedErrorPageTest
@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((requests) -> {
requests.antMatchers("/error").permitAll();
requests.antMatchers("/public/**").permitAll();
requests.requestMatchers("/error").permitAll();
requests.requestMatchers("/public/**").permitAll();
requests.anyRequest().authenticated();
});
http.setSharedObject(SecurityContextRepository.class, new RequestAttributeSecurityContextRepository());
http.httpBasic();
return http.build();
}