Skip to content

Commit d010873

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

File tree

2 files changed

+60
-30
lines changed

2 files changed

+60
-30
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: 37 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,32 +16,14 @@
1616

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

19-
import java.security.KeyFactory;
20-
import java.security.NoSuchAlgorithmException;
21-
import java.security.PrivateKey;
22-
import java.security.interfaces.RSAPrivateKey;
23-
import java.security.interfaces.RSAPublicKey;
24-
import java.security.spec.EncodedKeySpec;
25-
import java.security.spec.InvalidKeySpecException;
26-
import java.security.spec.X509EncodedKeySpec;
27-
import java.text.ParseException;
28-
import java.time.Instant;
29-
import java.util.Arrays;
30-
import java.util.Base64;
31-
import java.util.Collections;
32-
import java.util.Date;
33-
import java.util.List;
34-
import java.util.Map;
35-
36-
import javax.crypto.SecretKey;
37-
3819
import com.nimbusds.jose.JOSEException;
3920
import com.nimbusds.jose.JOSEObjectType;
4021
import com.nimbusds.jose.JWSAlgorithm;
4122
import com.nimbusds.jose.JWSHeader;
4223
import com.nimbusds.jose.JWSSigner;
4324
import com.nimbusds.jose.crypto.MACSigner;
4425
import com.nimbusds.jose.crypto.RSASSASigner;
26+
import com.nimbusds.jose.jwk.JWKSet;
4527
import com.nimbusds.jose.jwk.source.JWKSource;
4628
import com.nimbusds.jose.proc.BadJOSEException;
4729
import com.nimbusds.jose.proc.DefaultJOSEObjectTypeVerifier;
@@ -57,7 +39,6 @@
5739
import org.junit.jupiter.api.BeforeAll;
5840
import org.junit.jupiter.api.Test;
5941
import org.mockito.ArgumentCaptor;
60-
6142
import org.springframework.cache.Cache;
6243
import org.springframework.cache.concurrent.ConcurrentMapCache;
6344
import org.springframework.core.ParameterizedTypeReference;
@@ -75,18 +56,29 @@
7556
import org.springframework.web.client.RestClientException;
7657
import org.springframework.web.client.RestOperations;
7758

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;
59+
import javax.crypto.SecretKey;
60+
import java.security.KeyFactory;
61+
import java.security.NoSuchAlgorithmException;
62+
import java.security.PrivateKey;
63+
import java.security.interfaces.RSAPrivateKey;
64+
import java.security.interfaces.RSAPublicKey;
65+
import java.security.spec.EncodedKeySpec;
66+
import java.security.spec.InvalidKeySpecException;
67+
import java.security.spec.X509EncodedKeySpec;
68+
import java.text.ParseException;
69+
import java.time.Instant;
70+
import java.util.Arrays;
71+
import java.util.Base64;
72+
import java.util.Collections;
73+
import java.util.Date;
74+
import java.util.List;
75+
import java.util.Map;
76+
77+
import static org.assertj.core.api.Assertions.*;
8278
import static org.mockito.ArgumentMatchers.any;
8379
import static org.mockito.ArgumentMatchers.eq;
8480
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;
81+
import static org.mockito.Mockito.*;
9082

9183
/**
9284
* Tests for {@link NimbusJwtDecoder}
@@ -559,6 +551,22 @@ public void decodeWhenUsingSecretKeyWithKidThenStillUsesKey() throws Exception {
559551
// @formatter:on
560552
}
561553

554+
// gh-7056
555+
@Test
556+
public void decodeWhenUsingJwkSource() throws Exception {
557+
JWKSource<SecurityContext> source = (a, b) -> {
558+
try {
559+
return JWKSet.parse(JWK_SET).getKeys();
560+
}
561+
catch (ParseException e) {
562+
throw new RuntimeException(e);
563+
}
564+
};
565+
NimbusJwtDecoder decoder = NimbusJwtDecoder.withJwkSource(source).build();
566+
Jwt jwt = decoder.decode(SIGNED_JWT);
567+
assertThat(jwt.getClaimAsString("sub")).isEqualTo("test-subject");
568+
}
569+
562570
// gh-8730
563571
@Test
564572
public void withSecretKeyWhenUsingCustomTypeHeaderThenSuccessfullyDecodes() throws Exception {

0 commit comments

Comments
 (0)