diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/SpringOpaqueTokenIntrospector.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/SpringOpaqueTokenIntrospector.java index 2500c3f17ec..51bf54592eb 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/SpringOpaqueTokenIntrospector.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/SpringOpaqueTokenIntrospector.java @@ -22,6 +22,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.LinkedHashMap; import java.util.Map; import org.apache.commons.logging.Log; @@ -179,16 +180,17 @@ private Map adaptToNimbusResponse(ResponseEntity claims) { - claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.AUD, (k, v) -> { + Map converted = new LinkedHashMap<>(claims); + converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.AUD, (k, v) -> { if (v instanceof String) { return Collections.singletonList(v); } return v; }); - claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.CLIENT_ID, (k, v) -> v.toString()); - claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.EXP, + converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.CLIENT_ID, (k, v) -> v.toString()); + converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.EXP, (k, v) -> Instant.ofEpochSecond(((Number) v).longValue())); - claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.IAT, + converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.IAT, (k, v) -> Instant.ofEpochSecond(((Number) v).longValue())); // RFC-7662 page 7 directs users to RFC-7519 for defining the values of these // issuer fields. @@ -208,11 +210,11 @@ private OAuth2AuthenticatedPrincipal convertClaimsSet(Map claims // may be awkward to debug, we do not want to manipulate this value. Previous // versions of Spring Security // would *only* allow valid URLs, which is not what we wish to achieve here. - claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.ISS, (k, v) -> v.toString()); - claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.NBF, + converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.ISS, (k, v) -> v.toString()); + converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.NBF, (k, v) -> Instant.ofEpochSecond(((Number) v).longValue())); Collection authorities = new ArrayList<>(); - claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.SCOPE, (k, v) -> { + converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.SCOPE, (k, v) -> { if (v instanceof String) { Collection scopes = Arrays.asList(((String) v).split(" ")); for (String scope : scopes) { @@ -222,7 +224,7 @@ private OAuth2AuthenticatedPrincipal convertClaimsSet(Map claims } return v; }); - return new OAuth2IntrospectionAuthenticatedPrincipal(claims, authorities); + return new OAuth2IntrospectionAuthenticatedPrincipal(converted, authorities); } } diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/SpringReactiveOpaqueTokenIntrospector.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/SpringReactiveOpaqueTokenIntrospector.java index 6eb86f7076e..f6b2ceb8e02 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/SpringReactiveOpaqueTokenIntrospector.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/SpringReactiveOpaqueTokenIntrospector.java @@ -22,6 +22,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.LinkedHashMap; import java.util.Map; import reactor.core.publisher.Mono; @@ -136,16 +137,17 @@ private Mono> adaptToNimbusResponse(ClientResponse responseE } private OAuth2AuthenticatedPrincipal convertClaimsSet(Map claims) { - claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.AUD, (k, v) -> { + Map converted = new LinkedHashMap<>(claims); + converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.AUD, (k, v) -> { if (v instanceof String) { return Collections.singletonList(v); } return v; }); - claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.CLIENT_ID, (k, v) -> v.toString()); - claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.EXP, + converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.CLIENT_ID, (k, v) -> v.toString()); + converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.EXP, (k, v) -> Instant.ofEpochSecond(((Number) v).longValue())); - claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.IAT, + converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.IAT, (k, v) -> Instant.ofEpochSecond(((Number) v).longValue())); // RFC-7662 page 7 directs users to RFC-7519 for defining the values of these // issuer fields. @@ -165,11 +167,11 @@ private OAuth2AuthenticatedPrincipal convertClaimsSet(Map claims // may be awkward to debug, we do not want to manipulate this value. Previous // versions of Spring Security // would *only* allow valid URLs, which is not what we wish to achieve here. - claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.ISS, (k, v) -> v.toString()); - claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.NBF, + converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.ISS, (k, v) -> v.toString()); + converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.NBF, (k, v) -> Instant.ofEpochSecond(((Number) v).longValue())); Collection authorities = new ArrayList<>(); - claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.SCOPE, (k, v) -> { + converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.SCOPE, (k, v) -> { if (v instanceof String) { Collection scopes = Arrays.asList(((String) v).split(" ")); for (String scope : scopes) { @@ -179,7 +181,7 @@ private OAuth2AuthenticatedPrincipal convertClaimsSet(Map claims } return v; }); - return new OAuth2IntrospectionAuthenticatedPrincipal(claims, authorities); + return new OAuth2IntrospectionAuthenticatedPrincipal(converted, authorities); } private OAuth2IntrospectionException onError(Throwable ex) {