diff --git a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JwtDecoderProviderConfigurationUtils.java b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JwtDecoderProviderConfigurationUtils.java index 3aba32e867..5cf7ace331 100644 --- a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JwtDecoderProviderConfigurationUtils.java +++ b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JwtDecoderProviderConfigurationUtils.java @@ -100,18 +100,27 @@ final class JwtDecoderProviderConfigurationUtils { } private static URI oidc(URI issuer) { - return UriComponentsBuilder.fromUri(issuer).replacePath(issuer.getPath() + OIDC_METADATA_PATH) + // @formatter:off + return UriComponentsBuilder.fromUri(issuer) + .replacePath(issuer.getPath() + OIDC_METADATA_PATH) .build(Collections.emptyMap()); + // @formatter:on } private static URI oidcRfc8414(URI issuer) { - return UriComponentsBuilder.fromUri(issuer).replacePath(OIDC_METADATA_PATH + issuer.getPath()) + // @formatter:off + return UriComponentsBuilder.fromUri(issuer) + .replacePath(OIDC_METADATA_PATH + issuer.getPath()) .build(Collections.emptyMap()); + // @formatter:on } private static URI oauth(URI issuer) { - return UriComponentsBuilder.fromUri(issuer).replacePath(OAUTH_METADATA_PATH + issuer.getPath()) + // @formatter:off + return UriComponentsBuilder.fromUri(issuer) + .replacePath(OAUTH_METADATA_PATH + issuer.getPath()) .build(Collections.emptyMap()); + // @formatter:on } } diff --git a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoder.java b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoder.java index 632d755cc7..97213b90c2 100644 --- a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoder.java +++ b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoder.java @@ -147,7 +147,12 @@ public final class NimbusJwtDecoder implements JwtDecoder { JWTClaimsSet jwtClaimsSet = this.jwtProcessor.process(parsedJwt, null); Map headers = new LinkedHashMap<>(parsedJwt.getHeader().toJSONObject()); Map claims = this.claimSetConverter.convert(jwtClaimsSet.getClaims()); - return Jwt.withTokenValue(token).headers((h) -> h.putAll(headers)).claims((c) -> c.putAll(claims)).build(); + // @formatter:off + return Jwt.withTokenValue(token) + .headers((h) -> h.putAll(headers)) + .claims((c) -> c.putAll(claims)) + .build(); + // @formatter:on } catch (RemoteKeySourceException ex) { if (ex.getCause() instanceof ParseException) { diff --git a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusReactiveJwtDecoder.java b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusReactiveJwtDecoder.java index 95909265ac..122cf14c37 100644 --- a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusReactiveJwtDecoder.java +++ b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusReactiveJwtDecoder.java @@ -159,10 +159,13 @@ public final class NimbusReactiveJwtDecoder implements ReactiveJwtDecoder { private Mono decode(JWT parsedToken) { try { - return this.jwtProcessor.convert(parsedToken).map((set) -> createJwt(parsedToken, set)) + // @formatter:off + return this.jwtProcessor.convert(parsedToken) + .map((set) -> createJwt(parsedToken, set)) .map(this::validateJwt) .onErrorMap((ex) -> !(ex instanceof IllegalStateException) && !(ex instanceof JwtException), (ex) -> new JwtException("An error occurred while attempting to decode the Jwt: ", ex)); + // @formatter:on } catch (JwtException ex) { throw ex; diff --git a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/ReactiveRemoteJWKSource.java b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/ReactiveRemoteJWKSource.java index ec2bc3f901..498fa81a57 100644 --- a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/ReactiveRemoteJWKSource.java +++ b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/ReactiveRemoteJWKSource.java @@ -54,9 +54,14 @@ class ReactiveRemoteJWKSource implements ReactiveJWKSource { @Override public Mono> get(JWKSelector jwkSelector) { - return this.cachedJWKSet.get().switchIfEmpty(Mono.defer(() -> getJWKSet())) + // @formatter:off + return this.cachedJWKSet.get() + .switchIfEmpty(Mono.defer(() -> getJWKSet())) .flatMap((jwkSet) -> get(jwkSelector, jwkSet)) - .switchIfEmpty(Mono.defer(() -> getJWKSet().map((jwkSet) -> jwkSelector.select(jwkSet)))); + .switchIfEmpty(Mono.defer(() -> getJWKSet() + .map((jwkSet) -> jwkSelector.select(jwkSet))) + ); + // @formatter:on } private Mono> get(JWKSelector jwkSelector, JWKSet jwkSet) { @@ -89,8 +94,17 @@ class ReactiveRemoteJWKSource implements ReactiveJWKSource { * @throws RemoteKeySourceException If JWK retrieval failed. */ private Mono getJWKSet() { - return this.webClient.get().uri(this.jwkSetURL).retrieve().bodyToMono(String.class).map(this::parse) - .doOnNext((jwkSet) -> this.cachedJWKSet.set(Mono.just(jwkSet))).cache(); + // @formatter:off + return this.webClient.get() + .uri(this.jwkSetURL) + .retrieve() + .bodyToMono(String.class) + .map(this::parse) + .doOnNext((jwkSet) -> this.cachedJWKSet + .set(Mono.just(jwkSet)) + ) + .cache(); + // @formatter:on } private JWKSet parse(String body) { diff --git a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jose/TestKeys.java b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jose/TestKeys.java index f0dba9b354..7a2b7fb70d 100644 --- a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jose/TestKeys.java +++ b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jose/TestKeys.java @@ -48,12 +48,15 @@ public final class TestKeys { public static final SecretKey DEFAULT_SECRET_KEY = new SecretKeySpec( Base64.getDecoder().decode(DEFAULT_ENCODED_SECRET_KEY), "AES"); + // @formatter:off public static final String DEFAULT_RSA_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3FlqJr5TRskIQIgdE3Dd" + "7D9lboWdcTUT8a+fJR7MAvQm7XXNoYkm3v7MQL1NYtDvL2l8CAnc0WdSTINU6IRv" + "c5Kqo2Q4csNX9SHOmEfzoROjQqahEcve1jBXluoCXdYuYpx4/1tfRgG6ii4Uhxh6" + "iI8qNMJQX+fLfqhbfYfxBQVRPywBkAbIP4x1EAsbC6FSNmkhCxiMNqEgxaIpY8C2" + "kJdJ/ZIV+WW4noDdzpKqHcwmB8FsrumlVY/DNVvUSDIipiq9PbP4H99TXN1o746o" - + "RaNa07rq1hoCgMSSy+85SagCoxlmyE+D+of9SsMY8Ol9t0rdzpobBuhyJ/o5dfvj" + "KwIDAQAB"; + + "RaNa07rq1hoCgMSSy+85SagCoxlmyE+D+of9SsMY8Ol9t0rdzpobBuhyJ/o5dfvj" + + "KwIDAQAB"; + // @formatter:on public static final RSAPublicKey DEFAULT_PUBLIC_KEY; static { @@ -65,6 +68,8 @@ public final class TestKeys { throw new IllegalArgumentException(ex); } } + + // @formatter:off public static final String DEFAULT_RSA_PRIVATE_KEY = "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDcWWomvlNGyQhA" + "iB0TcN3sP2VuhZ1xNRPxr58lHswC9Cbtdc2hiSbe/sxAvU1i0O8vaXwICdzRZ1JM" + "g1TohG9zkqqjZDhyw1f1Ic6YR/OhE6NCpqERy97WMFeW6gJd1i5inHj/W19GAbqK" @@ -89,7 +94,9 @@ public final class TestKeys { + "FiGm+mC/skFS0MWgW8evaHGDbWU180wheQ35hW6oKAb7myRHtr4q20ouEtQMdQIF" + "snV39G1iyqeeAsf7dxWElydXpRi2b68i3BIgzhzebQKBgQCdUQuTsqV9y/JFpu6H" + "c5TVvhG/ubfBspI5DhQqIGijnVBzFT//UfIYMSKJo75qqBEyP2EJSmCsunWsAFsM" - + "TszuiGTkrKcZy9G0wJqPztZZl2F2+bJgnA6nBEV7g5PA4Af+QSmaIhRwqGDAuROR" + "47jndeyIaMTNETEmOnms+as17g=="; + + "TszuiGTkrKcZy9G0wJqPztZZl2F2+bJgnA6nBEV7g5PA4Af+QSmaIhRwqGDAuROR" + + "47jndeyIaMTNETEmOnms+as17g=="; + // @formatter:on public static final RSAPrivateKey DEFAULT_PRIVATE_KEY; static { diff --git a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtBuilderTests.java b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtBuilderTests.java index 4aab4d0e2d..0aaf02945e 100644 --- a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtBuilderTests.java +++ b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtBuilderTests.java @@ -34,9 +34,18 @@ public class JwtBuilderTests { @Test public void buildWhenCalledTwiceThenGeneratesTwoJwts() { Jwt.Builder jwtBuilder = Jwt.withTokenValue("token"); - Jwt first = jwtBuilder.tokenValue("V1").header("TEST_HEADER_1", "H1").claim("TEST_CLAIM_1", "C1").build(); - Jwt second = jwtBuilder.tokenValue("V2").header("TEST_HEADER_1", "H2").header("TEST_HEADER_2", "H3") - .claim("TEST_CLAIM_1", "C2").claim("TEST_CLAIM_2", "C3").build(); + // @formatter:off + Jwt first = jwtBuilder.tokenValue("V1") + .header("TEST_HEADER_1", "H1") + .claim("TEST_CLAIM_1", "C1") + .build(); + Jwt second = jwtBuilder.tokenValue("V2") + .header("TEST_HEADER_1", "H2") + .header("TEST_HEADER_2", "H3") + .claim("TEST_CLAIM_1", "C2") + .claim("TEST_CLAIM_2", "C3") + .build(); + // @formatter:on assertThat(first.getHeaders()).hasSize(1); assertThat(first.getHeaders().get("TEST_HEADER_1")).isEqualTo("H1"); assertThat(first.getClaims()).hasSize(1); @@ -53,7 +62,10 @@ public class JwtBuilderTests { @Test public void expiresAtWhenUsingGenericOrNamedClaimMethodRequiresInstant() { - Jwt.Builder jwtBuilder = Jwt.withTokenValue("token").header("needs", "a header"); + // @formatter:off + Jwt.Builder jwtBuilder = Jwt.withTokenValue("token") + .header("needs", "a header"); + // @formatter:on Instant now = Instant.now(); Jwt jwt = jwtBuilder.expiresAt(now).build(); assertThat(jwt.getExpiresAt()).isSameAs(now); @@ -65,7 +77,10 @@ public class JwtBuilderTests { @Test public void issuedAtWhenUsingGenericOrNamedClaimMethodRequiresInstant() { - Jwt.Builder jwtBuilder = Jwt.withTokenValue("token").header("needs", "a header"); + // @formatter:off + Jwt.Builder jwtBuilder = Jwt.withTokenValue("token") + .header("needs", "a header"); + // @formatter:on Instant now = Instant.now(); Jwt jwt = jwtBuilder.issuedAt(now).build(); assertThat(jwt.getIssuedAt()).isSameAs(now); @@ -77,7 +92,10 @@ public class JwtBuilderTests { @Test public void subjectWhenUsingGenericOrNamedClaimMethodThenLastOneWins() { - Jwt.Builder jwtBuilder = Jwt.withTokenValue("token").header("needs", "a header"); + // @formatter:off + Jwt.Builder jwtBuilder = Jwt.withTokenValue("token") + .header("needs", "a header"); + // @formatter:on String generic = new String("sub"); String named = new String("sub"); Jwt jwt = jwtBuilder.subject(named).claim(JwtClaimNames.SUB, generic).build(); @@ -88,14 +106,23 @@ public class JwtBuilderTests { @Test public void claimsWhenRemovingAClaimThenIsNotPresent() { - Jwt.Builder jwtBuilder = Jwt.withTokenValue("token").claim("needs", "a claim").header("needs", "a header"); - Jwt jwt = jwtBuilder.subject("sub").claims((claims) -> claims.remove(JwtClaimNames.SUB)).build(); + // @formatter:off + Jwt.Builder jwtBuilder = Jwt.withTokenValue("token") + .claim("needs", "a claim") + .header("needs", "a header"); + Jwt jwt = jwtBuilder.subject("sub") + .claims((claims) -> claims.remove(JwtClaimNames.SUB)) + .build(); + // @formatter:on assertThat(jwt.getSubject()).isNull(); } @Test public void claimsWhenAddingAClaimThenIsPresent() { - Jwt.Builder jwtBuilder = Jwt.withTokenValue("token").header("needs", "a header"); + // @formatter:off + Jwt.Builder jwtBuilder = Jwt.withTokenValue("token") + .header("needs", "a header"); + // @formatter:on String name = new String("name"); String value = new String("value"); Jwt jwt = jwtBuilder.claims((claims) -> claims.put(name, value)).build(); @@ -105,17 +132,29 @@ public class JwtBuilderTests { @Test public void headersWhenRemovingAClaimThenIsNotPresent() { - Jwt.Builder jwtBuilder = Jwt.withTokenValue("token").claim("needs", "a claim").header("needs", "a header"); - Jwt jwt = jwtBuilder.header("alg", "none").headers((headers) -> headers.remove("alg")).build(); + // @formatter:off + Jwt.Builder jwtBuilder = Jwt.withTokenValue("token") + .claim("needs", "a claim") + .header("needs", "a header"); + Jwt jwt = jwtBuilder.header("alg", "none") + .headers((headers) -> headers.remove("alg")) + .build(); + // @formatter:on assertThat(jwt.getHeaders().get("alg")).isNull(); } @Test public void headersWhenAddingAClaimThenIsPresent() { - Jwt.Builder jwtBuilder = Jwt.withTokenValue("token").claim("needs", "a claim"); + // @formatter:off + Jwt.Builder jwtBuilder = Jwt.withTokenValue("token") + .claim("needs", "a claim"); + // @formatter:on String name = new String("name"); String value = new String("value"); - Jwt jwt = jwtBuilder.headers((headers) -> headers.put(name, value)).build(); + // @formatter:off + Jwt jwt = jwtBuilder.headers((headers) -> headers.put(name, value)) + .build(); + // @formatter:on assertThat(jwt.getHeaders()).hasSize(1); assertThat(jwt.getHeaders().get(name)).isSameAs(value); } diff --git a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtDecodersTests.java b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtDecodersTests.java index 7f6b4da77e..868fe4713b 100644 --- a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtDecodersTests.java +++ b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtDecodersTests.java @@ -55,15 +55,30 @@ public class JwtDecodersTests { * Contains those parameters required to construct a JwtDecoder as well as any * required parameters */ + // @formatter:off private static final String DEFAULT_RESPONSE_TEMPLATE = "{\n" + " \"authorization_endpoint\": \"https://example.com/o/oauth2/v2/auth\", \n" - + " \"id_token_signing_alg_values_supported\": [\n" + " \"RS256\"\n" + " ], \n" - + " \"issuer\": \"%s\", \n" + " \"jwks_uri\": \"%s/.well-known/jwks.json\", \n" - + " \"response_types_supported\": [\n" + " \"code\", \n" + " \"token\", \n" - + " \"id_token\", \n" + " \"code token\", \n" + " \"code id_token\", \n" - + " \"token id_token\", \n" + " \"code token id_token\", \n" + " \"none\"\n" - + " ], \n" + " \"subject_types_supported\": [\n" + " \"public\"\n" + " ], \n" - + " \"token_endpoint\": \"https://example.com/oauth2/v4/token\"\n" + "}"; + + " \"id_token_signing_alg_values_supported\": [\n" + + " \"RS256\"\n" + + " ], \n" + + " \"issuer\": \"%s\", \n" + + " \"jwks_uri\": \"%s/.well-known/jwks.json\", \n" + + " \"response_types_supported\": [\n" + + " \"code\", \n" + + " \"token\", \n" + + " \"id_token\", \n" + + " \"code token\", \n" + + " \"code id_token\", \n" + + " \"token id_token\", \n" + + " \"code token id_token\", \n" + + " \"none\"\n" + + " ], \n" + + " \"subject_types_supported\": [\n" + + " \"public\"\n" + + " ], \n" + + " \"token_endpoint\": \"https://example.com/oauth2/v4/token\"\n" + + "}"; + // @formatter:on private static final String JWK_SET = "{\"keys\":[{\"p\":\"49neceJFs8R6n7WamRGy45F5Tv0YM-R2ODK3eSBUSLOSH2tAqjEVKOkLE5fiNA3ygqq15NcKRadB2pTVf-Yb5ZIBuKzko8bzYIkIqYhSh_FAdEEr0vHF5fq_yWSvc6swsOJGqvBEtuqtJY027u-G2gAQasCQdhyejer68zsTn8M\",\"kty\":\"RSA\",\"q\":\"tWR-ysspjZ73B6p2vVRVyHwP3KQWL5KEQcdgcmMOE_P_cPs98vZJfLhxobXVmvzuEWBpRSiqiuyKlQnpstKt94Cy77iO8m8ISfF3C9VyLWXi9HUGAJb99irWABFl3sNDff5K2ODQ8CmuXLYM25OwN3ikbrhEJozlXg_NJFSGD4E\",\"d\":\"FkZHYZlw5KSoqQ1i2RA2kCUygSUOf1OqMt3uomtXuUmqKBm_bY7PCOhmwbvbn4xZYEeHuTR8Xix-0KpHe3NKyWrtRjkq1T_un49_1LLVUhJ0dL-9_x0xRquVjhl_XrsRXaGMEHs8G9pLTvXQ1uST585gxIfmCe0sxPZLvwoic-bXf64UZ9BGRV3lFexWJQqCZp2S21HfoU7wiz6kfLRNi-K4xiVNB1gswm_8o5lRuY7zB9bRARQ3TS2G4eW7p5sxT3CgsGiQD3_wPugU8iDplqAjgJ5ofNJXZezoj0t6JMB_qOpbrmAM1EnomIPebSLW7Ky9SugEd6KMdL5lW6AuAQ\",\"e\":\"AQAB\",\"use\":\"sig\",\"kid\":\"one\",\"qi\":\"wdkFu_tV2V1l_PWUUimG516Zvhqk2SWDw1F7uNDD-Lvrv_WNRIJVzuffZ8WYiPy8VvYQPJUrT2EXL8P0ocqwlaSTuXctrORcbjwgxDQDLsiZE0C23HYzgi0cofbScsJdhcBg7d07LAf7cdJWG0YVl1FkMCsxUlZ2wTwHfKWf-v4\",\"dp\":\"uwnPxqC-IxG4r33-SIT02kZC1IqC4aY7PWq0nePiDEQMQWpjjNH50rlq9EyLzbtdRdIouo-jyQXB01K15-XXJJ60dwrGLYNVqfsTd0eGqD1scYJGHUWG9IDgCsxyEnuG3s0AwbW2UolWVSsU2xMZGb9PurIUZECeD1XDZwMp2s0\",\"dq\":\"hra786AunB8TF35h8PpROzPoE9VJJMuLrc6Esm8eZXMwopf0yhxfN2FEAvUoTpLJu93-UH6DKenCgi16gnQ0_zt1qNNIVoRfg4rw_rjmsxCYHTVL3-RDeC8X_7TsEySxW0EgFTHh-nr6I6CQrAJjPM88T35KHtdFATZ7BCBB8AE\",\"n\":\"oXJ8OyOv_eRnce4akdanR4KYRfnC2zLV4uYNQpcFn6oHL0dj7D6kxQmsXoYgJV8ZVDn71KGmuLvolxsDncc2UrhyMBY6DVQVgMSVYaPCTgW76iYEKGgzTEw5IBRQL9w3SRJWd3VJTZZQjkXef48Ocz06PGF3lhbz4t5UEZtdF4rIe7u-977QwHuh7yRPBQ3sII-cVoOUMgaXB9SHcGF2iZCtPzL_IffDUcfhLQteGebhW8A6eUHgpD5A1PQ-JCw_G7UOzZAjjDjtNM2eqm8j-Ms_gqnm4MiCZ4E-9pDN77CAAPVN7kuX6ejs9KBXpk01z48i9fORYk9u7rAkh1HuQw\"}]}"; @@ -93,24 +108,33 @@ public class JwtDecodersTests { public void issuerWhenResponseIsTypicalThenReturnedDecoderValidatesIssuer() { prepareConfigurationResponse(); JwtDecoder decoder = JwtDecoders.fromOidcIssuerLocation(this.issuer); - assertThatExceptionOfType(JwtValidationException.class).isThrownBy(() -> decoder.decode(ISSUER_MISMATCH)) + // @formatter:off + assertThatExceptionOfType(JwtValidationException.class) + .isThrownBy(() -> decoder.decode(ISSUER_MISMATCH)) .withMessageContaining("The iss claim is not valid"); + // @formatter:on } @Test public void issuerWhenOidcFallbackResponseIsTypicalThenReturnedDecoderValidatesIssuer() { prepareConfigurationResponseOidc(); JwtDecoder decoder = JwtDecoders.fromIssuerLocation(this.issuer); - assertThatExceptionOfType(JwtValidationException.class).isThrownBy(() -> decoder.decode(ISSUER_MISMATCH)) + // @formatter:off + assertThatExceptionOfType(JwtValidationException.class) + .isThrownBy(() -> decoder.decode(ISSUER_MISMATCH)) .withMessageContaining("The iss claim is not valid"); + // @formatter:on } @Test public void issuerWhenOAuth2ResponseIsTypicalThenReturnedDecoderValidatesIssuer() { prepareConfigurationResponseOAuth2(); JwtDecoder decoder = JwtDecoders.fromIssuerLocation(this.issuer); - assertThatExceptionOfType(JwtValidationException.class).isThrownBy(() -> decoder.decode(ISSUER_MISMATCH)) + // @formatter:off + assertThatExceptionOfType(JwtValidationException.class) + .isThrownBy(() -> decoder.decode(ISSUER_MISMATCH)) .withMessageContaining("The iss claim is not valid"); + // @formatter:on } @Test @@ -147,13 +171,19 @@ public class JwtDecodersTests { @Test public void issuerWhenOidcFallbackResponseIsNonCompliantThenThrowsRuntimeException() { prepareConfigurationResponseOidc("{ \"missing_required_keys\" : \"and_values\" }"); - assertThatExceptionOfType(RuntimeException.class).isThrownBy(() -> JwtDecoders.fromIssuerLocation(this.issuer)); + // @formatter:off + assertThatExceptionOfType(RuntimeException.class) + .isThrownBy(() -> JwtDecoders.fromIssuerLocation(this.issuer)); + // @formatter:on } @Test public void issuerWhenOAuth2ResponseIsNonCompliantThenThrowsRuntimeException() { prepareConfigurationResponseOAuth2("{ \"missing_required_keys\" : \"and_values\" }"); - assertThatExceptionOfType(RuntimeException.class).isThrownBy(() -> JwtDecoders.fromIssuerLocation(this.issuer)); + // @formatter:off + assertThatExceptionOfType(RuntimeException.class) + .isThrownBy(() -> JwtDecoders.fromIssuerLocation(this.issuer)); + // @formatter:on } // gh-7512 @@ -161,8 +191,11 @@ public class JwtDecodersTests { public void issuerWhenResponseDoesNotContainJwksUriThenThrowsIllegalArgumentException() throws JsonMappingException, JsonProcessingException { prepareConfigurationResponse(this.buildResponseWithMissingJwksUri()); - assertThatIllegalArgumentException().isThrownBy(() -> JwtDecoders.fromOidcIssuerLocation(this.issuer)) + // @formatter:off + assertThatIllegalArgumentException() + .isThrownBy(() -> JwtDecoders.fromOidcIssuerLocation(this.issuer)) .withMessage("The public JWK set URI must not be null"); + // @formatter:on } // gh-7512 @@ -170,8 +203,12 @@ public class JwtDecodersTests { public void issuerWhenOidcFallbackResponseDoesNotContainJwksUriThenThrowsIllegalArgumentException() throws JsonMappingException, JsonProcessingException { prepareConfigurationResponseOidc(this.buildResponseWithMissingJwksUri()); - assertThatIllegalArgumentException().isThrownBy(() -> JwtDecoders.fromIssuerLocation(this.issuer)) - .isInstanceOf(IllegalArgumentException.class).withMessage("The public JWK set URI must not be null"); + // @formatter:off + assertThatIllegalArgumentException() + .isThrownBy(() -> JwtDecoders.fromIssuerLocation(this.issuer)) + .isInstanceOf(IllegalArgumentException.class) + .withMessage("The public JWK set URI must not be null"); + // @formatter:on } // gh-7512 @@ -179,59 +216,85 @@ public class JwtDecodersTests { public void issuerWhenOAuth2ResponseDoesNotContainJwksUriThenThrowsIllegalArgumentException() throws JsonMappingException, JsonProcessingException { prepareConfigurationResponseOAuth2(this.buildResponseWithMissingJwksUri()); - assertThatIllegalArgumentException().isThrownBy(() -> JwtDecoders.fromIssuerLocation(this.issuer)) + // @formatter:off + assertThatIllegalArgumentException() + .isThrownBy(() -> JwtDecoders.fromIssuerLocation(this.issuer)) .withMessage("The public JWK set URI must not be null"); + // @formatter:on } @Test public void issuerWhenResponseIsMalformedThenThrowsRuntimeException() { prepareConfigurationResponse("malformed"); + // @formatter:off assertThatExceptionOfType(RuntimeException.class) .isThrownBy(() -> JwtDecoders.fromOidcIssuerLocation(this.issuer)); + // @formatter:on } @Test public void issuerWhenOidcFallbackResponseIsMalformedThenThrowsRuntimeException() { prepareConfigurationResponseOidc("malformed"); - assertThatExceptionOfType(RuntimeException.class).isThrownBy(() -> JwtDecoders.fromIssuerLocation(this.issuer)); + // @formatter:off + assertThatExceptionOfType(RuntimeException.class) + .isThrownBy(() -> JwtDecoders.fromIssuerLocation(this.issuer)); + // @formatter:on } @Test public void issuerWhenOAuth2ResponseIsMalformedThenThrowsRuntimeException() { prepareConfigurationResponseOAuth2("malformed"); - assertThatExceptionOfType(RuntimeException.class).isThrownBy(() -> JwtDecoders.fromIssuerLocation(this.issuer)); + // @formatter:off + assertThatExceptionOfType(RuntimeException.class) + .isThrownBy(() -> JwtDecoders.fromIssuerLocation(this.issuer)); + // @formatter:on } @Test public void issuerWhenRespondingIssuerMismatchesRequestedIssuerThenThrowsIllegalStateException() { prepareConfigurationResponse(String.format(DEFAULT_RESPONSE_TEMPLATE, this.issuer + "/wrong", this.issuer)); - assertThatIllegalStateException().isThrownBy(() -> JwtDecoders.fromOidcIssuerLocation(this.issuer)); + // @formatter:off + assertThatIllegalStateException() + .isThrownBy(() -> JwtDecoders.fromOidcIssuerLocation(this.issuer)); + // @formatter:on } @Test public void issuerWhenOidcFallbackRespondingIssuerMismatchesRequestedIssuerThenThrowsIllegalStateException() { prepareConfigurationResponseOidc(String.format(DEFAULT_RESPONSE_TEMPLATE, this.issuer + "/wrong", this.issuer)); - assertThatIllegalStateException().isThrownBy(() -> JwtDecoders.fromIssuerLocation(this.issuer)); + // @formatter:off + assertThatIllegalStateException() + .isThrownBy(() -> JwtDecoders.fromIssuerLocation(this.issuer)); + // @formatter:on } @Test public void issuerWhenOAuth2RespondingIssuerMismatchesRequestedIssuerThenThrowsIllegalStateException() { prepareConfigurationResponseOAuth2( String.format(DEFAULT_RESPONSE_TEMPLATE, this.issuer + "/wrong", this.issuer)); - assertThatIllegalStateException().isThrownBy(() -> JwtDecoders.fromIssuerLocation(this.issuer)); + // @formatter:off + assertThatIllegalStateException() + .isThrownBy(() -> JwtDecoders.fromIssuerLocation(this.issuer)); + // @formatter:on } @Test public void issuerWhenRequestedIssuerIsUnresponsiveThenThrowsIllegalArgumentException() throws Exception { this.server.shutdown(); - assertThatIllegalArgumentException().isThrownBy(() -> JwtDecoders.fromOidcIssuerLocation("https://issuer")); + // @formatter:off + assertThatIllegalArgumentException() + .isThrownBy(() -> JwtDecoders.fromOidcIssuerLocation("https://issuer")); + // @formatter:on } @Test public void issuerWhenOidcFallbackRequestedIssuerIsUnresponsiveThenThrowsIllegalArgumentException() throws Exception { this.server.shutdown(); - assertThatIllegalArgumentException().isThrownBy(() -> JwtDecoders.fromIssuerLocation("https://issuer")); + // @formatter:off + assertThatIllegalArgumentException() + .isThrownBy(() -> JwtDecoders.fromIssuerLocation("https://issuer")); + // @formatter:on } private void prepareConfigurationResponse() { @@ -272,8 +335,13 @@ public class JwtDecodersTests { Dispatcher dispatcher = new Dispatcher() { @Override public MockResponse dispatch(RecordedRequest request) { - return Optional.of(request).map(RecordedRequest::getRequestUrl).map(HttpUrl::toString) - .map(responses::get).orElse(new MockResponse().setResponseCode(404)); + // @formatter:off + return Optional.of(request) + .map(RecordedRequest::getRequestUrl) + .map(HttpUrl::toString) + .map(responses::get) + .orElse(new MockResponse().setResponseCode(404)); + // @formatter:on } }; this.server.setDispatcher(dispatcher); @@ -285,12 +353,20 @@ public class JwtDecodersTests { private String oidc() { URI uri = URI.create(this.issuer); - return UriComponentsBuilder.fromUri(uri).replacePath(uri.getPath() + OIDC_METADATA_PATH).toUriString(); + // @formatter:off + return UriComponentsBuilder.fromUri(uri) + .replacePath(uri.getPath() + OIDC_METADATA_PATH) + .toUriString(); + // @formatter:on } private String oauth() { URI uri = URI.create(this.issuer); - return UriComponentsBuilder.fromUri(uri).replacePath(OAUTH_METADATA_PATH + uri.getPath()).toUriString(); + // @formatter:off + return UriComponentsBuilder.fromUri(uri) + .replacePath(OAUTH_METADATA_PATH + uri.getPath()) + .toUriString(); + // @formatter:on } private String jwks() { @@ -298,7 +374,11 @@ public class JwtDecodersTests { } private MockResponse response(String body) { - return new MockResponse().setBody(body).setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); + // @formatter:off + return new MockResponse() + .setBody(body) + .setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); + // @formatter:on } public String buildResponseWithMissingJwksUri() throws JsonMappingException, JsonProcessingException { diff --git a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtIssuerValidatorTests.java b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtIssuerValidatorTests.java index 5127b086a6..547c851c2b 100644 --- a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtIssuerValidatorTests.java +++ b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtIssuerValidatorTests.java @@ -36,7 +36,10 @@ public class JwtIssuerValidatorTests { @Test public void validateWhenIssuerMatchesThenReturnsSuccess() { Jwt jwt = TestJwts.jwt().claim("iss", ISSUER).build(); - assertThat(this.validator.validate(jwt)).isEqualTo(OAuth2TokenValidatorResult.success()); + // @formatter:off + assertThat(this.validator.validate(jwt)) + .isEqualTo(OAuth2TokenValidatorResult.success()); + // @formatter:on } @Test @@ -58,17 +61,26 @@ public class JwtIssuerValidatorTests { public void validateWhenIssuerMatchesAndIsNotAUriThenReturnsSuccess() { Jwt jwt = TestJwts.jwt().claim(JwtClaimNames.ISS, "issuer").build(); JwtIssuerValidator validator = new JwtIssuerValidator("issuer"); - assertThat(validator.validate(jwt)).isEqualTo(OAuth2TokenValidatorResult.success()); + // @formatter:off + assertThat(validator.validate(jwt)) + .isEqualTo(OAuth2TokenValidatorResult.success()); + // @formatter:on } @Test public void validateWhenJwtIsNullThenThrowsIllegalArgumentException() { - assertThatIllegalArgumentException().isThrownBy(() -> this.validator.validate(null)); + // @formatter:off + assertThatIllegalArgumentException() + .isThrownBy(() -> this.validator.validate(null)); + // @formatter:on } @Test public void constructorWhenNullIssuerIsGivenThenThrowsIllegalArgumentException() { - assertThatIllegalArgumentException().isThrownBy(() -> new JwtIssuerValidator(null)); + // @formatter:off + assertThatIllegalArgumentException() + .isThrownBy(() -> new JwtIssuerValidator(null)); + // @formatter:on } } diff --git a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtTimestampValidatorTests.java b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtTimestampValidatorTests.java index 7f17fb761b..4f1708e85d 100644 --- a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtTimestampValidatorTests.java +++ b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtTimestampValidatorTests.java @@ -57,7 +57,11 @@ public class JwtTimestampValidatorTests { Jwt jwt = TestJwts.jwt().expiresAt(oneHourAgo).build(); JwtTimestampValidator jwtValidator = new JwtTimestampValidator(); Collection details = jwtValidator.validate(jwt).getErrors(); - Collection messages = details.stream().map(OAuth2Error::getDescription).collect(Collectors.toList()); + // @formatter:off + Collection messages = details.stream() + .map(OAuth2Error::getDescription) + .collect(Collectors.toList()); + // @formatter:on assertThat(messages).contains("Jwt expired at " + oneHourAgo); } @@ -67,7 +71,11 @@ public class JwtTimestampValidatorTests { Jwt jwt = TestJwts.jwt().notBefore(oneHourFromNow).build(); JwtTimestampValidator jwtValidator = new JwtTimestampValidator(); Collection details = jwtValidator.validate(jwt).getErrors(); - Collection messages = details.stream().map(OAuth2Error::getDescription).collect(Collectors.toList()); + // @formatter:off + Collection messages = details.stream() + .map(OAuth2Error::getDescription) + .collect(Collectors.toList()); + // @formatter:on assertThat(messages).contains("Jwt used before " + oneHourFromNow); } @@ -84,13 +92,22 @@ public class JwtTimestampValidatorTests { assertThat(jwtValidator.validate(jwt).hasErrors()).isFalse(); jwt = TestJwts.jwt().expiresAt(justOverOneDayAgo).build(); OAuth2TokenValidatorResult result = jwtValidator.validate(jwt); - Collection messages = result.getErrors().stream().map(OAuth2Error::getDescription) + // @formatter:off + Collection messages = result.getErrors() + .stream() + .map(OAuth2Error::getDescription) .collect(Collectors.toList()); + // @formatter:on assertThat(result.hasErrors()).isTrue(); assertThat(messages).contains("Jwt expired at " + justOverOneDayAgo); jwt = TestJwts.jwt().notBefore(justOverOneDayFromNow).build(); result = jwtValidator.validate(jwt); - messages = result.getErrors().stream().map(OAuth2Error::getDescription).collect(Collectors.toList()); + // @formatter:off + messages = result.getErrors() + .stream() + .map(OAuth2Error::getDescription) + .collect(Collectors.toList()); + // @formatter:on assertThat(result.hasErrors()).isTrue(); assertThat(messages).contains("Jwt used before " + justOverOneDayFromNow); } diff --git a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoderJwkSupportTests.java b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoderJwkSupportTests.java index 26d7c5f9c9..28f407ded2 100644 --- a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoderJwkSupportTests.java +++ b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoderJwkSupportTests.java @@ -111,8 +111,11 @@ public class NimbusJwtDecoderJwkSupportTests { // gh-5457 @Test public void decodeWhenPlainJwtThenExceptionDoesNotMentionClass() { - assertThatExceptionOfType(JwtException.class).isThrownBy(() -> this.jwtDecoder.decode(UNSIGNED_JWT)) + // @formatter:off + assertThatExceptionOfType(JwtException.class) + .isThrownBy(() -> this.jwtDecoder.decode(UNSIGNED_JWT)) .withMessageContaining("Unsupported algorithm of none"); + // @formatter:on } @Test @@ -121,8 +124,11 @@ public class NimbusJwtDecoderJwkSupportTests { server.enqueue(new MockResponse().setBody(JWK_SET)); String jwkSetUrl = server.url("/.well-known/jwks.json").toString(); NimbusJwtDecoderJwkSupport jwtDecoder = new NimbusJwtDecoderJwkSupport(jwkSetUrl); - assertThatExceptionOfType(JwtException.class).isThrownBy(() -> jwtDecoder.decode(MALFORMED_JWT)) + // @formatter:off + assertThatExceptionOfType(JwtException.class) + .isThrownBy(() -> jwtDecoder.decode(MALFORMED_JWT)) .withMessage("An error occurred while attempting to decode the Jwt: Malformed payload"); + // @formatter:on server.shutdown(); } } @@ -133,8 +139,11 @@ public class NimbusJwtDecoderJwkSupportTests { server.enqueue(new MockResponse().setBody(MALFORMED_JWK_SET)); String jwkSetUrl = server.url("/.well-known/jwks.json").toString(); NimbusJwtDecoderJwkSupport jwtDecoder = new NimbusJwtDecoderJwkSupport(jwkSetUrl); - assertThatExceptionOfType(JwtException.class).isThrownBy(() -> jwtDecoder.decode(SIGNED_JWT)) + // @formatter:off + assertThatExceptionOfType(JwtException.class) + .isThrownBy(() -> jwtDecoder.decode(SIGNED_JWT)) .withMessage("An error occurred while attempting to decode the Jwt: Malformed Jwk set"); + // @formatter:on server.shutdown(); } } @@ -145,8 +154,11 @@ public class NimbusJwtDecoderJwkSupportTests { server.enqueue(new MockResponse().setBody(MALFORMED_JWK_SET)); String jwkSetUrl = server.url("/.well-known/jwks.json").toString(); NimbusJwtDecoderJwkSupport jwtDecoder = new NimbusJwtDecoderJwkSupport(jwkSetUrl); - assertThatExceptionOfType(JwtException.class).isThrownBy(() -> jwtDecoder.decode(SIGNED_JWT)) + // @formatter:off + assertThatExceptionOfType(JwtException.class) + .isThrownBy(() -> jwtDecoder.decode(SIGNED_JWT)) .withMessageContaining("An error occurred while attempting to decode the Jwt"); + // @formatter:on server.shutdown(); } } @@ -176,8 +188,11 @@ public class NimbusJwtDecoderJwkSupportTests { OAuth2TokenValidator jwtValidator = mock(OAuth2TokenValidator.class); given(jwtValidator.validate(any(Jwt.class))).willReturn(OAuth2TokenValidatorResult.failure(failure)); decoder.setJwtValidator(jwtValidator); - assertThatExceptionOfType(JwtValidationException.class).isThrownBy(() -> decoder.decode(SIGNED_JWT)) + // @formatter:off + assertThatExceptionOfType(JwtValidationException.class) + .isThrownBy(() -> decoder.decode(SIGNED_JWT)) .withMessageContaining("mock-description"); + // @formatter:on } } @@ -193,9 +208,14 @@ public class NimbusJwtDecoderJwkSupportTests { OAuth2TokenValidator jwtValidator = mock(OAuth2TokenValidator.class); given(jwtValidator.validate(any(Jwt.class))).willReturn(result); decoder.setJwtValidator(jwtValidator); - assertThatExceptionOfType(JwtValidationException.class).isThrownBy(() -> decoder.decode(SIGNED_JWT)) - .withMessageContaining("mock-description").satisfies((ex) -> assertThat(ex) - .hasFieldOrPropertyWithValue("errors", Arrays.asList(firstFailure, secondFailure))); + // @formatter:off + assertThatExceptionOfType(JwtValidationException.class) + .isThrownBy(() -> decoder.decode(SIGNED_JWT)) + .withMessageContaining("mock-description") + .satisfies((ex) -> assertThat(ex) + .hasFieldOrPropertyWithValue("errors", Arrays.asList(firstFailure, secondFailure)) + ); + // @formatter:on } } diff --git a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoderTests.java b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoderTests.java index 2c2154e997..5795786265 100644 --- a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoderTests.java +++ b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoderTests.java @@ -75,9 +75,7 @@ import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm; import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestOperations; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; @@ -128,22 +126,34 @@ public class NimbusJwtDecoderTests { @Test public void constructorWhenJwtProcessorIsNullThenThrowIllegalArgumentException() { - assertThatIllegalArgumentException().isThrownBy(() -> new NimbusJwtDecoder(null)); + // @formatter:off + assertThatIllegalArgumentException() + .isThrownBy(() -> new NimbusJwtDecoder(null)); + // @formatter:on } @Test public void setClaimSetConverterWhenIsNullThenThrowsIllegalArgumentException() { - assertThatIllegalArgumentException().isThrownBy(() -> this.jwtDecoder.setClaimSetConverter(null)); + // @formatter:off + assertThatIllegalArgumentException() + .isThrownBy(() -> this.jwtDecoder.setClaimSetConverter(null)); + // @formatter:on } @Test public void setJwtValidatorWhenNullThenThrowIllegalArgumentException() { - assertThatIllegalArgumentException().isThrownBy(() -> this.jwtDecoder.setJwtValidator(null)); + // @formatter:off + assertThatIllegalArgumentException() + .isThrownBy(() -> this.jwtDecoder.setJwtValidator(null)); + // @formatter:on } @Test public void decodeWhenJwtInvalidThenThrowJwtException() { - assertThatExceptionOfType(JwtException.class).isThrownBy(() -> this.jwtDecoder.decode("invalid")); + // @formatter:off + assertThatExceptionOfType(JwtException.class) + .isThrownBy(() -> this.jwtDecoder.decode("invalid")); + // @formatter:on } // gh-5168 @@ -160,14 +170,20 @@ public class NimbusJwtDecoderTests { // gh-5457 @Test public void decodeWhenPlainJwtThenExceptionDoesNotMentionClass() { - assertThatExceptionOfType(BadJwtException.class).isThrownBy(() -> this.jwtDecoder.decode(UNSIGNED_JWT)) + // @formatter:off + assertThatExceptionOfType(BadJwtException.class) + .isThrownBy(() -> this.jwtDecoder.decode(UNSIGNED_JWT)) .withMessageContaining("Unsupported algorithm of none"); + // @formatter:on } @Test public void decodeWhenJwtIsMalformedThenReturnsStockException() { - assertThatExceptionOfType(BadJwtException.class).isThrownBy(() -> this.jwtDecoder.decode(MALFORMED_JWT)) + // @formatter:off + assertThatExceptionOfType(BadJwtException.class) + .isThrownBy(() -> this.jwtDecoder.decode(MALFORMED_JWT)) .withMessage("An error occurred while attempting to decode the Jwt: Malformed payload"); + // @formatter:on } @Test @@ -176,8 +192,11 @@ public class NimbusJwtDecoderTests { OAuth2TokenValidator jwtValidator = mock(OAuth2TokenValidator.class); given(jwtValidator.validate(any(Jwt.class))).willReturn(OAuth2TokenValidatorResult.failure(failure)); this.jwtDecoder.setJwtValidator(jwtValidator); - assertThatExceptionOfType(JwtValidationException.class).isThrownBy(() -> this.jwtDecoder.decode(SIGNED_JWT)) + // @formatter:off + assertThatExceptionOfType(JwtValidationException.class) + .isThrownBy(() -> this.jwtDecoder.decode(SIGNED_JWT)) .withMessageContaining("mock-description"); + // @formatter:on } @Test @@ -188,9 +207,14 @@ public class NimbusJwtDecoderTests { OAuth2TokenValidator jwtValidator = mock(OAuth2TokenValidator.class); given(jwtValidator.validate(any(Jwt.class))).willReturn(result); this.jwtDecoder.setJwtValidator(jwtValidator); - assertThatExceptionOfType(JwtValidationException.class).isThrownBy(() -> this.jwtDecoder.decode(SIGNED_JWT)) - .withMessageContaining("mock-description").satisfies((ex) -> assertThat(ex) - .hasFieldOrPropertyWithValue("errors", Arrays.asList(firstFailure, secondFailure))); + // @formatter:off + assertThatExceptionOfType(JwtValidationException.class) + .isThrownBy(() -> this.jwtDecoder.decode(SIGNED_JWT)) + .withMessageContaining("mock-description") + .satisfies((ex) -> assertThat(ex) + .hasFieldOrPropertyWithValue("errors", Arrays.asList(firstFailure, secondFailure)) + ); + // @formatter:on } @Test @@ -202,8 +226,11 @@ public class NimbusJwtDecoderTests { OAuth2Error error2 = new OAuth2Error("mock-error-second", "mock-description-second", "mock-uri-second"); OAuth2TokenValidatorResult result = OAuth2TokenValidatorResult.failure(errorEmpty, error, error2); given(jwtValidator.validate(any(Jwt.class))).willReturn(result); - Assertions.assertThatExceptionOfType(JwtValidationException.class) - .isThrownBy(() -> this.jwtDecoder.decode(SIGNED_JWT)).withMessageContaining("mock-description"); + // @formatter:off + assertThatExceptionOfType(JwtValidationException.class) + .isThrownBy(() -> this.jwtDecoder.decode(SIGNED_JWT)) + .withMessageContaining("mock-description"); + // @formatter:on } @Test @@ -222,7 +249,10 @@ public class NimbusJwtDecoderTests { Converter, Map> claimSetConverter = mock(Converter.class); this.jwtDecoder.setClaimSetConverter(claimSetConverter); given(claimSetConverter.convert(any(Map.class))).willThrow(new IllegalArgumentException("bad conversion")); - assertThatExceptionOfType(BadJwtException.class).isThrownBy(() -> this.jwtDecoder.decode(SIGNED_JWT)); + // @formatter:off + assertThatExceptionOfType(BadJwtException.class) + .isThrownBy(() -> this.jwtDecoder.decode(SIGNED_JWT)); + // @formatter:on } @Test @@ -235,9 +265,12 @@ public class NimbusJwtDecoderTests { @Test public void decodeWhenJwkResponseIsMalformedThenReturnsStockException() { NimbusJwtDecoder jwtDecoder = new NimbusJwtDecoder(withSigning(MALFORMED_JWK_SET)); - assertThatExceptionOfType(JwtException.class).isThrownBy(() -> jwtDecoder.decode(SIGNED_JWT)) + // @formatter:off + assertThatExceptionOfType(JwtException.class) + .isThrownBy(() -> jwtDecoder.decode(SIGNED_JWT)) .isNotInstanceOf(BadJwtException.class) .withMessage("An error occurred while attempting to decode the Jwt: Malformed Jwk set"); + // @formatter:on } @Test @@ -246,9 +279,12 @@ public class NimbusJwtDecoderTests { String jwkSetUri = server.url("/.well-known/jwks.json").toString(); NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withJwkSetUri(jwkSetUri).build(); server.shutdown(); - assertThatExceptionOfType(JwtException.class).isThrownBy(() -> jwtDecoder.decode(SIGNED_JWT)) + // @formatter:off + assertThatExceptionOfType(JwtException.class) + .isThrownBy(() -> jwtDecoder.decode(SIGNED_JWT)) .isNotInstanceOf(BadJwtException.class) .withMessageContaining("An error occurred while attempting to decode the Jwt"); + // @formatter:on } } @@ -259,58 +295,89 @@ public class NimbusJwtDecoderTests { String jwkSetUri = server.url("/.well-known/jwks.json").toString(); NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withJwkSetUri(jwkSetUri).cache(cache).build(); server.shutdown(); - assertThatExceptionOfType(JwtException.class).isThrownBy(() -> jwtDecoder.decode(SIGNED_JWT)) + // @formatter:off + assertThatExceptionOfType(JwtException.class) + .isThrownBy(() -> jwtDecoder.decode(SIGNED_JWT)) .isNotInstanceOf(BadJwtException.class) .withMessageContaining("An error occurred while attempting to decode the Jwt"); + // @formatter:on } } @Test public void withJwkSetUriWhenNullOrEmptyThenThrowsException() { - assertThatIllegalArgumentException().isThrownBy(() -> NimbusJwtDecoder.withJwkSetUri(null)); + // @formatter:off + assertThatIllegalArgumentException() + .isThrownBy(() -> NimbusJwtDecoder.withJwkSetUri(null)); + // @formatter:on } @Test public void jwsAlgorithmWhenNullThenThrowsException() { NimbusJwtDecoder.JwkSetUriJwtDecoderBuilder builder = NimbusJwtDecoder.withJwkSetUri(JWK_SET_URI); - assertThatIllegalArgumentException().isThrownBy(() -> builder.jwsAlgorithm(null)); + // @formatter:off + assertThatIllegalArgumentException() + .isThrownBy(() -> builder.jwsAlgorithm(null)); + // @formatter:on } @Test public void restOperationsWhenNullThenThrowsException() { NimbusJwtDecoder.JwkSetUriJwtDecoderBuilder builder = NimbusJwtDecoder.withJwkSetUri(JWK_SET_URI); - assertThatIllegalArgumentException().isThrownBy(() -> builder.restOperations(null)); + // @formatter:off + assertThatIllegalArgumentException() + .isThrownBy(() -> builder.restOperations(null)); + // @formatter:on } @Test public void cacheWhenNullThenThrowsException() { NimbusJwtDecoder.JwkSetUriJwtDecoderBuilder builder = NimbusJwtDecoder.withJwkSetUri(JWK_SET_URI); - assertThatIllegalArgumentException().isThrownBy(() -> builder.cache(null)); + // @formatter:off + assertThatIllegalArgumentException() + .isThrownBy(() -> builder.cache(null)); + // @formatter:on } @Test public void withPublicKeyWhenNullThenThrowsException() { - assertThatIllegalArgumentException().isThrownBy(() -> NimbusJwtDecoder.withPublicKey(null)); + // @formatter:off + assertThatIllegalArgumentException() + .isThrownBy(() -> NimbusJwtDecoder.withPublicKey(null)); + // @formatter:on } @Test public void buildWhenSignatureAlgorithmMismatchesKeyTypeThenThrowsException() { - Assertions.assertThatCode( - () -> NimbusJwtDecoder.withPublicKey(key()).signatureAlgorithm(SignatureAlgorithm.ES256).build()) - .isInstanceOf(IllegalStateException.class); + // @formatter:off + assertThatIllegalStateException() + .isThrownBy(() -> NimbusJwtDecoder.withPublicKey(key()) + .signatureAlgorithm(SignatureAlgorithm.ES256) + .build() + ); + // @formatter:on } @Test public void decodeWhenUsingPublicKeyThenSuccessfullyDecodes() throws Exception { NimbusJwtDecoder decoder = NimbusJwtDecoder.withPublicKey(key()).build(); - assertThat(decoder.decode(RS256_SIGNED_JWT)).extracting(Jwt::getSubject).isEqualTo("test-subject"); + // @formatter:off + assertThat(decoder.decode(RS256_SIGNED_JWT)) + .extracting(Jwt::getSubject) + .isEqualTo("test-subject"); + // @formatter:on } @Test public void decodeWhenUsingPublicKeyWithRs512ThenSuccessfullyDecodes() throws Exception { - NimbusJwtDecoder decoder = NimbusJwtDecoder.withPublicKey(key()).signatureAlgorithm(SignatureAlgorithm.RS512) + // @formatter:off + NimbusJwtDecoder decoder = NimbusJwtDecoder.withPublicKey(key()) + .signatureAlgorithm(SignatureAlgorithm.RS512) .build(); - assertThat(decoder.decode(RS512_SIGNED_JWT)).extracting(Jwt::getSubject).isEqualTo("test-subject"); + assertThat(decoder.decode(RS512_SIGNED_JWT)) + .extracting(Jwt::getSubject) + .isEqualTo("test-subject"); + // @formatter:on } // gh-7049 @@ -318,20 +385,35 @@ public class NimbusJwtDecoderTests { public void decodeWhenUsingPublicKeyWithKidThenStillUsesKey() throws Exception { RSAPublicKey publicKey = TestKeys.DEFAULT_PUBLIC_KEY; RSAPrivateKey privateKey = TestKeys.DEFAULT_PRIVATE_KEY; - JWSHeader header = new JWSHeader.Builder(JWSAlgorithm.RS256).keyID("one").build(); - JWTClaimsSet claimsSet = new JWTClaimsSet.Builder().subject("test-subject") - .expirationTime(Date.from(Instant.now().plusSeconds(60))).build(); + // @formatter:off + JWSHeader header = new JWSHeader.Builder(JWSAlgorithm.RS256) + .keyID("one") + .build(); + JWTClaimsSet claimsSet = new JWTClaimsSet.Builder() + .subject("test-subject") + .expirationTime(Date.from(Instant.now().plusSeconds(60))) + .build(); + // @formatter:on SignedJWT signedJwt = signedJwt(privateKey, header, claimsSet); - NimbusJwtDecoder decoder = NimbusJwtDecoder.withPublicKey(publicKey) - .signatureAlgorithm(SignatureAlgorithm.RS256).build(); - assertThat(decoder.decode(signedJwt.serialize())).extracting(Jwt::getSubject).isEqualTo("test-subject"); + // @formatter:off + NimbusJwtDecoder decoder = NimbusJwtDecoder + .withPublicKey(publicKey) + .signatureAlgorithm(SignatureAlgorithm.RS256) + .build(); + assertThat(decoder.decode(signedJwt.serialize())) + .extracting(Jwt::getSubject) + .isEqualTo("test-subject"); + // @formatter:on } @Test public void decodeWhenSignatureMismatchesAlgorithmThenThrowsException() throws Exception { NimbusJwtDecoder decoder = NimbusJwtDecoder.withPublicKey(key()).signatureAlgorithm(SignatureAlgorithm.RS512) .build(); - assertThatExceptionOfType(BadJwtException.class).isThrownBy(() -> decoder.decode(RS256_SIGNED_JWT)); + // @formatter:off + assertThatExceptionOfType(BadJwtException.class) + .isThrownBy(() -> decoder.decode(RS256_SIGNED_JWT)); + // @formatter:on } // gh-8730 @@ -343,91 +425,143 @@ public class NimbusJwtDecoderTests { JWTClaimsSet claimsSet = new JWTClaimsSet.Builder().expirationTime(Date.from(Instant.now().plusSeconds(60))) .build(); SignedJWT signedJwt = signedJwt(privateKey, header, claimsSet); + // @formatter:off NimbusJwtDecoder decoder = NimbusJwtDecoder.withPublicKey(publicKey) .signatureAlgorithm(SignatureAlgorithm.RS256) - .jwtProcessorCustomizer( - (p) -> p.setJWSTypeVerifier(new DefaultJOSEObjectTypeVerifier<>(new JOSEObjectType("JWS")))) + .jwtProcessorCustomizer((p) -> p + .setJWSTypeVerifier(new DefaultJOSEObjectTypeVerifier<>(new JOSEObjectType("JWS"))) + ) .build(); + // @formatter:on assertThat(decoder.decode(signedJwt.serialize()).containsClaim(JwtClaimNames.EXP)).isNotNull(); } @Test public void withPublicKeyWhenJwtProcessorCustomizerNullThenThrowsIllegalArgumentException() { + // @formatter:off assertThatIllegalArgumentException() .isThrownBy(() -> NimbusJwtDecoder.withPublicKey(key()).jwtProcessorCustomizer(null)) .withMessage("jwtProcessorCustomizer cannot be null"); + // @formatter:on } @Test public void withSecretKeyWhenNullThenThrowsIllegalArgumentException() { - assertThatIllegalArgumentException().isThrownBy(() -> NimbusJwtDecoder.withSecretKey(null)) + // @formatter:off + assertThatIllegalArgumentException() + .isThrownBy(() -> NimbusJwtDecoder.withSecretKey(null)) .withMessage("secretKey cannot be null"); + // @formatter:on } @Test public void withSecretKeyWhenMacAlgorithmNullThenThrowsIllegalArgumentException() { SecretKey secretKey = TestKeys.DEFAULT_SECRET_KEY; + // @formatter:off assertThatIllegalArgumentException() .isThrownBy(() -> NimbusJwtDecoder.withSecretKey(secretKey).macAlgorithm(null)) .withMessage("macAlgorithm cannot be null"); + // @formatter:on } @Test public void decodeWhenUsingSecretKeyThenSuccessfullyDecodes() throws Exception { SecretKey secretKey = TestKeys.DEFAULT_SECRET_KEY; MacAlgorithm macAlgorithm = MacAlgorithm.HS256; - JWTClaimsSet claimsSet = new JWTClaimsSet.Builder().subject("test-subject") - .expirationTime(Date.from(Instant.now().plusSeconds(60))).build(); + // @formatter:off + JWTClaimsSet claimsSet = new JWTClaimsSet.Builder() + .subject("test-subject") + .expirationTime(Date.from(Instant.now().plusSeconds(60))) + .build(); + // @formatter:on SignedJWT signedJWT = signedJwt(secretKey, macAlgorithm, claimsSet); - NimbusJwtDecoder decoder = NimbusJwtDecoder.withSecretKey(secretKey).macAlgorithm(macAlgorithm).build(); - assertThat(decoder.decode(signedJWT.serialize())).extracting(Jwt::getSubject).isEqualTo("test-subject"); + // @formatter:off + NimbusJwtDecoder decoder = NimbusJwtDecoder.withSecretKey(secretKey) + .macAlgorithm(macAlgorithm) + .build(); + assertThat(decoder.decode(signedJWT.serialize())) + .extracting(Jwt::getSubject) + .isEqualTo("test-subject"); + // @formatter:on } @Test public void decodeWhenUsingSecretKeyAndIncorrectAlgorithmThenThrowsJwtException() throws Exception { SecretKey secretKey = TestKeys.DEFAULT_SECRET_KEY; MacAlgorithm macAlgorithm = MacAlgorithm.HS256; - JWTClaimsSet claimsSet = new JWTClaimsSet.Builder().subject("test-subject") - .expirationTime(Date.from(Instant.now().plusSeconds(60))).build(); + // @formatter:off + JWTClaimsSet claimsSet = new JWTClaimsSet.Builder() + .subject("test-subject") + .expirationTime(Date.from(Instant.now().plusSeconds(60))) + .build(); + // @formatter:on SignedJWT signedJWT = signedJwt(secretKey, macAlgorithm, claimsSet); - NimbusJwtDecoder decoder = NimbusJwtDecoder.withSecretKey(secretKey).macAlgorithm(MacAlgorithm.HS512).build(); - assertThatExceptionOfType(BadJwtException.class).isThrownBy(() -> decoder.decode(signedJWT.serialize())) + // @formatter:off + NimbusJwtDecoder decoder = NimbusJwtDecoder.withSecretKey(secretKey) + .macAlgorithm(MacAlgorithm.HS512) + .build(); + assertThatExceptionOfType(BadJwtException.class) + .isThrownBy(() -> decoder.decode(signedJWT.serialize())) .withMessageContaining("Unsupported algorithm of HS256"); + // @formatter:on } // gh-7056 @Test public void decodeWhenUsingSecertKeyWithKidThenStillUsesKey() throws Exception { SecretKey secretKey = TestKeys.DEFAULT_SECRET_KEY; - JWSHeader header = new JWSHeader.Builder(JWSAlgorithm.HS256).keyID("one").build(); - JWTClaimsSet claimsSet = new JWTClaimsSet.Builder().subject("test-subject") - .expirationTime(Date.from(Instant.now().plusSeconds(60))).build(); + // @formatter:off + JWSHeader header = new JWSHeader.Builder(JWSAlgorithm.HS256) + .keyID("one") + .build(); + JWTClaimsSet claimsSet = new JWTClaimsSet.Builder() + .subject("test-subject") + .expirationTime(Date.from(Instant.now().plusSeconds(60))) + .build(); + // @formatter:on SignedJWT signedJwt = signedJwt(secretKey, header, claimsSet); - NimbusJwtDecoder decoder = NimbusJwtDecoder.withSecretKey(secretKey).macAlgorithm(MacAlgorithm.HS256).build(); - assertThat(decoder.decode(signedJwt.serialize())).extracting(Jwt::getSubject).isEqualTo("test-subject"); + // @formatter:off + NimbusJwtDecoder decoder = NimbusJwtDecoder.withSecretKey(secretKey) + .macAlgorithm(MacAlgorithm.HS256) + .build(); + assertThat(decoder.decode(signedJwt.serialize())) + .extracting(Jwt::getSubject) + .isEqualTo("test-subject"); + // @formatter:on } // gh-8730 @Test public void withSecretKeyWhenUsingCustomTypeHeaderThenSuccessfullyDecodes() throws Exception { SecretKey secretKey = TestKeys.DEFAULT_SECRET_KEY; - JWSHeader header = new JWSHeader.Builder(JWSAlgorithm.HS256).type(new JOSEObjectType("JWS")).build(); - JWTClaimsSet claimsSet = new JWTClaimsSet.Builder().expirationTime(Date.from(Instant.now().plusSeconds(60))) + // @formatter:off + JWSHeader header = new JWSHeader.Builder(JWSAlgorithm.HS256) + .type(new JOSEObjectType("JWS")) .build(); + JWTClaimsSet claimsSet = new JWTClaimsSet.Builder() + .expirationTime(Date.from(Instant.now().plusSeconds(60))) + .build(); + // @formatter:on SignedJWT signedJwt = signedJwt(secretKey, header, claimsSet); - NimbusJwtDecoder decoder = NimbusJwtDecoder.withSecretKey(secretKey).macAlgorithm(MacAlgorithm.HS256) - .jwtProcessorCustomizer( - (p) -> p.setJWSTypeVerifier(new DefaultJOSEObjectTypeVerifier<>(new JOSEObjectType("JWS")))) + // @formatter:off + NimbusJwtDecoder decoder = NimbusJwtDecoder.withSecretKey(secretKey) + .macAlgorithm(MacAlgorithm.HS256) + .jwtProcessorCustomizer((p) -> p + .setJWSTypeVerifier(new DefaultJOSEObjectTypeVerifier<>(new JOSEObjectType("JWS"))) + ) .build(); + // @formatter:on assertThat(decoder.decode(signedJwt.serialize()).containsClaim(JwtClaimNames.EXP)).isNotNull(); } @Test public void withSecretKeyWhenJwtProcessorCustomizerNullThenThrowsIllegalArgumentException() { SecretKey secretKey = TestKeys.DEFAULT_SECRET_KEY; + // @formatter:off assertThatIllegalArgumentException() .isThrownBy(() -> NimbusJwtDecoder.withSecretKey(secretKey).jwtProcessorCustomizer(null)) .withMessage("jwtProcessorCustomizer cannot be null"); + // @formatter:on } @Test @@ -443,8 +577,11 @@ public class NimbusJwtDecoderTests { @Test public void jwsKeySelectorWhenOneAlgorithmThenReturnsSingleSelector() { JWKSource jwkSource = mock(JWKSource.class); + // @formatter:off JWSKeySelector jwsKeySelector = NimbusJwtDecoder.withJwkSetUri(JWK_SET_URI) - .jwsAlgorithm(SignatureAlgorithm.RS512).jwsKeySelector(jwkSource); + .jwsAlgorithm(SignatureAlgorithm.RS512) + .jwsKeySelector(jwkSource); + // @formatter:on assertThat(jwsKeySelector instanceof JWSVerificationKeySelector); JWSVerificationKeySelector jwsVerificationKeySelector = (JWSVerificationKeySelector) jwsKeySelector; assertThat(jwsVerificationKeySelector.isAllowed(JWSAlgorithm.RS512)).isTrue(); @@ -453,9 +590,12 @@ public class NimbusJwtDecoderTests { @Test public void jwsKeySelectorWhenMultipleAlgorithmThenReturnsCompositeSelector() { JWKSource jwkSource = mock(JWKSource.class); + // @formatter:off JWSKeySelector jwsKeySelector = NimbusJwtDecoder.withJwkSetUri(JWK_SET_URI) - .jwsAlgorithm(SignatureAlgorithm.RS256).jwsAlgorithm(SignatureAlgorithm.RS512) + .jwsAlgorithm(SignatureAlgorithm.RS256) + .jwsAlgorithm(SignatureAlgorithm.RS512) .jwsKeySelector(jwkSource); + // @formatter:on assertThat(jwsKeySelector instanceof JWSVerificationKeySelector); JWSVerificationKeySelector jwsAlgorithmMapKeySelector = (JWSVerificationKeySelector) jwsKeySelector; assertThat(jwsAlgorithmMapKeySelector.isAllowed(JWSAlgorithm.RS256)).isTrue(); @@ -468,8 +608,11 @@ public class NimbusJwtDecoderTests { RestOperations restOperations = mock(RestOperations.class); given(restOperations.exchange(any(RequestEntity.class), eq(String.class))) .willReturn(new ResponseEntity<>(JWK_SET, HttpStatus.OK)); + // @formatter:off JWTProcessor processor = NimbusJwtDecoder.withJwkSetUri(JWK_SET_URI) - .restOperations(restOperations).processor(); + .restOperations(restOperations) + .processor(); + // @formatter:on NimbusJwtDecoder jwtDecoder = new NimbusJwtDecoder(processor); jwtDecoder.decode(SIGNED_JWT); ArgumentCaptor requestEntityCaptor = ArgumentCaptor.forClass(RequestEntity.class); @@ -484,8 +627,12 @@ public class NimbusJwtDecoderTests { RestOperations restOperations = mock(RestOperations.class); given(restOperations.exchange(any(RequestEntity.class), eq(String.class))) .willReturn(new ResponseEntity<>(JWK_SET, HttpStatus.OK)); - NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withJwkSetUri(JWK_SET_URI).restOperations(restOperations) - .cache(cache).build(); + // @formatter:off + NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withJwkSetUri(JWK_SET_URI) + .restOperations(restOperations) + .cache(cache) + .build(); + // @formatter:on jwtDecoder.decode(SIGNED_JWT); assertThat(cache.get(JWK_SET_URI, String.class)).isEqualTo(JWK_SET); ArgumentCaptor requestEntityCaptor = ArgumentCaptor.forClass(RequestEntity.class); @@ -500,8 +647,12 @@ public class NimbusJwtDecoderTests { RestOperations restOperations = mock(RestOperations.class); Cache cache = mock(Cache.class); given(cache.get(eq(JWK_SET_URI), any(Callable.class))).willReturn(JWK_SET); - NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withJwkSetUri(JWK_SET_URI).cache(cache) - .restOperations(restOperations).build(); + // @formatter:off + NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withJwkSetUri(JWK_SET_URI) + .cache(cache) + .restOperations(restOperations) + .build(); + // @formatter:on jwtDecoder.decode(SIGNED_JWT); verify(cache).get(eq(JWK_SET_URI), any(Callable.class)); verifyNoMoreInteractions(cache); @@ -514,11 +665,16 @@ public class NimbusJwtDecoderTests { RestOperations restOperations = mock(RestOperations.class); given(restOperations.exchange(any(RequestEntity.class), eq(String.class))) .willThrow(new RestClientException("Cannot retrieve JWK Set")); - NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withJwkSetUri(JWK_SET_URI).restOperations(restOperations) - .cache(cache).build(); - assertThatExceptionOfType(JwtException.class).isThrownBy(() -> jwtDecoder.decode(SIGNED_JWT)) + // @formatter:off + NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withJwkSetUri(JWK_SET_URI) + .restOperations(restOperations) + .cache(cache) + .build(); + assertThatExceptionOfType(JwtException.class) + .isThrownBy(() -> jwtDecoder.decode(SIGNED_JWT)) .isNotInstanceOf(BadJwtException.class) .withMessageContaining("An error occurred while attempting to decode the Jwt"); + // @formatter:on } // gh-8730 @@ -527,20 +683,27 @@ public class NimbusJwtDecoderTests { RestOperations restOperations = mock(RestOperations.class); given(restOperations.exchange(any(RequestEntity.class), eq(String.class))) .willReturn(new ResponseEntity<>(JWK_SET, HttpStatus.OK)); - NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withJwkSetUri(JWK_SET_URI).restOperations(restOperations) - .jwtProcessorCustomizer( - (p) -> p.setJWSTypeVerifier(new DefaultJOSEObjectTypeVerifier<>(new JOSEObjectType("JWS")))) + // @formatter:off + NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withJwkSetUri(JWK_SET_URI) + .restOperations(restOperations) + .jwtProcessorCustomizer((p) -> p + .setJWSTypeVerifier(new DefaultJOSEObjectTypeVerifier<>(new JOSEObjectType("JWS"))) + ) .build(); - assertThatExceptionOfType(BadJwtException.class).isThrownBy(() -> jwtDecoder.decode(SIGNED_JWT)) + assertThatExceptionOfType(BadJwtException.class) + .isThrownBy(() -> jwtDecoder.decode(SIGNED_JWT)) .withMessageContaining("An error occurred while attempting to decode the Jwt: " + "Required JOSE header \"typ\" (type) parameter is missing"); + // @formatter:on } @Test public void withJwkSetUriWhenJwtProcessorCustomizerNullThenThrowsIllegalArgumentException() { + // @formatter:off assertThatIllegalArgumentException() .isThrownBy(() -> NimbusJwtDecoder.withJwkSetUri(JWK_SET_URI).jwtProcessorCustomizer(null)) .withMessage("jwtProcessorCustomizer cannot be null"); + // @formatter:on } private RSAPublicKey key() throws InvalidKeySpecException { @@ -574,7 +737,11 @@ public class NimbusJwtDecoderTests { RestOperations restOperations = mock(RestOperations.class); given(restOperations.exchange(any(RequestEntity.class), eq(String.class))) .willReturn(new ResponseEntity<>(jwkResponse, HttpStatus.OK)); - return NimbusJwtDecoder.withJwkSetUri(JWK_SET_URI).restOperations(restOperations).processor(); + // @formatter:off + return NimbusJwtDecoder.withJwkSetUri(JWK_SET_URI) + .restOperations(restOperations) + .processor(); + // @formatter:on } private static JWTProcessor withoutSigning() { diff --git a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusReactiveJwtDecoderTests.java b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusReactiveJwtDecoderTests.java index a33eb0af3e..f53f822c57 100644 --- a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusReactiveJwtDecoderTests.java +++ b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusReactiveJwtDecoderTests.java @@ -86,10 +86,19 @@ public class NimbusReactiveJwtDecoderTests { private String unsignedToken = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJleHAiOi0yMDMzMjI0OTcsImp0aSI6IjEyMyIsInR5cCI6IkpXVCJ9."; - private String jwkSet = "{\n" + " \"keys\":[\n" + " {\n" + " \"kty\":\"RSA\",\n" - + " \"e\":\"AQAB\",\n" + " \"use\":\"sig\",\n" + " \"kid\":\"key-id-1\",\n" + // @formatter:off + private String jwkSet = "{\n" + + " \"keys\":[\n" + + " {\n" + + " \"kty\":\"RSA\",\n" + + " \"e\":\"AQAB\",\n" + + " \"use\":\"sig\",\n" + + " \"kid\":\"key-id-1\",\n" + " \"n\":\"qL48v1clgFw-Evm145pmh8nRYiNt72Gupsshn7Qs8dxEydCRp1DPOV_PahPk1y2nvldBNIhfNL13JOAiJ6BTiF-2ICuICAhDArLMnTH61oL1Hepq8W1xpa9gxsnL1P51thvfmiiT4RTW57koy4xIWmIp8ZXXfYgdH2uHJ9R0CQBuYKe7nEOObjxCFWC8S30huOfW2cYtv0iB23h6w5z2fDLjddX6v_FXM7ktcokgpm3_XmvT_-bL6_GGwz9k6kJOyMTubecr-WT__le8ikY66zlplYXRQh6roFfFCL21Pt8xN5zrk-0AMZUnmi8F2S2ztSBmAVJ7H71ELXsURBVZpw\"\n" - + " }\n" + " ]\n" + "}"; + + " }\n" + + " ]\n" + + "}"; + // @formatter:on private String jwkSetUri = "https://issuer/certs"; @@ -126,8 +135,11 @@ public class NimbusReactiveJwtDecoderTests { @Test public void decodeWhenInvalidUrl() { this.decoder = new NimbusReactiveJwtDecoder("https://s"); - assertThatIllegalStateException().isThrownBy(() -> this.decoder.decode(this.messageReadToken).block()) + // @formatter:off + assertThatIllegalStateException() + .isThrownBy(() -> this.decoder.decode(this.messageReadToken).block()) .withCauseInstanceOf(UnknownHostException.class); + // @formatter:on } @Test @@ -162,13 +174,19 @@ public class NimbusReactiveJwtDecoderTests { @Test public void decodeWhenNoPeriodThenFail() { - assertThatExceptionOfType(BadJwtException.class).isThrownBy(() -> this.decoder.decode("").block()); + // @formatter:off + assertThatExceptionOfType(BadJwtException.class) + .isThrownBy(() -> this.decoder.decode("").block()); + // @formatter:on } @Test public void decodeWhenInvalidJwkSetUrlThenFail() { this.decoder = new NimbusReactiveJwtDecoder("http://localhost:1280/certs"); - assertThatIllegalStateException().isThrownBy(() -> this.decoder.decode(this.messageReadToken).block()); + // @formatter:off + assertThatIllegalStateException() + .isThrownBy(() -> this.decoder.decode(this.messageReadToken).block()); + // @formatter:on } @Test @@ -179,23 +197,34 @@ public class NimbusReactiveJwtDecoderTests { @Test public void decodeWhenAlgNoneThenFail() { - assertThatExceptionOfType(BadJwtException.class).isThrownBy(() -> this.decoder.decode( - "ew0KICAiYWxnIjogIm5vbmUiLA0KICAidHlwIjogIkpXVCINCn0.ew0KICAic3ViIjogIjEyMzQ1Njc4OTAiLA0KICAibmFtZSI6ICJKb2huIERvZSIsDQogICJpYXQiOiAxNTE2MjM5MDIyDQp9.") - .block()).withMessage("Unsupported algorithm of none"); + // @formatter:off + assertThatExceptionOfType(BadJwtException.class) + .isThrownBy(() -> this.decoder + .decode("ew0KICAiYWxnIjogIm5vbmUiLA0KICAidHlwIjogIkpXVCINCn0.ew0KICAic3ViIjogIjEyMzQ1Njc4OTAiLA0KICAibmFtZSI6ICJKb2huIERvZSIsDQogICJpYXQiOiAxNTE2MjM5MDIyDQp9.") + .block() + ) + .withMessage("Unsupported algorithm of none"); + // @formatter:on } @Test public void decodeWhenInvalidAlgMismatchThenFail() { - assertThatExceptionOfType(BadJwtException.class).isThrownBy(() -> this.decoder.decode( - "ew0KICAiYWxnIjogIkVTMjU2IiwNCiAgInR5cCI6ICJKV1QiDQp9.ew0KICAic3ViIjogIjEyMzQ1Njc4OTAiLA0KICAibmFtZSI6ICJKb2huIERvZSIsDQogICJpYXQiOiAxNTE2MjM5MDIyDQp9.") - .block()); + // @formatter:off + assertThatExceptionOfType(BadJwtException.class) + .isThrownBy(() -> this.decoder + .decode("ew0KICAiYWxnIjogIkVTMjU2IiwNCiAgInR5cCI6ICJKV1QiDQp9.ew0KICAic3ViIjogIjEyMzQ1Njc4OTAiLA0KICAibmFtZSI6ICJKb2huIERvZSIsDQogICJpYXQiOiAxNTE2MjM5MDIyDQp9.") + .block() + ); + // @formatter:on } @Test public void decodeWhenUnsignedTokenThenMessageDoesNotMentionClass() { + // @formatter:off assertThatExceptionOfType(BadJwtException.class) .isThrownBy(() -> this.decoder.decode(this.unsignedToken).block()) .withMessage("Unsupported algorithm of none"); + // @formatter:on } @Test @@ -205,9 +234,11 @@ public class NimbusReactiveJwtDecoderTests { OAuth2Error error = new OAuth2Error("mock-error", "mock-description", "mock-uri"); OAuth2TokenValidatorResult result = OAuth2TokenValidatorResult.failure(error); given(jwtValidator.validate(any(Jwt.class))).willReturn(result); + // @formatter:off assertThatExceptionOfType(JwtValidationException.class) .isThrownBy(() -> this.decoder.decode(this.messageReadToken).block()) .withMessageContaining("mock-description"); + // @formatter:on } @Test @@ -219,9 +250,11 @@ public class NimbusReactiveJwtDecoderTests { OAuth2Error error2 = new OAuth2Error("mock-error-second", "mock-description-second", "mock-uri-second"); OAuth2TokenValidatorResult result = OAuth2TokenValidatorResult.failure(errorEmpty, error, error2); given(jwtValidator.validate(any(Jwt.class))).willReturn(result); + // @formatter:off assertThatExceptionOfType(JwtValidationException.class) .isThrownBy(() -> this.decoder.decode(this.messageReadToken).block()) .withMessageContaining("mock-description"); + // @formatter:on } @Test @@ -241,18 +274,26 @@ public class NimbusReactiveJwtDecoderTests { Converter, Map> claimSetConverter = mock(Converter.class); this.decoder.setClaimSetConverter(claimSetConverter); given(claimSetConverter.convert(any(Map.class))).willThrow(new IllegalArgumentException("bad conversion")); + // @formatter:off assertThatExceptionOfType(BadJwtException.class) .isThrownBy(() -> this.decoder.decode(this.messageReadToken).block()); + // @formatter:on } @Test public void setJwtValidatorWhenGivenNullThrowsIllegalArgumentException() { - assertThatIllegalArgumentException().isThrownBy(() -> this.decoder.setJwtValidator(null)); + // @formatter:off + assertThatIllegalArgumentException() + .isThrownBy(() -> this.decoder.setJwtValidator(null)); + // @formatter:on } @Test public void setClaimSetConverterWhenNullThrowsIllegalArgumentException() { - assertThatIllegalArgumentException().isThrownBy(() -> this.decoder.setClaimSetConverter(null)); + // @formatter:off + assertThatIllegalArgumentException() + .isThrownBy(() -> this.decoder.setClaimSetConverter(null)); + // @formatter:on } @Test @@ -269,25 +310,39 @@ public class NimbusReactiveJwtDecoderTests { @Test public void withJwkSetUriWhenJwtProcessorCustomizerNullThenThrowsIllegalArgumentException() { - assertThatIllegalArgumentException().isThrownBy( - () -> NimbusReactiveJwtDecoder.withJwkSetUri(this.jwkSetUri).jwtProcessorCustomizer(null).build()) + // @formatter:off + assertThatIllegalArgumentException() + .isThrownBy(() -> NimbusReactiveJwtDecoder + .withJwkSetUri(this.jwkSetUri) + .jwtProcessorCustomizer(null) + .build() + ) .withMessage("jwtProcessorCustomizer cannot be null"); + // @formatter:on } @Test public void restOperationsWhenNullThenThrowsException() { NimbusReactiveJwtDecoder.JwkSetUriReactiveJwtDecoderBuilder builder = NimbusReactiveJwtDecoder .withJwkSetUri(this.jwkSetUri); - assertThatIllegalArgumentException().isThrownBy(() -> builder.webClient(null)); + // @formatter:off + assertThatIllegalArgumentException() + .isThrownBy(() -> builder.webClient(null)); + // @formatter:on } // gh-5603 @Test public void decodeWhenSignedThenOk() { WebClient webClient = mockJwkSetResponse(this.jwkSet); - NimbusReactiveJwtDecoder decoder = NimbusReactiveJwtDecoder.withJwkSetUri(this.jwkSetUri).webClient(webClient) + // @formatter:off + NimbusReactiveJwtDecoder decoder = NimbusReactiveJwtDecoder.withJwkSetUri(this.jwkSetUri) + .webClient(webClient) .build(); - assertThat(decoder.decode(this.messageReadToken).block()).extracting(Jwt::getExpiresAt).isNotNull(); + assertThat(decoder.decode(this.messageReadToken).block()) + .extracting(Jwt::getExpiresAt) + .isNotNull(); + // @formatter:on verify(webClient).get(); } @@ -295,66 +350,108 @@ public class NimbusReactiveJwtDecoderTests { @Test public void withJwkSetUriWhenUsingCustomTypeHeaderThenRefuseOmittedType() { WebClient webClient = mockJwkSetResponse(this.jwkSet); - NimbusReactiveJwtDecoder decoder = NimbusReactiveJwtDecoder.withJwkSetUri(this.jwkSetUri).webClient(webClient) - .jwtProcessorCustomizer( - (p) -> p.setJWSTypeVerifier(new DefaultJOSEObjectTypeVerifier<>(new JOSEObjectType("JWS")))) + // @formatter:off + NimbusReactiveJwtDecoder decoder = NimbusReactiveJwtDecoder.withJwkSetUri(this.jwkSetUri) + .webClient(webClient) + .jwtProcessorCustomizer((p) -> p + .setJWSTypeVerifier(new DefaultJOSEObjectTypeVerifier<>(new JOSEObjectType("JWS"))) + ) .build(); - assertThatExceptionOfType(BadJwtException.class).isThrownBy(() -> decoder.decode(this.messageReadToken).block()) + assertThatExceptionOfType(BadJwtException.class) + .isThrownBy(() -> decoder.decode(this.messageReadToken).block()) .havingRootCause().withMessage("Required JOSE header \"typ\" (type) parameter is missing"); + // @formatter:on } @Test public void withPublicKeyWhenNullThenThrowsException() { - assertThatIllegalArgumentException().isThrownBy(() -> NimbusReactiveJwtDecoder.withPublicKey(null)); + // @formatter:off + assertThatIllegalArgumentException() + .isThrownBy(() -> NimbusReactiveJwtDecoder.withPublicKey(null)); + // @formatter:on } @Test public void buildWhenSignatureAlgorithmMismatchesKeyTypeThenThrowsException() { - assertThatIllegalStateException().isThrownBy(() -> NimbusReactiveJwtDecoder.withPublicKey(key()) - .signatureAlgorithm(SignatureAlgorithm.ES256).build()); + // @formatter:off + assertThatIllegalStateException() + .isThrownBy(() -> NimbusReactiveJwtDecoder.withPublicKey(key()) + .signatureAlgorithm(SignatureAlgorithm.ES256) + .build() + ); + // @formatter:on } @Test public void buildWhenJwtProcessorCustomizerNullThenThrowsIllegalArgumentException() { + // @formatter:off assertThatIllegalArgumentException() - .isThrownBy(() -> NimbusReactiveJwtDecoder.withPublicKey(key()).jwtProcessorCustomizer(null).build()) + .isThrownBy(() -> NimbusReactiveJwtDecoder.withPublicKey(key()) + .jwtProcessorCustomizer(null) + .build() + ) .withMessage("jwtProcessorCustomizer cannot be null"); + // @formatter:on } @Test public void decodeWhenUsingPublicKeyThenSuccessfullyDecodes() throws Exception { - NimbusReactiveJwtDecoder decoder = NimbusReactiveJwtDecoder.withPublicKey(key()).build(); - assertThat(decoder.decode(this.rsa256).block()).extracting(Jwt::getSubject).isEqualTo("test-subject"); + // @formatter:off + NimbusReactiveJwtDecoder decoder = NimbusReactiveJwtDecoder.withPublicKey(key()) + .build(); + assertThat(decoder.decode(this.rsa256).block()) + .extracting(Jwt::getSubject) + .isEqualTo("test-subject"); + // @formatter:on } @Test public void decodeWhenUsingPublicKeyWithRs512ThenSuccessfullyDecodes() throws Exception { + // @formatter:off NimbusReactiveJwtDecoder decoder = NimbusReactiveJwtDecoder.withPublicKey(key()) - .signatureAlgorithm(SignatureAlgorithm.RS512).build(); - assertThat(decoder.decode(this.rsa512).block()).extracting(Jwt::getSubject).isEqualTo("test-subject"); + .signatureAlgorithm(SignatureAlgorithm.RS512) + .build(); + assertThat(decoder.decode(this.rsa512).block()) + .extracting(Jwt::getSubject) + .isEqualTo("test-subject"); + // @formatter:on } @Test public void decodeWhenSignatureMismatchesAlgorithmThenThrowsException() throws Exception { + // @formatter:off NimbusReactiveJwtDecoder decoder = NimbusReactiveJwtDecoder.withPublicKey(key()) - .signatureAlgorithm(SignatureAlgorithm.RS512).build(); - assertThatExceptionOfType(BadJwtException.class).isThrownBy(() -> decoder.decode(this.rsa256).block()); + .signatureAlgorithm(SignatureAlgorithm.RS512) + .build(); + assertThatExceptionOfType(BadJwtException.class) + .isThrownBy(() -> decoder + .decode(this.rsa256) + .block() + ); + // @formatter:on } // gh-8730 @Test public void withPublicKeyWhenUsingCustomTypeHeaderThenRefuseOmittedType() throws Exception { + // @formatter:off NimbusReactiveJwtDecoder decoder = NimbusReactiveJwtDecoder.withPublicKey(key()) - .jwtProcessorCustomizer( - (p) -> p.setJWSTypeVerifier(new DefaultJOSEObjectTypeVerifier<>(new JOSEObjectType("JWS")))) + .jwtProcessorCustomizer((p) -> p + .setJWSTypeVerifier(new DefaultJOSEObjectTypeVerifier<>(new JOSEObjectType("JWS"))) + ) .build(); - assertThatExceptionOfType(BadJwtException.class).isThrownBy(() -> decoder.decode(this.rsa256).block()) + assertThatExceptionOfType(BadJwtException.class) + .isThrownBy(() -> decoder.decode(this.rsa256).block()) .havingRootCause().withMessage("Required JOSE header \"typ\" (type) parameter is missing"); + // @formatter:on } @Test public void withJwkSourceWhenNullThenThrowsException() { - assertThatIllegalArgumentException().isThrownBy(() -> NimbusReactiveJwtDecoder.withJwkSource(null)); + // @formatter:off + assertThatIllegalArgumentException() + .isThrownBy(() -> NimbusReactiveJwtDecoder.withJwkSource(null)); + // @formatter:on } @Test @@ -366,54 +463,87 @@ public class NimbusReactiveJwtDecoderTests { @Test public void decodeWhenCustomJwkSourceResolutionThenDecodes() { + // @formatter:off NimbusReactiveJwtDecoder decoder = NimbusReactiveJwtDecoder - .withJwkSource((jwt) -> Flux.fromIterable(parseJWKSet(this.jwkSet).getKeys())).build(); - assertThat(decoder.decode(this.messageReadToken).block()).extracting(Jwt::getExpiresAt).isNotNull(); + .withJwkSource((jwt) -> Flux.fromIterable(parseJWKSet(this.jwkSet).getKeys())) + .build(); + assertThat(decoder.decode(this.messageReadToken).block()) + .extracting(Jwt::getExpiresAt) + .isNotNull(); + // @formatter:on } // gh-8730 @Test public void withJwkSourceWhenUsingCustomTypeHeaderThenRefuseOmittedType() { - NimbusReactiveJwtDecoder decoder = NimbusReactiveJwtDecoder.withJwkSource((jwt) -> Flux.empty()) - .jwtProcessorCustomizer( - (p) -> p.setJWSTypeVerifier(new DefaultJOSEObjectTypeVerifier<>(new JOSEObjectType("JWS")))) + // @formatter:off + NimbusReactiveJwtDecoder decoder = NimbusReactiveJwtDecoder + .withJwkSource((jwt) -> Flux.empty()) + .jwtProcessorCustomizer((p) -> p + .setJWSTypeVerifier(new DefaultJOSEObjectTypeVerifier<>(new JOSEObjectType("JWS"))) + ) .build(); - assertThatExceptionOfType(BadJwtException.class).isThrownBy(() -> decoder.decode(this.messageReadToken).block()) - .havingRootCause().withMessage("Required JOSE header \"typ\" (type) parameter is missing"); + assertThatExceptionOfType(BadJwtException.class) + .isThrownBy(() -> decoder.decode(this.messageReadToken).block()) + .havingRootCause() + .withMessage("Required JOSE header \"typ\" (type) parameter is missing"); + // @formatter:on } @Test public void withSecretKeyWhenSecretKeyNullThenThrowsIllegalArgumentException() { - assertThatIllegalArgumentException().isThrownBy(() -> NimbusReactiveJwtDecoder.withSecretKey(null)) + // @formatter:off + assertThatIllegalArgumentException() + .isThrownBy(() -> NimbusReactiveJwtDecoder.withSecretKey(null)) .withMessage("secretKey cannot be null"); + // @formatter:on } @Test public void withSecretKeyWhenJwtProcessorCustomizerNullThenThrowsIllegalArgumentException() { SecretKey secretKey = TestKeys.DEFAULT_SECRET_KEY; + // @formatter:off assertThatIllegalArgumentException() - .isThrownBy( - () -> NimbusReactiveJwtDecoder.withSecretKey(secretKey).jwtProcessorCustomizer(null).build()) + .isThrownBy(() -> NimbusReactiveJwtDecoder + .withSecretKey(secretKey) + .jwtProcessorCustomizer(null) + .build() + ) .withMessage("jwtProcessorCustomizer cannot be null"); + // @formatter:on } @Test public void withSecretKeyWhenMacAlgorithmNullThenThrowsIllegalArgumentException() { SecretKey secretKey = TestKeys.DEFAULT_SECRET_KEY; + // @formatter:off assertThatIllegalArgumentException() - .isThrownBy(() -> NimbusReactiveJwtDecoder.withSecretKey(secretKey).macAlgorithm(null)) + .isThrownBy(() -> NimbusReactiveJwtDecoder + .withSecretKey(secretKey) + .macAlgorithm(null) + ) .withMessage("macAlgorithm cannot be null"); + // @formatter:on } @Test public void decodeWhenSecretKeyThenSuccess() throws Exception { SecretKey secretKey = TestKeys.DEFAULT_SECRET_KEY; MacAlgorithm macAlgorithm = MacAlgorithm.HS256; - JWTClaimsSet claimsSet = new JWTClaimsSet.Builder().subject("test-subject") - .expirationTime(Date.from(Instant.now().plusSeconds(60))).build(); + // @formatter:off + JWTClaimsSet claimsSet = new JWTClaimsSet.Builder() + .subject("test-subject") + .expirationTime(Date.from(Instant.now().plusSeconds(60))) + .build(); + // @formatter:on SignedJWT signedJWT = signedJwt(secretKey, macAlgorithm, claimsSet); - this.decoder = NimbusReactiveJwtDecoder.withSecretKey(secretKey).macAlgorithm(macAlgorithm).build(); - Jwt jwt = this.decoder.decode(signedJWT.serialize()).block(); + // @formatter:off + this.decoder = NimbusReactiveJwtDecoder.withSecretKey(secretKey) + .macAlgorithm(macAlgorithm) + .build(); + Jwt jwt = this.decoder.decode(signedJWT.serialize()) + .block(); + // @formatter:on assertThat(jwt.getSubject()).isEqualTo("test-subject"); } @@ -421,24 +551,34 @@ public class NimbusReactiveJwtDecoderTests { @Test public void withSecretKeyWhenUsingCustomTypeHeaderThenRefuseOmittedType() { SecretKey secretKey = TestKeys.DEFAULT_SECRET_KEY; + // @formatter:off NimbusReactiveJwtDecoder decoder = NimbusReactiveJwtDecoder.withSecretKey(secretKey) - .jwtProcessorCustomizer( - (p) -> p.setJWSTypeVerifier(new DefaultJOSEObjectTypeVerifier<>(new JOSEObjectType("JWS")))) + .jwtProcessorCustomizer((p) -> p + .setJWSTypeVerifier(new DefaultJOSEObjectTypeVerifier<>(new JOSEObjectType("JWS"))) + ) .build(); - assertThatExceptionOfType(BadJwtException.class).isThrownBy(() -> decoder.decode(this.messageReadToken).block()) + assertThatExceptionOfType(BadJwtException.class) + .isThrownBy(() -> decoder.decode(this.messageReadToken).block()) .havingRootCause().withMessage("Required JOSE header \"typ\" (type) parameter is missing"); + // @formatter:on } @Test public void decodeWhenSecretKeyAndAlgorithmMismatchThenThrowsJwtException() throws Exception { SecretKey secretKey = TestKeys.DEFAULT_SECRET_KEY; MacAlgorithm macAlgorithm = MacAlgorithm.HS256; - JWTClaimsSet claimsSet = new JWTClaimsSet.Builder().subject("test-subject") - .expirationTime(Date.from(Instant.now().plusSeconds(60))).build(); + JWTClaimsSet claimsSet = new JWTClaimsSet.Builder() + .subject("test-subject") + .expirationTime(Date.from(Instant.now().plusSeconds(60))) + .build(); SignedJWT signedJWT = signedJwt(secretKey, macAlgorithm, claimsSet); - this.decoder = NimbusReactiveJwtDecoder.withSecretKey(secretKey).macAlgorithm(MacAlgorithm.HS512).build(); + // @formatter:off + this.decoder = NimbusReactiveJwtDecoder.withSecretKey(secretKey) + .macAlgorithm(MacAlgorithm.HS512) + .build(); assertThatExceptionOfType(BadJwtException.class) .isThrownBy(() -> this.decoder.decode(signedJWT.serialize()).block()); + // @formatter:on } @Test @@ -464,9 +604,12 @@ public class NimbusReactiveJwtDecoderTests { @Test public void jwsKeySelectorWhenMultipleAlgorithmThenReturnsCompositeSelector() { JWKSource jwkSource = mock(JWKSource.class); + // @formatter:off JWSKeySelector jwsKeySelector = NimbusReactiveJwtDecoder.withJwkSetUri(this.jwkSetUri) - .jwsAlgorithm(SignatureAlgorithm.RS256).jwsAlgorithm(SignatureAlgorithm.RS512) + .jwsAlgorithm(SignatureAlgorithm.RS256) + .jwsAlgorithm(SignatureAlgorithm.RS512) .jwsKeySelector(jwkSource); + // @formatter:on assertThat(jwsKeySelector instanceof JWSVerificationKeySelector); JWSVerificationKeySelector jwsAlgorithmMapKeySelector = (JWSVerificationKeySelector) jwsKeySelector; assertThat(jwsAlgorithmMapKeySelector.isAllowed(JWSAlgorithm.RS256)).isTrue(); diff --git a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/ReactiveJwtDecodersTests.java b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/ReactiveJwtDecodersTests.java index 57a7c37c63..6c5d22ef30 100644 --- a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/ReactiveJwtDecodersTests.java +++ b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/ReactiveJwtDecodersTests.java @@ -54,15 +54,30 @@ public class ReactiveJwtDecodersTests { * Contains those parameters required to construct a ReactiveJwtDecoder as well as any * required parameters */ + // @formatter:off private static final String DEFAULT_RESPONSE_TEMPLATE = "{\n" + " \"authorization_endpoint\": \"https://example.com/o/oauth2/v2/auth\", \n" - + " \"id_token_signing_alg_values_supported\": [\n" + " \"RS256\"\n" + " ], \n" - + " \"issuer\": \"%s\", \n" + " \"jwks_uri\": \"%s/.well-known/jwks.json\", \n" - + " \"response_types_supported\": [\n" + " \"code\", \n" + " \"token\", \n" - + " \"id_token\", \n" + " \"code token\", \n" + " \"code id_token\", \n" - + " \"token id_token\", \n" + " \"code token id_token\", \n" + " \"none\"\n" - + " ], \n" + " \"subject_types_supported\": [\n" + " \"public\"\n" + " ], \n" - + " \"token_endpoint\": \"https://example.com/oauth2/v4/token\"\n" + "}"; + + " \"id_token_signing_alg_values_supported\": [\n" + + " \"RS256\"\n" + + " ], \n" + + " \"issuer\": \"%s\", \n" + + " \"jwks_uri\": \"%s/.well-known/jwks.json\", \n" + + " \"response_types_supported\": [\n" + + " \"code\", \n" + + " \"token\", \n" + + " \"id_token\", \n" + + " \"code token\", \n" + + " \"code id_token\", \n" + + " \"token id_token\", \n" + + " \"code token id_token\", \n" + + " \"none\"\n" + + " ], \n" + + " \"subject_types_supported\": [\n" + + " \"public\"\n" + + " ], \n" + + " \"token_endpoint\": \"https://example.com/oauth2/v4/token\"\n" + + "}"; + // @formatter:on private static final String JWK_SET = "{\"keys\":[{\"p\":\"49neceJFs8R6n7WamRGy45F5Tv0YM-R2ODK3eSBUSLOSH2tAqjEVKOkLE5fiNA3ygqq15NcKRadB2pTVf-Yb5ZIBuKzko8bzYIkIqYhSh_FAdEEr0vHF5fq_yWSvc6swsOJGqvBEtuqtJY027u-G2gAQasCQdhyejer68zsTn8M\",\"kty\":\"RSA\",\"q\":\"tWR-ysspjZ73B6p2vVRVyHwP3KQWL5KEQcdgcmMOE_P_cPs98vZJfLhxobXVmvzuEWBpRSiqiuyKlQnpstKt94Cy77iO8m8ISfF3C9VyLWXi9HUGAJb99irWABFl3sNDff5K2ODQ8CmuXLYM25OwN3ikbrhEJozlXg_NJFSGD4E\",\"d\":\"FkZHYZlw5KSoqQ1i2RA2kCUygSUOf1OqMt3uomtXuUmqKBm_bY7PCOhmwbvbn4xZYEeHuTR8Xix-0KpHe3NKyWrtRjkq1T_un49_1LLVUhJ0dL-9_x0xRquVjhl_XrsRXaGMEHs8G9pLTvXQ1uST585gxIfmCe0sxPZLvwoic-bXf64UZ9BGRV3lFexWJQqCZp2S21HfoU7wiz6kfLRNi-K4xiVNB1gswm_8o5lRuY7zB9bRARQ3TS2G4eW7p5sxT3CgsGiQD3_wPugU8iDplqAjgJ5ofNJXZezoj0t6JMB_qOpbrmAM1EnomIPebSLW7Ky9SugEd6KMdL5lW6AuAQ\",\"e\":\"AQAB\",\"use\":\"sig\",\"kid\":\"one\",\"qi\":\"wdkFu_tV2V1l_PWUUimG516Zvhqk2SWDw1F7uNDD-Lvrv_WNRIJVzuffZ8WYiPy8VvYQPJUrT2EXL8P0ocqwlaSTuXctrORcbjwgxDQDLsiZE0C23HYzgi0cofbScsJdhcBg7d07LAf7cdJWG0YVl1FkMCsxUlZ2wTwHfKWf-v4\",\"dp\":\"uwnPxqC-IxG4r33-SIT02kZC1IqC4aY7PWq0nePiDEQMQWpjjNH50rlq9EyLzbtdRdIouo-jyQXB01K15-XXJJ60dwrGLYNVqfsTd0eGqD1scYJGHUWG9IDgCsxyEnuG3s0AwbW2UolWVSsU2xMZGb9PurIUZECeD1XDZwMp2s0\",\"dq\":\"hra786AunB8TF35h8PpROzPoE9VJJMuLrc6Esm8eZXMwopf0yhxfN2FEAvUoTpLJu93-UH6DKenCgi16gnQ0_zt1qNNIVoRfg4rw_rjmsxCYHTVL3-RDeC8X_7TsEySxW0EgFTHh-nr6I6CQrAJjPM88T35KHtdFATZ7BCBB8AE\",\"n\":\"oXJ8OyOv_eRnce4akdanR4KYRfnC2zLV4uYNQpcFn6oHL0dj7D6kxQmsXoYgJV8ZVDn71KGmuLvolxsDncc2UrhyMBY6DVQVgMSVYaPCTgW76iYEKGgzTEw5IBRQL9w3SRJWd3VJTZZQjkXef48Ocz06PGF3lhbz4t5UEZtdF4rIe7u-977QwHuh7yRPBQ3sII-cVoOUMgaXB9SHcGF2iZCtPzL_IffDUcfhLQteGebhW8A6eUHgpD5A1PQ-JCw_G7UOzZAjjDjtNM2eqm8j-Ms_gqnm4MiCZ4E-9pDN77CAAPVN7kuX6ejs9KBXpk01z48i9fORYk9u7rAkh1HuQw\"}]}"; @@ -93,48 +108,60 @@ public class ReactiveJwtDecodersTests { public void issuerWhenResponseIsTypicalThenReturnedDecoderValidatesIssuer() { prepareConfigurationResponse(); ReactiveJwtDecoder decoder = ReactiveJwtDecoders.fromOidcIssuerLocation(this.issuer); + // @formatter:off assertThatExceptionOfType(JwtValidationException.class) .isThrownBy(() -> decoder.decode(ISSUER_MISMATCH).block()) .withMessageContaining("The iss claim is not valid"); + // @formatter:on } @Test public void issuerWhenOidcFallbackResponseIsTypicalThenReturnedDecoderValidatesIssuer() { prepareConfigurationResponseOidc(); ReactiveJwtDecoder decoder = ReactiveJwtDecoders.fromIssuerLocation(this.issuer); + // @formatter:off assertThatExceptionOfType(JwtValidationException.class) .isThrownBy(() -> decoder.decode(ISSUER_MISMATCH).block()) .withMessageContaining("The iss claim is not valid"); + // @formatter:on } @Test public void issuerWhenOAuth2ResponseIsTypicalThenReturnedDecoderValidatesIssuer() { prepareConfigurationResponseOAuth2(); ReactiveJwtDecoder decoder = ReactiveJwtDecoders.fromIssuerLocation(this.issuer); + // @formatter:off assertThatExceptionOfType(JwtValidationException.class) .isThrownBy(() -> decoder.decode(ISSUER_MISMATCH).block()) .withMessageContaining("The iss claim is not valid"); + // @formatter:on } @Test public void issuerWhenResponseIsNonCompliantThenThrowsRuntimeException() { prepareConfigurationResponse("{ \"missing_required_keys\" : \"and_values\" }"); + // @formatter:off assertThatExceptionOfType(RuntimeException.class) .isThrownBy(() -> ReactiveJwtDecoders.fromOidcIssuerLocation(this.issuer)); + // @formatter:on } @Test public void issuerWhenOidcFallbackResponseIsNonCompliantThenThrowsRuntimeException() { prepareConfigurationResponseOidc("{ \"missing_required_keys\" : \"and_values\" }"); + // @formatter:off assertThatExceptionOfType(RuntimeException.class) .isThrownBy(() -> ReactiveJwtDecoders.fromIssuerLocation(this.issuer)); + // @formatter:on } @Test public void issuerWhenOAuth2ResponseIsNonCompliantThenThrowsRuntimeException() { prepareConfigurationResponseOAuth2("{ \"missing_required_keys\" : \"and_values\" }"); + // @formatter:off assertThatExceptionOfType(RuntimeException.class) .isThrownBy(() -> ReactiveJwtDecoders.fromIssuerLocation(this.issuer)); + // @formatter:on } // gh-7512 @@ -142,8 +169,11 @@ public class ReactiveJwtDecodersTests { public void issuerWhenResponseDoesNotContainJwksUriThenThrowsIllegalArgumentException() throws JsonMappingException, JsonProcessingException { prepareConfigurationResponse(this.buildResponseWithMissingJwksUri()); - assertThatIllegalArgumentException().isThrownBy(() -> ReactiveJwtDecoders.fromOidcIssuerLocation(this.issuer)) + // @formatter:off + assertThatIllegalArgumentException() + .isThrownBy(() -> ReactiveJwtDecoders.fromOidcIssuerLocation(this.issuer)) .withMessage("The public JWK set URI must not be null"); + // @formatter:on } // gh-7512 @@ -151,8 +181,11 @@ public class ReactiveJwtDecodersTests { public void issuerWhenOidcFallbackResponseDoesNotContainJwksUriThenThrowsIllegalArgumentException() throws JsonMappingException, JsonProcessingException { prepareConfigurationResponseOidc(this.buildResponseWithMissingJwksUri()); - assertThatIllegalArgumentException().isThrownBy(() -> ReactiveJwtDecoders.fromIssuerLocation(this.issuer)) + // @formatter:off + assertThatIllegalArgumentException() + .isThrownBy(() -> ReactiveJwtDecoders.fromIssuerLocation(this.issuer)) .withMessage("The public JWK set URI must not be null"); + // @formatter:on } // gh-7512 @@ -160,62 +193,85 @@ public class ReactiveJwtDecodersTests { public void issuerWhenOAuth2ResponseDoesNotContainJwksUriThenThrowsIllegalArgumentException() throws JsonMappingException, JsonProcessingException { prepareConfigurationResponseOAuth2(this.buildResponseWithMissingJwksUri()); - assertThatIllegalArgumentException().isThrownBy(() -> ReactiveJwtDecoders.fromIssuerLocation(this.issuer)) + // @formatter:off + assertThatIllegalArgumentException() + .isThrownBy(() -> ReactiveJwtDecoders.fromIssuerLocation(this.issuer)) .withMessage("The public JWK set URI must not be null"); + // @formatter:on } @Test public void issuerWhenResponseIsMalformedThenThrowsRuntimeException() { prepareConfigurationResponse("malformed"); + // @formatter:off assertThatExceptionOfType(RuntimeException.class) .isThrownBy(() -> ReactiveJwtDecoders.fromOidcIssuerLocation(this.issuer)); + // @formatter:on } @Test public void issuerWhenOidcFallbackResponseIsMalformedThenThrowsRuntimeException() { prepareConfigurationResponseOidc("malformed"); + // @formatter:off assertThatExceptionOfType(RuntimeException.class) .isThrownBy(() -> ReactiveJwtDecoders.fromIssuerLocation(this.issuer)); + // @formatter:on } @Test public void issuerWhenOAuth2ResponseIsMalformedThenThrowsRuntimeException() { prepareConfigurationResponseOAuth2("malformed"); + // @formatter:off assertThatExceptionOfType(RuntimeException.class) .isThrownBy(() -> ReactiveJwtDecoders.fromIssuerLocation(this.issuer)); + // @formatter:on } @Test public void issuerWhenRespondingIssuerMismatchesRequestedIssuerThenThrowsIllegalStateException() { prepareConfigurationResponse(String.format(DEFAULT_RESPONSE_TEMPLATE, this.issuer + "/wrong", this.issuer)); - assertThatIllegalStateException().isThrownBy(() -> ReactiveJwtDecoders.fromOidcIssuerLocation(this.issuer)); + // @formatter:off + assertThatIllegalStateException() + .isThrownBy(() -> ReactiveJwtDecoders.fromOidcIssuerLocation(this.issuer)); + // @formatter:on } @Test public void issuerWhenOidcFallbackRespondingIssuerMismatchesRequestedIssuerThenThrowsIllegalStateException() { prepareConfigurationResponseOidc(String.format(DEFAULT_RESPONSE_TEMPLATE, this.issuer + "/wrong", this.issuer)); - assertThatIllegalStateException().isThrownBy(() -> ReactiveJwtDecoders.fromIssuerLocation(this.issuer)); + // @formatter:off + assertThatIllegalStateException() + .isThrownBy(() -> ReactiveJwtDecoders.fromIssuerLocation(this.issuer)); + // @formatter:on } @Test public void issuerWhenOAuth2RespondingIssuerMismatchesRequestedIssuerThenThrowsIllegalStateException() { prepareConfigurationResponseOAuth2( String.format(DEFAULT_RESPONSE_TEMPLATE, this.issuer + "/wrong", this.issuer)); - assertThatIllegalStateException().isThrownBy(() -> ReactiveJwtDecoders.fromIssuerLocation(this.issuer)); + // @formatter:off + assertThatIllegalStateException() + .isThrownBy(() -> ReactiveJwtDecoders.fromIssuerLocation(this.issuer)); + // @formatter:on } @Test public void issuerWhenRequestedIssuerIsUnresponsiveThenThrowsIllegalArgumentException() throws Exception { this.server.shutdown(); + // @formatter:off assertThatIllegalArgumentException() .isThrownBy(() -> ReactiveJwtDecoders.fromOidcIssuerLocation("https://issuer")); + // @formatter:on } @Test public void issuerWhenOidcFallbackRequestedIssuerIsUnresponsiveThenThrowsIllegalArgumentException() throws Exception { this.server.shutdown(); - assertThatIllegalArgumentException().isThrownBy(() -> ReactiveJwtDecoders.fromIssuerLocation("https://issuer")); + // @formatter:off + assertThatIllegalArgumentException() + .isThrownBy(() -> ReactiveJwtDecoders.fromIssuerLocation("https://issuer")); + // @formatter:on } private void prepareConfigurationResponse() { @@ -256,8 +312,13 @@ public class ReactiveJwtDecodersTests { Dispatcher dispatcher = new Dispatcher() { @Override public MockResponse dispatch(RecordedRequest request) { - return Optional.of(request).map(RecordedRequest::getRequestUrl).map(HttpUrl::toString) - .map(responses::get).orElse(new MockResponse().setResponseCode(404)); + // @formatter:off + return Optional.of(request) + .map(RecordedRequest::getRequestUrl) + .map(HttpUrl::toString) + .map(responses::get) + .orElse(new MockResponse().setResponseCode(404)); + // @formatter:on } }; this.server.setDispatcher(dispatcher); @@ -269,12 +330,20 @@ public class ReactiveJwtDecodersTests { private String oidc() { URI uri = URI.create(this.issuer); - return UriComponentsBuilder.fromUri(uri).replacePath(uri.getPath() + OIDC_METADATA_PATH).toUriString(); + // @formatter:off + return UriComponentsBuilder.fromUri(uri) + .replacePath(uri.getPath() + OIDC_METADATA_PATH) + .toUriString(); + // @formatter:on } private String oauth() { URI uri = URI.create(this.issuer); - return UriComponentsBuilder.fromUri(uri).replacePath(OAUTH_METADATA_PATH + uri.getPath()).toUriString(); + // @formatter:off + return UriComponentsBuilder.fromUri(uri) + .replacePath(OAUTH_METADATA_PATH + uri.getPath()) + .toUriString(); + // @formatter:on } private String jwks() { @@ -282,7 +351,10 @@ public class ReactiveJwtDecodersTests { } private MockResponse response(String body) { - return new MockResponse().setBody(body).setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); + // @formatter:off + return new MockResponse().setBody(body) + .setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); + // @formatter:on } public String buildResponseWithMissingJwksUri() throws JsonMappingException, JsonProcessingException { diff --git a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/ReactiveRemoteJWKSourceTests.java b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/ReactiveRemoteJWKSourceTests.java index 312d5bdc9c..7fecc4fc5e 100644 --- a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/ReactiveRemoteJWKSourceTests.java +++ b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/ReactiveRemoteJWKSourceTests.java @@ -52,23 +52,43 @@ public class ReactiveRemoteJWKSourceTests { private MockWebServer server; - private String keys = "{\n" + " \"keys\": [\n" + " {\n" + " \"alg\": \"RS256\", \n" + // @formatter:off + private String keys = "{\n" + + " \"keys\": [\n" + + " {\n" + + " \"alg\": \"RS256\", \n" + " \"e\": \"AQAB\", \n" + " \"kid\": \"1923397381d9574bb873202a90c32b7ceeaed027\", \n" + " \"kty\": \"RSA\", \n" + " \"n\": \"m4I5Dk5GnbzzUtqaljDVbpMONi1JLNJ8ZuXE8VvjCAVebDg5vTYhQ33jUwGgbn1wFmytUMgMmvK8A8Gpshl0sO2GBIZoh6_pwLrk657ZEtv-hx9fYKnzwyrfHqxtSswMAyr7XtKl8Ha1I03uFMSaYaaBTwVXCHByhzr4PVXfKAYJNbbcteUZfE8ODlBQkjQLI0IB78Nu8XIRrdzTF_5LCuM6rLUNtX6_KdzPpeX9KEtB7OBAfkdZEtBzGI-aYNLtIaL4qO6cVxBeVDLMoj9kVsRPylrwhEFQcGOjtJhwJwXFzTMZVhkiLFCHxZkkjoMrK5osSRlhduuGI9ot8XTUKQ\", \n" - + " \"use\": \"sig\"\n" + " }, \n" + " {\n" + " \"alg\": \"RS256\", \n" + + " \"use\": \"sig\"\n" + + " }, \n" + + " {\n" + + " \"alg\": \"RS256\", \n" + " \"e\": \"AQAB\", \n" + " \"kid\": \"7ddf54d3032d1f0d48c3618892ca74c1ac30ad77\", \n" + " \"kty\": \"RSA\", \n" + " \"n\": \"yLlYyux949b7qS-DdqTNjdZb4NtqiNH-Jt7DtRxmfW9XZLOQ6Q2NYgmPe9hyy5GHG7W3zsd6Q-rzq5eGRNEUx1767K1dS5PtkVWPiPG_M7rDqCu3HsLmKQKhRjHYaCWl5NuiMB5mXoPhSwrHd2yeGE7QHIV7_CiQFc1xQsXeiC-nTeJohJO3HI97w0GXE8pHspLYq9oG87f5IHxFr89abmwRug-D7QWQyW5b4doe4ZL-52J-8WHd52kGrGfu4QyV83oAad3I_9Q-yiWOXUr_0GIrzz4_-u5HgqYexnodFhZZSaKuRSg_b5qCnPhW8gBDLAHkmQzQMaWsN14L0pokbQ\", \n" - + " \"use\": \"sig\"\n" + " }\n" + " ]\n" + "}\n"; + + " \"use\": \"sig\"\n" + + " }\n" + + " ]\n" + + "}\n"; + // @formatter:on - private String keys2 = "{\n" + " \"keys\": [\n" + " {\n" + " \"alg\": \"RS256\", \n" - + " \"e\": \"AQAB\", \n" + " \"kid\": \"rotated\", \n" + // @formatter:off + private String keys2 = "{\n" + + " \"keys\": [\n" + + " {\n" + + " \"alg\": \"RS256\", \n" + + " \"e\": \"AQAB\", \n" + + " \"kid\": \"rotated\", \n" + " \"kty\": \"RSA\", \n" + " \"n\": \"m4I5Dk5GnbzzUtqaljDVbpMONi1JLNJ8ZuXE8VvjCAVebDg5vTYhQ33jUwGgbn1wFmytUMgMmvK8A8Gpshl0sO2GBIZoh6_pwLrk657ZEtv-hx9fYKnzwyrfHqxtSswMAyr7XtKl8Ha1I03uFMSaYaaBTwVXCHByhzr4PVXfKAYJNbbcteUZfE8ODlBQkjQLI0IB78Nu8XIRrdzTF_5LCuM6rLUNtX6_KdzPpeX9KEtB7OBAfkdZEtBzGI-aYNLtIaL4qO6cVxBeVDLMoj9kVsRPylrwhEFQcGOjtJhwJwXFzTMZVhkiLFCHxZkkjoMrK5osSRlhduuGI9ot8XTUKQ\", \n" - + " \"use\": \"sig\"\n" + " }\n" + " ]\n" + "}\n"; + + " \"use\": \"sig\"\n" + + " }\n" + + " ]\n" + + "}\n"; + // @formatter:on @Before public void setup() { diff --git a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/TestJwts.java b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/TestJwts.java index f975408bcc..f710d485e5 100644 --- a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/TestJwts.java +++ b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/TestJwts.java @@ -25,13 +25,25 @@ public final class TestJwts { } public static Jwt.Builder jwt() { - return Jwt.withTokenValue("token").header("alg", "none").audience(Arrays.asList("https://audience.example.org")) - .expiresAt(Instant.MAX).issuedAt(Instant.MIN).issuer("https://issuer.example.org").jti("jti") - .notBefore(Instant.MIN).subject("mock-test-subject"); + // @formatter:off + return Jwt.withTokenValue("token") + .header("alg", "none") + .audience(Arrays.asList("https://audience.example.org")) + .expiresAt(Instant.MAX) + .issuedAt(Instant.MIN) + .issuer("https://issuer.example.org") + .jti("jti") + .notBefore(Instant.MIN) + .subject("mock-test-subject"); + // @formatter:on } public static Jwt user() { - return jwt().claim("sub", "mock-test-subject").build(); + // @formatter:off + return jwt() + .claim("sub", "mock-test-subject") + .build(); + // @formatter:on } }