diff --git a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java index a2af85654e..d30f2c52c4 100644 --- a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java +++ b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java @@ -1667,11 +1667,15 @@ public class ServerHttpSecurity { this.cors.configure(this); } if (this.httpBasic != null) { - this.httpBasic.authenticationManager(this.authenticationManager); + if (this.httpBasic.authenticationManager == null) { + this.httpBasic.authenticationManager(this.authenticationManager); + } this.httpBasic.configure(this); } if (this.formLogin != null) { - this.formLogin.authenticationManager(this.authenticationManager); + if (this.formLogin.authenticationManager == null) { + this.formLogin.authenticationManager(this.authenticationManager); + } if (this.securityContextRepository != null) { this.formLogin.securityContextRepository(this.securityContextRepository); } diff --git a/config/src/test/java/org/springframework/security/config/web/server/FormLoginTests.java b/config/src/test/java/org/springframework/security/config/web/server/FormLoginTests.java index cbf1a2782b..96a174f3b6 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/FormLoginTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/FormLoginTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,8 @@ import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.PageFactory; +import org.springframework.security.authentication.ReactiveAuthenticationManager; +import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.config.annotation.web.reactive.ServerHttpSecurityConfigurationBuilder; import org.springframework.security.htmlunit.server.WebTestClientHtmlUnitDriverBuilder; import org.springframework.security.test.web.reactive.server.WebTestClientBuilder; @@ -40,6 +42,10 @@ import reactor.core.publisher.Mono; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatCode; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verifyZeroInteractions; /** * @author Rob Winch @@ -152,6 +158,42 @@ public class FormLoginTests { assertThat(driver.getCurrentUrl()).endsWith("/custom"); } + @Test + public void customAuthenticationManager() { + ReactiveAuthenticationManager defaultAuthenticationManager = mock(ReactiveAuthenticationManager.class); + ReactiveAuthenticationManager customAuthenticationManager = mock(ReactiveAuthenticationManager.class); + + given(defaultAuthenticationManager.authenticate(any())).willThrow(new RuntimeException("should not interact with default auth manager")); + given(customAuthenticationManager.authenticate(any())).willReturn(Mono.just(new TestingAuthenticationToken("user", "password", "ROLE_USER", "ROLE_ADMIN"))); + + SecurityWebFilterChain securityWebFilter = this.http + .authenticationManager(defaultAuthenticationManager) + .formLogin() + .authenticationManager(customAuthenticationManager) + .and() + .build(); + + WebTestClient webTestClient = WebTestClientBuilder + .bindToWebFilters(securityWebFilter) + .build(); + + WebDriver driver = WebTestClientHtmlUnitDriverBuilder + .webTestClientSetup(webTestClient) + .build(); + + DefaultLoginPage loginPage = DefaultLoginPage.to(driver) + .assertAt(); + + HomePage homePage = loginPage.loginForm() + .username("user") + .password("password") + .submit(HomePage.class); + + homePage.assertAt(); + + verifyZeroInteractions(defaultAuthenticationManager); + } + public static class CustomLoginPage { private WebDriver driver; diff --git a/config/src/test/java/org/springframework/security/config/web/server/ServerHttpSecurityTests.java b/config/src/test/java/org/springframework/security/config/web/server/ServerHttpSecurityTests.java index 9e45b0c92f..daedfb9a6a 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/ServerHttpSecurityTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/ServerHttpSecurityTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.BDDMockito.given; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import java.util.Arrays; @@ -282,6 +283,25 @@ public class ServerHttpSecurityTests { assertThat(result.getResponseCookies().getFirst("SESSION")).isNull(); } + @Test + public void basicWithCustomAuthenticationManager() { + ReactiveAuthenticationManager customAuthenticationManager = mock(ReactiveAuthenticationManager.class); + given(customAuthenticationManager.authenticate(any())).willReturn(Mono.just(new TestingAuthenticationToken("rob", "rob", "ROLE_USER", "ROLE_ADMIN"))); + + SecurityWebFilterChain securityFilterChain = this.http.httpBasic().authenticationManager(customAuthenticationManager).and().build(); + WebFilterChainProxy springSecurityFilterChain = new WebFilterChainProxy(securityFilterChain); + WebTestClient client = WebTestClientBuilder.bindToWebFilters(springSecurityFilterChain).build(); + + client.get() + .uri("/") + .headers(headers -> headers.setBasicAuth("rob", "rob")) + .exchange() + .expectStatus().isOk() + .expectBody(String.class).consumeWith(b -> assertThat(b.getResponseBody()).isEqualTo("ok")); + + verifyZeroInteractions(this.authenticationManager); + } + @Test @SuppressWarnings("unchecked") public void addsX509FilterWhenX509AuthenticationIsConfigured() {