33
33
import javax .crypto .SecretKey ;
34
34
35
35
import com .nimbusds .jose .JOSEException ;
36
+ import com .nimbusds .jose .JOSEObjectType ;
36
37
import com .nimbusds .jose .JWSAlgorithm ;
37
38
import com .nimbusds .jose .KeySourceException ;
38
39
import com .nimbusds .jose .RemoteKeySourceException ;
41
42
import com .nimbusds .jose .jwk .source .JWKSetSource ;
42
43
import com .nimbusds .jose .jwk .source .JWKSource ;
43
44
import com .nimbusds .jose .jwk .source .JWKSourceBuilder ;
45
+ import com .nimbusds .jose .proc .DefaultJOSEObjectTypeVerifier ;
46
+ import com .nimbusds .jose .proc .JOSEObjectTypeVerifier ;
44
47
import com .nimbusds .jose .proc .JWSKeySelector ;
45
48
import com .nimbusds .jose .proc .JWSVerificationKeySelector ;
46
49
import com .nimbusds .jose .proc .SecurityContext ;
@@ -265,11 +268,20 @@ public static SecretKeyJwtDecoderBuilder withSecretKey(SecretKey secretKey) {
265
268
*/
266
269
public static final class JwkSetUriJwtDecoderBuilder {
267
270
271
+ private static final JOSEObjectTypeVerifier <SecurityContext > JWT_TYPE_VERIFIER = new DefaultJOSEObjectTypeVerifier <>(
272
+ JOSEObjectType .JWT , null );
273
+
274
+ private static final JOSEObjectTypeVerifier <SecurityContext > NO_TYPE_VERIFIER = (header , context ) -> {
275
+ };
276
+
268
277
private Function <RestOperations , String > jwkSetUri ;
269
278
270
279
private Function <JWKSource <SecurityContext >, Set <JWSAlgorithm >> defaultAlgorithms = (source ) -> Set
271
280
.of (JWSAlgorithm .RS256 );
272
281
282
+ private JOSEObjectTypeVerifier <SecurityContext > typeVerifier = new DefaultJOSEObjectTypeVerifier <>(
283
+ JOSEObjectType .JWT , null );
284
+
273
285
private Set <SignatureAlgorithm > signatureAlgorithms = new HashSet <>();
274
286
275
287
private RestOperations restOperations = new RestTemplate ();
@@ -295,6 +307,54 @@ private JwkSetUriJwtDecoderBuilder(Function<RestOperations, String> jwkSetUri,
295
307
};
296
308
}
297
309
310
+ /**
311
+ * Whether to use Nimbus's typ header verification. This is {@code true} by
312
+ * default, however it may change to {@code false} in a future major release.
313
+ *
314
+ * <p>
315
+ * By turning off this feature, {@link NimbusJwtDecoder} expects applications to
316
+ * check the {@code typ} header themselves in order to determine what kind of
317
+ * validation is needed
318
+ * </p>
319
+ *
320
+ * <p>
321
+ * This is done for you when you use {@link JwtValidators} to construct a
322
+ * validator.
323
+ *
324
+ * <p>
325
+ * That means that this: <code>
326
+ * NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(issuer).build();
327
+ * jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithIssuer(issuer);
328
+ * </code>
329
+ *
330
+ * <p>
331
+ * Is equivalent to this: <code>
332
+ * NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(issuer)
333
+ * .validateType(false)
334
+ * .build();
335
+ * jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithIssuer(issuer);
336
+ * </code>
337
+ *
338
+ * <p>
339
+ * The difference is that by setting this to {@code false}, it allows you to
340
+ * provide validation by type, like for {@code at+jwt}:
341
+ *
342
+ * <code>
343
+ * NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(issuer)
344
+ * .validateType(false)
345
+ * .build();
346
+ * jwtDecoder.setJwtValidator(new MyAtJwtValidator());
347
+ * </code>
348
+ * @param shouldValidateTypHeader whether Nimbus should validate the typ header or
349
+ * not
350
+ * @return a {@link JwkSetUriJwtDecoderBuilder} for further configurations
351
+ * @since 6.5
352
+ */
353
+ public JwkSetUriJwtDecoderBuilder validateType (boolean shouldValidateTypHeader ) {
354
+ this .typeVerifier = shouldValidateTypHeader ? JWT_TYPE_VERIFIER : NO_TYPE_VERIFIER ;
355
+ return this ;
356
+ }
357
+
298
358
/**
299
359
* Append the given signing
300
360
* <a href="https://tools.ietf.org/html/rfc7515#section-4.1.1" target=
@@ -389,6 +449,7 @@ JWKSource<SecurityContext> jwkSource() {
389
449
JWTProcessor <SecurityContext > processor () {
390
450
JWKSource <SecurityContext > jwkSource = jwkSource ();
391
451
ConfigurableJWTProcessor <SecurityContext > jwtProcessor = new DefaultJWTProcessor <>();
452
+ jwtProcessor .setJWSTypeVerifier (this .typeVerifier );
392
453
jwtProcessor .setJWSKeySelector (jwsKeySelector (jwkSource ));
393
454
// Spring Security validates the claim set independent from Nimbus
394
455
jwtProcessor .setJWTClaimsSetVerifier ((claims , context ) -> {
@@ -481,8 +542,17 @@ public void close() {
481
542
*/
482
543
public static final class PublicKeyJwtDecoderBuilder {
483
544
545
+ private static final JOSEObjectTypeVerifier <SecurityContext > JWT_TYPE_VERIFIER = new DefaultJOSEObjectTypeVerifier <>(
546
+ JOSEObjectType .JWT , null );
547
+
548
+ private static final JOSEObjectTypeVerifier <SecurityContext > NO_TYPE_VERIFIER = (header , context ) -> {
549
+ };
550
+
484
551
private JWSAlgorithm jwsAlgorithm ;
485
552
553
+ private JOSEObjectTypeVerifier <SecurityContext > typeVerifier = new DefaultJOSEObjectTypeVerifier <>(
554
+ JOSEObjectType .JWT , null );
555
+
486
556
private RSAPublicKey key ;
487
557
488
558
private Consumer <ConfigurableJWTProcessor <SecurityContext >> jwtProcessorCustomizer ;
@@ -495,6 +565,54 @@ private PublicKeyJwtDecoderBuilder(RSAPublicKey key) {
495
565
};
496
566
}
497
567
568
+ /**
569
+ * Whether to use Nimbus's typ header verification. This is {@code true} by
570
+ * default, however it may change to {@code false} in a future major release.
571
+ *
572
+ * <p>
573
+ * By turning off this feature, {@link NimbusJwtDecoder} expects applications to
574
+ * check the {@code typ} header themselves in order to determine what kind of
575
+ * validation is needed
576
+ * </p>
577
+ *
578
+ * <p>
579
+ * This is done for you when you use {@link JwtValidators} to construct a
580
+ * validator.
581
+ *
582
+ * <p>
583
+ * That means that this: <code>
584
+ * NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(issuer).build();
585
+ * jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithIssuer(issuer);
586
+ * </code>
587
+ *
588
+ * <p>
589
+ * Is equivalent to this: <code>
590
+ * NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(issuer)
591
+ * .validateType(false)
592
+ * .build();
593
+ * jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithIssuer(issuer);
594
+ * </code>
595
+ *
596
+ * <p>
597
+ * The difference is that by setting this to {@code false}, it allows you to
598
+ * provide validation by type, like for {@code at+jwt}:
599
+ *
600
+ * <code>
601
+ * NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(issuer)
602
+ * .validateType(false)
603
+ * .build();
604
+ * jwtDecoder.setJwtValidator(new MyAtJwtValidator());
605
+ * </code>
606
+ * @param shouldValidateTypHeader whether Nimbus should validate the typ header or
607
+ * not
608
+ * @return a {@link JwkSetUriJwtDecoderBuilder} for further configurations
609
+ * @since 6.5
610
+ */
611
+ public PublicKeyJwtDecoderBuilder validateType (boolean shouldValidateTypHeader ) {
612
+ this .typeVerifier = shouldValidateTypHeader ? JWT_TYPE_VERIFIER : NO_TYPE_VERIFIER ;
613
+ return this ;
614
+ }
615
+
498
616
/**
499
617
* Use the given signing
500
618
* <a href="https://tools.ietf.org/html/rfc7515#section-4.1.1" target=
@@ -533,6 +651,7 @@ JWTProcessor<SecurityContext> processor() {
533
651
+ this .jwsAlgorithm + ". Please indicate one of RS256, RS384, or RS512." );
534
652
JWSKeySelector <SecurityContext > jwsKeySelector = new SingleKeyJWSKeySelector <>(this .jwsAlgorithm , this .key );
535
653
DefaultJWTProcessor <SecurityContext > jwtProcessor = new DefaultJWTProcessor <>();
654
+ jwtProcessor .setJWSTypeVerifier (this .typeVerifier );
536
655
jwtProcessor .setJWSKeySelector (jwsKeySelector );
537
656
// Spring Security validates the claim set independent from Nimbus
538
657
jwtProcessor .setJWTClaimsSetVerifier ((claims , context ) -> {
@@ -557,10 +676,19 @@ public NimbusJwtDecoder build() {
557
676
*/
558
677
public static final class SecretKeyJwtDecoderBuilder {
559
678
679
+ private static final JOSEObjectTypeVerifier <SecurityContext > JWT_TYPE_VERIFIER = new DefaultJOSEObjectTypeVerifier <>(
680
+ JOSEObjectType .JWT , null );
681
+
682
+ private static final JOSEObjectTypeVerifier <SecurityContext > NO_TYPE_VERIFIER = (header , context ) -> {
683
+ };
684
+
560
685
private final SecretKey secretKey ;
561
686
562
687
private JWSAlgorithm jwsAlgorithm = JWSAlgorithm .HS256 ;
563
688
689
+ private JOSEObjectTypeVerifier <SecurityContext > typeVerifier = new DefaultJOSEObjectTypeVerifier <>(
690
+ JOSEObjectType .JWT , null );
691
+
564
692
private Consumer <ConfigurableJWTProcessor <SecurityContext >> jwtProcessorCustomizer ;
565
693
566
694
private SecretKeyJwtDecoderBuilder (SecretKey secretKey ) {
@@ -570,6 +698,54 @@ private SecretKeyJwtDecoderBuilder(SecretKey secretKey) {
570
698
};
571
699
}
572
700
701
+ /**
702
+ * Whether to use Nimbus's typ header verification. This is {@code true} by
703
+ * default, however it may change to {@code false} in a future major release.
704
+ *
705
+ * <p>
706
+ * By turning off this feature, {@link NimbusJwtDecoder} expects applications to
707
+ * check the {@code typ} header themselves in order to determine what kind of
708
+ * validation is needed
709
+ * </p>
710
+ *
711
+ * <p>
712
+ * This is done for you when you use {@link JwtValidators} to construct a
713
+ * validator.
714
+ *
715
+ * <p>
716
+ * That means that this: <code>
717
+ * NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(issuer).build();
718
+ * jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithIssuer(issuer);
719
+ * </code>
720
+ *
721
+ * <p>
722
+ * Is equivalent to this: <code>
723
+ * NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(issuer)
724
+ * .validateType(false)
725
+ * .build();
726
+ * jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithIssuer(issuer);
727
+ * </code>
728
+ *
729
+ * <p>
730
+ * The difference is that by setting this to {@code false}, it allows you to
731
+ * provide validation by type, like for {@code at+jwt}:
732
+ *
733
+ * <code>
734
+ * NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(issuer)
735
+ * .validateType(false)
736
+ * .build();
737
+ * jwtDecoder.setJwtValidator(new MyAtJwtValidator());
738
+ * </code>
739
+ * @param shouldValidateTypHeader whether Nimbus should validate the typ header or
740
+ * not
741
+ * @return a {@link JwkSetUriJwtDecoderBuilder} for further configurations
742
+ * @since 6.5
743
+ */
744
+ public SecretKeyJwtDecoderBuilder validateType (boolean shouldValidateTypHeader ) {
745
+ this .typeVerifier = shouldValidateTypHeader ? JWT_TYPE_VERIFIER : NO_TYPE_VERIFIER ;
746
+ return this ;
747
+ }
748
+
573
749
/**
574
750
* Use the given
575
751
* <a href="https://tools.ietf.org/html/rfc7515#section-4.1.1" target=
@@ -615,6 +791,7 @@ JWTProcessor<SecurityContext> processor() {
615
791
this .secretKey );
616
792
DefaultJWTProcessor <SecurityContext > jwtProcessor = new DefaultJWTProcessor <>();
617
793
jwtProcessor .setJWSKeySelector (jwsKeySelector );
794
+ jwtProcessor .setJWSTypeVerifier (this .typeVerifier );
618
795
// Spring Security validates the claim set independent from Nimbus
619
796
jwtProcessor .setJWTClaimsSetVerifier ((claims , context ) -> {
620
797
});
0 commit comments