Skip to content

Commit a4a7545

Browse files
committed
Add builder to create NimbusJwtDecoder with JwkSource
Signed-off-by: Mark Bonnekessel <[email protected]>
1 parent 07a50b4 commit a4a7545

File tree

2 files changed

+47
-6
lines changed

2 files changed

+47
-6
lines changed

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

+23-1
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,16 @@ public static SecretKeyJwtDecoderBuilder withSecretKey(SecretKey secretKey) {
261261
return new SecretKeyJwtDecoderBuilder(secretKey);
262262
}
263263

264+
/**
265+
* Use the given <a href="https://tools.ietf.org/html/rfc7517#section-5">JWK Set</a>
266+
* uri.
267+
* @param jwkSetUri the JWK Set uri to use
268+
* @return a {@link JwkSetUriJwtDecoderBuilder} for further configurations
269+
*/
270+
public static JwkSetUriJwtDecoderBuilder withJwkSource(JWKSource<SecurityContext> jwkSetUri) {
271+
return new JwkSetUriJwtDecoderBuilder(jwkSetUri);
272+
}
273+
264274
/**
265275
* A builder for creating {@link NimbusJwtDecoder} instances based on a
266276
* <a target="_blank" href="https://tools.ietf.org/html/rfc7517#section-5">JWK Set</a>
@@ -274,7 +284,7 @@ public static final class JwkSetUriJwtDecoderBuilder {
274284
private static final JOSEObjectTypeVerifier<SecurityContext> NO_TYPE_VERIFIER = (header, context) -> {
275285
};
276286

277-
private final Function<RestOperations, String> jwkSetUri;
287+
private Function<RestOperations, String> jwkSetUri;
278288

279289
private Function<JWKSource<SecurityContext>, Set<JWSAlgorithm>> defaultAlgorithms = (source) -> Set
280290
.of(JWSAlgorithm.RS256);
@@ -289,6 +299,8 @@ public static final class JwkSetUriJwtDecoderBuilder {
289299

290300
private Consumer<ConfigurableJWTProcessor<SecurityContext>> jwtProcessorCustomizer;
291301

302+
private JWKSource<SecurityContext> jwkSource;
303+
292304
private JwkSetUriJwtDecoderBuilder(String jwkSetUri) {
293305
Assert.hasText(jwkSetUri, "jwkSetUri cannot be empty");
294306
this.jwkSetUri = (rest) -> jwkSetUri;
@@ -306,6 +318,13 @@ private JwkSetUriJwtDecoderBuilder(Function<RestOperations, String> jwkSetUri,
306318
};
307319
}
308320

321+
private JwkSetUriJwtDecoderBuilder(JWKSource<SecurityContext> jwkSource) {
322+
Assert.notNull(jwkSource, "jwkSource cannot be null");
323+
this.jwkSource = jwkSource;
324+
this.jwtProcessorCustomizer = (processor) -> {
325+
};
326+
}
327+
309328
/**
310329
* Whether to use Nimbus's typ header verification. This is {@code true} by
311330
* default, however it may change to {@code false} in a future major release.
@@ -436,6 +455,9 @@ JWSKeySelector<SecurityContext> jwsKeySelector(JWKSource<SecurityContext> jwkSou
436455
}
437456

438457
JWKSource<SecurityContext> jwkSource() {
458+
if (jwkSource != null) {
459+
return jwkSource;
460+
}
439461
String jwkSetUri = this.jwkSetUri.apply(this.restOperations);
440462
return JWKSourceBuilder.create(new SpringJWKSource<>(this.restOperations, this.cache, jwkSetUri))
441463
.refreshAheadCache(false)

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

+24-5
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package org.springframework.security.oauth2.jwt;
1818

19+
import java.io.IOException;
20+
import java.net.URL;
1921
import java.security.KeyFactory;
2022
import java.security.NoSuchAlgorithmException;
2123
import java.security.PrivateKey;
@@ -35,14 +37,14 @@
3537

3638
import javax.crypto.SecretKey;
3739

38-
import com.nimbusds.jose.JOSEException;
39-
import com.nimbusds.jose.JOSEObjectType;
40-
import com.nimbusds.jose.JWSAlgorithm;
41-
import com.nimbusds.jose.JWSHeader;
42-
import com.nimbusds.jose.JWSSigner;
40+
import com.nimbusds.jose.*;
4341
import com.nimbusds.jose.crypto.MACSigner;
4442
import com.nimbusds.jose.crypto.RSASSASigner;
43+
import com.nimbusds.jose.jwk.JWKSet;
44+
import com.nimbusds.jose.jwk.source.JWKSetCacheRefreshEvaluator;
45+
import com.nimbusds.jose.jwk.source.JWKSetSource;
4546
import com.nimbusds.jose.jwk.source.JWKSource;
47+
import com.nimbusds.jose.jwk.source.JWKSourceBuilder;
4648
import com.nimbusds.jose.proc.BadJOSEException;
4749
import com.nimbusds.jose.proc.DefaultJOSEObjectTypeVerifier;
4850
import com.nimbusds.jose.proc.JWSKeySelector;
@@ -60,6 +62,7 @@
6062

6163
import org.springframework.cache.Cache;
6264
import org.springframework.cache.concurrent.ConcurrentMapCache;
65+
import org.springframework.cache.support.NoOpCache;
6366
import org.springframework.core.ParameterizedTypeReference;
6467
import org.springframework.core.convert.converter.Converter;
6568
import org.springframework.http.HttpStatus;
@@ -559,6 +562,22 @@ public void decodeWhenUsingSecretKeyWithKidThenStillUsesKey() throws Exception {
559562
// @formatter:on
560563
}
561564

565+
// gh-7056
566+
@Test
567+
public void decodeWhenUsingJwkSource() throws Exception {
568+
JWKSource<SecurityContext> source = (a, b) -> {
569+
try {
570+
return JWKSet.parse(JWK_SET).getKeys();
571+
}
572+
catch (ParseException e) {
573+
throw new RuntimeException(e);
574+
}
575+
};
576+
NimbusJwtDecoder decoder = NimbusJwtDecoder.withJwkSource(source).build();
577+
Jwt jwt = decoder.decode(SIGNED_JWT);
578+
assertThat(jwt.getClaimAsString("sub")).isEqualTo("test-subject");
579+
}
580+
562581
// gh-8730
563582
@Test
564583
public void withSecretKeyWhenUsingCustomTypeHeaderThenSuccessfullyDecodes() throws Exception {

0 commit comments

Comments
 (0)