Browse Source

Add Builder#authentication

This commit consolidates logic common to applying one
authenticaiton to another. Specifically, it will copy the
authorities in one authentication into the builder instance
of another.

Closes gh-18053
pull/18050/head
Josh Cummings 2 months ago
parent
commit
4102007119
  1. 29
      core/src/main/java/org/springframework/security/core/BuildableAuthentication.java
  2. 10
      core/src/test/java/org/springframework/security/authentication/AbstractAuthenticationBuilderTests.java
  3. 4
      oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilter.java
  4. 18
      web/src/main/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.java
  5. 18
      web/src/main/java/org/springframework/security/web/authentication/AuthenticationFilter.java
  6. 18
      web/src/main/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilter.java
  7. 18
      web/src/main/java/org/springframework/security/web/authentication/www/BasicAuthenticationFilter.java
  8. 18
      web/src/main/java/org/springframework/security/web/server/authentication/AuthenticationWebFilter.java

29
core/src/main/java/org/springframework/security/core/BuildableAuthentication.java

@ -17,7 +17,6 @@ @@ -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 { @@ -84,6 +83,30 @@ public interface BuildableAuthentication extends Authentication {
*/
interface Builder<B extends Builder<B>> {
/**
* Apply this authentication instance
* <p>
* 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.
* </p>
* @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<String> 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}.
* <p>
@ -145,8 +168,8 @@ public interface BuildableAuthentication extends Authentication { @@ -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
*/

10
core/src/test/java/org/springframework/security/authentication/AbstractAuthenticationBuilderTests.java

@ -37,6 +37,16 @@ class AbstractAuthenticationBuilderTests { @@ -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<String> authorities = AuthorityUtils.authorityListToSet(result.getAuthorities());
assertThat(authorities).containsExactlyInAnyOrder("FACTOR_ONE", "FACTOR_TWO");
}
private static final class TestAbstractAuthenticationBuilder
extends TestingAuthenticationToken.Builder<TestAbstractAuthenticationBuilder> {

4
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 { @@ -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();

18
web/src/main/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.java

@ -17,8 +17,6 @@ @@ -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 @@ -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 @@ -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<String> 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);

18
web/src/main/java/org/springframework/security/web/authentication/AuthenticationFilter.java

@ -17,8 +17,6 @@ @@ -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 @@ -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 { @@ -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<String> 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);

18
web/src/main/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilter.java

@ -17,8 +17,6 @@ @@ -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 @@ -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 @@ -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<String> 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);

18
web/src/main/java/org/springframework/security/web/authentication/www/BasicAuthenticationFilter.java

@ -18,8 +18,6 @@ package org.springframework.security.web.authentication.www; @@ -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; @@ -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 { @@ -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<String> 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();

18
web/src/main/java/org/springframework/security/web/server/authentication/AuthenticationWebFilter.java

@ -16,9 +16,7 @@ @@ -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 @@ -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 { @@ -145,20 +142,7 @@ public class AuthenticationWebFilter implements WebFilter {
if (!(result instanceof BuildableAuthentication buildable)) {
return result;
}
return buildable.toBuilder()
// @formatter:off
.authorities((a) -> {
Set<String> 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));
}

Loading…
Cancel
Save