Skip to content

Commit b83a4c2

Browse files
committed
Polish Preserve Null Claim Values
Preserves the original behavior of ClaimTypeConverter so that its converters can maintain their default behavior of null meaning that conversion failed. Issue gh-10135
1 parent 30a1c1a commit b83a4c2

File tree

4 files changed

+24
-35
lines changed

4 files changed

+24
-35
lines changed

oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/converter/ClaimTypeConverter.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,10 @@ public Map<String, Object> convert(Map<String, Object> claims) {
5656
this.claimTypeConverters.forEach((claimName, typeConverter) -> {
5757
if (claims.containsKey(claimName)) {
5858
Object claim = claims.get(claimName);
59-
result.put(claimName, typeConverter.convert(claim));
59+
Object mappedClaim = typeConverter.convert(claim);
60+
if (mappedClaim != null) {
61+
result.put(claimName, mappedClaim);
62+
}
6063
}
6164
});
6265
return result;

oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/converter/ClaimTypeConverterTests.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,6 @@ public class ClaimTypeConverterTests {
6262

6363
private static final String JSON_OBJECT_CLAIM = "json-object-claim";
6464

65-
private static final String NULL_OBJECT_CLAIM = "null-object-claim";
66-
6765
private ClaimTypeConverter claimTypeConverter;
6866

6967
@BeforeEach
@@ -79,7 +77,6 @@ public void setup() {
7977
TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(String.class)));
8078
Converter<Object, ?> mapStringObjectConverter = getConverter(TypeDescriptor.map(Map.class,
8179
TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(Object.class)));
82-
Converter<Object, ?> nullConverter = (value) -> null;
8380
Map<String, Converter<Object, ?>> claimTypeConverters = new HashMap<>();
8481
claimTypeConverters.put(STRING_CLAIM, stringConverter);
8582
claimTypeConverters.put(BOOLEAN_CLAIM, booleanConverter);
@@ -88,7 +85,6 @@ public void setup() {
8885
claimTypeConverters.put(COLLECTION_STRING_CLAIM, collectionStringConverter);
8986
claimTypeConverters.put(LIST_STRING_CLAIM, listStringConverter);
9087
claimTypeConverters.put(MAP_STRING_OBJECT_CLAIM, mapStringObjectConverter);
91-
claimTypeConverters.put(NULL_OBJECT_CLAIM, nullConverter);
9288
this.claimTypeConverter = new ClaimTypeConverter(claimTypeConverters);
9389
}
9490

@@ -142,7 +138,6 @@ public void convertWhenAllClaimsRequireConversionThenConvertAll() throws Excepti
142138
claims.put(MAP_STRING_OBJECT_CLAIM, mapIntegerObject);
143139
claims.put(JSON_ARRAY_CLAIM, jsonArray);
144140
claims.put(JSON_OBJECT_CLAIM, jsonObject);
145-
claims.put(NULL_OBJECT_CLAIM, instant.toString());
146141
claims = this.claimTypeConverter.convert(claims);
147142
assertThat(claims.get(STRING_CLAIM)).isEqualTo("true");
148143
assertThat(claims.get(BOOLEAN_CLAIM)).isEqualTo(Boolean.TRUE);
@@ -153,7 +148,6 @@ public void convertWhenAllClaimsRequireConversionThenConvertAll() throws Excepti
153148
assertThat(claims.get(MAP_STRING_OBJECT_CLAIM)).isEqualTo(mapStringObject);
154149
assertThat(claims.get(JSON_ARRAY_CLAIM)).isEqualTo(jsonArrayListString);
155150
assertThat(claims.get(JSON_OBJECT_CLAIM)).isEqualTo(jsonObjectMap);
156-
assertThat(claims.get(NULL_OBJECT_CLAIM)).isNull();
157151
}
158152

159153
@Test

oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/MappedJwtClaimSetConverter.java

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -52,18 +52,19 @@ public final class MappedJwtClaimSetConverter implements Converter<Map<String, O
5252

5353
private final Map<String, Converter<Object, ?>> claimTypeConverters;
5454

55-
private final Converter<Map<String, Object>, Map<String, Object>> delegate;
56-
5755
/**
5856
* Constructs a {@link MappedJwtClaimSetConverter} with the provided arguments
5957
*
6058
* This will completely replace any set of default converters.
59+
*
60+
* A converter that returns {@code null} removes the claim from the claim set. A
61+
* converter that returns a non-{@code null} value adds or replaces that claim in the
62+
* claim set.
6163
* @param claimTypeConverters The {@link Map} of converters to use
6264
*/
6365
public MappedJwtClaimSetConverter(Map<String, Converter<Object, ?>> claimTypeConverters) {
6466
Assert.notNull(claimTypeConverters, "claimTypeConverters cannot be null");
6567
this.claimTypeConverters = claimTypeConverters;
66-
this.delegate = new ClaimTypeConverter(claimTypeConverters);
6768
}
6869

6970
/**
@@ -87,6 +88,10 @@ public MappedJwtClaimSetConverter(Map<String, Converter<Object, ?>> claimTypeCon
8788
*
8889
* To completely replace the underlying {@link Map} of converters, see
8990
* {@link MappedJwtClaimSetConverter#MappedJwtClaimSetConverter(Map)}.
91+
*
92+
* A converter that returns {@code null} removes the claim from the claim set. A
93+
* converter that returns a non-{@code null} value adds or replaces that claim in the
94+
* claim set.
9095
* @param claimTypeConverters
9196
* @return An instance of {@link MappedJwtClaimSetConverter} that contains the
9297
* converters provided, plus any defaults that were not overridden.
@@ -143,9 +148,16 @@ private static String convertIssuer(Object source) {
143148
@Override
144149
public Map<String, Object> convert(Map<String, Object> claims) {
145150
Assert.notNull(claims, "claims cannot be null");
146-
Map<String, Object> mappedClaims = this.delegate.convert(claims);
147-
mappedClaims = removeClaims(mappedClaims);
148-
mappedClaims = addClaims(mappedClaims);
151+
Map<String, Object> mappedClaims = new HashMap<>(claims);
152+
for (Map.Entry<String, Converter<Object, ?>> entry : this.claimTypeConverters.entrySet()) {
153+
String claimName = entry.getKey();
154+
Converter<Object, ?> converter = entry.getValue();
155+
if (converter != null) {
156+
Object claim = claims.get(claimName);
157+
Object mappedClaim = converter.convert(claim);
158+
mappedClaims.compute(claimName, (key, value) -> mappedClaim);
159+
}
160+
}
149161
Instant issuedAt = (Instant) mappedClaims.get(JwtClaimNames.IAT);
150162
Instant expiresAt = (Instant) mappedClaims.get(JwtClaimNames.EXP);
151163
if (issuedAt == null && expiresAt != null) {
@@ -154,24 +166,4 @@ public Map<String, Object> convert(Map<String, Object> claims) {
154166
return mappedClaims;
155167
}
156168

157-
private Map<String, Object> removeClaims(Map<String, Object> claims) {
158-
Map<String, Object> result = new HashMap<>();
159-
for (Map.Entry<String, Object> entry : claims.entrySet()) {
160-
if (entry.getValue() != null) {
161-
result.put(entry.getKey(), entry.getValue());
162-
}
163-
}
164-
return result;
165-
}
166-
167-
private Map<String, Object> addClaims(Map<String, Object> claims) {
168-
Map<String, Object> result = new HashMap<>(claims);
169-
for (Map.Entry<String, Converter<Object, ?>> entry : this.claimTypeConverters.entrySet()) {
170-
if (!claims.containsKey(entry.getKey()) && entry.getValue().convert(null) != null) {
171-
result.put(entry.getKey(), entry.getValue().convert(null));
172-
}
173-
}
174-
return result;
175-
}
176-
177169
}

oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/MappedJwtClaimSetConverterTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.

0 commit comments

Comments
 (0)