diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerAuthenticationManagerResolver.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerAuthenticationManagerResolver.java index 6f12c0e8ef..21a18e5fb2 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerAuthenticationManagerResolver.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerAuthenticationManagerResolver.java @@ -91,6 +91,7 @@ public final class JwtIssuerAuthenticationManagerResolver implements Authenticat * Construct a {@link JwtIssuerAuthenticationManagerResolver} using the provided * parameters * @param trustedIssuers an array of trusted issuers + * @since 6.2 */ public static JwtIssuerAuthenticationManagerResolver fromTrustedIssuers(String... trustedIssuers) { return fromTrustedIssuers(Set.of(trustedIssuers)); @@ -100,6 +101,7 @@ public final class JwtIssuerAuthenticationManagerResolver implements Authenticat * Construct a {@link JwtIssuerAuthenticationManagerResolver} using the provided * parameters * @param trustedIssuers a collection of trusted issuers + * @since 6.2 */ public static JwtIssuerAuthenticationManagerResolver fromTrustedIssuers(Collection trustedIssuers) { Assert.notEmpty(trustedIssuers, "trustedIssuers cannot be empty"); @@ -110,6 +112,7 @@ public final class JwtIssuerAuthenticationManagerResolver implements Authenticat * Construct a {@link JwtIssuerAuthenticationManagerResolver} using the provided * parameters * @param trustedIssuers a predicate to validate issuers + * @since 6.2 */ public static JwtIssuerAuthenticationManagerResolver fromTrustedIssuers(Predicate trustedIssuers) { Assert.notNull(trustedIssuers, "trustedIssuers cannot be null"); @@ -225,7 +228,7 @@ public final class JwtIssuerAuthenticationManagerResolver implements Authenticat } else { this.logger.debug(LogMessage - .format("Did not resolve AuthenticationManager since issuer '%s' is not trusted", issuer)); + .format("Did not resolve AuthenticationManager since issuer is not trusted", issuer)); } return null; } diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerReactiveAuthenticationManagerResolver.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerReactiveAuthenticationManagerResolver.java index d8e7a6ce90..6c1cc0a1db 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerReactiveAuthenticationManagerResolver.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerReactiveAuthenticationManagerResolver.java @@ -95,6 +95,7 @@ public final class JwtIssuerReactiveAuthenticationManagerResolver * Construct a {@link JwtIssuerReactiveAuthenticationManagerResolver} using the * provided parameters * @param trustedIssuers an array of trusted issuers + * @since 6.2 */ public static JwtIssuerReactiveAuthenticationManagerResolver fromTrustedIssuers(String... trustedIssuers) { return fromTrustedIssuers(Set.of(trustedIssuers)); @@ -104,6 +105,7 @@ public final class JwtIssuerReactiveAuthenticationManagerResolver * Construct a {@link JwtIssuerReactiveAuthenticationManagerResolver} using the * provided parameters * @param trustedIssuers a collection of trusted issuers + * @since 6.2 */ public static JwtIssuerReactiveAuthenticationManagerResolver fromTrustedIssuers(Collection trustedIssuers) { Assert.notEmpty(trustedIssuers, "trustedIssuers cannot be empty"); @@ -114,6 +116,7 @@ public final class JwtIssuerReactiveAuthenticationManagerResolver * Construct a {@link JwtIssuerReactiveAuthenticationManagerResolver} using the * provided parameters * @param trustedIssuers a predicate to validate issuers + * @since 6.2 */ public static JwtIssuerReactiveAuthenticationManagerResolver fromTrustedIssuers(Predicate trustedIssuers) { Assert.notNull(trustedIssuers, "trustedIssuers cannot be null"); @@ -219,7 +222,7 @@ public final class JwtIssuerReactiveAuthenticationManagerResolver public Mono resolve(String issuer) { if (!this.trustedIssuer.test(issuer)) { this.logger.debug(LogMessage - .format("Did not resolve AuthenticationManager since issuer '%s' is not trusted", issuer)); + .format("Did not resolve AuthenticationManager since issuer is not trusted", issuer)); return Mono.empty(); } // @formatter:off diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerAuthenticationManagerResolverTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerAuthenticationManagerResolverTests.java index bc2b1a2f21..1563c8c79c 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerAuthenticationManagerResolverTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerAuthenticationManagerResolverTests.java @@ -65,7 +65,7 @@ public class JwtIssuerAuthenticationManagerResolverTests { private String noIssuer = jwt("sub", "sub"); @Test - public void resolveWhenUsingTrustedIssuerThenReturnsAuthenticationManager() throws Exception { + public void resolveWhenUsingFromTrustedIssuersThenReturnsAuthenticationManager() throws Exception { try (MockWebServer server = new MockWebServer()) { server.start(); String issuer = server.url("").toString(); @@ -73,7 +73,7 @@ public class JwtIssuerAuthenticationManagerResolverTests { server.enqueue(new MockResponse().setResponseCode(200) .setHeader("Content-Type", "application/json") .setBody(String.format(DEFAULT_RESPONSE_TEMPLATE, issuer, issuer) - )); + )); server.enqueue(new MockResponse().setResponseCode(200) .setHeader("Content-Type", "application/json") .setBody(JWK_SET) @@ -96,6 +96,38 @@ public class JwtIssuerAuthenticationManagerResolverTests { } } + @Test + public void resolveWhenUsingFromTrustedIssuersPredicateThenReturnsAuthenticationManager() throws Exception { + try (MockWebServer server = new MockWebServer()) { + server.start(); + String issuer = server.url("").toString(); + // @formatter:off + server.enqueue(new MockResponse().setResponseCode(200) + .setHeader("Content-Type", "application/json") + .setBody(String.format(DEFAULT_RESPONSE_TEMPLATE, issuer, issuer) + )); + server.enqueue(new MockResponse().setResponseCode(200) + .setHeader("Content-Type", "application/json") + .setBody(JWK_SET) + ); + server.enqueue(new MockResponse().setResponseCode(200) + .setHeader("Content-Type", "application/json") + .setBody(JWK_SET) + ); + // @formatter:on + JWSObject jws = new JWSObject(new JWSHeader(JWSAlgorithm.RS256), + new Payload(new JSONObject(Collections.singletonMap(JwtClaimNames.ISS, issuer)))); + jws.sign(new RSASSASigner(TestKeys.DEFAULT_PRIVATE_KEY)); + JwtIssuerAuthenticationManagerResolver authenticationManagerResolver = JwtIssuerAuthenticationManagerResolver + .fromTrustedIssuers(issuer::equals); + Authentication token = withBearerToken(jws.serialize()); + AuthenticationManager authenticationManager = authenticationManagerResolver.resolve(null); + assertThat(authenticationManager).isNotNull(); + Authentication authentication = authenticationManager.authenticate(token); + assertThat(authentication.isAuthenticated()).isTrue(); + } + } + @Test public void resolveWhednUsingTrustedIssuerThenReturnsAuthenticationManager() throws Exception { try (MockWebServer server = new MockWebServer()) { @@ -230,7 +262,7 @@ public class JwtIssuerAuthenticationManagerResolverTests { } @Test - public void constructorWhenNullOrEmptyIssuersThenException() { + public void factoryWhenNullOrEmptyIssuersThenException() { assertThatIllegalArgumentException() .isThrownBy(() -> JwtIssuerAuthenticationManagerResolver.fromTrustedIssuers((Predicate) null)); assertThatIllegalArgumentException() diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerReactiveAuthenticationManagerResolverTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerReactiveAuthenticationManagerResolverTests.java index ee21661321..81f0e6e59c 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerReactiveAuthenticationManagerResolverTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtIssuerReactiveAuthenticationManagerResolverTests.java @@ -72,7 +72,7 @@ public class JwtIssuerReactiveAuthenticationManagerResolverTests { private String noIssuer = jwt("sub", "sub"); @Test - public void resolveWhenUsingTrustedIssuerThenReturnsAuthenticationManager() throws Exception { + public void resolveWhenUsingFromTrustedIssuersThenReturnsAuthenticationManager() throws Exception { try (MockWebServer server = new MockWebServer()) { String issuer = server.url("").toString(); server.enqueue(new MockResponse().setResponseCode(200).setHeader("Content-Type", "application/json") @@ -95,6 +95,30 @@ public class JwtIssuerReactiveAuthenticationManagerResolverTests { } } + @Test + public void resolveWhenUsingFromTrustedIssuersPredicateThenReturnsAuthenticationManager() throws Exception { + try (MockWebServer server = new MockWebServer()) { + String issuer = server.url("").toString(); + server.enqueue(new MockResponse().setResponseCode(200).setHeader("Content-Type", "application/json") + .setBody(String.format(DEFAULT_RESPONSE_TEMPLATE, issuer, issuer))); + server.enqueue(new MockResponse().setResponseCode(200).setHeader("Content-Type", "application/json") + .setBody(JWK_SET)); + server.enqueue(new MockResponse().setResponseCode(200).setHeader("Content-Type", "application/json") + .setBody(JWK_SET)); + JWSObject jws = new JWSObject(new JWSHeader(JWSAlgorithm.RS256), + new Payload(new JSONObject(Collections.singletonMap(JwtClaimNames.ISS, issuer)))); + jws.sign(new RSASSASigner(TestKeys.DEFAULT_PRIVATE_KEY)); + JwtIssuerReactiveAuthenticationManagerResolver authenticationManagerResolver = JwtIssuerReactiveAuthenticationManagerResolver + .fromTrustedIssuers(issuer::equals); + ReactiveAuthenticationManager authenticationManager = authenticationManagerResolver.resolve(null).block(); + assertThat(authenticationManager).isNotNull(); + BearerTokenAuthenticationToken token = withBearerToken(jws.serialize()); + Authentication authentication = authenticationManager.authenticate(token).block(); + assertThat(authentication).isNotNull(); + assertThat(authentication.isAuthenticated()).isTrue(); + } + } + // gh-10444 @Test public void resolveWhednUsingTrustedIssuerThenReturnsAuthenticationManager() throws Exception { @@ -229,7 +253,7 @@ public class JwtIssuerReactiveAuthenticationManagerResolverTests { } @Test - public void constructorWhenNullOrEmptyIssuersThenException() { + public void factoryWhenNullOrEmptyIssuersThenException() { assertThatIllegalArgumentException().isThrownBy( () -> JwtIssuerReactiveAuthenticationManagerResolver.fromTrustedIssuers((Predicate) null)); assertThatIllegalArgumentException().isThrownBy(