mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-10-22 18:28:51 +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.AuthenticatedPrincipal;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.BuildableAuthentication;
|
|
||||||
import org.springframework.security.core.CredentialsContainer;
|
import org.springframework.security.core.CredentialsContainer;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
import org.springframework.security.core.authority.AuthorityUtils;
|
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
|
* A common abstract implementation of {@link Authentication.Builder}. It implements
|
||||||
* implements the builder methods that correspond to the {@link Authentication}
|
* the builder methods that correspond to the {@link Authentication} methods that
|
||||||
* methods that {@link AbstractAuthenticationToken} implements
|
* {@link AbstractAuthenticationToken} implements
|
||||||
*
|
*
|
||||||
* @param <B>
|
* @param <B>
|
||||||
* @since 7.0
|
* @since 7.0
|
||||||
*/
|
*/
|
||||||
protected abstract static class AbstractAuthenticationBuilder<B extends AbstractAuthenticationBuilder<B>>
|
protected abstract static class AbstractAuthenticationBuilder<B extends AbstractAuthenticationBuilder<B>>
|
||||||
implements BuildableAuthentication.Builder<B> {
|
implements Authentication.Builder<B> {
|
||||||
|
|
||||||
private boolean authenticated;
|
private boolean authenticated;
|
||||||
|
|
||||||
|
@ -19,6 +19,9 @@ package org.springframework.security.core;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
import java.util.Collection;
|
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.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
@ -136,4 +139,112 @@ public interface Authentication extends Principal, Serializable {
|
|||||||
*/
|
*/
|
||||||
void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
|
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;
|
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
|
* An {@link Authentication} that is also buildable.
|
||||||
* 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:
|
|
||||||
*
|
*
|
||||||
* <pre>
|
* @author Josh Cummings
|
||||||
* SecurityContext context = SecurityContextHolder.createEmptyContext();
|
* @since 7.0
|
||||||
* 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
|
|
||||||
*/
|
*/
|
||||||
public interface BuildableAuthentication extends Authentication {
|
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
|
* {@link Authentication} interface and that custom information is often contained in
|
||||||
* the {@link Authentication#getPrincipal} value.
|
* the {@link Authentication#getPrincipal} value.
|
||||||
* </p>
|
* </p>
|
||||||
* @return an {@link Builder} for building a new {@link BuildableAuthentication} based
|
* @return an {@link Builder} for building a new {@link Authentication} based on this
|
||||||
* on this instance
|
* instance
|
||||||
* @since 7.0
|
|
||||||
*/
|
*/
|
||||||
Builder<?> toBuilder();
|
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