Skip to content

Commit 844e4cc

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

File tree

2 files changed

+55
-10
lines changed

2 files changed

+55
-10
lines changed

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

Lines changed: 23 additions & 1 deletion
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 (this.jwkSource != null) {
459+
return this.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

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import com.nimbusds.jose.JWSSigner;
4343
import com.nimbusds.jose.crypto.MACSigner;
4444
import com.nimbusds.jose.crypto.RSASSASigner;
45+
import com.nimbusds.jose.jwk.JWKSet;
4546
import com.nimbusds.jose.jwk.source.JWKSource;
4647
import com.nimbusds.jose.proc.BadJOSEException;
4748
import com.nimbusds.jose.proc.DefaultJOSEObjectTypeVerifier;
@@ -75,18 +76,24 @@
7576
import org.springframework.web.client.RestClientException;
7677
import org.springframework.web.client.RestOperations;
7778

78-
import static org.assertj.core.api.Assertions.assertThat;
79-
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
80-
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
81-
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
79+
import javax.crypto.SecretKey;
80+
import java.security.KeyFactory;
81+
import java.security.NoSuchAlgorithmException;
82+
import java.security.PrivateKey;
83+
import java.security.interfaces.RSAPrivateKey;
84+
import java.security.interfaces.RSAPublicKey;
85+
import java.security.spec.EncodedKeySpec;
86+
import java.security.spec.InvalidKeySpecException;
87+
import java.security.spec.X509EncodedKeySpec;
88+
import java.text.ParseException;
89+
import java.time.Instant;
90+
import java.util.*;
91+
92+
import static org.assertj.core.api.Assertions.*;
8293
import static org.mockito.ArgumentMatchers.any;
8394
import static org.mockito.ArgumentMatchers.eq;
8495
import static org.mockito.BDDMockito.given;
85-
import static org.mockito.Mockito.mock;
86-
import static org.mockito.Mockito.times;
87-
import static org.mockito.Mockito.verify;
88-
import static org.mockito.Mockito.verifyNoInteractions;
89-
import static org.mockito.Mockito.verifyNoMoreInteractions;
96+
import static org.mockito.Mockito.*;
9097

9198
/**
9299
* Tests for {@link NimbusJwtDecoder}
@@ -559,6 +566,22 @@ public void decodeWhenUsingSecretKeyWithKidThenStillUsesKey() throws Exception {
559566
// @formatter:on
560567
}
561568

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

0 commit comments

Comments
 (0)