diff --git a/config/src/main/java/org/springframework/security/config/annotation/authentication/builders/AuthenticationManagerBuilder.java b/config/src/main/java/org/springframework/security/config/annotation/authentication/builders/AuthenticationManagerBuilder.java index 961cf67c56..64f5fd489b 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/authentication/builders/AuthenticationManagerBuilder.java +++ b/config/src/main/java/org/springframework/security/config/annotation/authentication/builders/AuthenticationManagerBuilder.java @@ -18,14 +18,10 @@ package org.springframework.security.config.annotation.authentication.builders; import java.util.ArrayList; import java.util.List; -import java.util.stream.Stream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.jspecify.annotations.Nullable; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.ObjectProvider; import org.springframework.security.authentication.AuthenticationEventPublisher; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationProvider; @@ -41,8 +37,6 @@ import org.springframework.security.config.annotation.authentication.configurers import org.springframework.security.config.annotation.authentication.configurers.userdetails.DaoAuthenticationConfigurer; import org.springframework.security.config.annotation.authentication.configurers.userdetails.UserDetailsAwareConfigurer; import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.context.SecurityContextHolderStrategy; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.util.Assert; @@ -241,10 +235,6 @@ public class AuthenticationManagerBuilder if (this.eventPublisher != null) { providerManager.setAuthenticationEventPublisher(this.eventPublisher); } - SecurityContextHolderStrategy securityContextHolderStrategy = getBeanProvider( - SecurityContextHolderStrategy.class) - .getIfUnique(SecurityContextHolder::getContextHolderStrategy); - providerManager.setSecurityContextHolderStrategy(securityContextHolderStrategy); providerManager = postProcess(providerManager); return providerManager; } @@ -293,24 +283,4 @@ public class AuthenticationManagerBuilder return configurer; } - private ObjectProvider getBeanProvider(Class clazz) { - BeanFactory beanFactory = getSharedObject(BeanFactory.class); - return (beanFactory != null) ? beanFactory.getBeanProvider(clazz) : new SingleObjectProvider<>(null); - } - - private static final class SingleObjectProvider implements ObjectProvider { - - private final @Nullable O object; - - private SingleObjectProvider(@Nullable O object) { - this.object = object; - } - - @Override - public Stream stream() { - return Stream.ofNullable(this.object); - } - - } - } diff --git a/config/src/main/java/org/springframework/security/config/annotation/authentication/configuration/AuthenticationConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/authentication/configuration/AuthenticationConfiguration.java index 72f9e8ac88..77b5f38986 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/authentication/configuration/AuthenticationConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/authentication/configuration/AuthenticationConfiguration.java @@ -27,7 +27,6 @@ import org.apache.commons.logging.LogFactory; import org.springframework.aop.framework.ProxyFactoryBean; import org.springframework.aop.target.LazyInitTargetSource; -import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; @@ -84,7 +83,6 @@ public class AuthenticationConfiguration { AuthenticationEventPublisher authenticationEventPublisher = getAuthenticationEventPublisher(context); DefaultPasswordEncoderAuthenticationManagerBuilder result = new DefaultPasswordEncoderAuthenticationManagerBuilder( objectPostProcessor, defaultPasswordEncoder); - result.setSharedObject(BeanFactory.class, this.applicationContext); if (authenticationEventPublisher != null) { result.authenticationEventPublisher(authenticationEventPublisher); } diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.java index fe1c4028d0..7b0fc0a13c 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.java @@ -318,7 +318,6 @@ public class GlobalMethodSecurityConfiguration implements ImportAware, SmartInit .postProcess(new DefaultAuthenticationEventPublisher()); this.auth = new AuthenticationManagerBuilder(this.objectPostProcessor); this.auth.authenticationEventPublisher(eventPublisher); - this.auth.setSharedObject(BeanFactory.class, this.context); configure(this.auth); this.authenticationManager = (this.disableAuthenticationRegistry) ? getAuthenticationConfiguration().getAuthenticationManager() : this.auth.build(); diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configuration/HttpSecurityConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/web/configuration/HttpSecurityConfiguration.java index 791b45566c..ad641ea656 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configuration/HttpSecurityConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configuration/HttpSecurityConfiguration.java @@ -21,7 +21,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; @@ -117,7 +116,6 @@ class HttpSecurityConfiguration { LazyPasswordEncoder passwordEncoder = new LazyPasswordEncoder(this.context); AuthenticationManagerBuilder authenticationBuilder = new DefaultPasswordEncoderAuthenticationManagerBuilder( this.objectPostProcessor, passwordEncoder); - authenticationBuilder.setSharedObject(BeanFactory.class, this.context); authenticationBuilder.parentAuthenticationManager(authenticationManager()); authenticationBuilder.authenticationEventPublisher(getAuthenticationEventPublisher()); HttpSecurity http = new HttpSecurity(this.objectPostProcessor, authenticationBuilder, createSharedObjects()); diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/WebAuthnConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/WebAuthnConfigurer.java index c23fbc230c..7ec3279efb 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/WebAuthnConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/WebAuthnConfigurer.java @@ -162,10 +162,8 @@ public class WebAuthnConfigurer> WebAuthnRelyingPartyOperations rpOperations = webAuthnRelyingPartyOperations(userEntities, userCredentials); PublicKeyCredentialCreationOptionsRepository creationOptionsRepository = creationOptionsRepository(); WebAuthnAuthenticationFilter webAuthnAuthnFilter = new WebAuthnAuthenticationFilter(); - ProviderManager manager = new ProviderManager( - new WebAuthnAuthenticationProvider(rpOperations, userDetailsService)); - manager.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy()); - webAuthnAuthnFilter.setAuthenticationManager(manager); + webAuthnAuthnFilter.setAuthenticationManager( + new ProviderManager(new WebAuthnAuthenticationProvider(rpOperations, userDetailsService))); WebAuthnRegistrationFilter webAuthnRegistrationFilter = new WebAuthnRegistrationFilter(userCredentials, rpOperations); PublicKeyCredentialCreationOptionsFilter creationOptionsFilter = new PublicKeyCredentialCreationOptionsFilter( diff --git a/config/src/main/java/org/springframework/security/config/authentication/AuthenticationManagerFactoryBean.java b/config/src/main/java/org/springframework/security/config/authentication/AuthenticationManagerFactoryBean.java index 14e3b5f53b..afa0b11bea 100644 --- a/config/src/main/java/org/springframework/security/config/authentication/AuthenticationManagerFactoryBean.java +++ b/config/src/main/java/org/springframework/security/config/authentication/AuthenticationManagerFactoryBean.java @@ -30,8 +30,6 @@ import org.springframework.security.authentication.ObservationAuthenticationMana import org.springframework.security.authentication.ProviderManager; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.config.BeanIds; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.context.SecurityContextHolderStrategy; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.password.PasswordEncoder; @@ -74,10 +72,6 @@ public class AuthenticationManagerFactoryBean implements FactoryBean authorities; diff --git a/core/src/main/java/org/springframework/security/authentication/DelegatingReactiveAuthenticationManager.java b/core/src/main/java/org/springframework/security/authentication/DelegatingReactiveAuthenticationManager.java index 1a40d210e0..c30fcbae3e 100644 --- a/core/src/main/java/org/springframework/security/authentication/DelegatingReactiveAuthenticationManager.java +++ b/core/src/main/java/org/springframework/security/authentication/DelegatingReactiveAuthenticationManager.java @@ -27,7 +27,6 @@ import reactor.core.publisher.Mono; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; -import org.springframework.security.core.context.ReactiveSecurityContextHolder; import org.springframework.util.Assert; /** @@ -58,20 +57,6 @@ public class DelegatingReactiveAuthenticationManager implements ReactiveAuthenti @Override public Mono authenticate(Authentication authentication) { - return ReactiveSecurityContextHolder.getContext().flatMap((context) -> { - Mono result = doAuthenticate(authentication); - Authentication current = context.getAuthentication(); - if (current == null) { - return result; - } - if (!current.isAuthenticated()) { - return result; - } - return doAuthenticate(current).map((r) -> r.toBuilder().apply(current).build()); - }).switchIfEmpty(doAuthenticate(authentication)); - } - - private Mono doAuthenticate(Authentication authentication) { Flux result = Flux.fromIterable(this.delegates); Function> logging = (m) -> m.authenticate(authentication) .doOnError(AuthenticationException.class, (ex) -> ex.setAuthenticationRequest(authentication)) diff --git a/core/src/main/java/org/springframework/security/authentication/ProviderManager.java b/core/src/main/java/org/springframework/security/authentication/ProviderManager.java index 417d144849..7167943a33 100644 --- a/core/src/main/java/org/springframework/security/authentication/ProviderManager.java +++ b/core/src/main/java/org/springframework/security/authentication/ProviderManager.java @@ -33,8 +33,6 @@ import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.CredentialsContainer; import org.springframework.security.core.SpringSecurityMessageSource; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.context.SecurityContextHolderStrategy; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; @@ -94,9 +92,6 @@ public class ProviderManager implements AuthenticationManager, MessageSourceAwar private static final Log logger = LogFactory.getLog(ProviderManager.class); - private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder - .getContextHolderStrategy(); - private AuthenticationEventPublisher eventPublisher = new NullEventPublisher(); private List providers = Collections.emptyList(); @@ -187,7 +182,7 @@ public class ProviderManager implements AuthenticationManager, MessageSourceAwar try { result = provider.authenticate(authentication); if (result != null) { - copyDetails(authentication, result); + result = copyDetails(authentication, result); break; } } @@ -214,7 +209,6 @@ public class ProviderManager implements AuthenticationManager, MessageSourceAwar lastException = ex; } } - result = applyPreviousAuthentication(result); if (result == null && this.parent != null) { // Allow the parent to try. try { @@ -271,20 +265,6 @@ public class ProviderManager implements AuthenticationManager, MessageSourceAwar throw lastException; } - private @Nullable Authentication applyPreviousAuthentication(@Nullable Authentication result) { - if (result == null) { - return null; - } - Authentication current = this.securityContextHolderStrategy.getContext().getAuthentication(); - if (current == null) { - return result; - } - if (!current.isAuthenticated()) { - return result; - } - return result.toBuilder().apply(current).build(); - } - @SuppressWarnings("deprecation") private void prepareException(AuthenticationException ex, Authentication auth) { ex.setAuthenticationRequest(auth); @@ -297,21 +277,20 @@ public class ProviderManager implements AuthenticationManager, MessageSourceAwar * @param source source authentication * @param dest the destination authentication object */ - private void copyDetails(Authentication source, Authentication dest) { - if ((dest instanceof AbstractAuthenticationToken token) && (dest.getDetails() == null)) { - token.setDetails(source.getDetails()); + private Authentication copyDetails(Authentication source, Authentication dest) { + if (source.getDetails() == null) { + return dest; } + if (dest.getDetails() != null) { + return dest; + } + return dest.toBuilder().details(source.getDetails()).build(); } public List getProviders() { return this.providers; } - public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) { - Assert.notNull(securityContextHolderStrategy, "securityContextHolderStrategy cannot be null"); - this.securityContextHolderStrategy = securityContextHolderStrategy; - } - @Override public void setMessageSource(MessageSource messageSource) { this.messages = new MessageSourceAccessor(messageSource); diff --git a/core/src/test/java/org/springframework/security/authentication/DelegatingReactiveAuthenticationManagerTests.java b/core/src/test/java/org/springframework/security/authentication/DelegatingReactiveAuthenticationManagerTests.java index 6c430bdf03..d44278a60f 100644 --- a/core/src/test/java/org/springframework/security/authentication/DelegatingReactiveAuthenticationManagerTests.java +++ b/core/src/test/java/org/springframework/security/authentication/DelegatingReactiveAuthenticationManagerTests.java @@ -27,13 +27,10 @@ import reactor.test.StepVerifier; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.context.ReactiveSecurityContextHolder; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; /** * @author Rob Winch @@ -121,24 +118,6 @@ public class DelegatingReactiveAuthenticationManagerTests { assertThat(expected.getAuthenticationRequest()).isEqualTo(this.authentication); } - @Test - void authenticateWhenPreviousAuthenticationThenApplies() { - Authentication factorOne = new TestingAuthenticationToken("user", "pass", "FACTOR_ONE"); - Authentication factorTwo = new TestingAuthenticationToken("user", "pass", "FACTOR_TWO"); - ReactiveAuthenticationManager provider = mock(ReactiveAuthenticationManager.class); - given(provider.authenticate(any())).willReturn(Mono.just(factorTwo)); - ReactiveAuthenticationManager manager = new DelegatingReactiveAuthenticationManager(provider); - Authentication request = new TestingAuthenticationToken("user", "password"); - StepVerifier - .create(manager.authenticate(request) - .flatMapIterable(Authentication::getAuthorities) - .map(GrantedAuthority::getAuthority) - .contextWrite(ReactiveSecurityContextHolder.withAuthentication(factorOne))) - .expectNext("FACTOR_TWO") - .expectNext("FACTOR_ONE") - .verifyComplete(); - } - private DelegatingReactiveAuthenticationManager managerWithContinueOnError() { DelegatingReactiveAuthenticationManager manager = new DelegatingReactiveAuthenticationManager(this.delegate1, this.delegate2); diff --git a/core/src/test/java/org/springframework/security/authentication/ProviderManagerTests.java b/core/src/test/java/org/springframework/security/authentication/ProviderManagerTests.java index e1c69c5fe7..69fff2567c 100644 --- a/core/src/test/java/org/springframework/security/authentication/ProviderManagerTests.java +++ b/core/src/test/java/org/springframework/security/authentication/ProviderManagerTests.java @@ -18,17 +18,15 @@ package org.springframework.security.authentication; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.List; -import java.util.Set; import org.junit.jupiter.api.Test; import org.springframework.context.MessageSource; 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.SecurityContextHolderStrategy; -import org.springframework.security.core.context.SecurityContextImpl; +import org.springframework.security.core.GrantedAuthority; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -51,7 +49,7 @@ public class ProviderManagerTests { @Test void authenticationFailsWithUnsupportedToken() { - Authentication token = new AbstractAuthenticationToken(null) { + Authentication token = new AbstractAuthenticationToken((Collection) null) { @Override public Object getCredentials() { return ""; @@ -82,24 +80,24 @@ public class ProviderManagerTests { @Test void authenticationSucceedsWithSupportedTokenAndReturnsExpectedObject() { - Authentication a = mock(Authentication.class); + Authentication a = new TestingAuthenticationToken("user", "pass", "FACTOR"); ProviderManager mgr = new ProviderManager(createProviderWhichReturns(a)); AuthenticationEventPublisher publisher = mock(AuthenticationEventPublisher.class); mgr.setAuthenticationEventPublisher(publisher); Authentication result = mgr.authenticate(a); - assertThat(result).isEqualTo(a); + assertThat(result.getPrincipal()).isEqualTo(a.getPrincipal()); verify(publisher).publishAuthenticationSuccess(result); } @Test void authenticationSucceedsWhenFirstProviderReturnsNullButSecondAuthenticates() { - Authentication a = mock(Authentication.class); + Authentication a = new TestingAuthenticationToken("user", "pass", "FACTOR"); ProviderManager mgr = new ProviderManager( Arrays.asList(createProviderWhichReturns(null), createProviderWhichReturns(a))); AuthenticationEventPublisher publisher = mock(AuthenticationEventPublisher.class); mgr.setAuthenticationEventPublisher(publisher); Authentication result = mgr.authenticate(a); - assertThat(result).isSameAs(a); + assertThat(result.getPrincipal()).isEqualTo(a.getPrincipal()); verify(publisher).publishAuthenticationSuccess(result); } @@ -166,11 +164,12 @@ public class ProviderManagerTests { @Test void authenticationExceptionIsIgnoredIfLaterProviderAuthenticates() { - Authentication authReq = mock(Authentication.class); + Authentication result = new TestingAuthenticationToken("user", "pass", "FACTOR"); ProviderManager mgr = new ProviderManager( createProviderWhichThrows(new BadCredentialsException("", new Throwable())), - createProviderWhichReturns(authReq)); - assertThat(mgr.authenticate(mock(Authentication.class))).isSameAs(authReq); + createProviderWhichReturns(result)); + Authentication request = new TestingAuthenticationToken("user", "pass"); + assertThat(mgr.authenticate(request).getPrincipal()).isEqualTo(result.getPrincipal()); } @Test @@ -314,22 +313,6 @@ public class ProviderManagerTests { verifyNoMoreInteractions(publisher); // Child should not publish (duplicate event) } - @Test - void authenticateWhenPreviousAuthenticationThenApplies() { - Authentication factorOne = new TestingAuthenticationToken("user", "pass", "FACTOR_ONE"); - Authentication factorTwo = new TestingAuthenticationToken("user", "pass", "FACTOR_TWO"); - SecurityContextHolderStrategy securityContextHolderStrategy = mock(SecurityContextHolderStrategy.class); - given(securityContextHolderStrategy.getContext()).willReturn(new SecurityContextImpl(factorOne)); - AuthenticationProvider provider = mock(AuthenticationProvider.class); - given(provider.authenticate(any())).willReturn(factorTwo); - given(provider.supports(any())).willReturn(true); - ProviderManager manager = new ProviderManager(provider); - manager.setSecurityContextHolderStrategy(securityContextHolderStrategy); - Authentication request = new TestingAuthenticationToken("user", "password"); - Set authorities = AuthorityUtils.authorityListToSet(manager.authenticate(request).getAuthorities()); - assertThat(authorities).containsExactlyInAnyOrder("FACTOR_ONE", "FACTOR_TWO"); - } - private AuthenticationProvider createProviderWhichThrows(final AuthenticationException ex) { AuthenticationProvider provider = mock(AuthenticationProvider.class); given(provider.supports(any(Class.class))).willReturn(true); 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 a817d7013e..6bbbb3f766 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 @@ -248,6 +248,12 @@ public abstract class AbstractAuthenticationProcessingFilter extends GenericFilt // return immediately as subclass has indicated that it hasn't completed return; } + Authentication current = this.securityContextHolderStrategy.getContext().getAuthentication(); + if (current != null && current.isAuthenticated()) { + authenticationResult = authenticationResult.toBuilder() + .authorities((a) -> a.addAll(current.getAuthorities())) + .build(); + } this.sessionStrategy.onAuthentication(authenticationResult, request, response); // Authentication success if (this.continueChainBeforeSuccessfulAuthentication) { 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 5366ebd84b..8295a962bc 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 @@ -184,6 +184,12 @@ public class AuthenticationFilter extends OncePerRequestFilter { filterChain.doFilter(request, response); return; } + Authentication current = this.securityContextHolderStrategy.getContext().getAuthentication(); + if (current != null && current.isAuthenticated()) { + authenticationResult = authenticationResult.toBuilder() + .authorities((a) -> a.addAll(current.getAuthorities())) + .build(); + } HttpSession session = request.getSession(false); if (session != null) { request.changeSessionId(); 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 8189cc2b1f..b0910c85ed 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 @@ -204,6 +204,12 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi principal, credentials); authenticationRequest.setDetails(this.authenticationDetailsSource.buildDetails(request)); Authentication authenticationResult = this.authenticationManager.authenticate(authenticationRequest); + Authentication current = this.securityContextHolderStrategy.getContext().getAuthentication(); + if (current != null && current.isAuthenticated()) { + authenticationResult = authenticationResult.toBuilder() + .authorities((a) -> a.addAll(current.getAuthorities())) + .build(); + } successfulAuthentication(request, response, authenticationResult); } catch (AuthenticationException ex) { 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 98fdd58da1..91f40b01b7 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 @@ -186,6 +186,10 @@ public class BasicAuthenticationFilter extends OncePerRequestFilter { this.logger.trace(LogMessage.format("Found username '%s' in Basic Authorization header", username)); if (authenticationIsRequired(username)) { Authentication authResult = this.authenticationManager.authenticate(authRequest); + Authentication current = this.securityContextHolderStrategy.getContext().getAuthentication(); + if (current != null && current.isAuthenticated()) { + authResult = authResult.toBuilder().authorities((a) -> a.addAll(current.getAuthorities())).build(); + } SecurityContext context = this.securityContextHolderStrategy.createEmptyContext(); context.setAuthentication(authResult); this.securityContextHolderStrategy.setContext(context); 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 3bbbdb108c..2f83629181 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 @@ -122,12 +122,26 @@ public class AuthenticationWebFilter implements WebFilter { .flatMap((authenticationManager) -> authenticationManager.authenticate(token)) .switchIfEmpty(Mono .defer(() -> Mono.error(new IllegalStateException("No provider found for " + token.getClass())))) + .flatMap(this::applyCurrentAuthenication) .flatMap( (authentication) -> onAuthenticationSuccess(authentication, new WebFilterExchange(exchange, chain))) .doOnError(AuthenticationException.class, (ex) -> logger.debug(LogMessage.format("Authentication failed: %s", ex.getMessage()), ex)); } + private Mono applyCurrentAuthenication(Authentication result) { + return ReactiveSecurityContextHolder.getContext().map((context) -> { + Authentication current = context.getAuthentication(); + if (current == null) { + return result; + } + if (!current.isAuthenticated()) { + return result; + } + return result.toBuilder().authorities((a) -> a.addAll(current.getAuthorities())).build(); + }).switchIfEmpty(Mono.just(result)); + } + 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/AuthenticationFilterTests.java b/web/src/test/java/org/springframework/security/web/authentication/AuthenticationFilterTests.java index 3851311bee..aaf17d62c9 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 @@ -144,6 +144,7 @@ public class AuthenticationFilterTests { this.authenticationConverter); SecurityContextHolderStrategy strategy = mock(SecurityContextHolderStrategy.class); given(strategy.createEmptyContext()).willReturn(new SecurityContextImpl()); + given(strategy.getContext()).willReturn(new SecurityContextImpl()); filter.setSecurityContextHolderStrategy(strategy); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/"); MockHttpServletResponse response = new MockHttpServletResponse();