@@ -261,6 +261,16 @@ public static SecretKeyJwtDecoderBuilder withSecretKey(SecretKey secretKey) {
261
261
return new SecretKeyJwtDecoderBuilder (secretKey );
262
262
}
263
263
264
+ /**
265
+ * Use the given {@code JWKSource} to create a JwkSourceJwtDecoderBuilder.
266
+ * @param jwkSource the JWK Source to use
267
+ * @return a {@link JwkSetUriJwtDecoderBuilder} for further configurations
268
+ * @since 7.0
269
+ */
270
+ public static JwkSourceJwtDecoderBuilder withJwkSource (JWKSource <SecurityContext > jwkSource ) {
271
+ return new JwkSourceJwtDecoderBuilder (jwkSource );
272
+ }
273
+
264
274
/**
265
275
* A builder for creating {@link NimbusJwtDecoder} instances based on a
266
276
* <a target="_blank" href="https://tools.ietf.org/html/rfc7517#section-5">JWK Set</a>
@@ -274,7 +284,7 @@ public static final class JwkSetUriJwtDecoderBuilder {
274
284
private static final JOSEObjectTypeVerifier <SecurityContext > NO_TYPE_VERIFIER = (header , context ) -> {
275
285
};
276
286
277
- private final Function <RestOperations , String > jwkSetUri ;
287
+ private Function <RestOperations , String > jwkSetUri ;
278
288
279
289
private Function <JWKSource <SecurityContext >, Set <JWSAlgorithm >> defaultAlgorithms = (source ) -> Set
280
290
.of (JWSAlgorithm .RS256 );
@@ -289,6 +299,8 @@ public static final class JwkSetUriJwtDecoderBuilder {
289
299
290
300
private Consumer <ConfigurableJWTProcessor <SecurityContext >> jwtProcessorCustomizer ;
291
301
302
+ private JWKSource <SecurityContext > jwkSource ;
303
+
292
304
private JwkSetUriJwtDecoderBuilder (String jwkSetUri ) {
293
305
Assert .hasText (jwkSetUri , "jwkSetUri cannot be empty" );
294
306
this .jwkSetUri = (rest ) -> jwkSetUri ;
@@ -306,6 +318,13 @@ private JwkSetUriJwtDecoderBuilder(Function<RestOperations, String> jwkSetUri,
306
318
};
307
319
}
308
320
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
+
309
328
/**
310
329
* Whether to use Nimbus's typ header verification. This is {@code true} by
311
330
* default, however it may change to {@code false} in a future major release.
@@ -436,6 +455,9 @@ JWSKeySelector<SecurityContext> jwsKeySelector(JWKSource<SecurityContext> jwkSou
436
455
}
437
456
438
457
JWKSource <SecurityContext > jwkSource () {
458
+ if (this .jwkSource != null ) {
459
+ return this .jwkSource ;
460
+ }
439
461
String jwkSetUri = this .jwkSetUri .apply (this .restOperations );
440
462
return JWKSourceBuilder .create (new SpringJWKSource <>(this .restOperations , this .cache , jwkSetUri ))
441
463
.refreshAheadCache (false )
@@ -535,6 +557,106 @@ public void close() {
535
557
536
558
}
537
559
560
+ /**
561
+ * A builder for creating {@link NimbusJwtDecoder} instances based on a {@code JWKSource}.
562
+ */
563
+ public static final class JwkSourceJwtDecoderBuilder {
564
+
565
+ private static final JOSEObjectTypeVerifier <SecurityContext > NO_TYPE_VERIFIER = (header , context ) -> {
566
+ };
567
+
568
+ private final Function <JWKSource <SecurityContext >, Set <JWSAlgorithm >> defaultAlgorithms = (source ) -> Set
569
+ .of (JWSAlgorithm .RS256 );
570
+
571
+ private final JOSEObjectTypeVerifier <SecurityContext > typeVerifier = NO_TYPE_VERIFIER ;
572
+
573
+ private final Set <SignatureAlgorithm > signatureAlgorithms = new HashSet <>();
574
+
575
+ private Consumer <ConfigurableJWTProcessor <SecurityContext >> jwtProcessorCustomizer ;
576
+
577
+ private final JWKSource <SecurityContext > jwkSource ;
578
+
579
+ private JwkSourceJwtDecoderBuilder (JWKSource <SecurityContext > jwkSource ) {
580
+ Assert .notNull (jwkSource , "jwkSource cannot be null" );
581
+ this .jwkSource = jwkSource ;
582
+ this .jwtProcessorCustomizer = (processor ) -> {
583
+ };
584
+ }
585
+
586
+ /**
587
+ * Append the given signing
588
+ * <a href="https://tools.ietf.org/html/rfc7515#section-4.1.1" target=
589
+ * "_blank">algorithm</a> to the set of algorithms to use.
590
+ * @param signatureAlgorithm the algorithm to use
591
+ * @return a {@link JwkSourceJwtDecoderBuilder } for further configurations
592
+ */
593
+ public JwkSourceJwtDecoderBuilder jwsAlgorithm (SignatureAlgorithm signatureAlgorithm ) {
594
+ Assert .notNull (signatureAlgorithm , "signatureAlgorithm cannot be null" );
595
+ this .signatureAlgorithms .add (signatureAlgorithm );
596
+ return this ;
597
+ }
598
+
599
+ /**
600
+ * Configure the list of
601
+ * <a href="https://tools.ietf.org/html/rfc7515#section-4.1.1" target=
602
+ * "_blank">algorithms</a> to use with the given {@link Consumer}.
603
+ * @param signatureAlgorithmsConsumer a {@link Consumer} for further configuring
604
+ * the algorithm list
605
+ * @return a {@link JwkSourceJwtDecoderBuilder } for further configurations
606
+ */
607
+ public JwkSourceJwtDecoderBuilder jwsAlgorithms (Consumer <Set <SignatureAlgorithm >> signatureAlgorithmsConsumer ) {
608
+ Assert .notNull (signatureAlgorithmsConsumer , "signatureAlgorithmsConsumer cannot be null" );
609
+ signatureAlgorithmsConsumer .accept (this .signatureAlgorithms );
610
+ return this ;
611
+ }
612
+
613
+ /**
614
+ * Use the given {@link Consumer} to customize the {@link JWTProcessor
615
+ * ConfigurableJWTProcessor} before passing it to the build
616
+ * {@link NimbusJwtDecoder}.
617
+ * @param jwtProcessorCustomizer the callback used to alter the processor
618
+ * @return a {@link JwkSourceJwtDecoderBuilder } for further configurations
619
+ * @since 5.4
620
+ */
621
+ public JwkSourceJwtDecoderBuilder jwtProcessorCustomizer (
622
+ Consumer <ConfigurableJWTProcessor <SecurityContext >> jwtProcessorCustomizer ) {
623
+ Assert .notNull (jwtProcessorCustomizer , "jwtProcessorCustomizer cannot be null" );
624
+ this .jwtProcessorCustomizer = jwtProcessorCustomizer ;
625
+ return this ;
626
+ }
627
+
628
+ JWSKeySelector <SecurityContext > jwsKeySelector (JWKSource <SecurityContext > jwkSource ) {
629
+ if (this .signatureAlgorithms .isEmpty ()) {
630
+ return new JWSVerificationKeySelector <>(this .defaultAlgorithms .apply (jwkSource ), jwkSource );
631
+ }
632
+ Set <JWSAlgorithm > jwsAlgorithms = new HashSet <>();
633
+ for (SignatureAlgorithm signatureAlgorithm : this .signatureAlgorithms ) {
634
+ JWSAlgorithm jwsAlgorithm = JWSAlgorithm .parse (signatureAlgorithm .getName ());
635
+ jwsAlgorithms .add (jwsAlgorithm );
636
+ }
637
+ return new JWSVerificationKeySelector <>(jwsAlgorithms , jwkSource );
638
+ }
639
+
640
+ JWTProcessor <SecurityContext > processor () {
641
+ ConfigurableJWTProcessor <SecurityContext > jwtProcessor = new DefaultJWTProcessor <>();
642
+ jwtProcessor .setJWSTypeVerifier (this .typeVerifier );
643
+ jwtProcessor .setJWSKeySelector (jwsKeySelector (jwkSource ));
644
+ // Spring Security validates the claim set independent from Nimbus
645
+ jwtProcessor .setJWTClaimsSetVerifier ((claims , context ) -> {
646
+ });
647
+ this .jwtProcessorCustomizer .accept (jwtProcessor );
648
+ return jwtProcessor ;
649
+ }
650
+
651
+ /**
652
+ * Build the configured {@link NimbusJwtDecoder}.
653
+ * @return the configured {@link NimbusJwtDecoder}
654
+ */
655
+ public NimbusJwtDecoder build () {
656
+ return new NimbusJwtDecoder (processor ());
657
+ }
658
+ }
659
+
538
660
/**
539
661
* A builder for creating {@link NimbusJwtDecoder} instances based on a public key.
540
662
*/
0 commit comments