From 980d35503a6a50d5b89cff71137aa35d61096cef Mon Sep 17 00:00:00 2001 From: Arvid Ottenberg Date: Thu, 29 Oct 2020 22:26:15 +0100 Subject: [PATCH 1/5] enable customization of the JwtClaimIssuerConverter and therefore the BearerTokenResolver in the JwtIssuerAuthenticationManagerResolver class (gh-8535) --- .../JwtIssuerAuthenticationManagerResolver.java | 12 +++++++++++- ...tIssuerReactiveAuthenticationManagerResolver.java | 12 +++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) 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 af1cddc205d..aaff468bfb3 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 @@ -65,7 +65,7 @@ public final class JwtIssuerAuthenticationManagerResolver implements Authenticat private final AuthenticationManagerResolver issuerAuthenticationManagerResolver; - private final Converter issuerConverter = new JwtClaimIssuerConverter(); + private Converter issuerConverter = new JwtClaimIssuerConverter(); /** * Construct a {@link JwtIssuerAuthenticationManagerResolver} using the provided @@ -130,6 +130,16 @@ public AuthenticationManager resolve(HttpServletRequest request) { return authenticationManager; } + /** + * Set a custom issuer converter + * + * @since 5.5 + */ + public void setIssuerConverter(Converter issuerConverter) { + Assert.notNull(issuerConverter, "issuerConverter cannot be null"); + this.issuerConverter = issuerConverter; + } + private static class JwtClaimIssuerConverter implements Converter { private final BearerTokenResolver resolver = new DefaultBearerTokenResolver(); 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 e73635e887d..fcd4fbc42ef 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 @@ -65,7 +65,7 @@ public final class JwtIssuerReactiveAuthenticationManagerResolver private final ReactiveAuthenticationManagerResolver issuerAuthenticationManagerResolver; - private final Converter> issuerConverter = new JwtClaimIssuerConverter(); + private Converter> issuerConverter = new JwtClaimIssuerConverter(); /** * Construct a {@link JwtIssuerReactiveAuthenticationManagerResolver} using the @@ -131,6 +131,16 @@ public Mono resolve(ServerWebExchange exchange) { // @formatter:on } + /** + * Set a custom issuer converter + * + * @since 5.5 + */ + public void setIssuerConverter(Converter> issuerConverter) { + Assert.notNull(issuerConverter, "converter cannot be null"); + this.issuerConverter = issuerConverter; + } + private static class JwtClaimIssuerConverter implements Converter> { private final ServerBearerTokenAuthenticationConverter converter = new ServerBearerTokenAuthenticationConverter(); From ef95c69e7220e98221bc3e14b87f6836e58ce3b8 Mon Sep 17 00:00:00 2001 From: Arvid Ottenberg Date: Fri, 30 Oct 2020 00:36:32 +0100 Subject: [PATCH 2/5] change setIssuerConverter setter method to setBearerTokenResolver on JwtIssuerReactiveAuthenticationManagerResolver --- .../JwtIssuerAuthenticationManagerResolver.java | 17 +++++++++++++---- ...erReactiveAuthenticationManagerResolver.java | 17 +++++++++++++---- 2 files changed, 26 insertions(+), 8 deletions(-) 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 aaff468bfb3..a73eb2a21e6 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 @@ -135,14 +135,23 @@ public AuthenticationManager resolve(HttpServletRequest request) { * * @since 5.5 */ - public void setIssuerConverter(Converter issuerConverter) { - Assert.notNull(issuerConverter, "issuerConverter cannot be null"); - this.issuerConverter = issuerConverter; + public void setBearerTokenResolver(BearerTokenResolver bearerTokenResolver) { + Assert.notNull(bearerTokenResolver, "bearerTokenResolver cannot be null"); + this.issuerConverter = new JwtClaimIssuerConverter(bearerTokenResolver); } private static class JwtClaimIssuerConverter implements Converter { - private final BearerTokenResolver resolver = new DefaultBearerTokenResolver(); + private BearerTokenResolver resolver; + + JwtClaimIssuerConverter() { + this.resolver = new DefaultBearerTokenResolver(); + } + + JwtClaimIssuerConverter(BearerTokenResolver bearerTokenResolver) { + Assert.notNull(bearerTokenResolver, "bearerTokenResolver cannot be null"); + this.resolver = bearerTokenResolver; + } @Override public String convert(@NonNull HttpServletRequest request) { 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 fcd4fbc42ef..68010eb799d 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 @@ -136,14 +136,23 @@ public Mono resolve(ServerWebExchange exchange) { * * @since 5.5 */ - public void setIssuerConverter(Converter> issuerConverter) { - Assert.notNull(issuerConverter, "converter cannot be null"); - this.issuerConverter = issuerConverter; + public void setServerBearerTokenAuthenticationConverter(ServerBearerTokenAuthenticationConverter serverBearerTokenAuthenticationConverter) { + Assert.notNull(serverBearerTokenAuthenticationConverter, "serverBearerTokenAuthenticationConverter cannot be null"); + this.issuerConverter = new JwtClaimIssuerConverter(serverBearerTokenAuthenticationConverter); } private static class JwtClaimIssuerConverter implements Converter> { - private final ServerBearerTokenAuthenticationConverter converter = new ServerBearerTokenAuthenticationConverter(); + private ServerBearerTokenAuthenticationConverter converter; + + JwtClaimIssuerConverter() { + this.converter = new ServerBearerTokenAuthenticationConverter(); + } + + JwtClaimIssuerConverter(ServerBearerTokenAuthenticationConverter serverBearerTokenAuthenticationConverter) { + Assert.notNull(serverBearerTokenAuthenticationConverter, "serverBearerTokenAuthenticationConverter cannot be null"); + this.converter = serverBearerTokenAuthenticationConverter; + } @Override public Mono convert(@NonNull ServerWebExchange exchange) { From bba7e2786ee3c8e8a88364dafa61155c55821fc9 Mon Sep 17 00:00:00 2001 From: Arvid Ottenberg Date: Fri, 30 Oct 2020 00:51:52 +0100 Subject: [PATCH 3/5] fix formatting in JwtIssuerReactiveAuthenticationManagerResolver --- .../JwtIssuerReactiveAuthenticationManagerResolver.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) 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 68010eb799d..ebc5020ce4f 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 @@ -136,8 +136,10 @@ public Mono resolve(ServerWebExchange exchange) { * * @since 5.5 */ - public void setServerBearerTokenAuthenticationConverter(ServerBearerTokenAuthenticationConverter serverBearerTokenAuthenticationConverter) { - Assert.notNull(serverBearerTokenAuthenticationConverter, "serverBearerTokenAuthenticationConverter cannot be null"); + public void setServerBearerTokenAuthenticationConverter( + ServerBearerTokenAuthenticationConverter serverBearerTokenAuthenticationConverter) { + Assert.notNull(serverBearerTokenAuthenticationConverter, + "serverBearerTokenAuthenticationConverter cannot be null"); this.issuerConverter = new JwtClaimIssuerConverter(serverBearerTokenAuthenticationConverter); } @@ -150,7 +152,8 @@ private static class JwtClaimIssuerConverter implements Converter Date: Sat, 31 Oct 2020 18:22:15 +0100 Subject: [PATCH 4/5] update java docs; set bearer token resolver final on JwtIssuerAuthenticationManagerResolver; reuse contructors of JwtAuthenticationManagerResolvers --- .../JwtIssuerAuthenticationManagerResolver.java | 6 +++--- .../JwtIssuerReactiveAuthenticationManagerResolver.java | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) 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 a73eb2a21e6..f324d84f4dc 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 @@ -131,7 +131,7 @@ public AuthenticationManager resolve(HttpServletRequest request) { } /** - * Set a custom issuer converter + * Set a custom bearer token resolver * * @since 5.5 */ @@ -142,10 +142,10 @@ public void setBearerTokenResolver(BearerTokenResolver bearerTokenResolver) { private static class JwtClaimIssuerConverter implements Converter { - private BearerTokenResolver resolver; + private final BearerTokenResolver resolver; JwtClaimIssuerConverter() { - this.resolver = new DefaultBearerTokenResolver(); + this(new DefaultBearerTokenResolver()); } JwtClaimIssuerConverter(BearerTokenResolver bearerTokenResolver) { 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 ebc5020ce4f..2db203df607 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 @@ -132,7 +132,7 @@ public Mono resolve(ServerWebExchange exchange) { } /** - * Set a custom issuer converter + * Set a custom server bearer token authentication converter * * @since 5.5 */ @@ -145,10 +145,10 @@ public void setServerBearerTokenAuthenticationConverter( private static class JwtClaimIssuerConverter implements Converter> { - private ServerBearerTokenAuthenticationConverter converter; + private final ServerBearerTokenAuthenticationConverter converter; JwtClaimIssuerConverter() { - this.converter = new ServerBearerTokenAuthenticationConverter(); + this(new ServerBearerTokenAuthenticationConverter()); } JwtClaimIssuerConverter(ServerBearerTokenAuthenticationConverter serverBearerTokenAuthenticationConverter) { From 5dd538e1c35092aaf74603166beffd4b57925385 Mon Sep 17 00:00:00 2001 From: Arvid Ottenberg Date: Mon, 2 Nov 2020 22:44:47 +0100 Subject: [PATCH 5/5] add unit tests for customization of JwtIssuerAuthenticationManagerResolver, JwtIssuerReactiveAuthenticationManagerResolver --- ...uerAuthenticationManagerResolverTests.java | 28 +++++++++++++++++++ ...iveAuthenticationManagerResolverTests.java | 18 ++++++++++++ 2 files changed, 46 insertions(+) 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 c6d3a5397a4..3fd3d3f4985 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 @@ -21,6 +21,8 @@ import java.util.HashMap; import java.util.Map; +import javax.servlet.http.HttpServletRequest; + import com.nimbusds.jose.JWSAlgorithm; import com.nimbusds.jose.JWSHeader; import com.nimbusds.jose.JWSObject; @@ -39,11 +41,15 @@ import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.jose.TestKeys; import org.springframework.security.oauth2.jwt.JwtClaimNames; +import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver; 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.mockito.Mockito.any; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; /** * Tests for {@link JwtIssuerAuthenticationManagerResolver} @@ -113,6 +119,19 @@ public void resolveWhenUsingCustomIssuerAuthenticationManagerResolverThenUses() assertThat(authenticationManagerResolver.resolve(request)).isSameAs(authenticationManager); } + @Test + public void resolveWhenUsingCustomIssuerAuthenticationManagerResolverAndCustomBearerTokenResolverThenUses() { + AuthenticationManager authenticationManager = mock(AuthenticationManager.class); + JwtIssuerAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerAuthenticationManagerResolver( + (issuer) -> authenticationManager); + BearerTokenResolver bearerTokenResolverSpy = spy(new TestBearerTokenResolver()); + authenticationManagerResolver.setBearerTokenResolver(bearerTokenResolverSpy); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader("Authorization", "Bearer " + this.jwt); + assertThat(authenticationManagerResolver.resolve(request)).isSameAs(authenticationManager); + verify(bearerTokenResolverSpy).resolve(any()); + } + @Test public void resolveWhenUsingExternalSourceThenRespondsToChanges() { MockHttpServletRequest request = new MockHttpServletRequest(); @@ -196,4 +215,13 @@ private String jwt(String claim, String value) { return jwt.serialize(); } + static class TestBearerTokenResolver implements BearerTokenResolver { + + @Override + public String resolve(HttpServletRequest request) { + return "eyJhbGciOiJub25lIn0.eyJpc3MiOiJ0cnVzdGVkIn0."; + } + + } + } 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 02979d65bcf..278096aaed0 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 @@ -41,11 +41,15 @@ import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.jose.TestKeys; import org.springframework.security.oauth2.jwt.JwtClaimNames; +import org.springframework.security.oauth2.server.resource.web.server.ServerBearerTokenAuthenticationConverter; 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.mockito.Mockito.any; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; /** * Tests for {@link JwtIssuerReactiveAuthenticationManagerResolver} @@ -111,6 +115,20 @@ public void resolveWhenUsingCustomIssuerAuthenticationManagerResolverThenUses() assertThat(authenticationManagerResolver.resolve(exchange).block()).isSameAs(authenticationManager); } + @Test + public void resolveWhenUsingCustomIssuerAuthenticationManagerResolverAndCustomServerBearerTokenAuthenticationConverterThenUses() { + ReactiveAuthenticationManager authenticationManager = mock(ReactiveAuthenticationManager.class); + JwtIssuerReactiveAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerReactiveAuthenticationManagerResolver( + (issuer) -> Mono.just(authenticationManager)); + ServerBearerTokenAuthenticationConverter serverBearerTokenAuthenticationConverterSpy = spy( + new ServerBearerTokenAuthenticationConverter()); + authenticationManagerResolver + .setServerBearerTokenAuthenticationConverter(serverBearerTokenAuthenticationConverterSpy); + MockServerWebExchange exchange = withBearerToken(this.jwt); + assertThat(authenticationManagerResolver.resolve(exchange).block()).isSameAs(authenticationManager); + verify(serverBearerTokenAuthenticationConverterSpy).convert(any()); + } + @Test public void resolveWhenUsingExternalSourceThenRespondsToChanges() { MockServerWebExchange exchange = withBearerToken(this.jwt);