diff --git a/core/src/test/java/org/springframework/security/authentication/NonBuildableAuthenticationToken.java b/core/src/test/java/org/springframework/security/authentication/NonBuildableAuthenticationToken.java new file mode 100644 index 0000000000..8099b826f3 --- /dev/null +++ b/core/src/test/java/org/springframework/security/authentication/NonBuildableAuthenticationToken.java @@ -0,0 +1,25 @@ +/* + * Copyright 2004-present 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.authentication; + +public class NonBuildableAuthenticationToken extends TestingAuthenticationToken { + + public NonBuildableAuthenticationToken(String user, String password, String... authorities) { + super(user, password, authorities); + } + +} diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilter.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilter.java index 740b77ad6d..6541b5aa7a 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilter.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilter.java @@ -17,6 +17,7 @@ package org.springframework.security.oauth2.server.resource.web.authentication; import java.io.IOException; +import java.lang.reflect.Method; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; @@ -56,7 +57,6 @@ import org.springframework.security.web.context.RequestAttributeSecurityContextR import org.springframework.security.web.context.SecurityContextRepository; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; -import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; import org.springframework.web.filter.OncePerRequestFilter; @@ -214,7 +214,12 @@ public class BearerTokenAuthenticationFilter extends OncePerRequestFilter { } private static boolean declaresToBuilder(Authentication authentication) { - return ReflectionUtils.findMethod(authentication.getClass(), "toBuilder") != null; + for (Method method : authentication.getClass().getDeclaredMethods()) { + if (method.getName().equals("toBuilder") && method.getParameterTypes().length == 0) { + return true; + } + } + return false; } /** diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilterTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilterTests.java index bdfed6bbcd..b4939bb9e8 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilterTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilterTests.java @@ -38,6 +38,7 @@ import org.springframework.security.authentication.AuthenticationDetailsSource; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManagerResolver; import org.springframework.security.authentication.AuthenticationServiceException; +import org.springframework.security.authentication.NonBuildableAuthenticationToken; import org.springframework.security.authentication.SecurityAssertions; import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.core.Authentication; @@ -316,6 +317,24 @@ public class BearerTokenAuthenticationFilterTests { // @formatter:on } + @Test + void doFilterWhenNonBuildableAuthenticationSubclassThenSkipsToBuilder() throws Exception { + TestingAuthenticationToken existingAuthn = new TestingAuthenticationToken("username", "password", "FACTORONE"); + SecurityContextHolder.setContext(new SecurityContextImpl(existingAuthn)); + given(this.authenticationManager.authenticate(any())) + .willReturn(new NonBuildableAuthenticationToken("username", "password", "FACTORTWO")); + given(this.bearerTokenResolver.resolve(any())).willReturn("token"); + BearerTokenAuthenticationFilter filter = addMocks( + new BearerTokenAuthenticationFilter(this.authenticationManager)); + filter.doFilter(this.request, this.response, this.filterChain); + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + // @formatter:off + SecurityAssertions.assertThat(authentication).authorities() + .extracting(GrantedAuthority::getAuthority) + .containsExactly("FACTORTWO"); + // @formatter:on + } + @Test public void setAuthenticationEntryPointWhenNullThenThrowsException() { BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(this.authenticationManager); diff --git a/web/src/main/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.java b/web/src/main/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.java index 19c1dca43a..42e9d0ce5a 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.java +++ b/web/src/main/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.java @@ -17,6 +17,7 @@ package org.springframework.security.web.authentication; import java.io.IOException; +import java.lang.reflect.Method; import java.util.Set; import java.util.stream.Collectors; @@ -252,7 +253,7 @@ public abstract class AbstractAuthenticationProcessingFilter extends GenericFilt return; } Authentication current = this.securityContextHolderStrategy.getContext().getAuthentication(); - if (current != null && current.isAuthenticated()) { + if (current != null && current.isAuthenticated() && declaresToBuilder(authenticationResult)) { authenticationResult = authenticationResult.toBuilder() // @formatter:off .authorities((a) -> { @@ -285,6 +286,15 @@ public abstract class AbstractAuthenticationProcessingFilter extends GenericFilt } } + private static boolean declaresToBuilder(Authentication authentication) { + for (Method method : authentication.getClass().getDeclaredMethods()) { + if (method.getName().equals("toBuilder") && method.getParameterTypes().length == 0) { + return true; + } + } + return false; + } + /** * Indicates whether this filter should attempt to process a login request for the * current invocation. diff --git a/web/src/main/java/org/springframework/security/web/authentication/AuthenticationFilter.java b/web/src/main/java/org/springframework/security/web/authentication/AuthenticationFilter.java index c1d6d08a24..0425405200 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/AuthenticationFilter.java +++ b/web/src/main/java/org/springframework/security/web/authentication/AuthenticationFilter.java @@ -17,6 +17,7 @@ package org.springframework.security.web.authentication; import java.io.IOException; +import java.lang.reflect.Method; import java.util.Set; import java.util.stream.Collectors; @@ -188,7 +189,7 @@ public class AuthenticationFilter extends OncePerRequestFilter { return; } Authentication current = this.securityContextHolderStrategy.getContext().getAuthentication(); - if (current != null && current.isAuthenticated()) { + if (current != null && current.isAuthenticated() && declaresToBuilder(authenticationResult)) { authenticationResult = authenticationResult.toBuilder() // @formatter:off .authorities((a) -> { @@ -215,6 +216,15 @@ public class AuthenticationFilter extends OncePerRequestFilter { } } + private static boolean declaresToBuilder(Authentication authentication) { + for (Method method : authentication.getClass().getDeclaredMethods()) { + if (method.getName().equals("toBuilder") && method.getParameterTypes().length == 0) { + return true; + } + } + return false; + } + @Override protected String getAlreadyFilteredAttributeName() { String name = getFilterName(); diff --git a/web/src/main/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilter.java b/web/src/main/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilter.java index 3d8f8acc3f..7f0322cf6a 100755 --- a/web/src/main/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilter.java +++ b/web/src/main/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilter.java @@ -17,6 +17,7 @@ package org.springframework.security.web.authentication.preauth; import java.io.IOException; +import java.lang.reflect.Method; import java.util.Set; import java.util.stream.Collectors; @@ -208,7 +209,7 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi authenticationRequest.setDetails(this.authenticationDetailsSource.buildDetails(request)); Authentication authenticationResult = this.authenticationManager.authenticate(authenticationRequest); Authentication current = this.securityContextHolderStrategy.getContext().getAuthentication(); - if (current != null && current.isAuthenticated()) { + if (current != null && current.isAuthenticated() && declaresToBuilder(authenticationResult)) { authenticationResult = authenticationResult.toBuilder() // @formatter:off .authorities((a) -> { @@ -234,6 +235,15 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi } } + private static boolean declaresToBuilder(Authentication authentication) { + for (Method method : authentication.getClass().getDeclaredMethods()) { + if (method.getName().equals("toBuilder") && method.getParameterTypes().length == 0) { + return true; + } + } + return false; + } + /** * Puts the Authentication instance returned by the authentication * manager into the secure context. diff --git a/web/src/main/java/org/springframework/security/web/authentication/www/BasicAuthenticationFilter.java b/web/src/main/java/org/springframework/security/web/authentication/www/BasicAuthenticationFilter.java index e2f6435e78..8e679b82ef 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/www/BasicAuthenticationFilter.java +++ b/web/src/main/java/org/springframework/security/web/authentication/www/BasicAuthenticationFilter.java @@ -17,6 +17,7 @@ package org.springframework.security.web.authentication.www; import java.io.IOException; +import java.lang.reflect.Method; import java.nio.charset.Charset; import java.util.Set; import java.util.stream.Collectors; @@ -190,7 +191,7 @@ public class BasicAuthenticationFilter extends OncePerRequestFilter { if (authenticationIsRequired(username)) { Authentication authResult = this.authenticationManager.authenticate(authRequest); Authentication current = this.securityContextHolderStrategy.getContext().getAuthentication(); - if (current != null && current.isAuthenticated()) { + if (current != null && current.isAuthenticated() && declaresToBuilder(authResult)) { authResult = authResult.toBuilder() // @formatter:off .authorities((a) -> { @@ -234,6 +235,15 @@ public class BasicAuthenticationFilter extends OncePerRequestFilter { chain.doFilter(request, response); } + private static boolean declaresToBuilder(Authentication authentication) { + for (Method method : authentication.getClass().getDeclaredMethods()) { + if (method.getName().equals("toBuilder") && method.getParameterTypes().length == 0) { + return true; + } + } + return false; + } + protected boolean authenticationIsRequired(String username) { // Only reauthenticate if username doesn't match SecurityContextHolder and user // isn't authenticated (see SEC-53) diff --git a/web/src/main/java/org/springframework/security/web/server/authentication/AuthenticationWebFilter.java b/web/src/main/java/org/springframework/security/web/server/authentication/AuthenticationWebFilter.java index 47d06ee1ac..528ab64d54 100644 --- a/web/src/main/java/org/springframework/security/web/server/authentication/AuthenticationWebFilter.java +++ b/web/src/main/java/org/springframework/security/web/server/authentication/AuthenticationWebFilter.java @@ -16,6 +16,7 @@ package org.springframework.security.web.server.authentication; +import java.lang.reflect.Method; import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; @@ -141,6 +142,9 @@ public class AuthenticationWebFilter implements WebFilter { if (!current.isAuthenticated()) { return result; } + if (!declaresToBuilder(result)) { + return result; + } return result.toBuilder() // @formatter:off .authorities((a) -> { @@ -158,6 +162,15 @@ public class AuthenticationWebFilter implements WebFilter { }).switchIfEmpty(Mono.just(result)); } + private static boolean declaresToBuilder(Authentication authentication) { + for (Method method : authentication.getClass().getDeclaredMethods()) { + if (method.getName().equals("toBuilder") && method.getParameterTypes().length == 0) { + return true; + } + } + return false; + } + protected Mono onAuthenticationSuccess(Authentication authentication, WebFilterExchange webFilterExchange) { ServerWebExchange exchange = webFilterExchange.getExchange(); SecurityContextImpl securityContext = new SecurityContextImpl(); diff --git a/web/src/test/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilterTests.java b/web/src/test/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilterTests.java index f57f601695..5ecd64ac9d 100644 --- a/web/src/test/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilterTests.java +++ b/web/src/test/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilterTests.java @@ -37,6 +37,8 @@ import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.InternalAuthenticationServiceException; +import org.springframework.security.authentication.NonBuildableAuthenticationToken; +import org.springframework.security.authentication.SecurityAssertions; import org.springframework.security.authentication.TestAuthentication; import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; @@ -480,6 +482,22 @@ public class AbstractAuthenticationProcessingFilterTests { .containsExactly(DefaultEqualsGrantedAuthority.AUTHORITY); } + @Test + void doFilterWhenNotOverridingToBuilderThenDoesNotMergeAuthorities() throws Exception { + TestingAuthenticationToken existingAuthn = new TestingAuthenticationToken("username", "password", "FACTORONE"); + SecurityContextHolder.setContext(new SecurityContextImpl(existingAuthn)); + MockHttpServletRequest request = createMockAuthenticationRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + MockAuthenticationFilter filter = new MockAuthenticationFilter( + new NonBuildableAuthenticationToken("username", "password", "FACTORTWO")); + filter.doFilter(request, response, new MockFilterChain(false)); + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + SecurityAssertions.assertThat(authentication) + .authorities() + .extracting(GrantedAuthority::getAuthority) + .containsExactly("FACTORTWO"); + } + /** * https://github.com/spring-projects/spring-security/pull/3905 */ diff --git a/web/src/test/java/org/springframework/security/web/authentication/AuthenticationFilterTests.java b/web/src/test/java/org/springframework/security/web/authentication/AuthenticationFilterTests.java index 9788ccf2f8..c3dd84c11a 100644 --- a/web/src/test/java/org/springframework/security/web/authentication/AuthenticationFilterTests.java +++ b/web/src/test/java/org/springframework/security/web/authentication/AuthenticationFilterTests.java @@ -37,6 +37,8 @@ import org.springframework.mock.web.MockHttpSession; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManagerResolver; import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.NonBuildableAuthenticationToken; +import org.springframework.security.authentication.SecurityAssertions; import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; @@ -348,6 +350,26 @@ public class AuthenticationFilterTests { .containsExactlyInAnyOrder(DefaultEqualsGrantedAuthority.AUTHORITY); } + @Test + void doFilterWhenNotOverridingToBuilderThenDoesNotMergeAuthorities() throws Exception { + TestingAuthenticationToken existingAuthn = new TestingAuthenticationToken("username", "password", "FACTORONE"); + SecurityContextHolder.setContext(new SecurityContextImpl(existingAuthn)); + given(this.authenticationConverter.convert(any())).willReturn(existingAuthn); + given(this.authenticationManager.authenticate(any())) + .willReturn(new NonBuildableAuthenticationToken("user", "password", "FACTORTWO")); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/"); + MockHttpServletResponse response = new MockHttpServletResponse(); + FilterChain chain = new MockFilterChain(); + AuthenticationFilter filter = new AuthenticationFilter(this.authenticationManager, + this.authenticationConverter); + filter.doFilter(request, response, chain); + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + SecurityAssertions.assertThat(authentication) + .authorities() + .extracting(GrantedAuthority::getAuthority) + .containsExactly("FACTORTWO"); + } + @Test public void filterWhenCustomSecurityContextRepositoryAndSuccessfulAuthenticationRepositoryUsed() throws Exception { SecurityContextRepository securityContextRepository = mock(SecurityContextRepository.class); diff --git a/web/src/test/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilterTests.java b/web/src/test/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilterTests.java index ebf578e4db..834acab5ce 100644 --- a/web/src/test/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilterTests.java +++ b/web/src/test/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilterTests.java @@ -32,6 +32,8 @@ import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.NonBuildableAuthenticationToken; +import org.springframework.security.authentication.SecurityAssertions; import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; @@ -436,6 +438,22 @@ public class AbstractPreAuthenticatedProcessingFilterTests { // @formatter:on } + @Test + void doFilterWhenNotOverridingToBuilderThenDoesNotMergeAuthorities() throws Exception { + TestingAuthenticationToken existingAuthn = new TestingAuthenticationToken("username", "password", "FACTORONE"); + SecurityContextHolder.setContext(new SecurityContextImpl(existingAuthn)); + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + this.filter = createFilterAuthenticatesWith( + new NonBuildableAuthenticationToken("username", "password", "FACTORTWO")); + this.filter.doFilter(request, response, new MockFilterChain()); + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + SecurityAssertions.assertThat(authentication) + .authorities() + .extracting(GrantedAuthority::getAuthority) + .containsExactly("FACTORTWO"); + } + private AbstractPreAuthenticatedProcessingFilter createFilterAuthenticatesWith(Authentication authentication) { ConcretePreAuthenticatedProcessingFilter filter = new ConcretePreAuthenticatedProcessingFilter(); filter.setRequiresAuthenticationRequestMatcher(AnyRequestMatcher.INSTANCE); diff --git a/web/src/test/java/org/springframework/security/web/authentication/www/BasicAuthenticationFilterTests.java b/web/src/test/java/org/springframework/security/web/authentication/www/BasicAuthenticationFilterTests.java index 006e5f7b79..c13422e8a3 100644 --- a/web/src/test/java/org/springframework/security/web/authentication/www/BasicAuthenticationFilterTests.java +++ b/web/src/test/java/org/springframework/security/web/authentication/www/BasicAuthenticationFilterTests.java @@ -36,6 +36,8 @@ import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockHttpSession; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.NonBuildableAuthenticationToken; +import org.springframework.security.authentication.SecurityAssertions; import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; @@ -539,6 +541,25 @@ public class BasicAuthenticationFilterTests { .containsExactly(DefaultEqualsGrantedAuthority.AUTHORITY); } + @Test + void doFilterWhenNotOverridingToBuilderThenDoesNotMergeAuthorities() throws Exception { + TestingAuthenticationToken existingAuthn = new TestingAuthenticationToken("username", "password", "FACTORONE"); + SecurityContextHolder.setContext(new SecurityContextImpl(existingAuthn)); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader(HttpHeaders.AUTHORIZATION, "Basic " + CodecTestUtils.encodeBase64("a:b")); + MockHttpServletResponse response = new MockHttpServletResponse(); + AuthenticationManager manager = mock(AuthenticationManager.class); + given(manager.authenticate(any())) + .willReturn(new NonBuildableAuthenticationToken("username", "password", "FACTORTWO")); + BasicAuthenticationFilter filter = new BasicAuthenticationFilter(manager); + filter.doFilter(request, response, new MockFilterChain()); + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + SecurityAssertions.assertThat(authentication) + .authorities() + .extracting(GrantedAuthority::getAuthority) + .containsExactly("FACTORTWO"); + } + @Test public void doFilterWhenCustomAuthenticationConverterRequestThenAuthenticate() throws Exception { this.filter.setAuthenticationConverter(new TestAuthenticationConverter()); diff --git a/web/src/test/java/org/springframework/security/web/server/authentication/AuthenticationWebFilterTests.java b/web/src/test/java/org/springframework/security/web/server/authentication/AuthenticationWebFilterTests.java index a9c8c35b5a..47d3b04f3c 100644 --- a/web/src/test/java/org/springframework/security/web/server/authentication/AuthenticationWebFilterTests.java +++ b/web/src/test/java/org/springframework/security/web/server/authentication/AuthenticationWebFilterTests.java @@ -25,8 +25,10 @@ import org.mockito.junit.jupiter.MockitoExtension; import reactor.core.publisher.Mono; import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.NonBuildableAuthenticationToken; import org.springframework.security.authentication.ReactiveAuthenticationManager; import org.springframework.security.authentication.ReactiveAuthenticationManagerResolver; +import org.springframework.security.authentication.SecurityAssertions; import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; @@ -230,6 +232,31 @@ public class AuthenticationWebFilterTests { .containsExactly(DefaultEqualsGrantedAuthority.AUTHORITY); } + @Test + void doFilterWhenNotOverridingToBuilderThenDoesNotMergeAuthorities() throws Exception { + TestingAuthenticationToken existingAuthn = new TestingAuthenticationToken("username", "password", "FACTORONE"); + given(this.authenticationManager.authenticate(any())) + .willReturn(Mono.just(new NonBuildableAuthenticationToken("user", "password", "FACTORTWO"))); + given(this.securityContextRepository.save(any(), any())).willReturn(Mono.empty()); + this.filter = new AuthenticationWebFilter(this.authenticationManager); + this.filter.setSecurityContextRepository(this.securityContextRepository); + WebTestClient client = WebTestClientBuilder.bindToWebFilters(new RunAsWebFilter(existingAuthn), this.filter) + .build(); + client.get() + .uri("/") + .headers((headers) -> headers.setBasicAuth("test", "this")) + .exchange() + .expectStatus() + .isOk(); + ArgumentCaptor context = ArgumentCaptor.forClass(SecurityContext.class); + verify(this.securityContextRepository).save(any(), context.capture()); + Authentication authentication = context.getValue().getAuthentication(); + SecurityAssertions.assertThat(authentication) + .authorities() + .extracting(GrantedAuthority::getAuthority) + .containsExactly("FACTORTWO"); + } + @Test public void filterWhenAuthenticationManagerResolverDefaultsAndAuthenticationFailThenUnauthorized() { given(this.authenticationManager.authenticate(any()))