From 4744752a1b777348e017159f2efdfaa467e373fe Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Fri, 29 Aug 2025 14:57:01 -0600 Subject: [PATCH] Add Internal Authentication Implementations This commit allows a default implementation of Authentication.Builder that performs the builder operations. In this way, authorities and other previous authentication material can still be effectively be propagated in the event a custom authentication does not implement the method. Issue gh-17861 --- .../security/core/Authentication.java | 4 +- .../core/NoopAuthenticationBuilder.java | 69 --------- .../security/core/SimpleAuthentication.java | 143 ++++++++++++++++++ 3 files changed, 145 insertions(+), 71 deletions(-) delete mode 100644 core/src/main/java/org/springframework/security/core/NoopAuthenticationBuilder.java create mode 100644 core/src/main/java/org/springframework/security/core/SimpleAuthentication.java diff --git a/core/src/main/java/org/springframework/security/core/Authentication.java b/core/src/main/java/org/springframework/security/core/Authentication.java index 4531842aab..6a46224dc8 100644 --- a/core/src/main/java/org/springframework/security/core/Authentication.java +++ b/core/src/main/java/org/springframework/security/core/Authentication.java @@ -65,7 +65,7 @@ public interface Authentication extends Principal, Serializable { * instance. *

* @return the authorities granted to the principal, or an empty collection if the - * token has not been authenticated. Never null.Saml2AssertAu + * token has not been authenticated. Never null. */ Collection getAuthorities(); @@ -144,7 +144,7 @@ public interface Authentication extends Principal, Serializable { * @since 7.0 */ default Builder toBuilder() { - return new NoopAuthenticationBuilder(this); + return new SimpleAuthentication.Builder(this); } /** diff --git a/core/src/main/java/org/springframework/security/core/NoopAuthenticationBuilder.java b/core/src/main/java/org/springframework/security/core/NoopAuthenticationBuilder.java deleted file mode 100644 index 982630c8e4..0000000000 --- a/core/src/main/java/org/springframework/security/core/NoopAuthenticationBuilder.java +++ /dev/null @@ -1,69 +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.util.Collection; -import java.util.function.Consumer; - -import org.jspecify.annotations.Nullable; - -/** - * An adapter implementation of {@link Authentication.Builder} that provides a no-op - * implementation for the principal, credentials, and authorities - * - * @author Josh Cummings - * @since 7.0 - */ -class NoopAuthenticationBuilder implements Authentication.Builder { - - private Authentication original; - - NoopAuthenticationBuilder(Authentication authentication) { - this.original = authentication; - } - - @Override - public NoopAuthenticationBuilder authenticated(boolean authenticated) { - return this; - } - - @Override - 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> authorities) { - return this; - } - - @Override - public Authentication build() { - return this.original; - } - -} diff --git a/core/src/main/java/org/springframework/security/core/SimpleAuthentication.java b/core/src/main/java/org/springframework/security/core/SimpleAuthentication.java new file mode 100644 index 0000000000..ac301a9ff9 --- /dev/null +++ b/core/src/main/java/org/springframework/security/core/SimpleAuthentication.java @@ -0,0 +1,143 @@ +/* + * 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.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 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 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 { + + private final Collection authorities = new LinkedHashSet<>(); + + private @Nullable Object principal; + + private @Nullable Object credentials; + + private @Nullable Object details; + + private boolean authenticated; + + Builder(Authentication authentication) { + 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> 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); + } + + } + +}