1
0
mirror of synced 2026-05-22 13:23:17 +00:00

Add Missing Serialization Support

Closes gh-19013

Signed-off-by: Josh Cummings <3627351+jzheaux@users.noreply.github.com>
This commit is contained in:
Josh Cummings
2026-03-31 15:54:49 -06:00
parent 43b132bec6
commit d4678c8e04
32 changed files with 134 additions and 3 deletions
@@ -48,6 +48,7 @@ import org.springframework.security.jackson.SecurityJacksonModules;
* @since 7.0
* @see SecurityJacksonModules
*/
@SuppressWarnings("serial")
public class CasJacksonModule extends SecurityJacksonModule {
public CasJacksonModule() {
@@ -20,6 +20,7 @@ import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.security.Principal;
import java.time.Duration;
import java.time.Instant;
import java.util.Collection;
import java.util.Date;
@@ -85,6 +86,9 @@ import org.springframework.security.authentication.password.CompromisedPasswordE
import org.springframework.security.authorization.AuthorityAuthorizationDecision;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationDeniedException;
import org.springframework.security.authorization.FactorAuthorizationDecision;
import org.springframework.security.authorization.RequiredFactor;
import org.springframework.security.authorization.RequiredFactorError;
import org.springframework.security.authorization.event.AuthorizationEvent;
import org.springframework.security.authorization.event.AuthorizationGrantedEvent;
import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;
@@ -161,6 +165,7 @@ import org.springframework.security.oauth2.jwt.JwtException;
import org.springframework.security.oauth2.jwt.JwtValidationException;
import org.springframework.security.oauth2.jwt.TestJwts;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationCode;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsent;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationServerMetadata;
import org.springframework.security.oauth2.server.authorization.OAuth2ClientRegistration;
@@ -168,15 +173,22 @@ import org.springframework.security.oauth2.server.authorization.OAuth2TokenIntro
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
import org.springframework.security.oauth2.server.authorization.TestOAuth2Authorizations;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AccessTokenAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeRequestAuthenticationException;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeRequestAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationConsentAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationGrantAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientCredentialsAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientRegistrationAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2DeviceAuthorizationConsentAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2DeviceAuthorizationRequestAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2DeviceCodeAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2DeviceVerificationAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2PushedAuthorizationRequestAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2RefreshTokenAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenExchangeActor;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenExchangeAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenExchangeCompositeAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenIntrospectionAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenRevocationAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
@@ -190,6 +202,7 @@ import org.springframework.security.oauth2.server.authorization.settings.Authori
import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
import org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat;
import org.springframework.security.oauth2.server.authorization.settings.TokenSettings;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenClaimNames;
import org.springframework.security.oauth2.server.resource.BearerTokenError;
import org.springframework.security.oauth2.server.resource.BearerTokenErrors;
import org.springframework.security.oauth2.server.resource.InvalidBearerTokenException;
@@ -429,6 +442,8 @@ final class SerializationSamples {
generatorByClassName.put(RegisteredClient.class, (r) -> registeredClient);
generatorByClassName.put(OAuth2Authorization.class, (r) -> authorization);
generatorByClassName.put(OAuth2Authorization.Token.class, (r) -> authorization.getAccessToken());
generatorByClassName.put(OAuth2AuthorizationCode.class,
(r) -> new OAuth2AuthorizationCode("code", Instant.now(), Instant.now().plusSeconds(300)));
generatorByClassName.put(OAuth2AuthorizationConsent.class,
(r) -> OAuth2AuthorizationConsent.withId("registeredClientId", "principalName")
.scope("scope1")
@@ -454,6 +469,58 @@ final class SerializationSamples {
authenticationToken.setDetails(details);
return authenticationToken;
});
generatorByClassName.put(
org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeAuthenticationToken.class,
(r) -> {
org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeAuthenticationToken token = new org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeAuthenticationToken(
"code", principal, "https://localhost/callback", Map.of("custom_param", "custom_value"));
token.setDetails(details);
return token;
});
generatorByClassName.put(OAuth2AuthorizationCodeRequestAuthenticationException.class, (r) -> {
OAuth2AuthorizationCodeRequestAuthenticationToken authToken = new OAuth2AuthorizationCodeRequestAuthenticationToken(
"https://localhost/authorize", "clientId", principal, "https://localhost/callback", "state",
authorizationRequest.getScopes(), authorizationRequest.getAdditionalParameters());
return new OAuth2AuthorizationCodeRequestAuthenticationException(
new OAuth2Error("invalid_request", "Missing required parameter", "https://example.com/error"),
authToken);
});
generatorByClassName.put(OAuth2ClientCredentialsAuthenticationToken.class, (r) -> {
OAuth2ClientCredentialsAuthenticationToken token = new OAuth2ClientCredentialsAuthenticationToken(principal,
Set.of("scope1", "scope2"), Map.of("custom_param", "custom_value"));
token.setDetails(details);
return token;
});
generatorByClassName.put(OAuth2DeviceCodeAuthenticationToken.class, (r) -> {
OAuth2DeviceCodeAuthenticationToken token = new OAuth2DeviceCodeAuthenticationToken("device-code",
principal, Map.of("custom_param", "custom_value"));
token.setDetails(details);
return token;
});
generatorByClassName.put(OAuth2RefreshTokenAuthenticationToken.class, (r) -> {
OAuth2RefreshTokenAuthenticationToken token = new OAuth2RefreshTokenAuthenticationToken("refresh-token",
principal, Set.of("scope1", "scope2"), Map.of("custom_param", "custom_value"));
token.setDetails(details);
return token;
});
generatorByClassName.put(OAuth2TokenExchangeAuthenticationToken.class, (r) -> {
OAuth2TokenExchangeAuthenticationToken token = new OAuth2TokenExchangeAuthenticationToken(
"urn:ietf:params:oauth:token-type:access_token", "subject-token",
"urn:ietf:params:oauth:token-type:jwt", principal, "actor-token",
"urn:ietf:params:oauth:token-type:jwt", Set.of("https://resource.example.com"), Set.of("audience"),
Set.of("scope1"), Map.of("custom_param", "custom_value"));
token.setDetails(details);
return token;
});
OAuth2TokenExchangeActor actor = new OAuth2TokenExchangeActor(Map.of(OAuth2TokenClaimNames.ISS,
"https://issuer.example.com", OAuth2TokenClaimNames.SUB, "actor-subject"));
generatorByClassName.put(OAuth2TokenExchangeActor.class, (r) -> actor);
generatorByClassName.put(OAuth2TokenExchangeCompositeAuthenticationToken.class, (r) -> {
AbstractAuthenticationToken token = new OAuth2TokenExchangeCompositeAuthenticationToken(authentication,
List.of(actor));
token.setDetails(details);
return token;
});
generatorByClassName.put(OAuth2AuthorizationConsentAuthenticationToken.class, (r) -> {
OAuth2AuthorizationConsentAuthenticationToken authenticationToken = new OAuth2AuthorizationConsentAuthenticationToken(
"authorizationUri", "clientId", principal, "state", authorizationRequest.getScopes(),
@@ -670,6 +737,12 @@ final class SerializationSamples {
generatorByClassName.put(AuthorizationDecision.class, (r) -> new AuthorizationDecision(true));
generatorByClassName.put(AuthorityAuthorizationDecision.class,
(r) -> new AuthorityAuthorizationDecision(true, AuthorityUtils.createAuthorityList("ROLE_USER")));
RequiredFactor factor = RequiredFactor.withAuthority("authority").validDuration(Duration.ofSeconds(5)).build();
generatorByClassName.put(RequiredFactor.class, (r) -> factor);
RequiredFactorError error = RequiredFactorError.createMissing(factor);
generatorByClassName.put(RequiredFactorError.class, (r) -> error);
generatorByClassName.put(FactorAuthorizationDecision.class,
(r) -> new FactorAuthorizationDecision(List.of(error)));
generatorByClassName.put(CycleInRoleHierarchyException.class, (r) -> new CycleInRoleHierarchyException());
generatorByClassName.put(AuthorizationEvent.class,
(r) -> new AuthorizationEvent(new SerializableSupplier<>(authentication), "source",
@@ -16,6 +16,7 @@
package org.springframework.security.authorization;
import java.io.Serial;
import java.util.Collections;
import java.util.List;
@@ -29,6 +30,9 @@ import org.springframework.util.Assert;
*/
public class FactorAuthorizationDecision implements AuthorizationResult {
@Serial
private static final long serialVersionUID = -245342816437885039L;
private final List<RequiredFactorError> factorErrors;
/**
@@ -16,6 +16,8 @@
package org.springframework.security.authorization;
import java.io.Serial;
import java.io.Serializable;
import java.time.Duration;
import java.util.Objects;
@@ -40,7 +42,10 @@ import org.springframework.util.Assert;
* @author Rob Winch
* @since 7.0
*/
public final class RequiredFactor {
public final class RequiredFactor implements Serializable {
@Serial
private static final long serialVersionUID = 295501208651764485L;
private final String authority;
@@ -16,6 +16,8 @@
package org.springframework.security.authorization;
import java.io.Serial;
import java.io.Serializable;
import java.util.Objects;
import org.springframework.security.core.authority.FactorGrantedAuthority;
@@ -27,7 +29,10 @@ import org.springframework.util.Assert;
* @author Rob Winch
* @since 7.0
*/
public class RequiredFactorError {
public class RequiredFactorError implements Serializable {
@Serial
private static final long serialVersionUID = 1946221547278528901L;
private final RequiredFactor requiredFactor;
@@ -16,6 +16,7 @@
package org.springframework.security.authentication;
@SuppressWarnings("serial")
public class NonBuildableAuthenticationToken extends TestingAuthenticationToken {
public NonBuildableAuthenticationToken(String user, String password, String... authorities) {
@@ -226,6 +226,7 @@ public final class InMemoryOAuth2AuthorizationService implements OAuth2Authoriza
return userCode != null && userCode.getToken().getTokenValue().equals(token);
}
@SuppressWarnings("serial")
private static final class MaxSizeHashMap<K, V> extends LinkedHashMap<K, V> {
private final int maxSize;
@@ -16,6 +16,7 @@
package org.springframework.security.oauth2.server.authorization;
import java.io.Serial;
import java.time.Instant;
import org.springframework.security.oauth2.core.AbstractOAuth2Token;
@@ -32,6 +33,9 @@ import org.springframework.security.oauth2.core.AbstractOAuth2Token;
*/
public class OAuth2AuthorizationCode extends AbstractOAuth2Token {
@Serial
private static final long serialVersionUID = 3789328028057414501L;
/**
* Constructs an {@code OAuth2AuthorizationCode} using the provided parameters.
* @param tokenValue the token value
@@ -16,6 +16,7 @@
package org.springframework.security.oauth2.server.authorization.authentication;
import java.io.Serial;
import java.util.Map;
import org.springframework.lang.Nullable;
@@ -36,6 +37,9 @@ import org.springframework.util.Assert;
*/
public class OAuth2AuthorizationCodeAuthenticationToken extends OAuth2AuthorizationGrantAuthenticationToken {
@Serial
private static final long serialVersionUID = 4629166286850598162L;
private final String code;
private final String redirectUri;
@@ -16,6 +16,8 @@
package org.springframework.security.oauth2.server.authorization.authentication;
import java.io.Serial;
import org.springframework.lang.Nullable;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
@@ -33,6 +35,9 @@ import org.springframework.security.oauth2.core.OAuth2Error;
*/
public class OAuth2AuthorizationCodeRequestAuthenticationException extends OAuth2AuthenticationException {
@Serial
private static final long serialVersionUID = -3791188557904282453L;
private final OAuth2AuthorizationCodeRequestAuthenticationToken authorizationCodeRequestAuthentication;
/**
@@ -16,6 +16,7 @@
package org.springframework.security.oauth2.server.authorization.authentication;
import java.io.Serial;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
@@ -36,6 +37,9 @@ import org.springframework.security.oauth2.core.AuthorizationGrantType;
*/
public class OAuth2ClientCredentialsAuthenticationToken extends OAuth2AuthorizationGrantAuthenticationToken {
@Serial
private static final long serialVersionUID = -220223451609576578L;
private final Set<String> scopes;
/**
@@ -16,6 +16,7 @@
package org.springframework.security.oauth2.server.authorization.authentication;
import java.io.Serial;
import java.util.Map;
import org.springframework.lang.Nullable;
@@ -34,6 +35,9 @@ import org.springframework.util.Assert;
*/
public class OAuth2DeviceCodeAuthenticationToken extends OAuth2AuthorizationGrantAuthenticationToken {
@Serial
private static final long serialVersionUID = 8364555864666204030L;
private final String deviceCode;
/**
@@ -16,6 +16,7 @@
package org.springframework.security.oauth2.server.authorization.authentication;
import java.io.Serial;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
@@ -36,6 +37,9 @@ import org.springframework.util.Assert;
*/
public class OAuth2RefreshTokenAuthenticationToken extends OAuth2AuthorizationGrantAuthenticationToken {
@Serial
private static final long serialVersionUID = 328697547826078993L;
private final String refreshToken;
private final Set<String> scopes;
@@ -16,6 +16,8 @@
package org.springframework.security.oauth2.server.authorization.authentication;
import java.io.Serial;
import java.io.Serializable;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
@@ -33,7 +35,10 @@ import org.springframework.util.Assert;
* @since 7.0
* @see OAuth2TokenExchangeCompositeAuthenticationToken
*/
public final class OAuth2TokenExchangeActor implements ClaimAccessor {
public final class OAuth2TokenExchangeActor implements ClaimAccessor, Serializable {
@Serial
private static final long serialVersionUID = -3966261411784615574L;
private final Map<String, Object> claims;
@@ -16,6 +16,7 @@
package org.springframework.security.oauth2.server.authorization.authentication;
import java.io.Serial;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
@@ -37,6 +38,9 @@ import org.springframework.util.Assert;
*/
public class OAuth2TokenExchangeAuthenticationToken extends OAuth2AuthorizationGrantAuthenticationToken {
@Serial
private static final long serialVersionUID = 2484741634669297785L;
private final String requestedTokenType;
private final String subjectToken;
@@ -16,6 +16,7 @@
package org.springframework.security.oauth2.server.authorization.authentication;
import java.io.Serial;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -35,6 +36,9 @@ import org.springframework.util.Assert;
*/
public class OAuth2TokenExchangeCompositeAuthenticationToken extends AbstractAuthenticationToken {
@Serial
private static final long serialVersionUID = 1912280308201180854L;
private final Authentication subject;
private final List<OAuth2TokenExchangeActor> actors;
@@ -154,6 +154,7 @@ public final class OAuth2AccessTokenGenerator implements OAuth2TokenGenerator<OA
this.clock = clock;
}
@SuppressWarnings("serial")
private static final class OAuth2AccessTokenClaims extends OAuth2AccessToken implements ClaimAccessor {
private final Map<String, Object> claims;
@@ -23,6 +23,7 @@ import org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames
/**
* @author Joe Grandja
*/
@SuppressWarnings("serial")
public class TestOidcAuthorizationRequest extends OAuth2AuthorizationRequest {
private final String nonce;
@@ -25,6 +25,7 @@ import org.springframework.security.core.GrantedAuthority;
* @author Rob Winch
* @since 7.0
*/
@SuppressWarnings("serial")
public class DefaultEqualsGrantedAuthority implements GrantedAuthority {
public static final String AUTHORITY = "CUSTOM_AUTHORITY";