diff --git a/core/src/main/java/org/springframework/security/core/BuildableAuthentication.java b/core/src/main/java/org/springframework/security/core/BuildableAuthentication.java
index b4ce0d3c34..577c6a9456 100644
--- a/core/src/main/java/org/springframework/security/core/BuildableAuthentication.java
+++ b/core/src/main/java/org/springframework/security/core/BuildableAuthentication.java
@@ -17,7 +17,6 @@
package org.springframework.security.core;
import java.util.Collection;
-import java.util.HashSet;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@@ -84,6 +83,30 @@ public interface BuildableAuthentication extends Authentication {
*/
interface Builder> {
+ /**
+ * Apply this authentication instance
+ *
+ * By default, merges the authorities in the provided {@code authentication} with
+ * the authentication being built. Only those authorities that haven't already
+ * been specified to the builder will be added.
+ *
+ * @param authentication the {@link Authentication} to appluy
+ * @return the {@link Builder} for additional configuration
+ * @see BuildableAuthentication#getAuthorities
+ */
+ default B authentication(Authentication authentication) {
+ return authorities((a) -> {
+ Set newAuthorities = a.stream()
+ .map(GrantedAuthority::getAuthority)
+ .collect(Collectors.toUnmodifiableSet());
+ for (GrantedAuthority currentAuthority : authentication.getAuthorities()) {
+ if (!newAuthorities.contains(currentAuthority.getAuthority())) {
+ a.add(currentAuthority);
+ }
+ }
+ });
+ }
+
/**
* Mutate the authorities with this {@link Consumer}.
*
@@ -145,8 +168,8 @@ public interface BuildableAuthentication extends Authentication {
/**
* Mark this authentication as authenticated or not
- * @param authenticated whether this is an authenticated
- * {@link Authentication} instance
+ * @param authenticated whether this is an authenticated {@link Authentication}
+ * instance
* @return the {@link Builder} for additional configuration
* @see Authentication#isAuthenticated
*/
diff --git a/core/src/test/java/org/springframework/security/authentication/AbstractAuthenticationBuilderTests.java b/core/src/test/java/org/springframework/security/authentication/AbstractAuthenticationBuilderTests.java
index 6bd66b7166..15b61d6f46 100644
--- a/core/src/test/java/org/springframework/security/authentication/AbstractAuthenticationBuilderTests.java
+++ b/core/src/test/java/org/springframework/security/authentication/AbstractAuthenticationBuilderTests.java
@@ -37,6 +37,16 @@ class AbstractAuthenticationBuilderTests {
assertThat(authorities).containsExactlyInAnyOrder("FACTOR_ONE", "FACTOR_TWO");
}
+ @Test
+ void authenticationWhenAuthoritiesThenAdds() {
+ TestingAuthenticationToken factorOne = new TestingAuthenticationToken("user", "pass", "FACTOR_ONE");
+ TestingAuthenticationToken factorTwo = new TestingAuthenticationToken("user", "pass", "FACTOR_TWO");
+ TestAbstractAuthenticationBuilder builder = new TestAbstractAuthenticationBuilder(factorOne);
+ Authentication result = builder.authentication(factorTwo).build();
+ Set authorities = AuthorityUtils.authorityListToSet(result.getAuthorities());
+ assertThat(authorities).containsExactlyInAnyOrder("FACTOR_ONE", "FACTOR_TWO");
+ }
+
private static final class TestAbstractAuthenticationBuilder
extends TestingAuthenticationToken.Builder {
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 88366dca7f..1bc65bbd37 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
@@ -184,9 +184,7 @@ public class BearerTokenAuthenticationFilter extends OncePerRequestFilter {
Authentication current = this.securityContextHolderStrategy.getContext().getAuthentication();
if (current != null && current.isAuthenticated()) {
if (authenticationResult instanceof BuildableAuthentication buildable) {
- authenticationResult = buildable.toBuilder()
- .authorities((a) -> a.addAll(current.getAuthorities()))
- .build();
+ authenticationResult = buildable.toBuilder().authentication(current).build();
}
}
SecurityContext context = this.securityContextHolderStrategy.createEmptyContext();
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 6f90f475cc..a7113235df 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,8 +17,6 @@
package org.springframework.security.web.authentication;
import java.io.IOException;
-import java.util.Set;
-import java.util.stream.Collectors;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
@@ -42,7 +40,6 @@ import org.springframework.security.authentication.event.InteractiveAuthenticati
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.BuildableAuthentication;
-import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityMessageSource;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
@@ -255,20 +252,7 @@ public abstract class AbstractAuthenticationProcessingFilter extends GenericFilt
Authentication current = this.securityContextHolderStrategy.getContext().getAuthentication();
if (current != null && current.isAuthenticated()) {
if (authenticationResult instanceof BuildableAuthentication buildable) {
- authenticationResult = buildable.toBuilder()
- // @formatter:off
- .authorities((a) -> {
- Set newAuthorities = a.stream()
- .map(GrantedAuthority::getAuthority)
- .collect(Collectors.toUnmodifiableSet());
- for (GrantedAuthority currentAuthority : current.getAuthorities()) {
- if (!newAuthorities.contains(currentAuthority.getAuthority())) {
- a.add(currentAuthority);
- }
- }
- })
- .build();
- // @formatter:on
+ authenticationResult = buildable.toBuilder().authentication(current).build();
}
}
this.sessionStrategy.onAuthentication(authenticationResult, request, response);
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 40ef7f4951..17c32292f7 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,8 +17,6 @@
package org.springframework.security.web.authentication;
import java.io.IOException;
-import java.util.Set;
-import java.util.stream.Collectors;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
@@ -34,7 +32,6 @@ import org.springframework.security.authentication.AuthenticationManagerResolver
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.BuildableAuthentication;
-import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
@@ -191,20 +188,7 @@ public class AuthenticationFilter extends OncePerRequestFilter {
Authentication current = this.securityContextHolderStrategy.getContext().getAuthentication();
if (current != null && current.isAuthenticated()) {
if (authenticationResult instanceof BuildableAuthentication buildable) {
- authenticationResult = buildable.toBuilder()
- // @formatter:off
- .authorities((a) -> {
- Set newAuthorities = a.stream()
- .map(GrantedAuthority::getAuthority)
- .collect(Collectors.toUnmodifiableSet());
- for (GrantedAuthority currentAuthority : current.getAuthorities()) {
- if (!newAuthorities.contains(currentAuthority.getAuthority())) {
- a.add(currentAuthority);
- }
- }
- })
- .build();
- // @formatter:on
+ authenticationResult = buildable.toBuilder().authentication(current).build();
}
}
HttpSession session = request.getSession(false);
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 dab00ce0f1..9da11bbaf4 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,8 +17,6 @@
package org.springframework.security.web.authentication.preauth;
import java.io.IOException;
-import java.util.Set;
-import java.util.stream.Collectors;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
@@ -38,7 +36,6 @@ import org.springframework.security.authentication.event.InteractiveAuthenticati
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.BuildableAuthentication;
-import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
@@ -211,20 +208,7 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi
Authentication current = this.securityContextHolderStrategy.getContext().getAuthentication();
if (current != null && current.isAuthenticated()) {
if (authenticationResult instanceof BuildableAuthentication buildable) {
- authenticationResult = buildable.toBuilder()
- // @formatter:off
- .authorities((a) -> {
- Set newAuthorities = a.stream()
- .map(GrantedAuthority::getAuthority)
- .collect(Collectors.toUnmodifiableSet());
- for (GrantedAuthority currentAuthority : current.getAuthorities()) {
- if (!newAuthorities.contains(currentAuthority.getAuthority())) {
- a.add(currentAuthority);
- }
- }
- })
- .build();
- // @formatter:on
+ authenticationResult = buildable.toBuilder().authentication(current).build();
}
}
successfulAuthentication(request, response, authenticationResult);
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 92b96e8274..db542b2196 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
@@ -18,8 +18,6 @@ package org.springframework.security.web.authentication.www;
import java.io.IOException;
import java.nio.charset.Charset;
-import java.util.Set;
-import java.util.stream.Collectors;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
@@ -34,7 +32,6 @@ import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.BuildableAuthentication;
-import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
@@ -193,20 +190,7 @@ public class BasicAuthenticationFilter extends OncePerRequestFilter {
Authentication current = this.securityContextHolderStrategy.getContext().getAuthentication();
if (current != null && current.isAuthenticated()) {
if (authResult instanceof BuildableAuthentication buildable) {
- authResult = buildable.toBuilder()
- // @formatter:off
- .authorities((a) -> {
- Set newAuthorities = a.stream()
- .map(GrantedAuthority::getAuthority)
- .collect(Collectors.toUnmodifiableSet());
- for (GrantedAuthority currentAuthority : current.getAuthorities()) {
- if (!newAuthorities.contains(currentAuthority.getAuthority())) {
- a.add(currentAuthority);
- }
- }
- })
- .build();
- // @formatter:on
+ authResult = buildable.toBuilder().authentication(current).build();
}
}
SecurityContext context = this.securityContextHolderStrategy.createEmptyContext();
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 207783223a..fa89400309 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,9 +16,7 @@
package org.springframework.security.web.server.authentication;
-import java.util.Set;
import java.util.function.Function;
-import java.util.stream.Collectors;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -30,7 +28,6 @@ import org.springframework.security.authentication.ReactiveAuthenticationManager
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.BuildableAuthentication;
-import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.web.server.WebFilterExchange;
@@ -145,20 +142,7 @@ public class AuthenticationWebFilter implements WebFilter {
if (!(result instanceof BuildableAuthentication buildable)) {
return result;
}
- return buildable.toBuilder()
- // @formatter:off
- .authorities((a) -> {
- Set newAuthorities = a.stream()
- .map(GrantedAuthority::getAuthority)
- .collect(Collectors.toUnmodifiableSet());
- for (GrantedAuthority currentAuthority : current.getAuthorities()) {
- if (!newAuthorities.contains(currentAuthority.getAuthority())) {
- a.add(currentAuthority);
- }
- }
- })
- .build();
- // @formatter:on
+ return buildable.toBuilder().authentication(current).build();
}).switchIfEmpty(Mono.just(result));
}