Merge branch '3.2.x'

Closes gh-39117
This commit is contained in:
Andy Wilkinson 2024-01-12 13:02:56 +00:00
commit 907e4d97f7
2 changed files with 38 additions and 9 deletions

View File

@ -16,6 +16,8 @@
package org.springframework.boot.actuate.autoconfigure.security.reactive;
import reactor.core.publisher.Mono;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration;
@ -28,10 +30,14 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplicat
import org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration;
import org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration;
import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration;
import org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.WebFilterChainProxy;
import org.springframework.web.cors.reactive.PreFlightRequestHandler;
@ -50,7 +56,8 @@ import static org.springframework.security.config.Customizer.withDefaults;
@AutoConfiguration(before = ReactiveSecurityAutoConfiguration.class,
after = { HealthEndpointAutoConfiguration.class, InfoEndpointAutoConfiguration.class,
WebEndpointAutoConfiguration.class, ReactiveOAuth2ClientAutoConfiguration.class,
ReactiveOAuth2ResourceServerAutoConfiguration.class })
ReactiveOAuth2ResourceServerAutoConfiguration.class,
ReactiveUserDetailsServiceAutoConfiguration.class })
@ConditionalOnClass({ EnableWebFluxSecurity.class, WebFilterChainProxy.class })
@ConditionalOnMissingBean({ SecurityWebFilterChain.class, WebFilterChainProxy.class })
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@ -69,4 +76,10 @@ public class ReactiveManagementWebSecurityAutoConfiguration {
return http.build();
}
@Bean
@ConditionalOnMissingBean({ ReactiveAuthenticationManager.class, ReactiveUserDetailsService.class })
ReactiveAuthenticationManager denyAllAuthenticationManager() {
return (authentication) -> Mono.error(new UsernameNotFoundException(authentication.getName()));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 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.
@ -71,17 +71,26 @@ class ReactiveManagementWebSecurityAutoConfigurationTests {
HealthEndpointAutoConfiguration.class, InfoEndpointAutoConfiguration.class,
WebFluxAutoConfiguration.class, EnvironmentEndpointAutoConfiguration.class,
EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class,
ReactiveSecurityAutoConfiguration.class, ReactiveManagementWebSecurityAutoConfiguration.class))
.withUserConfiguration(UserDetailsServiceConfiguration.class);
ReactiveSecurityAutoConfiguration.class, ReactiveManagementWebSecurityAutoConfiguration.class));
@Test
void permitAllForHealth() {
this.contextRunner.run((context) -> assertThat(getAuthenticateHeader(context, "/actuator/health")).isNull());
this.contextRunner.withUserConfiguration(UserDetailsServiceConfiguration.class)
.run((context) -> assertThat(getAuthenticateHeader(context, "/actuator/health")).isNull());
}
@Test
void securesEverythingElse() {
this.contextRunner.withUserConfiguration(UserDetailsServiceConfiguration.class).run((context) -> {
assertThat(getAuthenticateHeader(context, "/actuator").get(0)).contains("Basic realm=");
assertThat(getAuthenticateHeader(context, "/foo").toString()).contains("Basic realm=");
});
}
@Test
void noExistingAuthenticationManagerOrUserDetailsService() {
this.contextRunner.run((context) -> {
assertThat(getAuthenticateHeader(context, "/actuator/health")).isNull();
assertThat(getAuthenticateHeader(context, "/actuator").get(0)).contains("Basic realm=");
assertThat(getAuthenticateHeader(context, "/foo").toString()).contains("Basic realm=");
});
@ -89,10 +98,12 @@ class ReactiveManagementWebSecurityAutoConfigurationTests {
@Test
void usesMatchersBasedOffConfiguredActuatorBasePath() {
this.contextRunner.withPropertyValues("management.endpoints.web.base-path=/").run((context) -> {
assertThat(getAuthenticateHeader(context, "/health")).isNull();
assertThat(getAuthenticateHeader(context, "/foo").get(0)).contains("Basic realm=");
});
this.contextRunner.withUserConfiguration(UserDetailsServiceConfiguration.class)
.withPropertyValues("management.endpoints.web.base-path=/")
.run((context) -> {
assertThat(getAuthenticateHeader(context, "/health")).isNull();
assertThat(getAuthenticateHeader(context, "/foo").get(0)).contains("Basic realm=");
});
}
@Test
@ -180,6 +191,11 @@ class ReactiveManagementWebSecurityAutoConfigurationTests {
return http.build();
}
@Bean
ReactiveAuthenticationManager authenticationManager() {
return mock(ReactiveAuthenticationManager.class);
}
}
@Configuration(proxyBeanMethods = false)