Skip to content

Commit 8368d84

Browse files
committed
Support customizing Jwt claims and headers
1 parent 4fe2d52 commit 8368d84

File tree

2 files changed

+55
-9
lines changed

2 files changed

+55
-9
lines changed

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

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.util.Set;
2626
import java.util.UUID;
2727
import java.util.concurrent.ConcurrentHashMap;
28+
import java.util.function.BiConsumer;
2829
import java.util.function.Function;
2930
import java.util.function.Supplier;
3031
import java.util.stream.Collectors;
@@ -86,6 +87,9 @@ public final class NimbusJwsEncoder implements JwtEncoder {
8687

8788
private final Function<JoseHeader, JWK> jwkSelector;
8889

90+
private BiConsumer<JoseHeader.Builder, JwtClaimsSet.Builder> jwtCustomizer = (headers, claims) -> {
91+
};
92+
8993
/**
9094
* Constructs a {@code NimbusJwsEncoder} using the provided parameters.
9195
* @param jwkSelector the {@code com.nimbusds.jose.jwk.JWK} selector
@@ -95,6 +99,17 @@ public NimbusJwsEncoder(Function<JoseHeader, JWK> jwkSelector) {
9599
this.jwkSelector = jwkSelector;
96100
}
97101

102+
/**
103+
* Sets the {@link Jwt} customizer to be provided the {@link JoseHeader.Builder} and
104+
* {@link JwtClaimsSet.Builder} allowing for further customizations.
105+
* @param jwtCustomizer the {@link Jwt} customizer to be provided the
106+
* {@link JoseHeader.Builder} and {@link JwtClaimsSet.Builder}
107+
*/
108+
public void setJwtCustomizer(BiConsumer<JoseHeader.Builder, JwtClaimsSet.Builder> jwtCustomizer) {
109+
Assert.notNull(jwtCustomizer, "jwtCustomizer cannot be null");
110+
this.jwtCustomizer = jwtCustomizer;
111+
}
112+
98113
@Override
99114
public Jwt encode(JoseHeader headers, JwtClaimsSet claims) throws JwtEncodingException {
100115
Assert.notNull(headers, "headers cannot be null");
@@ -121,18 +136,19 @@ else if (!StringUtils.hasText(jwk.getKeyID())) {
121136
});
122137

123138
// @formatter:off
124-
headers = JoseHeader.from(headers)
139+
JoseHeader.Builder headersBuilder = JoseHeader.from(headers)
125140
.type(JOSEObjectType.JWT.getType())
126-
.keyId(jwk.getKeyID())
127-
.build();
141+
.keyId(jwk.getKeyID());
142+
JwtClaimsSet.Builder claimsBuilder = JwtClaimsSet.from(claims)
143+
.id(UUID.randomUUID().toString());
128144
// @formatter:on
129-
JWSHeader jwsHeader = JWS_HEADER_CONVERTER.convert(headers);
130145

131-
// @formatter:off
132-
claims = JwtClaimsSet.from(claims)
133-
.id(UUID.randomUUID().toString())
134-
.build();
135-
// @formatter:on
146+
this.jwtCustomizer.accept(headersBuilder, claimsBuilder);
147+
148+
headers = headersBuilder.build();
149+
claims = claimsBuilder.build();
150+
151+
JWSHeader jwsHeader = JWS_HEADER_CONVERTER.convert(headers);
136152
JWTClaimsSet jwtClaimsSet = JWT_CLAIMS_SET_CONVERTER.convert(claims);
137153

138154
SignedJWT signedJwt = new SignedJWT(jwsHeader, jwtClaimsSet);

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.Arrays;
2121
import java.util.LinkedHashSet;
2222
import java.util.Set;
23+
import java.util.function.BiConsumer;
2324
import java.util.function.Function;
2425
import java.util.function.Supplier;
2526

@@ -47,6 +48,7 @@
4748
import static org.mockito.BDDMockito.willAnswer;
4849
import static org.mockito.Mockito.mock;
4950
import static org.mockito.Mockito.spy;
51+
import static org.mockito.Mockito.verify;
5052

5153
/**
5254
* Tests for {@link NimbusJwsEncoder}.
@@ -71,6 +73,12 @@ public void constructorWhenJwkSelectorNullThenThrowIllegalArgumentException() {
7173
.withMessage("jwkSelector cannot be null");
7274
}
7375

76+
@Test
77+
public void setJwtCustomizerWhenNullThenThrowIllegalArgumentException() {
78+
assertThatIllegalArgumentException().isThrownBy(() -> this.jwsEncoder.setJwtCustomizer(null))
79+
.withMessage("jwtCustomizer cannot be null");
80+
}
81+
7482
@Test
7583
public void encodeWhenHeadersNullThenThrowIllegalArgumentException() {
7684
JwtClaimsSet jwtClaimsSet = TestJwtClaimsSets.jwtClaimsSet().build();
@@ -160,6 +168,28 @@ public void encodeWhenSuccessThenDecodes() throws Exception {
160168
jwtDecoder.decode(encodedJws.getTokenValue());
161169
}
162170

171+
@Test
172+
public void encodeWhenCustomizerSetThenCalled() {
173+
// @formatter:off
174+
RSAKey rsaJwk = new RSAKey.Builder(TestKeys.DEFAULT_PUBLIC_KEY)
175+
.privateKey(TestKeys.DEFAULT_PRIVATE_KEY)
176+
.keyID("keyId")
177+
.build();
178+
// @formatter:on
179+
180+
given(this.jwkSelector.apply(any())).willReturn(rsaJwk);
181+
182+
BiConsumer<JoseHeader.Builder, JwtClaimsSet.Builder> jwtCustomizer = mock(BiConsumer.class);
183+
this.jwsEncoder.setJwtCustomizer(jwtCustomizer);
184+
185+
JoseHeader joseHeader = TestJoseHeaders.joseHeader().build();
186+
JwtClaimsSet jwtClaimsSet = TestJwtClaimsSets.jwtClaimsSet().build();
187+
188+
this.jwsEncoder.encode(joseHeader, jwtClaimsSet);
189+
190+
verify(jwtCustomizer).accept(any(JoseHeader.Builder.class), any(JwtClaimsSet.Builder.class));
191+
}
192+
163193
@Test
164194
public void defaultJwkSelectorConstructorWhenJwkSetProviderNullThenThrowIllegalArgumentException() {
165195
assertThatIllegalArgumentException().isThrownBy(() -> new NimbusJwsEncoder.DefaultJwkSelector(null))

0 commit comments

Comments
 (0)