mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-03-27 02:18:29 +00:00
Add AuthenticationManager to HttpSecurity
Closes gh-10040
This commit is contained in:
parent
88a3f5ad39
commit
585788ad0a
@ -143,6 +143,8 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
|
||||
private FilterOrderRegistration filterOrders = new FilterOrderRegistration();
|
||||
|
||||
private AuthenticationManager authenticationManager;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @param objectPostProcessor the {@link ObjectPostProcessor} that should be used
|
||||
@ -2722,6 +2724,18 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
return HttpSecurity.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the default {@link AuthenticationManager}.
|
||||
* @param authenticationManager the {@link AuthenticationManager} to use
|
||||
* @return the {@link HttpSecurity} for further customizations
|
||||
* @since 5.6
|
||||
*/
|
||||
public HttpSecurity authenticationManager(AuthenticationManager authenticationManager) {
|
||||
Assert.notNull(authenticationManager, "authenticationManager cannot be null");
|
||||
this.authenticationManager = authenticationManager;
|
||||
return HttpSecurity.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C> void setSharedObject(Class<C> sharedType, C object) {
|
||||
super.setSharedObject(sharedType, object);
|
||||
@ -2729,7 +2743,12 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
|
||||
@Override
|
||||
protected void beforeConfigure() throws Exception {
|
||||
setSharedObject(AuthenticationManager.class, getAuthenticationRegistry().build());
|
||||
if (this.authenticationManager != null) {
|
||||
setSharedObject(AuthenticationManager.class, this.authenticationManager);
|
||||
}
|
||||
else {
|
||||
setSharedObject(AuthenticationManager.class, getAuthenticationRegistry().build());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 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.
|
||||
@ -17,6 +17,7 @@
|
||||
package org.springframework.security.config.web.servlet
|
||||
|
||||
import org.springframework.context.ApplicationContext
|
||||
import org.springframework.security.authentication.AuthenticationManager
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository
|
||||
@ -63,11 +64,14 @@ operator fun HttpSecurity.invoke(httpConfiguration: HttpSecurityDsl.() -> Unit)
|
||||
* @since 5.3
|
||||
* @param http the [HttpSecurity] which all configurations will be applied to
|
||||
* @param init the configurations to apply to the provided [HttpSecurity]
|
||||
* @property authenticationManager the default [AuthenticationManager] to use
|
||||
*/
|
||||
@SecurityMarker
|
||||
class HttpSecurityDsl(private val http: HttpSecurity, private val init: HttpSecurityDsl.() -> Unit) {
|
||||
private val HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector"
|
||||
|
||||
var authenticationManager: AuthenticationManager? = null
|
||||
|
||||
/**
|
||||
* Allows configuring the [HttpSecurity] to only be invoked when matching the
|
||||
* provided pattern.
|
||||
@ -858,5 +862,6 @@ class HttpSecurityDsl(private val http: HttpSecurity, private val init: HttpSecu
|
||||
*/
|
||||
internal fun build() {
|
||||
init()
|
||||
authenticationManager?.also { this.http.authenticationManager(authenticationManager) }
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 2012-2021 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.builders;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
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.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.test.SpringTestRule;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.springframework.security.config.Customizer.withDefaults;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
|
||||
public class HttpSecurityAuthenticationManagerTests {
|
||||
|
||||
@Autowired
|
||||
MockMvc mvc;
|
||||
|
||||
@Rule
|
||||
public final SpringTestRule spring = new SpringTestRule();
|
||||
|
||||
@Test
|
||||
public void authenticationManagerWhenConfiguredThenUsed() throws Exception {
|
||||
this.spring.register(AuthenticationManagerConfig.class).autowire();
|
||||
|
||||
given(AuthenticationManagerConfig.AUTHENTICATION_MANAGER.authenticate(any()))
|
||||
.willReturn(new TestingAuthenticationToken("user", "test", "ROLE_USER"));
|
||||
|
||||
this.mvc.perform(get("/").with(httpBasic("user", "test")));
|
||||
|
||||
verify(AuthenticationManagerConfig.AUTHENTICATION_MANAGER).authenticate(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticationManagerWhenBuilderAndAuthenticationManagerConfiguredThenBuilderIgnored()
|
||||
throws Exception {
|
||||
this.spring.register(AuthenticationManagerBuilderConfig.class).autowire();
|
||||
|
||||
given(AuthenticationManagerBuilderConfig.AUTHENTICATION_MANAGER.authenticate(any()))
|
||||
.willReturn(new TestingAuthenticationToken("user", "test", "ROLE_USER"));
|
||||
|
||||
this.mvc.perform(get("/").with(httpBasic("user", "test")));
|
||||
|
||||
verify(AuthenticationManagerBuilderConfig.AUTHENTICATION_MANAGER).authenticate(any());
|
||||
verifyNoInteractions(AuthenticationManagerBuilderConfig.USER_DETAILS_SERVICE);
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class AuthenticationManagerConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
static final AuthenticationManager AUTHENTICATION_MANAGER = mock(AuthenticationManager.class);
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeRequests((authz) -> authz
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.httpBasic(withDefaults())
|
||||
.authenticationManager(AUTHENTICATION_MANAGER);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class AuthenticationManagerBuilderConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
static final AuthenticationManager AUTHENTICATION_MANAGER = mock(AuthenticationManager.class);
|
||||
static final UserDetailsService USER_DETAILS_SERVICE = mock(UserDetailsService.class);
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeRequests((authz) -> authz
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.httpBasic(withDefaults())
|
||||
.authenticationManager(AUTHENTICATION_MANAGER);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.userDetailsService(USER_DETAILS_SERVICE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -996,6 +996,24 @@ public class OAuth2ResourceServerConfigurerTests {
|
||||
verifyBean(AuthenticationProvider.class).authenticate(any(Authentication.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getWhenDefaultAndCustomJwtAuthenticationManagerThenCustomUsed() throws Exception {
|
||||
this.spring.register(DefaultAndJwtAuthenticationManagerConfig.class, BasicController.class).autowire();
|
||||
DefaultAndJwtAuthenticationManagerConfig config = this.spring.getContext()
|
||||
.getBean(DefaultAndJwtAuthenticationManagerConfig.class);
|
||||
AuthenticationManager defaultAuthenticationManager = config.defaultAuthenticationManager();
|
||||
AuthenticationManager jwtAuthenticationManager = config.jwtAuthenticationManager();
|
||||
given(defaultAuthenticationManager.authenticate(any()))
|
||||
.willThrow(new RuntimeException("should not interact with default auth manager"));
|
||||
given(jwtAuthenticationManager.authenticate(any())).willReturn(JWT_AUTHENTICATION_TOKEN);
|
||||
// @formatter:off
|
||||
this.mvc.perform(get("/authenticated").with(bearerToken("token")))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().string("mock-test-subject"));
|
||||
// @formatter:on
|
||||
verify(jwtAuthenticationManager).authenticate(any(Authentication.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getWhenIntrospectingThenOk() throws Exception {
|
||||
this.spring.register(RestOperationsConfig.class, OpaqueTokenConfig.class, BasicController.class).autowire();
|
||||
@ -1054,6 +1072,24 @@ public class OAuth2ResourceServerConfigurerTests {
|
||||
verifyBean(AuthenticationProvider.class).authenticate(any(Authentication.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getWhenDefaultAndCustomIntrospectionAuthenticationManagerThenCustomUsed() throws Exception {
|
||||
this.spring.register(DefaultAndOpaqueTokenAuthenticationManagerConfig.class, BasicController.class).autowire();
|
||||
DefaultAndOpaqueTokenAuthenticationManagerConfig config = this.spring.getContext()
|
||||
.getBean(DefaultAndOpaqueTokenAuthenticationManagerConfig.class);
|
||||
AuthenticationManager defaultAuthenticationManager = config.defaultAuthenticationManager();
|
||||
AuthenticationManager opaqueTokenAuthenticationManager = config.opaqueTokenAuthenticationManager();
|
||||
given(defaultAuthenticationManager.authenticate(any()))
|
||||
.willThrow(new RuntimeException("should not interact with default auth manager"));
|
||||
given(opaqueTokenAuthenticationManager.authenticate(any())).willReturn(INTROSPECTION_AUTHENTICATION_TOKEN);
|
||||
// @formatter:off
|
||||
this.mvc.perform(get("/authenticated").with(bearerToken("token")))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().string("mock-test-subject"));
|
||||
// @formatter:on
|
||||
verify(opaqueTokenAuthenticationManager).authenticate(any(Authentication.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getWhenCustomIntrospectionAuthenticationManagerInLambdaThenUsed() throws Exception {
|
||||
this.spring.register(OpaqueTokenAuthenticationManagerInLambdaConfig.class, BasicController.class).autowire();
|
||||
@ -2017,6 +2053,39 @@ public class OAuth2ResourceServerConfigurerTests {
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class DefaultAndJwtAuthenticationManagerConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
AuthenticationManager defaultAuthenticationManager = mock(AuthenticationManager.class);
|
||||
|
||||
AuthenticationManager jwtAuthenticationManager = mock(AuthenticationManager.class);
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.authenticationManager(this.defaultAuthenticationManager)
|
||||
.authorizeRequests((authz) -> authz
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.oauth2ResourceServer((oauth2) -> oauth2
|
||||
.jwt((jwt) -> jwt
|
||||
.authenticationManager(this.jwtAuthenticationManager)
|
||||
)
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
AuthenticationManager defaultAuthenticationManager() {
|
||||
return this.defaultAuthenticationManager;
|
||||
}
|
||||
|
||||
AuthenticationManager jwtAuthenticationManager() {
|
||||
return this.jwtAuthenticationManager;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class CustomJwtValidatorConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@ -2230,6 +2299,39 @@ public class OAuth2ResourceServerConfigurerTests {
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class DefaultAndOpaqueTokenAuthenticationManagerConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
AuthenticationManager defaultAuthenticationManager = mock(AuthenticationManager.class);
|
||||
|
||||
AuthenticationManager opaqueTokenAuthenticationManager = mock(AuthenticationManager.class);
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.authenticationManager(this.defaultAuthenticationManager)
|
||||
.authorizeRequests((authz) -> authz
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.oauth2ResourceServer((oauth2) -> oauth2
|
||||
.opaqueToken((opaque) -> opaque
|
||||
.authenticationManager(this.opaqueTokenAuthenticationManager)
|
||||
)
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
AuthenticationManager defaultAuthenticationManager() {
|
||||
return this.defaultAuthenticationManager;
|
||||
}
|
||||
|
||||
AuthenticationManager opaqueTokenAuthenticationManager() {
|
||||
return this.opaqueTokenAuthenticationManager;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class OpaqueAndJwtConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
|
@ -163,6 +163,12 @@ public class Saml2LoginConfigurerTests {
|
||||
performSaml2Login("ROLE_AUTH_MANAGER");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saml2LoginWhenDefaultAndSamlAuthenticationManagerThenSamlManagerIsUsed() throws Exception {
|
||||
this.spring.register(Saml2LoginConfigWithDefaultAndCustomAuthenticationManager.class).autowire();
|
||||
performSaml2Login("ROLE_AUTH_MANAGER");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saml2LoginWhenConfiguringAuthenticationDefaultsUsingCustomizerThenTheProviderIsConfigured()
|
||||
throws Exception {
|
||||
@ -290,6 +296,24 @@ public class Saml2LoginConfigurerTests {
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@Import(Saml2LoginConfigBeans.class)
|
||||
static class Saml2LoginConfigWithDefaultAndCustomAuthenticationManager extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.authenticationManager(getAuthenticationManagerMock("DEFAULT_AUTH_MANAGER"))
|
||||
.saml2Login((saml) -> saml
|
||||
.authenticationManager(getAuthenticationManagerMock("ROLE_AUTH_MANAGER"))
|
||||
);
|
||||
super.configure(http);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@Import(Saml2LoginConfigBeans.class)
|
||||
static class Saml2LoginConfigWithAuthenticationDefaultsWithPostProcessor extends WebSecurityConfigurerAdapter {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 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.
|
||||
@ -16,6 +16,9 @@
|
||||
|
||||
package org.springframework.security.config.web.servlet
|
||||
|
||||
import io.mockk.every
|
||||
import io.mockk.mockkObject
|
||||
import io.mockk.verify
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
@ -23,6 +26,10 @@ import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.http.HttpHeaders
|
||||
import org.springframework.security.authentication.AuthenticationManager
|
||||
import org.springframework.security.authentication.ProviderManager
|
||||
import org.springframework.security.authentication.TestingAuthenticationProvider
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken
|
||||
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
|
||||
@ -30,6 +37,7 @@ 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.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic
|
||||
import org.springframework.security.web.FilterChainProxy
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
|
||||
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter
|
||||
@ -41,6 +49,7 @@ import org.springframework.security.web.util.matcher.RegexRequestMatcher
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
import org.springframework.test.web.servlet.post
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc
|
||||
import javax.servlet.Filter
|
||||
|
||||
@ -217,6 +226,36 @@ class HttpSecurityDslTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `authentication manager when configured in DSL then used`() {
|
||||
this.spring.register(AuthenticationManagerConfig::class.java).autowire()
|
||||
mockkObject(AuthenticationManagerConfig.AUTHENTICATION_MANAGER)
|
||||
every {
|
||||
AuthenticationManagerConfig.AUTHENTICATION_MANAGER.authenticate(any())
|
||||
} returns TestingAuthenticationToken("user", "test", "ROLE_USER")
|
||||
val request = MockMvcRequestBuilders.get("/")
|
||||
.with(httpBasic("user", "password"))
|
||||
this.mockMvc.perform(request)
|
||||
verify(exactly = 1) { AuthenticationManagerConfig.AUTHENTICATION_MANAGER.authenticate(any()) }
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class AuthenticationManagerConfig : WebSecurityConfigurerAdapter() {
|
||||
companion object {
|
||||
val AUTHENTICATION_MANAGER: AuthenticationManager = ProviderManager(TestingAuthenticationProvider())
|
||||
}
|
||||
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
authenticationManager = AUTHENTICATION_MANAGER
|
||||
authorizeRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
httpBasic { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `HTTP security when custom filter configured then custom filter added to filter chain`() {
|
||||
this.spring.register(CustomFilterConfig::class.java).autowire()
|
||||
|
Loading…
x
Reference in New Issue
Block a user