Move toBuilder to BuildableAuthentication
Closes gh-18052
This commit is contained in:
+5
-4
@@ -28,6 +28,7 @@ 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;
|
||||
@@ -198,15 +199,15 @@ public abstract class AbstractAuthenticationToken implements Authentication, Cre
|
||||
}
|
||||
|
||||
/**
|
||||
* A common abstract implementation of {@link Authentication.Builder}. It implements
|
||||
* the builder methods that correspond to the {@link Authentication} methods that
|
||||
* {@link AbstractAuthenticationToken} implements
|
||||
* A common abstract implementation of {@link BuildableAuthentication.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 Authentication.Builder<B> {
|
||||
implements BuildableAuthentication.Builder<B> {
|
||||
|
||||
private boolean authenticated;
|
||||
|
||||
|
||||
+2
-1
@@ -20,6 +20,7 @@ import java.util.Collection;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.security.core.BuildableAuthentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -32,7 +33,7 @@ import org.springframework.util.Assert;
|
||||
* @author Ben Alex
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class RememberMeAuthenticationToken extends AbstractAuthenticationToken {
|
||||
public class RememberMeAuthenticationToken extends AbstractAuthenticationToken implements BuildableAuthentication {
|
||||
|
||||
private static final long serialVersionUID = 620L;
|
||||
|
||||
|
||||
+2
-1
@@ -22,6 +22,7 @@ import java.util.List;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.security.core.BuildableAuthentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -34,7 +35,7 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class TestingAuthenticationToken extends AbstractAuthenticationToken {
|
||||
public class TestingAuthenticationToken extends AbstractAuthenticationToken implements BuildableAuthentication {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
+3
-1
@@ -20,6 +20,7 @@ import java.util.Collection;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.security.core.BuildableAuthentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -35,7 +36,8 @@ import org.springframework.util.Assert;
|
||||
* @author Ben Alex
|
||||
* @author Norbert Nowak
|
||||
*/
|
||||
public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {
|
||||
public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken
|
||||
implements BuildableAuthentication {
|
||||
|
||||
private static final long serialVersionUID = 620L;
|
||||
|
||||
|
||||
+2
-1
@@ -22,6 +22,7 @@ import java.util.Collection;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.core.BuildableAuthentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -31,7 +32,7 @@ import org.springframework.util.Assert;
|
||||
* @author Josh Cummings
|
||||
* @since 7.0
|
||||
*/
|
||||
public class OneTimeTokenAuthentication extends AbstractAuthenticationToken {
|
||||
public class OneTimeTokenAuthentication extends AbstractAuthenticationToken implements BuildableAuthentication {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1195893764725073959L;
|
||||
|
||||
@@ -19,7 +19,6 @@ package org.springframework.security.core;
|
||||
import java.io.Serializable;
|
||||
import java.security.Principal;
|
||||
import java.util.Collection;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@@ -137,110 +136,4 @@ public interface Authentication extends Principal, Serializable {
|
||||
*/
|
||||
void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Return an {@link Builder} based on this instance. By default, returns a builder
|
||||
* that builds a {@link SimpleAuthentication}.
|
||||
* <p>
|
||||
* Although a {@code default} method, all {@link Authentication} implementations
|
||||
* should implement this. The reason is to ensure that the {@link Authentication} type
|
||||
* is preserved when {@link Builder#build} is invoked. This is especially important in
|
||||
* the event that your authentication implementation contains custom fields.
|
||||
* </p>
|
||||
* <p>
|
||||
* This isn't strictly necessary since it is recommended that applications code to the
|
||||
* {@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 Authentication} based on this
|
||||
* instance
|
||||
* @since 7.0
|
||||
*/
|
||||
default Builder<?> toBuilder() {
|
||||
return new SimpleAuthentication.Builder(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder based on a given {@link Authentication} instance
|
||||
*
|
||||
* @author Josh Cummings
|
||||
* @since 7.0
|
||||
*/
|
||||
interface Builder<B extends Builder<B>> {
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
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:
|
||||
*
|
||||
* <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
|
||||
*/
|
||||
public interface BuildableAuthentication extends Authentication {
|
||||
|
||||
/**
|
||||
* Return an {@link Builder} based on this instance.
|
||||
* <p>
|
||||
* Although a {@code default} method, all {@link BuildableAuthentication}
|
||||
* implementations should implement this. The reason is to ensure that the
|
||||
* {@link BuildableAuthentication} type is preserved when {@link Builder#build} is
|
||||
* invoked. This is especially important in the event that your authentication
|
||||
* implementation contains custom fields.
|
||||
* </p>
|
||||
* <p>
|
||||
* This isn't strictly necessary since it is recommended that applications code to the
|
||||
* {@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
|
||||
*/
|
||||
Builder<?> toBuilder();
|
||||
|
||||
/**
|
||||
* A builder based on a given {@link BuildableAuthentication} instance
|
||||
*
|
||||
* @author Josh Cummings
|
||||
* @since 7.0
|
||||
*/
|
||||
interface Builder<B extends Builder<B>> {
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,151 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.core;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@Transient
|
||||
final class SimpleAuthentication implements Authentication {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 3194696462184782814L;
|
||||
|
||||
private final @Nullable Object principal;
|
||||
|
||||
private final @Nullable Object credentials;
|
||||
|
||||
private final Collection<GrantedAuthority> authorities;
|
||||
|
||||
private final @Nullable Object details;
|
||||
|
||||
private final boolean authenticated;
|
||||
|
||||
private SimpleAuthentication(Builder builder) {
|
||||
this.principal = builder.principal;
|
||||
this.credentials = builder.credentials;
|
||||
this.authorities = builder.authorities;
|
||||
this.details = builder.details;
|
||||
this.authenticated = builder.authenticated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
return this.authorities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Object getCredentials() {
|
||||
return this.credentials;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Object getDetails() {
|
||||
return this.details;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Object getPrincipal() {
|
||||
return this.principal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAuthenticated() {
|
||||
return this.authenticated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
|
||||
throw new IllegalArgumentException(
|
||||
"Instead of calling this setter, please call toBuilder to create a new instance");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return (this.principal == null) ? "" : this.principal.toString();
|
||||
}
|
||||
|
||||
static final class Builder implements Authentication.Builder<Builder> {
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private final Collection<GrantedAuthority> authorities = new LinkedHashSet<>();
|
||||
|
||||
private @Nullable Object principal;
|
||||
|
||||
private @Nullable Object credentials;
|
||||
|
||||
private @Nullable Object details;
|
||||
|
||||
private boolean authenticated;
|
||||
|
||||
Builder(Authentication authentication) {
|
||||
this.logger.debug("Creating a builder which will result in exchanging an authentication of type "
|
||||
+ authentication.getClass() + " for " + SimpleAuthentication.class.getSimpleName() + ";"
|
||||
+ " consider implementing " + authentication.getClass().getSimpleName() + "#toBuilder");
|
||||
this.authorities.addAll(authentication.getAuthorities());
|
||||
this.principal = authentication.getPrincipal();
|
||||
this.credentials = authentication.getCredentials();
|
||||
this.details = authentication.getDetails();
|
||||
this.authenticated = authentication.isAuthenticated();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder authorities(Consumer<Collection<GrantedAuthority>> authorities) {
|
||||
authorities.accept(this.authorities);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder details(@Nullable Object details) {
|
||||
this.details = details;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder principal(@Nullable Object principal) {
|
||||
this.principal = principal;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder credentials(@Nullable Object credentials) {
|
||||
this.credentials = credentials;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder authenticated(boolean authenticated) {
|
||||
this.authenticated = authenticated;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication build() {
|
||||
return new SimpleAuthentication(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user