From 9b14465243a721b0b9d198fe24be182ed9a8a678 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Thu, 21 May 2026 10:36:10 -0600 Subject: [PATCH] Align Assertions in Builder with Deprecated Constructor The deprecated (introspectionUri, clientId, clientSecret) constructors that the builders replaced explicitly asserted non-null clientId and clientSecret. Bring the builder's build() in line with that contract by asserting at the API boundary rather than relying on downstream classes to enforce it. Closes gh-19201 Signed-off-by: Josh Cummings <3627351+jzheaux@users.noreply.github.com> --- .../introspection/SpringOpaqueTokenIntrospector.java | 2 ++ .../SpringReactiveOpaqueTokenIntrospector.java | 2 ++ .../introspection/SpringOpaqueTokenIntrospectorTests.java | 7 +++++++ .../SpringReactiveOpaqueTokenIntrospectorTests.java | 7 +++++++ 4 files changed, 18 insertions(+) diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/SpringOpaqueTokenIntrospector.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/SpringOpaqueTokenIntrospector.java index 2cd1a8fb34..e4b8e90256 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/SpringOpaqueTokenIntrospector.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/SpringOpaqueTokenIntrospector.java @@ -361,6 +361,8 @@ public class SpringOpaqueTokenIntrospector implements OpaqueTokenIntrospector { * @since 6.5 */ public SpringOpaqueTokenIntrospector build() { + Assert.notNull(this.clientId, "clientId cannot be null"); + Assert.notNull(this.clientSecret, "clientSecret cannot be null"); RestTemplate restTemplate = new RestTemplate(); restTemplate.getInterceptors().add(new BasicAuthenticationInterceptor(this.clientId, this.clientSecret)); return new SpringOpaqueTokenIntrospector(this.introspectionUri, restTemplate); diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/SpringReactiveOpaqueTokenIntrospector.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/SpringReactiveOpaqueTokenIntrospector.java index bee71d57b7..c77f9b638b 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/SpringReactiveOpaqueTokenIntrospector.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/SpringReactiveOpaqueTokenIntrospector.java @@ -314,6 +314,8 @@ public class SpringReactiveOpaqueTokenIntrospector implements ReactiveOpaqueToke * @since 6.5 */ public SpringReactiveOpaqueTokenIntrospector build() { + Assert.notNull(this.clientId, "clientId cannot be null"); + Assert.notNull(this.clientSecret, "clientSecret cannot be null"); WebClient webClient = WebClient.builder() .defaultHeaders((h) -> h.setBasicAuth(this.clientId, this.clientSecret)) .build(); diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/introspection/SpringOpaqueTokenIntrospectorTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/introspection/SpringOpaqueTokenIntrospectorTests.java index b75358ded7..8d00763caa 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/introspection/SpringOpaqueTokenIntrospectorTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/introspection/SpringOpaqueTokenIntrospectorTests.java @@ -383,6 +383,13 @@ public class SpringOpaqueTokenIntrospectorTests { } } + // gh-19201 + @Test + public void builderWhenMissingClientCredentialsThenThrowsException() { + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> SpringOpaqueTokenIntrospector.withIntrospectionUri(INTROSPECTION_URL).build()); + } + private static ResponseEntity> response(String content) { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/introspection/SpringReactiveOpaqueTokenIntrospectorTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/introspection/SpringReactiveOpaqueTokenIntrospectorTests.java index d614a65275..95aa52cf1a 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/introspection/SpringReactiveOpaqueTokenIntrospectorTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/introspection/SpringReactiveOpaqueTokenIntrospectorTests.java @@ -308,6 +308,13 @@ public class SpringReactiveOpaqueTokenIntrospectorTests { } } + // gh-19201 + @Test + public void builderWhenMissingClientCredentialsThenThrowsException() { + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> SpringReactiveOpaqueTokenIntrospector.withIntrospectionUri(INTROSPECTION_URL).build()); + } + private WebClient mockResponse(String response) { return mockResponse(toMap(response)); }