mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-10-22 18:28:51 +00:00
Polish Builders
- Added remaining properties - Removed apply method since Spring Security isn't using it right now - Made builders extensible since the authentications are extensible Issue gh-17861
This commit is contained in:
parent
44fef786aa
commit
a0fe6a5fee
@ -20,7 +20,7 @@ import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.apereo.cas.client.validation.Assertion;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
@ -106,6 +106,19 @@ public class CasAuthenticationToken extends AbstractAuthenticationToken implemen
|
||||
setAuthenticated(true);
|
||||
}
|
||||
|
||||
protected CasAuthenticationToken(Builder<?> builder) {
|
||||
super(builder);
|
||||
Assert.isTrue(!"".equals(builder.principal), "principal cannot be null or empty");
|
||||
Assert.notNull(!"".equals(builder.credentials), "credentials cannot be null or empty");
|
||||
Assert.notNull(builder.userDetails, "userDetails cannot be null");
|
||||
Assert.notNull(builder.assertion, "assertion cannot be null");
|
||||
this.keyHash = builder.keyHash;
|
||||
this.principal = builder.principal;
|
||||
this.credentials = builder.credentials;
|
||||
this.userDetails = builder.userDetails;
|
||||
this.assertion = builder.assertion;
|
||||
}
|
||||
|
||||
private static Integer extractKeyHash(String key) {
|
||||
Assert.hasLength(key, "key cannot be null or empty");
|
||||
return key.hashCode();
|
||||
@ -156,8 +169,8 @@ public class CasAuthenticationToken extends AbstractAuthenticationToken implemen
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder toBuilder() {
|
||||
return new Builder().apply(this);
|
||||
public Builder<?> toBuilder() {
|
||||
return new Builder<>(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -174,7 +187,7 @@ public class CasAuthenticationToken extends AbstractAuthenticationToken implemen
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
public static final class Builder extends AbstractAuthenticationBuilder<@NonNull CasAuthenticationToken, Builder> {
|
||||
public static class Builder<B extends Builder<B>> extends AbstractAuthenticationBuilder<Object, Object, B> {
|
||||
|
||||
private Integer keyHash;
|
||||
|
||||
@ -186,47 +199,47 @@ public class CasAuthenticationToken extends AbstractAuthenticationToken implemen
|
||||
|
||||
private Assertion assertion;
|
||||
|
||||
private Builder() {
|
||||
|
||||
protected Builder(CasAuthenticationToken token) {
|
||||
super(token);
|
||||
this.keyHash = token.keyHash;
|
||||
this.principal = token.principal;
|
||||
this.credentials = token.credentials;
|
||||
this.userDetails = token.userDetails;
|
||||
this.assertion = token.assertion;
|
||||
}
|
||||
|
||||
public Builder apply(CasAuthenticationToken authentication) {
|
||||
return super.apply(authentication).keyHash(authentication.keyHash)
|
||||
.principal(authentication.principal)
|
||||
.credentials(authentication.credentials)
|
||||
.userDetails(authentication.userDetails)
|
||||
.assertion(authentication.assertion);
|
||||
}
|
||||
|
||||
public Builder keyHash(Integer keyHash) {
|
||||
public B keyHash(Integer keyHash) {
|
||||
this.keyHash = keyHash;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder principal(Object principal) {
|
||||
this.principal = principal;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder credentials(Object credentials) {
|
||||
this.credentials = credentials;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder userDetails(UserDetails userDetails) {
|
||||
this.userDetails = userDetails;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder assertion(Assertion assertion) {
|
||||
this.assertion = assertion;
|
||||
return this;
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NonNull CasAuthenticationToken build(Collection<GrantedAuthority> authorities) {
|
||||
return new CasAuthenticationToken(this.keyHash, this.principal, this.credentials, authorities,
|
||||
this.userDetails, this.assertion);
|
||||
public B principal(@Nullable Object principal) {
|
||||
Assert.notNull(principal, "principal cannot be null");
|
||||
this.principal = principal;
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public B credentials(@Nullable Object credentials) {
|
||||
Assert.notNull(credentials, "credentials cannot be null");
|
||||
this.credentials = credentials;
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
public B userDetails(UserDetails userDetails) {
|
||||
this.userDetails = userDetails;
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
public B assertion(Assertion assertion) {
|
||||
this.assertion = assertion;
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CasAuthenticationToken build() {
|
||||
return new CasAuthenticationToken(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import java.util.Collection;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@ -52,7 +53,7 @@ public class CasServiceTicketAuthenticationToken extends AbstractAuthenticationT
|
||||
*
|
||||
*/
|
||||
public CasServiceTicketAuthenticationToken(String identifier, Object credentials) {
|
||||
super(null);
|
||||
super((Collection<? extends GrantedAuthority>) null);
|
||||
this.identifier = identifier;
|
||||
this.credentials = credentials;
|
||||
setAuthenticated(false);
|
||||
@ -75,6 +76,12 @@ public class CasServiceTicketAuthenticationToken extends AbstractAuthenticationT
|
||||
super.setAuthenticated(true);
|
||||
}
|
||||
|
||||
protected CasServiceTicketAuthenticationToken(Builder<?> builder) {
|
||||
super(builder);
|
||||
this.identifier = builder.principal;
|
||||
this.credentials = builder.credentials;
|
||||
}
|
||||
|
||||
public static CasServiceTicketAuthenticationToken stateful(Object credentials) {
|
||||
return new CasServiceTicketAuthenticationToken(CAS_STATEFUL_IDENTIFIER, credentials);
|
||||
}
|
||||
@ -110,4 +117,46 @@ public class CasServiceTicketAuthenticationToken extends AbstractAuthenticationT
|
||||
this.credentials = null;
|
||||
}
|
||||
|
||||
public Builder<?> toBuilder() {
|
||||
return new Builder<>(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder preserving the concrete {@link Authentication} type
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
public static class Builder<B extends Builder<B>> extends AbstractAuthenticationBuilder<String, Object, B> {
|
||||
|
||||
private String principal;
|
||||
|
||||
private @Nullable Object credentials;
|
||||
|
||||
protected Builder(CasServiceTicketAuthenticationToken token) {
|
||||
super(token);
|
||||
this.principal = token.identifier;
|
||||
this.credentials = token.credentials;
|
||||
}
|
||||
|
||||
@Override
|
||||
public B principal(@Nullable String principal) {
|
||||
Assert.notNull(principal, "principal cannot be null");
|
||||
this.principal = principal;
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public B credentials(@Nullable Object credentials) {
|
||||
Assert.notNull(credentials, "credentials cannot be null");
|
||||
this.credentials = credentials;
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CasServiceTicketAuthenticationToken build() {
|
||||
return new CasServiceTicketAuthenticationToken(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -165,7 +165,14 @@ public class CasAuthenticationTokenTests {
|
||||
Assertion assertionTwo = new AssertionImpl("test");
|
||||
CasAuthenticationToken factorTwo = new CasAuthenticationToken("yek", "bob", "ssap",
|
||||
AuthorityUtils.createAuthorityList("FACTOR_TWO"), PasswordEncodedUser.admin(), assertionTwo);
|
||||
CasAuthenticationToken authentication = factorOne.toBuilder().apply(factorTwo).build();
|
||||
CasAuthenticationToken authentication = factorOne.toBuilder()
|
||||
.authorities((a) -> a.addAll(factorTwo.getAuthorities()))
|
||||
.keyHash(factorTwo.getKeyHash())
|
||||
.principal(factorTwo.getPrincipal())
|
||||
.credentials(factorTwo.getCredentials())
|
||||
.userDetails(factorTwo.getUserDetails())
|
||||
.assertion(factorTwo.getAssertion())
|
||||
.build();
|
||||
Set<String> authorities = AuthorityUtils.authorityListToSet(authentication.getAuthorities());
|
||||
assertThat(authentication.getKeyHash()).isEqualTo(factorTwo.getKeyHash());
|
||||
assertThat(authentication.getPrincipal()).isEqualTo(factorTwo.getPrincipal());
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
@ -31,6 +33,7 @@ import org.springframework.security.config.test.SpringTestContext;
|
||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.Transient;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
@ -113,7 +116,7 @@ public class SessionManagementConfigurerTransientAuthenticationTests {
|
||||
static class SomeTransientAuthentication extends AbstractAuthenticationToken {
|
||||
|
||||
SomeTransientAuthentication() {
|
||||
super(null);
|
||||
super((Collection<? extends GrantedAuthority>) null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.security.config.http;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
@ -26,6 +28,7 @@ import org.springframework.security.config.test.SpringTestContext;
|
||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.Transient;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
@ -82,7 +85,7 @@ public class SessionManagementConfigTransientAuthenticationTests {
|
||||
static class SomeTransientAuthentication extends AbstractAuthenticationToken {
|
||||
|
||||
SomeTransientAuthentication() {
|
||||
super(null);
|
||||
super((Collection<? extends GrantedAuthority>) null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -20,7 +20,7 @@ import java.security.Principal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
@ -43,6 +43,8 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public abstract class AbstractAuthenticationToken implements Authentication, CredentialsContainer {
|
||||
|
||||
private static final long serialVersionUID = -3194696462184782834L;
|
||||
|
||||
private final Collection<GrantedAuthority> authorities;
|
||||
|
||||
private @Nullable Object details;
|
||||
@ -65,6 +67,12 @@ public abstract class AbstractAuthenticationToken implements Authentication, Cre
|
||||
this.authorities = Collections.unmodifiableList(new ArrayList<>(authorities));
|
||||
}
|
||||
|
||||
protected AbstractAuthenticationToken(AbstractAuthenticationBuilder<?, ?, ?> builder) {
|
||||
this(builder.authorities);
|
||||
this.authenticated = builder.authenticated;
|
||||
this.details = builder.details;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<GrantedAuthority> getAuthorities() {
|
||||
return this.authorities;
|
||||
@ -187,36 +195,40 @@ public abstract class AbstractAuthenticationToken implements Authentication, Cre
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
protected abstract static class AbstractAuthenticationBuilder<A extends Authentication, B extends AbstractAuthenticationBuilder<A, B>>
|
||||
implements Builder<A, B> {
|
||||
protected abstract static class AbstractAuthenticationBuilder<P, C, B extends AbstractAuthenticationBuilder<P, C, B>>
|
||||
implements Authentication.Builder<P, C, B> {
|
||||
|
||||
private final Collection<GrantedAuthority> authorities = new HashSet<>();
|
||||
protected boolean authenticated;
|
||||
|
||||
protected AbstractAuthenticationBuilder() {
|
||||
protected @Nullable Object details;
|
||||
|
||||
protected final Collection<GrantedAuthority> authorities;
|
||||
|
||||
protected AbstractAuthenticationBuilder(AbstractAuthenticationToken token) {
|
||||
this.authorities = new LinkedHashSet<>(token.getAuthorities());
|
||||
this.authenticated = token.isAuthenticated();
|
||||
this.details = token.getDetails();
|
||||
}
|
||||
|
||||
@Override
|
||||
public B authenticated(boolean authenticated) {
|
||||
this.authenticated = authenticated;
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public B details(@Nullable Object details) {
|
||||
this.details = details;
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public B authorities(Consumer<Collection<GrantedAuthority>> authorities) {
|
||||
authorities.accept(this.authorities);
|
||||
this.authenticated = true;
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public A build() {
|
||||
return build(this.authorities);
|
||||
}
|
||||
|
||||
@Override
|
||||
public B apply(Authentication token) {
|
||||
Assert.isTrue(token.isAuthenticated(), "cannot mutate an unauthenticated token");
|
||||
Assert.notNull(token.getPrincipal(), "principal cannot be null");
|
||||
this.authorities.addAll(token.getAuthorities());
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
protected abstract A build(Collection<GrantedAuthority> authorities);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -74,6 +74,12 @@ public class RememberMeAuthenticationToken extends AbstractAuthenticationToken {
|
||||
setAuthenticated(true);
|
||||
}
|
||||
|
||||
protected RememberMeAuthenticationToken(Builder<?> builder) {
|
||||
super(builder);
|
||||
this.keyHash = builder.keyHash;
|
||||
this.principal = builder.principal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns an empty <code>String</code>
|
||||
* @return an empty String
|
||||
@ -94,7 +100,7 @@ public class RememberMeAuthenticationToken extends AbstractAuthenticationToken {
|
||||
|
||||
@Override
|
||||
public Builder toBuilder() {
|
||||
return new Builder().apply(this);
|
||||
return new Builder(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -120,35 +126,33 @@ public class RememberMeAuthenticationToken extends AbstractAuthenticationToken {
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
public static final class Builder extends AbstractAuthenticationBuilder<RememberMeAuthenticationToken, Builder> {
|
||||
public static class Builder<B extends Builder<B>> extends AbstractAuthenticationBuilder<Object, Object, B> {
|
||||
|
||||
private @Nullable Integer keyHash;
|
||||
private Integer keyHash;
|
||||
|
||||
private @Nullable Object principal;
|
||||
private Object principal;
|
||||
|
||||
private Builder() {
|
||||
|
||||
}
|
||||
|
||||
public Builder apply(RememberMeAuthenticationToken token) {
|
||||
return super.apply(token).keyHash(token.getKeyHash()).principal(token.getPrincipal());
|
||||
}
|
||||
|
||||
public Builder principal(Object principal) {
|
||||
this.principal = principal;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder keyHash(int keyHash) {
|
||||
this.keyHash = keyHash;
|
||||
return this;
|
||||
protected Builder(RememberMeAuthenticationToken token) {
|
||||
super(token);
|
||||
this.keyHash = token.getKeyHash();
|
||||
this.principal = token.getPrincipal();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RememberMeAuthenticationToken build(Collection<GrantedAuthority> authorities) {
|
||||
Assert.notNull(this.keyHash, "keyHash cannot be null");
|
||||
Assert.notNull(this.principal, "principal cannot be null");
|
||||
return new RememberMeAuthenticationToken(this.keyHash, this.principal, authorities);
|
||||
public B principal(@Nullable Object principal) {
|
||||
Assert.notNull(principal, "principal cannot be null");
|
||||
this.principal = principal;
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
public B keyHash(int keyHash) {
|
||||
this.keyHash = keyHash;
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RememberMeAuthenticationToken build() {
|
||||
return new RememberMeAuthenticationToken(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ public class TestingAuthenticationToken extends AbstractAuthenticationToken {
|
||||
private final Object principal;
|
||||
|
||||
public TestingAuthenticationToken(Object principal, Object credentials) {
|
||||
super(null);
|
||||
super((Collection<? extends GrantedAuthority>) null);
|
||||
this.principal = principal;
|
||||
this.credentials = credentials;
|
||||
}
|
||||
@ -65,6 +65,12 @@ public class TestingAuthenticationToken extends AbstractAuthenticationToken {
|
||||
setAuthenticated(true);
|
||||
}
|
||||
|
||||
protected TestingAuthenticationToken(Builder<?> builder) {
|
||||
super(builder);
|
||||
this.principal = builder.principal;
|
||||
this.credentials = builder.credentials;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCredentials() {
|
||||
return this.credentials;
|
||||
@ -76,8 +82,8 @@ public class TestingAuthenticationToken extends AbstractAuthenticationToken {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder toBuilder() {
|
||||
return new Builder().apply(this);
|
||||
public Builder<?> toBuilder() {
|
||||
return new Builder<>(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -85,36 +91,35 @@ public class TestingAuthenticationToken extends AbstractAuthenticationToken {
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
public static final class Builder extends AbstractAuthenticationBuilder<TestingAuthenticationToken, Builder> {
|
||||
public static class Builder<B extends Builder<B>> extends AbstractAuthenticationBuilder<Object, Object, B> {
|
||||
|
||||
private @Nullable Object principal;
|
||||
private Object principal;
|
||||
|
||||
private @Nullable Object credentials;
|
||||
private Object credentials;
|
||||
|
||||
private Builder() {
|
||||
|
||||
}
|
||||
|
||||
public Builder apply(TestingAuthenticationToken authentication) {
|
||||
return super.apply(authentication).principal(authentication.getPrincipal())
|
||||
.credentials(authentication.getCredentials());
|
||||
}
|
||||
|
||||
public Builder principal(Object principal) {
|
||||
this.principal = principal;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder credentials(Object credentials) {
|
||||
this.credentials = credentials;
|
||||
return this;
|
||||
protected Builder(TestingAuthenticationToken token) {
|
||||
super(token);
|
||||
this.principal = token.principal;
|
||||
this.credentials = token.credentials;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TestingAuthenticationToken build(Collection<GrantedAuthority> authorities) {
|
||||
Assert.notNull(this.principal, "principal cannot be null");
|
||||
Assert.notNull(this.credentials, "credentials cannot be null");
|
||||
return new TestingAuthenticationToken(this.principal, this.credentials, authorities);
|
||||
public B principal(@Nullable Object principal) {
|
||||
Assert.notNull(principal, "principal cannot be null");
|
||||
this.principal = principal;
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public B credentials(@Nullable Object credentials) {
|
||||
Assert.notNull(credentials, "credentials cannot be null");
|
||||
this.credentials = credentials;
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestingAuthenticationToken build() {
|
||||
return new TestingAuthenticationToken(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationT
|
||||
*
|
||||
*/
|
||||
public UsernamePasswordAuthenticationToken(@Nullable Object principal, @Nullable Object credentials) {
|
||||
super(null);
|
||||
super((Collection<? extends GrantedAuthority>) null);
|
||||
this.principal = principal;
|
||||
this.credentials = credentials;
|
||||
setAuthenticated(false);
|
||||
@ -74,6 +74,12 @@ public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationT
|
||||
super.setAuthenticated(true); // must use super, as we override
|
||||
}
|
||||
|
||||
protected UsernamePasswordAuthenticationToken(Builder<?> builder) {
|
||||
super(builder);
|
||||
this.principal = builder.principal;
|
||||
this.credentials = builder.credentials;
|
||||
}
|
||||
|
||||
/**
|
||||
* This factory method can be safely used by any code that wishes to create a
|
||||
* unauthenticated <code>UsernamePasswordAuthenticationToken</code>.
|
||||
@ -126,8 +132,8 @@ public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationT
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<?, ?> toBuilder() {
|
||||
return new Builder<>().apply(this);
|
||||
public Builder<?> toBuilder() {
|
||||
return new Builder<>(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -135,35 +141,34 @@ public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationT
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
public static class Builder<A extends UsernamePasswordAuthenticationToken, B extends Builder<A, B>>
|
||||
extends AbstractAuthenticationBuilder<A, B> {
|
||||
public static class Builder<B extends Builder<B>> extends AbstractAuthenticationBuilder<Object, Object, B> {
|
||||
|
||||
private @Nullable Object principal;
|
||||
protected @Nullable Object principal;
|
||||
|
||||
private @Nullable Object credentials;
|
||||
protected @Nullable Object credentials;
|
||||
|
||||
protected Builder() {
|
||||
protected Builder(UsernamePasswordAuthenticationToken token) {
|
||||
super(token);
|
||||
this.principal = token.principal;
|
||||
this.credentials = token.credentials;
|
||||
}
|
||||
|
||||
public B apply(UsernamePasswordAuthenticationToken authentication) {
|
||||
return super.apply(authentication).principal(authentication.getPrincipal())
|
||||
.credentials(authentication.getCredentials());
|
||||
}
|
||||
|
||||
public B principal(Object principal) {
|
||||
@Override
|
||||
public B principal(@Nullable Object principal) {
|
||||
Assert.notNull(principal, "principal cannot be null");
|
||||
this.principal = principal;
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public B credentials(@Nullable Object credentials) {
|
||||
this.credentials = credentials;
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected A build(Collection<GrantedAuthority> authorities) {
|
||||
Assert.notNull(this.principal, "principal cannot be null");
|
||||
return (A) new UsernamePasswordAuthenticationToken(this.principal, this.credentials, authorities);
|
||||
public UsernamePasswordAuthenticationToken build() {
|
||||
return new UsernamePasswordAuthenticationToken(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.security.authentication.jaas;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import javax.security.auth.login.LoginContext;
|
||||
@ -51,13 +50,18 @@ public class JaasAuthenticationToken extends UsernamePasswordAuthenticationToken
|
||||
this.loginContext = loginContext;
|
||||
}
|
||||
|
||||
protected JaasAuthenticationToken(Builder<?> builder) {
|
||||
super(builder);
|
||||
this.loginContext = builder.loginContext;
|
||||
}
|
||||
|
||||
public LoginContext getLoginContext() {
|
||||
return this.loginContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder toBuilder() {
|
||||
return new Builder().apply(this);
|
||||
public Builder<?> toBuilder() {
|
||||
return new Builder<>(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -65,17 +69,13 @@ public class JaasAuthenticationToken extends UsernamePasswordAuthenticationToken
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
public static final class Builder
|
||||
extends UsernamePasswordAuthenticationToken.Builder<JaasAuthenticationToken, Builder> {
|
||||
public static class Builder<B extends Builder<B>> extends UsernamePasswordAuthenticationToken.Builder<B> {
|
||||
|
||||
private @Nullable LoginContext loginContext;
|
||||
private LoginContext loginContext;
|
||||
|
||||
private Builder() {
|
||||
|
||||
}
|
||||
|
||||
public Builder apply(JaasAuthenticationToken authentication) {
|
||||
return super.apply(authentication).loginContext(authentication.getLoginContext());
|
||||
protected Builder(JaasAuthenticationToken token) {
|
||||
super(token);
|
||||
this.loginContext = token.getLoginContext();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -83,17 +83,15 @@ public class JaasAuthenticationToken extends UsernamePasswordAuthenticationToken
|
||||
* @param loginContext the {@link LoginContext} to use
|
||||
* @return the {@link Builder} for further configuration
|
||||
*/
|
||||
public Builder loginContext(LoginContext loginContext) {
|
||||
public B loginContext(LoginContext loginContext) {
|
||||
this.loginContext = loginContext;
|
||||
return this;
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JaasAuthenticationToken build(Collection<GrantedAuthority> authorities) {
|
||||
UsernamePasswordAuthenticationToken token = super.build(authorities);
|
||||
Assert.notNull(this.loginContext, "loginContext cannot be null");
|
||||
return new JaasAuthenticationToken(token.getPrincipal(), token.getCredentials(),
|
||||
(List<GrantedAuthority>) token.getAuthorities(), this.loginContext);
|
||||
public JaasAuthenticationToken build() {
|
||||
Assert.notNull(this.principal, "principal cannot be null");
|
||||
return new JaasAuthenticationToken(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -44,6 +44,11 @@ public class OneTimeTokenAuthentication extends AbstractAuthenticationToken {
|
||||
setAuthenticated(true);
|
||||
}
|
||||
|
||||
protected OneTimeTokenAuthentication(Builder<?> builder) {
|
||||
super(builder);
|
||||
this.principal = builder.principal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrincipal() {
|
||||
return this.principal;
|
||||
@ -55,42 +60,36 @@ public class OneTimeTokenAuthentication extends AbstractAuthenticationToken {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder toBuilder() {
|
||||
return new Builder().apply(this);
|
||||
public Builder<?> toBuilder() {
|
||||
return new Builder<>(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for constructing a {@link OneTimeTokenAuthentication} instance
|
||||
*/
|
||||
public static final class Builder extends AbstractAuthenticationBuilder<OneTimeTokenAuthentication, Builder> {
|
||||
public static class Builder<B extends Builder<B>> extends AbstractAuthenticationBuilder<Object, Object, B> {
|
||||
|
||||
private @Nullable Object principal;
|
||||
private Object principal;
|
||||
|
||||
private Builder() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply this {@link OneTimeTokenAuthentication}
|
||||
* @return the {@link Builder} for further configuration
|
||||
*/
|
||||
public Builder apply(OneTimeTokenAuthentication authentication) {
|
||||
return super.apply(authentication).principal(authentication.principal);
|
||||
protected Builder(OneTimeTokenAuthentication token) {
|
||||
super(token);
|
||||
this.principal = token.principal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this principal
|
||||
* @return the {@link Builder} for further configuration
|
||||
*/
|
||||
public Builder principal(Object principal) {
|
||||
@Override
|
||||
public B principal(@Nullable Object principal) {
|
||||
Assert.notNull(principal, "principal cannot be null");
|
||||
this.principal = principal;
|
||||
return this;
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OneTimeTokenAuthentication build(Collection<GrantedAuthority> authorities) {
|
||||
Assert.notNull(this.principal, "principal cannot be null");
|
||||
return new OneTimeTokenAuthentication(this.principal, authorities);
|
||||
public OneTimeTokenAuthentication build() {
|
||||
return new OneTimeTokenAuthentication(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.security.core;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.security.Principal;
|
||||
import java.util.Collection;
|
||||
@ -26,7 +25,6 @@ import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Represents the token for an authentication request or for an authenticated principal
|
||||
@ -57,9 +55,6 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public interface Authentication extends Principal, Serializable {
|
||||
|
||||
@Serial
|
||||
long serialVersionUID = -3884394378624019849L;
|
||||
|
||||
/**
|
||||
* Set by an <code>AuthenticationManager</code> to indicate the authorities that the
|
||||
* principal has been granted. Note that classes should not rely on this value as
|
||||
@ -148,43 +143,36 @@ public interface Authentication extends Principal, Serializable {
|
||||
* instance
|
||||
* @since 7.0
|
||||
*/
|
||||
default Builder<?, ?> toBuilder() {
|
||||
return new NoopAuthenticationBuilder<>(this);
|
||||
default Builder<?, ?, ?> toBuilder() {
|
||||
return new NoopAuthenticationBuilder(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder based on a given {@link Authentication} instance
|
||||
*
|
||||
* @param <A> the type of {@link Authentication}
|
||||
* @author Josh Cummings
|
||||
* @since 7.0
|
||||
*/
|
||||
interface Builder<A extends Authentication, B extends Builder<A, B>> {
|
||||
interface Builder<P, C, B extends Builder<P, C, B>> {
|
||||
|
||||
/**
|
||||
* Apply this {@link Authentication} to the builder.
|
||||
* <p>
|
||||
* By default, this method adds the authorities from {@code authentication} to
|
||||
* this builder
|
||||
* @return the {@link Builder} for further configuration
|
||||
*/
|
||||
default B apply(Authentication authentication) {
|
||||
Assert.isTrue(authentication.isAuthenticated(), "cannot apply an unauthenticated token");
|
||||
return authorities((a) -> a.addAll(authentication.getAuthorities()));
|
||||
B authorities(Consumer<Collection<GrantedAuthority>> authorities);
|
||||
|
||||
default B credentials(@Nullable C credentials) {
|
||||
throw new UnsupportedOperationException(
|
||||
String.format("%s does not store credentials", this.getClass().getSimpleName()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply these authorities to the builder.
|
||||
* @param authorities the authorities to apply
|
||||
* @return the {@link Builder} for further configuration
|
||||
*/
|
||||
B authorities(Consumer<Collection<GrantedAuthority>> authorities);
|
||||
B details(@Nullable Object details);
|
||||
|
||||
B principal(@Nullable P principal);
|
||||
|
||||
B authenticated(boolean authenticated);
|
||||
|
||||
/**
|
||||
* Build an {@link Authentication} instance
|
||||
* @return the {@link Authentication} instance
|
||||
*/
|
||||
A build();
|
||||
Authentication build();
|
||||
|
||||
}
|
||||
|
||||
|
@ -19,34 +19,50 @@ package org.springframework.security.core;
|
||||
import java.util.Collection;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* An adapter implementation of {@link Authentication.Builder} that provides a no-op
|
||||
* implementation for the principal, credentials, and authorities
|
||||
*
|
||||
* @param <A> the type of {@link Authentication}
|
||||
* @author Josh Cummings
|
||||
* @since 7.0
|
||||
*/
|
||||
class NoopAuthenticationBuilder<A extends Authentication>
|
||||
implements Authentication.Builder<A, NoopAuthenticationBuilder<A>> {
|
||||
class NoopAuthenticationBuilder implements Authentication.Builder<Object, Object, NoopAuthenticationBuilder> {
|
||||
|
||||
private A original;
|
||||
private Authentication original;
|
||||
|
||||
NoopAuthenticationBuilder(A authentication) {
|
||||
Assert.isTrue(authentication.isAuthenticated(), "cannot mutate an unauthenticated token");
|
||||
Assert.notNull(authentication.getPrincipal(), "principal cannot be null");
|
||||
NoopAuthenticationBuilder(Authentication authentication) {
|
||||
this.original = authentication;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NoopAuthenticationBuilder<A> authorities(Consumer<Collection<GrantedAuthority>> authorities) {
|
||||
public NoopAuthenticationBuilder authenticated(boolean authenticated) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public A build() {
|
||||
public NoopAuthenticationBuilder principal(@Nullable Object principal) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NoopAuthenticationBuilder details(@Nullable Object details) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NoopAuthenticationBuilder credentials(@Nullable Object credentials) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NoopAuthenticationBuilder authorities(Consumer<Collection<GrantedAuthority>> authorities) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication build() {
|
||||
return this.original;
|
||||
}
|
||||
|
||||
|
@ -16,44 +16,44 @@
|
||||
|
||||
package org.springframework.security.authentication;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken.AbstractAuthenticationBuilder;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
||||
class AbstractAuthenticationBuilderTests {
|
||||
|
||||
@Test
|
||||
void applyWhenUnauthenticatedThenErrors() {
|
||||
TestAbstractAuthenticationBuilder builder = new TestAbstractAuthenticationBuilder();
|
||||
TestingAuthenticationToken unauthenticated = new TestingAuthenticationToken("user", "password");
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> builder.apply(unauthenticated));
|
||||
}
|
||||
|
||||
@Test
|
||||
void applyWhenAuthoritiesThenAdds() {
|
||||
TestAbstractAuthenticationBuilder builder = new TestAbstractAuthenticationBuilder();
|
||||
TestingAuthenticationToken factorOne = new TestingAuthenticationToken("user", "pass", "FACTOR_ONE");
|
||||
TestingAuthenticationToken factorTwo = new TestingAuthenticationToken("user", "pass", "FACTOR_TWO");
|
||||
Authentication result = builder.apply(factorOne).apply(factorTwo).build();
|
||||
TestAbstractAuthenticationBuilder builder = new TestAbstractAuthenticationBuilder(factorOne);
|
||||
Authentication result = builder.authorities((a) -> a.addAll(factorTwo.getAuthorities())).build();
|
||||
Set<String> authorities = AuthorityUtils.authorityListToSet(result.getAuthorities());
|
||||
assertThat(authorities).containsExactlyInAnyOrder("FACTOR_ONE", "FACTOR_TWO");
|
||||
}
|
||||
|
||||
private static final class TestAbstractAuthenticationBuilder
|
||||
extends AbstractAuthenticationBuilder<Authentication, TestAbstractAuthenticationBuilder> {
|
||||
extends AbstractAuthenticationBuilder<Object, Object, TestAbstractAuthenticationBuilder> {
|
||||
|
||||
private TestAbstractAuthenticationBuilder(TestingAuthenticationToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Authentication build(Collection<GrantedAuthority> authorities) {
|
||||
return new TestingAuthenticationToken("user", "password", authorities);
|
||||
public TestAbstractAuthenticationBuilder principal(@Nullable Object principal) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestingAuthenticationToken build() {
|
||||
return new TestingAuthenticationToken("user", "password", this.authorities);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -57,7 +57,11 @@ public class TestingAuthenticationTokenTests {
|
||||
AuthorityUtils.createAuthorityList("FACTOR_ONE"));
|
||||
TestingAuthenticationToken factorTwo = new TestingAuthenticationToken("bob", "ssap",
|
||||
AuthorityUtils.createAuthorityList("FACTOR_TWO"));
|
||||
TestingAuthenticationToken result = factorOne.toBuilder().apply(factorTwo).build();
|
||||
TestingAuthenticationToken result = factorOne.toBuilder()
|
||||
.authorities((a) -> a.addAll(factorTwo.getAuthorities()))
|
||||
.principal(factorTwo.getPrincipal())
|
||||
.credentials(factorTwo.getCredentials())
|
||||
.build();
|
||||
Set<String> authorities = AuthorityUtils.authorityListToSet(result.getAuthorities());
|
||||
assertThat(result.getPrincipal()).isSameAs(factorTwo.getPrincipal());
|
||||
assertThat(result.getCredentials()).isSameAs(factorTwo.getCredentials());
|
||||
|
@ -20,7 +20,6 @@ import java.util.Set;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@ -94,10 +93,14 @@ public class UsernamePasswordAuthenticationTokenTests {
|
||||
AuthorityUtils.createAuthorityList("FACTOR_ONE"));
|
||||
UsernamePasswordAuthenticationToken factorTwo = new UsernamePasswordAuthenticationToken("bob", "ssap",
|
||||
AuthorityUtils.createAuthorityList("FACTOR_TWO"));
|
||||
Authentication authentication = factorOne.toBuilder().apply(factorTwo).build();
|
||||
Set<String> authorities = AuthorityUtils.authorityListToSet(authentication.getAuthorities());
|
||||
assertThat(authentication.getPrincipal()).isEqualTo("bob");
|
||||
assertThat(authentication.getCredentials()).isEqualTo("ssap");
|
||||
UsernamePasswordAuthenticationToken result = factorOne.toBuilder()
|
||||
.authorities((a) -> a.addAll(factorTwo.getAuthorities()))
|
||||
.principal(factorTwo.getPrincipal())
|
||||
.credentials(factorTwo.getCredentials())
|
||||
.build();
|
||||
Set<String> authorities = AuthorityUtils.authorityListToSet(result.getAuthorities());
|
||||
assertThat(result.getPrincipal()).isEqualTo("bob");
|
||||
assertThat(result.getCredentials()).isEqualTo("ssap");
|
||||
assertThat(authorities).containsExactlyInAnyOrder("FACTOR_ONE", "FACTOR_TWO");
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,12 @@ class JaasAuthenticationTokenTests {
|
||||
AuthorityUtils.createAuthorityList("FACTOR_ONE"), mock(LoginContext.class));
|
||||
JaasAuthenticationToken factorTwo = new JaasAuthenticationToken("bob", "ssap",
|
||||
AuthorityUtils.createAuthorityList("FACTOR_TWO"), mock(LoginContext.class));
|
||||
JaasAuthenticationToken result = factorOne.toBuilder().apply(factorTwo).build();
|
||||
JaasAuthenticationToken result = factorOne.toBuilder()
|
||||
.authorities((a) -> a.addAll(factorTwo.getAuthorities()))
|
||||
.principal(factorTwo.getPrincipal())
|
||||
.credentials(factorTwo.getCredentials())
|
||||
.loginContext(factorTwo.getLoginContext())
|
||||
.build();
|
||||
Set<String> authorities = AuthorityUtils.authorityListToSet(result.getAuthorities());
|
||||
assertThat(result.getPrincipal()).isSameAs(factorTwo.getPrincipal());
|
||||
assertThat(result.getCredentials()).isSameAs(factorTwo.getCredentials());
|
||||
|
@ -32,7 +32,10 @@ class OneTimeTokenAuthenticationTests {
|
||||
AuthorityUtils.createAuthorityList("FACTOR_ONE"));
|
||||
OneTimeTokenAuthentication factorTwo = new OneTimeTokenAuthentication("bob",
|
||||
AuthorityUtils.createAuthorityList("FACTOR_TWO"));
|
||||
OneTimeTokenAuthentication result = factorOne.toBuilder().apply(factorTwo).build();
|
||||
OneTimeTokenAuthentication result = factorOne.toBuilder()
|
||||
.authorities((a) -> a.addAll(factorTwo.getAuthorities()))
|
||||
.principal(factorTwo.getPrincipal())
|
||||
.build();
|
||||
Set<String> authorities = AuthorityUtils.authorityListToSet(result.getAuthorities());
|
||||
assertThat(result.getPrincipal()).isSameAs(factorTwo.getPrincipal());
|
||||
assertThat(authorities).containsExactlyInAnyOrder("FACTOR_ONE", "FACTOR_TWO");
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.security.oauth2.client;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
@ -25,6 +26,7 @@ import java.util.function.Consumer;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
@ -157,7 +159,7 @@ public final class OAuth2AuthorizeRequest {
|
||||
|
||||
private static Authentication createAuthentication(final String principalName) {
|
||||
Assert.hasText(principalName, "principalName cannot be empty");
|
||||
return new AbstractAuthenticationToken(null) {
|
||||
return new AbstractAuthenticationToken((Collection<? extends GrantedAuthority>) null) {
|
||||
|
||||
@Override
|
||||
public Object getCredentials() {
|
||||
|
@ -18,6 +18,8 @@ package org.springframework.security.oauth2.client.authentication;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
@ -65,6 +67,14 @@ public class OAuth2AuthenticationToken extends AbstractAuthenticationToken {
|
||||
this.setAuthenticated(true);
|
||||
}
|
||||
|
||||
protected OAuth2AuthenticationToken(Builder<?> builder) {
|
||||
super(builder);
|
||||
Assert.notNull(builder.principal, "principal cannot be null");
|
||||
Assert.hasText(builder.authorizedClientRegistrationId, "authorizedClientRegistrationId cannot be empty");
|
||||
this.principal = builder.principal;
|
||||
this.authorizedClientRegistrationId = builder.authorizedClientRegistrationId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2User getPrincipal() {
|
||||
return this.principal;
|
||||
@ -86,8 +96,8 @@ public class OAuth2AuthenticationToken extends AbstractAuthenticationToken {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder toBuilder() {
|
||||
return new Builder().apply(this);
|
||||
public Builder<?> toBuilder() {
|
||||
return new Builder<>(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -95,34 +105,33 @@ public class OAuth2AuthenticationToken extends AbstractAuthenticationToken {
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
public static final class Builder extends AbstractAuthenticationBuilder<OAuth2AuthenticationToken, Builder> {
|
||||
public static class Builder<B extends Builder<B>> extends AbstractAuthenticationBuilder<OAuth2User, Object, B> {
|
||||
|
||||
private OAuth2User principal;
|
||||
|
||||
private String authorizedClientRegistrationId;
|
||||
|
||||
private Builder() {
|
||||
|
||||
}
|
||||
|
||||
public Builder apply(OAuth2AuthenticationToken authentication) {
|
||||
return super.apply(authentication).principal(authentication.getPrincipal())
|
||||
.authorizedClientRegistrationId(authentication.authorizedClientRegistrationId);
|
||||
}
|
||||
|
||||
public Builder principal(OAuth2User principal) {
|
||||
this.principal = principal;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder authorizedClientRegistrationId(String authorizedClientRegistrationId) {
|
||||
this.authorizedClientRegistrationId = authorizedClientRegistrationId;
|
||||
return this;
|
||||
protected Builder(OAuth2AuthenticationToken token) {
|
||||
super(token);
|
||||
this.principal = token.principal;
|
||||
this.authorizedClientRegistrationId = token.authorizedClientRegistrationId;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OAuth2AuthenticationToken build(Collection<GrantedAuthority> authorities) {
|
||||
return new OAuth2AuthenticationToken(this.principal, authorities, this.authorizedClientRegistrationId);
|
||||
public B principal(@Nullable OAuth2User principal) {
|
||||
Assert.notNull(principal, "principal cannot be null");
|
||||
this.principal = principal;
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
public B authorizedClientRegistrationId(String authorizedClientRegistrationId) {
|
||||
this.authorizedClientRegistrationId = authorizedClientRegistrationId;
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2AuthenticationToken build() {
|
||||
return new OAuth2AuthenticationToken(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.security.oauth2.client.web.reactive.function.client;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
@ -36,6 +37,7 @@ import org.springframework.http.HttpStatusCode;
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.authentication.AnonymousAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||
@ -551,7 +553,7 @@ public final class ServletOAuth2AuthorizedClientExchangeFilterFunction implement
|
||||
|
||||
private static Authentication createAuthentication(final String principalName) {
|
||||
Assert.hasText(principalName, "principalName cannot be empty");
|
||||
return new AbstractAuthenticationToken(null) {
|
||||
return new AbstractAuthenticationToken((Collection<? extends GrantedAuthority>) null) {
|
||||
|
||||
@Override
|
||||
public Object getCredentials() {
|
||||
|
@ -91,7 +91,11 @@ public class OAuth2AuthenticationTokenTests {
|
||||
AuthorityUtils.createAuthorityList("FACTOR_ONE"), "alice");
|
||||
OAuth2AuthenticationToken factorTwo = new OAuth2AuthenticationToken(TestOAuth2Users.create(),
|
||||
AuthorityUtils.createAuthorityList("FACTOR_TWO"), "bob");
|
||||
OAuth2AuthenticationToken result = factorOne.toBuilder().apply(factorTwo).build();
|
||||
OAuth2AuthenticationToken result = factorOne.toBuilder()
|
||||
.authorities((a) -> a.addAll(factorTwo.getAuthorities()))
|
||||
.principal(factorTwo.getPrincipal())
|
||||
.authorizedClientRegistrationId(factorTwo.getAuthorizedClientRegistrationId())
|
||||
.build();
|
||||
Set<String> authorities = AuthorityUtils.authorityListToSet(result.getAuthorities());
|
||||
assertThat(result.getPrincipal()).isSameAs(factorTwo.getPrincipal());
|
||||
assertThat(result.getAuthorizedClientRegistrationId()).isSameAs(factorTwo.getAuthorizedClientRegistrationId());
|
||||
|
@ -19,6 +19,8 @@ package org.springframework.security.oauth2.server.resource.authentication;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
@ -83,6 +85,15 @@ public abstract class AbstractOAuth2TokenAuthenticationToken<T extends OAuth2Tok
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
protected AbstractOAuth2TokenAuthenticationToken(AbstractOAuth2TokenAuthenticationBuilder<T, ?> builder) {
|
||||
super(builder);
|
||||
Assert.notNull(builder.credentials, "token cannot be null");
|
||||
Assert.notNull(builder.principal, "principal cannot be null");
|
||||
this.principal = builder.principal;
|
||||
this.credentials = builder.credentials;
|
||||
this.token = builder.token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrincipal() {
|
||||
return this.principal;
|
||||
@ -106,4 +117,47 @@ public abstract class AbstractOAuth2TokenAuthenticationToken<T extends OAuth2Tok
|
||||
*/
|
||||
public abstract Map<String, Object> getTokenAttributes();
|
||||
|
||||
/**
|
||||
* A builder preserving the concrete {@link Authentication} type
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
public abstract static class AbstractOAuth2TokenAuthenticationBuilder<T extends OAuth2Token, B extends AbstractOAuth2TokenAuthenticationBuilder<T, B>>
|
||||
extends AbstractAuthenticationBuilder<Object, Object, B> {
|
||||
|
||||
private Object principal;
|
||||
|
||||
private Object credentials;
|
||||
|
||||
private T token;
|
||||
|
||||
protected AbstractOAuth2TokenAuthenticationBuilder(AbstractOAuth2TokenAuthenticationToken<T> token) {
|
||||
super(token);
|
||||
this.principal = token.getPrincipal();
|
||||
this.credentials = token.getCredentials();
|
||||
this.token = token.getToken();
|
||||
}
|
||||
|
||||
@Override
|
||||
public B principal(@Nullable Object principal) {
|
||||
Assert.notNull(principal, "principal cannot be null");
|
||||
this.principal = principal;
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public B credentials(@Nullable Object credentials) {
|
||||
Assert.notNull(credentials, "credentials cannot be null");
|
||||
this.credentials = credentials;
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
public B token(T token) {
|
||||
Assert.notNull(token, "credentials cannot be null");
|
||||
this.token = token;
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,6 +21,8 @@ import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.Transient;
|
||||
@ -57,14 +59,19 @@ public class BearerTokenAuthentication extends AbstractOAuth2TokenAuthentication
|
||||
setAuthenticated(true);
|
||||
}
|
||||
|
||||
protected BearerTokenAuthentication(Builder<?> builder) {
|
||||
super(builder);
|
||||
this.attributes = Collections.unmodifiableMap(new LinkedHashMap<>(builder.attributes));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getTokenAttributes() {
|
||||
return this.attributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder toBuilder() {
|
||||
return new Builder().apply(this);
|
||||
public Builder<?> toBuilder() {
|
||||
return new Builder<>(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -72,34 +79,34 @@ public class BearerTokenAuthentication extends AbstractOAuth2TokenAuthentication
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
public static final class Builder extends AbstractAuthenticationBuilder<BearerTokenAuthentication, Builder> {
|
||||
public static class Builder<B extends Builder<B>>
|
||||
extends AbstractOAuth2TokenAuthenticationBuilder<OAuth2AccessToken, B> {
|
||||
|
||||
private OAuth2AuthenticatedPrincipal principal;
|
||||
private Map<String, Object> attributes;
|
||||
|
||||
private OAuth2AccessToken token;
|
||||
|
||||
private Builder() {
|
||||
|
||||
}
|
||||
|
||||
public Builder apply(BearerTokenAuthentication authentication) {
|
||||
return super.apply(authentication).principal((OAuth2AuthenticatedPrincipal) authentication.getPrincipal())
|
||||
.credentials(authentication.getToken());
|
||||
}
|
||||
|
||||
public Builder principal(OAuth2AuthenticatedPrincipal principal) {
|
||||
this.principal = principal;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder credentials(OAuth2AccessToken credentials) {
|
||||
this.token = credentials;
|
||||
return this;
|
||||
protected Builder(BearerTokenAuthentication token) {
|
||||
super(token);
|
||||
this.attributes = token.getTokenAttributes();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BearerTokenAuthentication build(Collection<GrantedAuthority> authorities) {
|
||||
return new BearerTokenAuthentication(this.principal, this.token, authorities);
|
||||
public B principal(@Nullable Object principal) {
|
||||
Assert.isInstanceOf(OAuth2AuthenticatedPrincipal.class, principal,
|
||||
"principal must be of type OAuth2AuthenticatedPrincipal");
|
||||
this.attributes = ((OAuth2AuthenticatedPrincipal) principal).getAttributes();
|
||||
return super.principal(principal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public B token(OAuth2AccessToken token) {
|
||||
Assert.isTrue(token.getTokenType() == OAuth2AccessToken.TokenType.BEARER,
|
||||
"credentials must be a bearer token");
|
||||
return super.token(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BearerTokenAuthentication build() {
|
||||
return new BearerTokenAuthentication(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -72,6 +72,11 @@ public class JwtAuthenticationToken extends AbstractOAuth2TokenAuthenticationTok
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
protected JwtAuthenticationToken(Builder<?> builder) {
|
||||
super(builder);
|
||||
this.name = builder.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getTokenAttributes() {
|
||||
return this.getToken().getClaims();
|
||||
@ -86,8 +91,8 @@ public class JwtAuthenticationToken extends AbstractOAuth2TokenAuthenticationTok
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder toBuilder() {
|
||||
return new Builder().apply(this);
|
||||
public Builder<?> toBuilder() {
|
||||
return new Builder<>(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -95,33 +100,23 @@ public class JwtAuthenticationToken extends AbstractOAuth2TokenAuthenticationTok
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
public static final class Builder extends AbstractAuthenticationBuilder<JwtAuthenticationToken, Builder> {
|
||||
|
||||
private Jwt jwt;
|
||||
public static class Builder<B extends Builder<B>> extends AbstractOAuth2TokenAuthenticationBuilder<Jwt, B> {
|
||||
|
||||
private String name;
|
||||
|
||||
private Builder() {
|
||||
|
||||
protected Builder(JwtAuthenticationToken token) {
|
||||
super(token);
|
||||
this.name = token.getName();
|
||||
}
|
||||
|
||||
public Builder apply(JwtAuthenticationToken token) {
|
||||
return super.apply(token).jwt(token.getToken()).name(token.getName());
|
||||
}
|
||||
|
||||
public Builder jwt(Jwt jwt) {
|
||||
this.jwt = jwt;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder name(String name) {
|
||||
public B name(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JwtAuthenticationToken build(Collection<GrantedAuthority> authorities) {
|
||||
return new JwtAuthenticationToken(this.jwt, authorities, this.name);
|
||||
public JwtAuthenticationToken build() {
|
||||
return new JwtAuthenticationToken(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -180,6 +180,12 @@ public class BearerTokenAuthenticationFilter extends OncePerRequestFilter {
|
||||
BearerTokenError error = BearerTokenErrors.invalidToken("Invalid bearer token");
|
||||
throw new OAuth2AuthenticationException(error);
|
||||
}
|
||||
Authentication current = this.securityContextHolderStrategy.getContext().getAuthentication();
|
||||
if (current != null && current.isAuthenticated()) {
|
||||
authenticationResult = authenticationResult.toBuilder()
|
||||
.authorities((a) -> a.addAll(current.getAuthorities()))
|
||||
.build();
|
||||
}
|
||||
SecurityContext context = this.securityContextHolderStrategy.createEmptyContext();
|
||||
context.setAuthentication(authenticationResult);
|
||||
this.securityContextHolderStrategy.setContext(context);
|
||||
|
@ -162,7 +162,11 @@ public class BearerTokenAuthenticationTests {
|
||||
new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, "nekot", Instant.now(),
|
||||
Instant.now().plusSeconds(3600)),
|
||||
AuthorityUtils.createAuthorityList("FACTOR_TWO"));
|
||||
BearerTokenAuthentication authentication = factorOne.toBuilder().apply(factorTwo).build();
|
||||
BearerTokenAuthentication authentication = factorOne.toBuilder()
|
||||
.authorities((a) -> a.addAll(factorTwo.getAuthorities()))
|
||||
.principal(factorTwo.getPrincipal())
|
||||
.token(factorTwo.getToken())
|
||||
.build();
|
||||
Set<String> authorities = AuthorityUtils.authorityListToSet(authentication.getAuthorities());
|
||||
assertThat(authentication.getPrincipal()).isSameAs(factorTwo.getPrincipal());
|
||||
assertThat(authentication.getToken()).isSameAs(factorTwo.getToken());
|
||||
|
@ -55,7 +55,7 @@ public class JwtAuthenticationTokenTests {
|
||||
|
||||
@Test
|
||||
public void constructorWhenJwtIsNullThenThrowsException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new JwtAuthenticationToken(null))
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new JwtAuthenticationToken((Jwt) null))
|
||||
.withMessageContaining("token cannot be null");
|
||||
}
|
||||
|
||||
@ -122,7 +122,11 @@ public class JwtAuthenticationTokenTests {
|
||||
AuthorityUtils.createAuthorityList("FACTOR_ONE"), "alice");
|
||||
JwtAuthenticationToken factorTwo = new JwtAuthenticationToken(builder().claim("d", "w").build(),
|
||||
AuthorityUtils.createAuthorityList("FACTOR_TWO"), "bob");
|
||||
JwtAuthenticationToken result = factorOne.toBuilder().apply(factorTwo).build();
|
||||
JwtAuthenticationToken result = factorOne.toBuilder()
|
||||
.authorities((a) -> a.addAll(factorTwo.getAuthorities()))
|
||||
.principal(factorTwo.getPrincipal())
|
||||
.name(factorTwo.getName())
|
||||
.build();
|
||||
Set<String> authorities = AuthorityUtils.authorityListToSet(result.getAuthorities());
|
||||
assertThat(result.getPrincipal()).isSameAs(factorTwo.getPrincipal());
|
||||
assertThat(result.getName()).isSameAs(factorTwo.getName());
|
||||
|
@ -18,7 +18,9 @@ package org.springframework.security.oauth2.server.resource.web.authentication;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import jakarta.servlet.Filter;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@ -37,8 +39,11 @@ import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.AuthenticationManagerResolver;
|
||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||
import org.springframework.security.core.context.SecurityContextImpl;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
@ -240,6 +245,7 @@ public class BearerTokenAuthenticationFilterTests {
|
||||
new BearerTokenAuthenticationFilter(this.authenticationManager));
|
||||
SecurityContextHolderStrategy strategy = mock(SecurityContextHolderStrategy.class);
|
||||
given(strategy.createEmptyContext()).willReturn(new SecurityContextImpl());
|
||||
given(strategy.getContext()).willReturn(new SecurityContextImpl());
|
||||
filter.setSecurityContextHolderStrategy(strategy);
|
||||
filter.doFilter(this.request, this.response, this.filterChain);
|
||||
verify(strategy).setContext(any());
|
||||
@ -339,6 +345,23 @@ public class BearerTokenAuthenticationFilterTests {
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
void authenticateWhenPreviousAuthenticationThenApplies() throws Exception {
|
||||
Authentication first = new TestingAuthenticationToken("user", "pass", "FACTOR_ONE");
|
||||
Authentication second = new TestingAuthenticationToken("user", "pass", "FACTOR_TWO");
|
||||
Filter filter = addMocks(new BearerTokenAuthenticationFilter(this.authenticationManager));
|
||||
given(this.bearerTokenResolver.resolve(this.request)).willReturn("token");
|
||||
given(this.authenticationManager.authenticate(any())).willReturn(second);
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(first);
|
||||
filter.doFilter(this.request, this.response, this.filterChain);
|
||||
Authentication result = SecurityContextHolder.getContext().getAuthentication();
|
||||
SecurityContextHolder.clearContext();
|
||||
|
||||
Set<String> authorities = AuthorityUtils.authorityListToSet(result.getAuthorities());
|
||||
assertThat(authorities).containsExactlyInAnyOrder("FACTOR_ONE", "FACTOR_TWO");
|
||||
}
|
||||
|
||||
private BearerTokenAuthenticationFilter addMocks(BearerTokenAuthenticationFilter filter) {
|
||||
filter.setAuthenticationEntryPoint(this.authenticationEntryPoint);
|
||||
filter.setBearerTokenResolver(this.bearerTokenResolver);
|
||||
|
@ -19,10 +19,11 @@ package org.springframework.security.saml2.provider.service.authentication;
|
||||
import java.io.Serial;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An authentication based off of a SAML 2.0 Assertion
|
||||
@ -56,6 +57,12 @@ public class Saml2AssertionAuthentication extends Saml2Authentication {
|
||||
setAuthenticated(true);
|
||||
}
|
||||
|
||||
protected Saml2AssertionAuthentication(Builder<?> builder) {
|
||||
super(builder);
|
||||
this.assertion = builder.assertion;
|
||||
this.relyingPartyRegistrationId = builder.relyingPartyRegistrationId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Saml2ResponseAssertionAccessor getCredentials() {
|
||||
return this.assertion;
|
||||
@ -66,8 +73,8 @@ public class Saml2AssertionAuthentication extends Saml2Authentication {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder toBuilder() {
|
||||
return new Builder().apply(this);
|
||||
public Builder<?> toBuilder() {
|
||||
return new Builder<>(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -75,44 +82,35 @@ public class Saml2AssertionAuthentication extends Saml2Authentication {
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
public static final class Builder
|
||||
extends AbstractAuthenticationBuilder<@NonNull Saml2AssertionAuthentication, @NonNull Builder> {
|
||||
|
||||
private Object principal;
|
||||
public static class Builder<B extends Builder<B>>
|
||||
extends Saml2Authentication.Builder<Saml2ResponseAssertionAccessor, B> {
|
||||
|
||||
private Saml2ResponseAssertionAccessor assertion;
|
||||
|
||||
private String relyingPartyRegistrationId;
|
||||
|
||||
private Builder() {
|
||||
|
||||
}
|
||||
|
||||
public Builder apply(Saml2AssertionAuthentication authentication) {
|
||||
return super.apply(authentication).principal(authentication.getPrincipal())
|
||||
.assertion(authentication.assertion)
|
||||
.relyingPartyRegistrationId(authentication.relyingPartyRegistrationId);
|
||||
}
|
||||
|
||||
public Builder principal(Object principal) {
|
||||
this.principal = principal;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder assertion(Saml2ResponseAssertionAccessor assertion) {
|
||||
this.assertion = assertion;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder relyingPartyRegistrationId(String relyingPartyRegistrationId) {
|
||||
this.relyingPartyRegistrationId = relyingPartyRegistrationId;
|
||||
return this;
|
||||
protected Builder(Saml2AssertionAuthentication token) {
|
||||
super(token);
|
||||
this.assertion = token.assertion;
|
||||
this.relyingPartyRegistrationId = token.relyingPartyRegistrationId;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Saml2AssertionAuthentication build(Collection<GrantedAuthority> authorities) {
|
||||
return new Saml2AssertionAuthentication(this.principal, this.assertion, authorities,
|
||||
this.relyingPartyRegistrationId);
|
||||
public B credentials(@Nullable Saml2ResponseAssertionAccessor credentials) {
|
||||
saml2Response(credentials.getResponseValue());
|
||||
Assert.notNull(credentials, "assertion cannot be null");
|
||||
this.assertion = credentials;
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
public B relyingPartyRegistrationId(String relyingPartyRegistrationId) {
|
||||
this.relyingPartyRegistrationId = relyingPartyRegistrationId;
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Saml2AssertionAuthentication build() {
|
||||
return new Saml2AssertionAuthentication(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,6 +19,8 @@ package org.springframework.security.saml2.provider.service.authentication;
|
||||
import java.io.Serial;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.core.AuthenticatedPrincipal;
|
||||
import org.springframework.security.core.Authentication;
|
||||
@ -69,6 +71,12 @@ public class Saml2Authentication extends AbstractAuthenticationToken {
|
||||
setAuthenticated(true);
|
||||
}
|
||||
|
||||
Saml2Authentication(Builder<?, ?> builder) {
|
||||
super(builder);
|
||||
this.principal = builder.principal;
|
||||
this.saml2Response = builder.saml2Response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrincipal() {
|
||||
return this.principal;
|
||||
@ -87,4 +95,29 @@ public class Saml2Authentication extends AbstractAuthenticationToken {
|
||||
return getSaml2Response();
|
||||
}
|
||||
|
||||
abstract static class Builder<C, B extends Builder<C, B>> extends AbstractAuthenticationBuilder<Object, C, B> {
|
||||
|
||||
private Object principal;
|
||||
|
||||
String saml2Response;
|
||||
|
||||
Builder(Saml2Authentication token) {
|
||||
super(token);
|
||||
this.principal = token.principal;
|
||||
this.saml2Response = token.saml2Response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public B principal(@Nullable Object principal) {
|
||||
Assert.notNull(principal, "principal cannot be null");
|
||||
this.principal = principal;
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
void saml2Response(String saml2Response) {
|
||||
this.saml2Response = saml2Response;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -33,7 +33,12 @@ class Saml2AssertionAuthenticationTests {
|
||||
prototype.nameId("alice").build(), AuthorityUtils.createAuthorityList("FACTOR_ONE"), "alice");
|
||||
Saml2AssertionAuthentication factorTwo = new Saml2AssertionAuthentication("bob",
|
||||
prototype.nameId("alice").build(), AuthorityUtils.createAuthorityList("FACTOR_TWO"), "bob");
|
||||
Saml2AssertionAuthentication result = factorOne.toBuilder().apply(factorTwo).build();
|
||||
Saml2AssertionAuthentication result = factorOne.toBuilder()
|
||||
.authorities((a) -> a.addAll(factorTwo.getAuthorities()))
|
||||
.principal(factorTwo.getPrincipal())
|
||||
.credentials(factorTwo.getCredentials())
|
||||
.relyingPartyRegistrationId(factorTwo.getRelyingPartyRegistrationId())
|
||||
.build();
|
||||
Set<String> authorities = AuthorityUtils.authorityListToSet(result.getAuthorities());
|
||||
assertThat(result.getPrincipal()).isSameAs(factorTwo.getPrincipal());
|
||||
assertThat(result.getCredentials()).isSameAs(factorTwo.getCredentials());
|
||||
|
@ -23,6 +23,7 @@ import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.security.core.Authentication} implementation for
|
||||
@ -47,7 +48,7 @@ public class PreAuthenticatedAuthenticationToken extends AbstractAuthenticationT
|
||||
* @param aCredentials The pre-authenticated credentials
|
||||
*/
|
||||
public PreAuthenticatedAuthenticationToken(Object aPrincipal, @Nullable Object aCredentials) {
|
||||
super(null);
|
||||
super((Collection<? extends GrantedAuthority>) null);
|
||||
this.principal = aPrincipal;
|
||||
this.credentials = aCredentials;
|
||||
}
|
||||
@ -67,6 +68,12 @@ public class PreAuthenticatedAuthenticationToken extends AbstractAuthenticationT
|
||||
setAuthenticated(true);
|
||||
}
|
||||
|
||||
protected PreAuthenticatedAuthenticationToken(Builder<?> builder) {
|
||||
super(builder);
|
||||
this.principal = builder.principal;
|
||||
this.credentials = builder.credentials;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the credentials
|
||||
*/
|
||||
@ -84,8 +91,8 @@ public class PreAuthenticatedAuthenticationToken extends AbstractAuthenticationT
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder toBuilder() {
|
||||
return new Builder().apply(this);
|
||||
public Builder<?> toBuilder() {
|
||||
return new Builder<>(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -93,34 +100,34 @@ public class PreAuthenticatedAuthenticationToken extends AbstractAuthenticationT
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
public static final class Builder
|
||||
extends AbstractAuthenticationBuilder<PreAuthenticatedAuthenticationToken, Builder> {
|
||||
public static class Builder<B extends Builder<B>> extends AbstractAuthenticationBuilder<Object, Object, B> {
|
||||
|
||||
private Object principal;
|
||||
|
||||
private Object credentials;
|
||||
private @Nullable Object credentials;
|
||||
|
||||
private Builder() {
|
||||
|
||||
}
|
||||
|
||||
public Builder apply(PreAuthenticatedAuthenticationToken token) {
|
||||
return super.apply(token).principal(token.getPrincipal()).credentials(token.getCredentials());
|
||||
}
|
||||
|
||||
public Builder principal(Object principal) {
|
||||
this.principal = principal;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder credentials(Object credentials) {
|
||||
this.credentials = credentials;
|
||||
return this;
|
||||
protected Builder(PreAuthenticatedAuthenticationToken token) {
|
||||
super(token);
|
||||
this.principal = token.principal;
|
||||
this.credentials = token.credentials;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PreAuthenticatedAuthenticationToken build(Collection<GrantedAuthority> authorities) {
|
||||
return new PreAuthenticatedAuthenticationToken(this.principal, this.credentials, authorities);
|
||||
public B principal(@Nullable Object principal) {
|
||||
Assert.notNull(principal, "principal cannot be null");
|
||||
this.principal = principal;
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public B credentials(@Nullable Object credentials) {
|
||||
this.credentials = credentials;
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreAuthenticatedAuthenticationToken build() {
|
||||
return new PreAuthenticatedAuthenticationToken(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -80,7 +80,11 @@ public class PreAuthenticatedAuthenticationTokenTests {
|
||||
AuthorityUtils.createAuthorityList("FACTOR_ONE"));
|
||||
PreAuthenticatedAuthenticationToken factorTwo = new PreAuthenticatedAuthenticationToken("bob", "ssap",
|
||||
AuthorityUtils.createAuthorityList("FACTOR_TWO"));
|
||||
PreAuthenticatedAuthenticationToken result = factorOne.toBuilder().apply(factorTwo).build();
|
||||
PreAuthenticatedAuthenticationToken result = factorOne.toBuilder()
|
||||
.authorities((a) -> a.addAll(factorTwo.getAuthorities()))
|
||||
.principal(factorTwo.getPrincipal())
|
||||
.credentials(factorTwo.getCredentials())
|
||||
.build();
|
||||
Set<String> authorities = AuthorityUtils.authorityListToSet(result.getAuthorities());
|
||||
assertThat(result.getPrincipal()).isSameAs(factorTwo.getPrincipal());
|
||||
assertThat(result.getCredentials()).isSameAs(factorTwo.getCredentials());
|
||||
|
@ -21,6 +21,7 @@ import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import jakarta.servlet.Filter;
|
||||
@ -46,6 +47,7 @@ import org.springframework.security.authentication.TestAuthentication;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.Transient;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
@ -810,7 +812,7 @@ public class HttpSessionSecurityContextRepositoryTests {
|
||||
private static class SomeTransientAuthentication extends AbstractAuthenticationToken {
|
||||
|
||||
SomeTransientAuthentication() {
|
||||
super(null);
|
||||
super((Collection<? extends GrantedAuthority>) null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -840,7 +842,7 @@ public class HttpSessionSecurityContextRepositoryTests {
|
||||
private static class SomeOtherTransientAuthentication extends AbstractAuthenticationToken {
|
||||
|
||||
SomeOtherTransientAuthentication() {
|
||||
super(null);
|
||||
super((Collection<? extends GrantedAuthority>) null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -49,6 +49,11 @@ public class WebAuthnAuthentication extends AbstractAuthenticationToken {
|
||||
super.setAuthenticated(true);
|
||||
}
|
||||
|
||||
private WebAuthnAuthentication(Builder<?> builder) {
|
||||
super(builder);
|
||||
this.principal = builder.principal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuthenticated(boolean authenticated) {
|
||||
Assert.isTrue(!authenticated, "Cannot set this token to trusted");
|
||||
@ -71,8 +76,8 @@ public class WebAuthnAuthentication extends AbstractAuthenticationToken {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder toBuilder() {
|
||||
return new Builder().apply(this);
|
||||
public Builder<?> toBuilder() {
|
||||
return new Builder<>(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -80,26 +85,25 @@ public class WebAuthnAuthentication extends AbstractAuthenticationToken {
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
public static final class Builder extends AbstractAuthenticationBuilder<WebAuthnAuthentication, Builder> {
|
||||
public static final class Builder<B extends Builder<B>>
|
||||
extends AbstractAuthenticationBuilder<PublicKeyCredentialUserEntity, Object, B> {
|
||||
|
||||
private PublicKeyCredentialUserEntity principal;
|
||||
|
||||
private Builder() {
|
||||
|
||||
}
|
||||
|
||||
public Builder apply(WebAuthnAuthentication authentication) {
|
||||
return super.apply(authentication).principal(authentication.getPrincipal());
|
||||
}
|
||||
|
||||
public Builder principal(PublicKeyCredentialUserEntity principal) {
|
||||
this.principal = principal;
|
||||
return this;
|
||||
private Builder(WebAuthnAuthentication token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected WebAuthnAuthentication build(Collection<GrantedAuthority> authorities) {
|
||||
return new WebAuthnAuthentication(this.principal, authorities);
|
||||
public B principal(@Nullable PublicKeyCredentialUserEntity principal) {
|
||||
Assert.notNull(principal, "principal cannot be null");
|
||||
this.principal = principal;
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebAuthnAuthentication build() {
|
||||
return new WebAuthnAuthentication(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -64,7 +64,10 @@ class WebAuthnAuthenticationTests {
|
||||
PublicKeyCredentialUserEntity bob = TestPublicKeyCredentialUserEntities.userEntity().build();
|
||||
WebAuthnAuthentication factorTwo = new WebAuthnAuthentication(bob,
|
||||
AuthorityUtils.createAuthorityList("FACTOR_TWO"));
|
||||
WebAuthnAuthentication result = factorOne.toBuilder().apply(factorTwo).build();
|
||||
WebAuthnAuthentication result = factorOne.toBuilder()
|
||||
.authorities((a) -> a.addAll(factorTwo.getAuthorities()))
|
||||
.principal(factorTwo.getPrincipal())
|
||||
.build();
|
||||
Set<String> authorities = AuthorityUtils.authorityListToSet(result.getAuthorities());
|
||||
assertThat(result.getPrincipal()).isSameAs(factorTwo.getPrincipal());
|
||||
assertThat(authorities).containsExactlyInAnyOrder("FACTOR_ONE", "FACTOR_TWO");
|
||||
|
Loading…
x
Reference in New Issue
Block a user