Treat Map Method Parameter as Immutable

Closes gh-14802
This commit is contained in:
Josh Cummings 2024-04-04 14:26:26 -06:00
parent 39dbd24dcb
commit 0af0751cfd
No known key found for this signature in database
GPG Key ID: A306A51F43B8E5A5
2 changed files with 20 additions and 16 deletions

View File

@ -22,6 +22,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
@ -179,16 +180,17 @@ public class SpringOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
} }
private OAuth2AuthenticatedPrincipal convertClaimsSet(Map<String, Object> claims) { private OAuth2AuthenticatedPrincipal convertClaimsSet(Map<String, Object> claims) {
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.AUD, (k, v) -> { Map<String, Object> converted = new LinkedHashMap<>(claims);
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.AUD, (k, v) -> {
if (v instanceof String) { if (v instanceof String) {
return Collections.singletonList(v); return Collections.singletonList(v);
} }
return v; return v;
}); });
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.CLIENT_ID, (k, v) -> v.toString()); converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.CLIENT_ID, (k, v) -> v.toString());
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.EXP, converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.EXP,
(k, v) -> Instant.ofEpochSecond(((Number) v).longValue())); (k, v) -> Instant.ofEpochSecond(((Number) v).longValue()));
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.IAT, converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.IAT,
(k, v) -> Instant.ofEpochSecond(((Number) v).longValue())); (k, v) -> Instant.ofEpochSecond(((Number) v).longValue()));
// RFC-7662 page 7 directs users to RFC-7519 for defining the values of these // RFC-7662 page 7 directs users to RFC-7519 for defining the values of these
// issuer fields. // issuer fields.
@ -208,11 +210,11 @@ public class SpringOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
// may be awkward to debug, we do not want to manipulate this value. Previous // may be awkward to debug, we do not want to manipulate this value. Previous
// versions of Spring Security // versions of Spring Security
// would *only* allow valid URLs, which is not what we wish to achieve here. // would *only* allow valid URLs, which is not what we wish to achieve here.
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.ISS, (k, v) -> v.toString()); converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.ISS, (k, v) -> v.toString());
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.NBF, converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.NBF,
(k, v) -> Instant.ofEpochSecond(((Number) v).longValue())); (k, v) -> Instant.ofEpochSecond(((Number) v).longValue()));
Collection<GrantedAuthority> authorities = new ArrayList<>(); Collection<GrantedAuthority> authorities = new ArrayList<>();
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.SCOPE, (k, v) -> { converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.SCOPE, (k, v) -> {
if (v instanceof String) { if (v instanceof String) {
Collection<String> scopes = Arrays.asList(((String) v).split(" ")); Collection<String> scopes = Arrays.asList(((String) v).split(" "));
for (String scope : scopes) { for (String scope : scopes) {
@ -222,7 +224,7 @@ public class SpringOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
} }
return v; return v;
}); });
return new OAuth2IntrospectionAuthenticatedPrincipal(claims, authorities); return new OAuth2IntrospectionAuthenticatedPrincipal(converted, authorities);
} }
} }

View File

@ -22,6 +22,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
@ -136,16 +137,17 @@ public class SpringReactiveOpaqueTokenIntrospector implements ReactiveOpaqueToke
} }
private OAuth2AuthenticatedPrincipal convertClaimsSet(Map<String, Object> claims) { private OAuth2AuthenticatedPrincipal convertClaimsSet(Map<String, Object> claims) {
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.AUD, (k, v) -> { Map<String, Object> converted = new LinkedHashMap<>(claims);
converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.AUD, (k, v) -> {
if (v instanceof String) { if (v instanceof String) {
return Collections.singletonList(v); return Collections.singletonList(v);
} }
return v; return v;
}); });
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.CLIENT_ID, (k, v) -> v.toString()); converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.CLIENT_ID, (k, v) -> v.toString());
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.EXP, converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.EXP,
(k, v) -> Instant.ofEpochSecond(((Number) v).longValue())); (k, v) -> Instant.ofEpochSecond(((Number) v).longValue()));
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.IAT, converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.IAT,
(k, v) -> Instant.ofEpochSecond(((Number) v).longValue())); (k, v) -> Instant.ofEpochSecond(((Number) v).longValue()));
// RFC-7662 page 7 directs users to RFC-7519 for defining the values of these // RFC-7662 page 7 directs users to RFC-7519 for defining the values of these
// issuer fields. // issuer fields.
@ -165,11 +167,11 @@ public class SpringReactiveOpaqueTokenIntrospector implements ReactiveOpaqueToke
// may be awkward to debug, we do not want to manipulate this value. Previous // may be awkward to debug, we do not want to manipulate this value. Previous
// versions of Spring Security // versions of Spring Security
// would *only* allow valid URLs, which is not what we wish to achieve here. // would *only* allow valid URLs, which is not what we wish to achieve here.
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.ISS, (k, v) -> v.toString()); converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.ISS, (k, v) -> v.toString());
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.NBF, converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.NBF,
(k, v) -> Instant.ofEpochSecond(((Number) v).longValue())); (k, v) -> Instant.ofEpochSecond(((Number) v).longValue()));
Collection<GrantedAuthority> authorities = new ArrayList<>(); Collection<GrantedAuthority> authorities = new ArrayList<>();
claims.computeIfPresent(OAuth2TokenIntrospectionClaimNames.SCOPE, (k, v) -> { converted.computeIfPresent(OAuth2TokenIntrospectionClaimNames.SCOPE, (k, v) -> {
if (v instanceof String) { if (v instanceof String) {
Collection<String> scopes = Arrays.asList(((String) v).split(" ")); Collection<String> scopes = Arrays.asList(((String) v).split(" "));
for (String scope : scopes) { for (String scope : scopes) {
@ -179,7 +181,7 @@ public class SpringReactiveOpaqueTokenIntrospector implements ReactiveOpaqueToke
} }
return v; return v;
}); });
return new OAuth2IntrospectionAuthenticatedPrincipal(claims, authorities); return new OAuth2IntrospectionAuthenticatedPrincipal(converted, authorities);
} }
private OAuth2IntrospectionException onError(Throwable ex) { private OAuth2IntrospectionException onError(Throwable ex) {