mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-10-20 17:28:49 +00:00
Move Builder to Authentication
Leaving the Builder in Authentication allows authentication implementations to implement Builder without needing to implement BuildableAuthentication. Issue gh-18052
This commit is contained in:
parent
4102007119
commit
21ff7688cc
@ -28,7 +28,6 @@ import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.security.core.AuthenticatedPrincipal;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.BuildableAuthentication;
|
||||
import org.springframework.security.core.CredentialsContainer;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
@ -199,15 +198,15 @@ public abstract class AbstractAuthenticationToken implements Authentication, Cre
|
||||
}
|
||||
|
||||
/**
|
||||
* A common abstract implementation of {@link BuildableAuthentication.Builder}. It
|
||||
* implements the builder methods that correspond to the {@link Authentication}
|
||||
* methods that {@link AbstractAuthenticationToken} implements
|
||||
* A common abstract implementation of {@link Authentication.Builder}. It implements
|
||||
* the builder methods that correspond to the {@link Authentication} methods that
|
||||
* {@link AbstractAuthenticationToken} implements
|
||||
*
|
||||
* @param <B>
|
||||
* @since 7.0
|
||||
*/
|
||||
protected abstract static class AbstractAuthenticationBuilder<B extends AbstractAuthenticationBuilder<B>>
|
||||
implements BuildableAuthentication.Builder<B> {
|
||||
implements Authentication.Builder<B> {
|
||||
|
||||
private boolean authenticated;
|
||||
|
||||
|
@ -19,6 +19,9 @@ package org.springframework.security.core;
|
||||
import java.io.Serializable;
|
||||
import java.security.Principal;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@ -136,4 +139,112 @@ public interface Authentication extends Principal, Serializable {
|
||||
*/
|
||||
void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* A builder based on a given {@link BuildableAuthentication} instance
|
||||
*
|
||||
* @author Josh Cummings
|
||||
* @since 7.0
|
||||
*/
|
||||
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>
|
||||
* Note that since a non-empty set of authorities implies an
|
||||
* {@link Authentication} is authenticated, this method also marks the
|
||||
* authentication as {@link #authenticated} by default.
|
||||
* </p>
|
||||
* @param authorities a consumer that receives the full set of authorities
|
||||
* @return the {@link Builder} for additional configuration
|
||||
* @see Authentication#getAuthorities
|
||||
*/
|
||||
B authorities(Consumer<Collection<GrantedAuthority>> authorities);
|
||||
|
||||
/**
|
||||
* Use this credential.
|
||||
* <p>
|
||||
* Note that since some credentials are insecure to store, this method is
|
||||
* implemented as unsupported by default. Only implement or use this method if you
|
||||
* support secure storage of the credential or if your implementation also
|
||||
* implements {@link CredentialsContainer} and the credentials are thereby erased.
|
||||
* </p>
|
||||
* @param credentials the credentials to use
|
||||
* @return the {@link Builder} for additional configuration
|
||||
* @see Authentication#getCredentials
|
||||
*/
|
||||
default B credentials(@Nullable Object credentials) {
|
||||
throw new UnsupportedOperationException(
|
||||
String.format("%s does not store credentials", this.getClass().getSimpleName()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this details object.
|
||||
* <p>
|
||||
* Implementations may choose to use these {@code details} in combination with any
|
||||
* principal from the pre-existing {@link Authentication} instance.
|
||||
* </p>
|
||||
* @param details the details to use
|
||||
* @return the {@link Builder} for additional configuration
|
||||
* @see Authentication#getDetails
|
||||
*/
|
||||
B details(@Nullable Object details);
|
||||
|
||||
/**
|
||||
* Use this principal.
|
||||
* <p>
|
||||
* Note that in many cases, the principal is strongly-typed. Implementations may
|
||||
* choose to do a type check and are not necessarily expected to allow any object
|
||||
* as a principal.
|
||||
* </p>
|
||||
* <p>
|
||||
* Implementations may choose to use this {@code principal} in combination with
|
||||
* any principal from the pre-existing {@link Authentication} instance.
|
||||
* </p>
|
||||
* @param principal the principal to use
|
||||
* @return the {@link Builder} for additional configuration
|
||||
* @see Authentication#getPrincipal
|
||||
*/
|
||||
B principal(@Nullable Object principal);
|
||||
|
||||
/**
|
||||
* Mark this authentication as authenticated or not
|
||||
* @param authenticated whether this is an authenticated {@link Authentication}
|
||||
* instance
|
||||
* @return the {@link Builder} for additional configuration
|
||||
* @see Authentication#isAuthenticated
|
||||
*/
|
||||
B authenticated(boolean authenticated);
|
||||
|
||||
/**
|
||||
* Build an {@link Authentication} instance
|
||||
* @return the {@link Authentication} instance
|
||||
*/
|
||||
Authentication build();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,42 +16,11 @@
|
||||
|
||||
package org.springframework.security.core;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
||||
/**
|
||||
* Represents the token for an authentication request or for an authenticated principal
|
||||
* once the request has been processed by the
|
||||
* {@link AuthenticationManager#authenticate(Authentication)} method.
|
||||
* <p>
|
||||
* Once the request has been authenticated, the <tt>Authentication</tt> will usually be
|
||||
* stored in a thread-local <tt>SecurityContext</tt> managed by the
|
||||
* {@link SecurityContextHolder} by the authentication mechanism which is being used. An
|
||||
* explicit authentication can be achieved, without using one of Spring Security's
|
||||
* authentication mechanisms, by creating an <tt>Authentication</tt> instance and using
|
||||
* the code:
|
||||
* An {@link Authentication} that is also buildable.
|
||||
*
|
||||
* <pre>
|
||||
* SecurityContext context = SecurityContextHolder.createEmptyContext();
|
||||
* context.setAuthentication(anAuthentication);
|
||||
* SecurityContextHolder.setContext(context);
|
||||
* </pre>
|
||||
*
|
||||
* Note that unless the <tt>Authentication</tt> has the <tt>authenticated</tt> property
|
||||
* set to <tt>true</tt>, it will still be authenticated by any security interceptor (for
|
||||
* method or web invocations) which encounters it.
|
||||
* <p>
|
||||
* In most cases, the framework transparently takes care of managing the security context
|
||||
* and authentication objects for you.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Josh Cummings
|
||||
* @since 7.0
|
||||
*/
|
||||
public interface BuildableAuthentication extends Authentication {
|
||||
|
||||
@ -69,118 +38,9 @@ public interface BuildableAuthentication extends Authentication {
|
||||
* {@link Authentication} interface and that custom information is often contained in
|
||||
* the {@link Authentication#getPrincipal} value.
|
||||
* </p>
|
||||
* @return an {@link Builder} for building a new {@link BuildableAuthentication} based
|
||||
* on this instance
|
||||
* @since 7.0
|
||||
* @return an {@link Builder} for building a new {@link Authentication} based on this
|
||||
* instance
|
||||
*/
|
||||
Builder<?> toBuilder();
|
||||
|
||||
/**
|
||||
* A builder based on a given {@link BuildableAuthentication} instance
|
||||
*
|
||||
* @author Josh Cummings
|
||||
* @since 7.0
|
||||
*/
|
||||
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>
|
||||
* Note that since a non-empty set of authorities implies an
|
||||
* {@link Authentication} is authenticated, this method also marks the
|
||||
* authentication as {@link #authenticated} by default.
|
||||
* </p>
|
||||
* @param authorities a consumer that receives the full set of authorities
|
||||
* @return the {@link Builder} for additional configuration
|
||||
* @see Authentication#getAuthorities
|
||||
*/
|
||||
B authorities(Consumer<Collection<GrantedAuthority>> authorities);
|
||||
|
||||
/**
|
||||
* Use this credential.
|
||||
* <p>
|
||||
* Note that since some credentials are insecure to store, this method is
|
||||
* implemented as unsupported by default. Only implement or use this method if you
|
||||
* support secure storage of the credential or if your implementation also
|
||||
* implements {@link CredentialsContainer} and the credentials are thereby erased.
|
||||
* </p>
|
||||
* @param credentials the credentials to use
|
||||
* @return the {@link Builder} for additional configuration
|
||||
* @see Authentication#getCredentials
|
||||
*/
|
||||
default B credentials(@Nullable Object credentials) {
|
||||
throw new UnsupportedOperationException(
|
||||
String.format("%s does not store credentials", this.getClass().getSimpleName()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this details object.
|
||||
* <p>
|
||||
* Implementations may choose to use these {@code details} in combination with any
|
||||
* principal from the pre-existing {@link Authentication} instance.
|
||||
* </p>
|
||||
* @param details the details to use
|
||||
* @return the {@link Builder} for additional configuration
|
||||
* @see Authentication#getDetails
|
||||
*/
|
||||
B details(@Nullable Object details);
|
||||
|
||||
/**
|
||||
* Use this principal.
|
||||
* <p>
|
||||
* Note that in many cases, the principal is strongly-typed. Implementations may
|
||||
* choose to do a type check and are not necessarily expected to allow any object
|
||||
* as a principal.
|
||||
* </p>
|
||||
* <p>
|
||||
* Implementations may choose to use this {@code principal} in combination with
|
||||
* any principal from the pre-existing {@link Authentication} instance.
|
||||
* </p>
|
||||
* @param principal the principal to use
|
||||
* @return the {@link Builder} for additional configuration
|
||||
* @see Authentication#getPrincipal
|
||||
*/
|
||||
B principal(@Nullable Object principal);
|
||||
|
||||
/**
|
||||
* Mark this authentication as authenticated or not
|
||||
* @param authenticated whether this is an authenticated {@link Authentication}
|
||||
* instance
|
||||
* @return the {@link Builder} for additional configuration
|
||||
* @see Authentication#isAuthenticated
|
||||
*/
|
||||
B authenticated(boolean authenticated);
|
||||
|
||||
/**
|
||||
* Build an {@link Authentication} instance
|
||||
* @return the {@link Authentication} instance
|
||||
*/
|
||||
Authentication build();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user