diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/RestClientSpringOpaqueTokenIntrospector.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/RestClientOpaqueTokenIntrospector.java
similarity index 85%
rename from oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/RestClientSpringOpaqueTokenIntrospector.java
rename to oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/RestClientOpaqueTokenIntrospector.java
index a3fe718dc0..cda1cb1d60 100644
--- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/RestClientSpringOpaqueTokenIntrospector.java
+++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/RestClientOpaqueTokenIntrospector.java
@@ -28,6 +28,7 @@ import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.function.Consumer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -59,7 +60,7 @@ import org.springframework.web.client.RestClient;
* @author Andrey Litvitski
* @since 7.1
*/
-public class RestClientSpringOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
+public class RestClientOpaqueTokenIntrospector implements OpaqueTokenIntrospector {
private static final String AUTHORITY_PREFIX = "SCOPE_";
@@ -81,7 +82,7 @@ public class RestClientSpringOpaqueTokenIntrospector implements OpaqueTokenIntro
* @param introspectionUri The introspection endpoint uri
* @param restClient The client for performing the introspection request
*/
- public RestClientSpringOpaqueTokenIntrospector(String introspectionUri, RestClient restClient) {
+ public RestClientOpaqueTokenIntrospector(String introspectionUri, RestClient restClient) {
Assert.notNull(introspectionUri, "introspectionUri cannot be null");
Assert.notNull(restClient, "restClient cannot be null");
this.requestEntityConverter = this.defaultRequestEntityConverter(URI.create(introspectionUri));
@@ -214,14 +215,13 @@ public class RestClientSpringOpaqueTokenIntrospector implements OpaqueTokenIntro
*
* Sets the {@link Converter Converter<OAuth2TokenIntrospectionClaimAccessor,
* OAuth2AuthenticatedPrincipal>} to use. Defaults to
- * {@link RestClientSpringOpaqueTokenIntrospector#defaultAuthenticationConverter}.
+ * {@link RestClientOpaqueTokenIntrospector#defaultAuthenticationConverter}.
*
*
* Use if you need a custom mapping of OAuth 2.0 token claims to the authenticated
* principal.
*
* @param authenticationConverter the converter
- * @since 7.1
*/
public void setAuthenticationConverter(
Converter authenticationConverter) {
@@ -230,14 +230,13 @@ public class RestClientSpringOpaqueTokenIntrospector implements OpaqueTokenIntro
}
/**
- * If {@link RestClientSpringOpaqueTokenIntrospector#authenticationConverter} is not
+ * If {@link RestClientOpaqueTokenIntrospector#authenticationConverter} is not
* explicitly set, this default converter will be used. transforms an
* {@link OAuth2TokenIntrospectionClaimAccessor} into an
* {@link OAuth2AuthenticatedPrincipal} by extracting claims, mapping scopes to
* authorities, and creating a principal.
* @return {@link Converter Converter<OAuth2TokenIntrospectionClaimAccessor,
* OAuth2AuthenticatedPrincipal>}
- * @since 7.1
*/
private OAuth2IntrospectionAuthenticatedPrincipal defaultAuthenticationConverter(
OAuth2TokenIntrospectionClaimAccessor accessor) {
@@ -257,15 +256,14 @@ public class RestClientSpringOpaqueTokenIntrospector implements OpaqueTokenIntro
}
/**
- * Creates a {@code RestClientSpringOpaqueTokenIntrospector.Builder} with the given
+ * Creates a {@code RestClientOpaqueTokenIntrospector.Builder} with the given
* introspection endpoint uri
* @param introspectionUri The introspection endpoint uri
- * @return the {@link RestClientSpringOpaqueTokenIntrospector.Builder}
- * @since 7.1
+ * @return the {@link RestClientOpaqueTokenIntrospector.Builder}
*/
- public static RestClientSpringOpaqueTokenIntrospector.Builder withIntrospectionUri(String introspectionUri) {
+ public static RestClientOpaqueTokenIntrospector.Builder withIntrospectionUri(String introspectionUri) {
Assert.notNull(introspectionUri, "introspectionUri cannot be null");
- return new RestClientSpringOpaqueTokenIntrospector.Builder(introspectionUri);
+ return new RestClientOpaqueTokenIntrospector.Builder(introspectionUri);
}
// gh-7563
@@ -295,7 +293,7 @@ public class RestClientSpringOpaqueTokenIntrospector implements OpaqueTokenIntro
}
/**
- * Used to build {@link RestClientSpringOpaqueTokenIntrospector}.
+ * Used to build {@link RestClientOpaqueTokenIntrospector}.
*
* @author Andrey Litvitski
* @since 7.1
@@ -308,6 +306,8 @@ public class RestClientSpringOpaqueTokenIntrospector implements OpaqueTokenIntro
private String clientSecret;
+ private final List> postProcessors = new ArrayList<>();
+
private Builder(String introspectionUri) {
this.introspectionUri = introspectionUri;
}
@@ -316,10 +316,9 @@ public class RestClientSpringOpaqueTokenIntrospector implements OpaqueTokenIntro
* The builder will {@link URLEncoder encode} the client id that you provide, so
* please give the unencoded value.
* @param clientId The unencoded client id
- * @return the {@link RestClientSpringOpaqueTokenIntrospector.Builder}
- * @since 7.1
+ * @return the {@link RestClientOpaqueTokenIntrospector.Builder}
*/
- public RestClientSpringOpaqueTokenIntrospector.Builder clientId(String clientId) {
+ public RestClientOpaqueTokenIntrospector.Builder clientId(String clientId) {
Assert.notNull(clientId, "clientId cannot be null");
this.clientId = URLEncoder.encode(clientId, StandardCharsets.UTF_8);
return this;
@@ -329,25 +328,39 @@ public class RestClientSpringOpaqueTokenIntrospector implements OpaqueTokenIntro
* The builder will {@link URLEncoder encode} the client secret that you provide,
* so please give the unencoded value.
* @param clientSecret The unencoded client secret
- * @return the {@link RestClientSpringOpaqueTokenIntrospector.Builder}
- * @since 7.1
+ * @return the {@link RestClientOpaqueTokenIntrospector.Builder}
*/
- public RestClientSpringOpaqueTokenIntrospector.Builder clientSecret(String clientSecret) {
+ public RestClientOpaqueTokenIntrospector.Builder clientSecret(String clientSecret) {
Assert.notNull(clientSecret, "clientSecret cannot be null");
this.clientSecret = URLEncoder.encode(clientSecret, StandardCharsets.UTF_8);
return this;
}
/**
- * Creates a {@code RestClientSpringOpaqueTokenIntrospector}
- * @return the {@link RestClientSpringOpaqueTokenIntrospector}
- * @since 7.1
+ * Adds a {@link Consumer} to customize the
+ * {@link RestClientOpaqueTokenIntrospector} after it is built. This allows for
+ * additional configuration that cannot be expressed through the builder methods.
+ * @param postProcessor the {@link Consumer} to customize the introspector
+ * @return the {@link RestClientOpaqueTokenIntrospector.Builder}
*/
- public RestClientSpringOpaqueTokenIntrospector build() {
+ public Builder postProcessor(Consumer postProcessor) {
+ Assert.notNull(postProcessor, "postProcessor cannot be null");
+ this.postProcessors.add(postProcessor);
+ return this;
+ }
+
+ /**
+ * Creates a {@code RestClientOpaqueTokenIntrospector}
+ * @return the {@link RestClientOpaqueTokenIntrospector}
+ */
+ public RestClientOpaqueTokenIntrospector build() {
RestClient restClient = RestClient.builder()
.defaultHeaders((headers) -> headers.setBasicAuth(this.clientId, this.clientSecret))
.build();
- return new RestClientSpringOpaqueTokenIntrospector(this.introspectionUri, restClient);
+ RestClientOpaqueTokenIntrospector introspector = new RestClientOpaqueTokenIntrospector(
+ this.introspectionUri, restClient);
+ this.postProcessors.forEach((postProcessor) -> postProcessor.accept(introspector));
+ return introspector;
}
}
diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/introspection/RestClientSpringOpaqueTokenIntrospectorTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/introspection/RestClientOpaqueTokenIntrospectorTests.java
similarity index 91%
rename from oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/introspection/RestClientSpringOpaqueTokenIntrospectorTests.java
rename to oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/introspection/RestClientOpaqueTokenIntrospectorTests.java
index 8b3fefdaeb..2ba3d3e0f0 100644
--- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/introspection/RestClientSpringOpaqueTokenIntrospectorTests.java
+++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/introspection/RestClientOpaqueTokenIntrospectorTests.java
@@ -45,11 +45,11 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.Mockito.mock;
/**
- * Tests for {@link RestClientSpringOpaqueTokenIntrospector}
+ * Tests for {@link RestClientOpaqueTokenIntrospector}
*
* @author Andrey Litvitski
*/
-public class RestClientSpringOpaqueTokenIntrospectorTests {
+public class RestClientOpaqueTokenIntrospectorTests {
private static final String INTROSPECTION_URL = "https://server.example.com";
@@ -112,7 +112,7 @@ public class RestClientSpringOpaqueTokenIntrospectorTests {
try (MockWebServer server = new MockWebServer()) {
server.setDispatcher(requiresAuth(CLIENT_ID, CLIENT_SECRET, ACTIVE_RESPONSE));
String introspectUri = server.url("/introspect").toString();
- OpaqueTokenIntrospector introspectionClient = RestClientSpringOpaqueTokenIntrospector
+ OpaqueTokenIntrospector introspectionClient = RestClientOpaqueTokenIntrospector
.withIntrospectionUri(introspectUri)
.clientId(CLIENT_ID)
.clientSecret(CLIENT_SECRET)
@@ -140,7 +140,7 @@ public class RestClientSpringOpaqueTokenIntrospectorTests {
try (MockWebServer server = new MockWebServer()) {
server.setDispatcher(requiresAuth(CLIENT_ID, CLIENT_SECRET, ACTIVE_RESPONSE));
String introspectUri = server.url("/introspect").toString();
- OpaqueTokenIntrospector introspectionClient = RestClientSpringOpaqueTokenIntrospector
+ OpaqueTokenIntrospector introspectionClient = RestClientOpaqueTokenIntrospector
.withIntrospectionUri(introspectUri)
.clientId(CLIENT_ID)
.clientSecret("wrong")
@@ -155,7 +155,7 @@ public class RestClientSpringOpaqueTokenIntrospectorTests {
try (MockWebServer server = new MockWebServer()) {
server.setDispatcher(requiresAuth(CLIENT_ID, CLIENT_SECRET, INACTIVE_RESPONSE));
String introspectUri = server.url("/introspect").toString();
- OpaqueTokenIntrospector introspectionClient = RestClientSpringOpaqueTokenIntrospector
+ OpaqueTokenIntrospector introspectionClient = RestClientOpaqueTokenIntrospector
.withIntrospectionUri(introspectUri)
.clientId(CLIENT_ID)
.clientSecret(CLIENT_SECRET)
@@ -179,7 +179,7 @@ public class RestClientSpringOpaqueTokenIntrospectorTests {
""";
server.setDispatcher(requiresAuth(CLIENT_ID, CLIENT_SECRET, response));
String introspectUri = server.url("/introspect").toString();
- OpaqueTokenIntrospector introspectionClient = RestClientSpringOpaqueTokenIntrospector
+ OpaqueTokenIntrospector introspectionClient = RestClientOpaqueTokenIntrospector
.withIntrospectionUri(introspectUri)
.clientId(CLIENT_ID)
.clientSecret(CLIENT_SECRET)
@@ -201,7 +201,7 @@ public class RestClientSpringOpaqueTokenIntrospectorTests {
server.start();
String introspectUri = server.url("/introspect").toString();
server.shutdown();
- OpaqueTokenIntrospector introspectionClient = RestClientSpringOpaqueTokenIntrospector
+ OpaqueTokenIntrospector introspectionClient = RestClientOpaqueTokenIntrospector
.withIntrospectionUri(introspectUri)
.clientId(CLIENT_ID)
.clientSecret(CLIENT_SECRET)
@@ -216,7 +216,7 @@ public class RestClientSpringOpaqueTokenIntrospectorTests {
try (MockWebServer server = new MockWebServer()) {
server.setDispatcher(requiresAuth(CLIENT_ID, CLIENT_SECRET, "{}"));
String introspectUri = server.url("/introspect").toString();
- OpaqueTokenIntrospector introspectionClient = RestClientSpringOpaqueTokenIntrospector
+ OpaqueTokenIntrospector introspectionClient = RestClientOpaqueTokenIntrospector
.withIntrospectionUri(introspectUri)
.clientId(CLIENT_ID)
.clientSecret(CLIENT_SECRET)
@@ -231,7 +231,7 @@ public class RestClientSpringOpaqueTokenIntrospectorTests {
try (MockWebServer server = new MockWebServer()) {
server.setDispatcher(requiresAuth(CLIENT_ID, CLIENT_SECRET, INVALID_RESPONSE));
String introspectUri = server.url("/introspect").toString();
- OpaqueTokenIntrospector introspectionClient = RestClientSpringOpaqueTokenIntrospector
+ OpaqueTokenIntrospector introspectionClient = RestClientOpaqueTokenIntrospector
.withIntrospectionUri(introspectUri)
.clientId(CLIENT_ID)
.clientSecret(CLIENT_SECRET)
@@ -247,7 +247,7 @@ public class RestClientSpringOpaqueTokenIntrospectorTests {
try (MockWebServer server = new MockWebServer()) {
server.setDispatcher(requiresAuth(CLIENT_ID, CLIENT_SECRET, MALFORMED_SCOPE_RESPONSE));
String introspectUri = server.url("/introspect").toString();
- OpaqueTokenIntrospector introspectionClient = RestClientSpringOpaqueTokenIntrospector
+ OpaqueTokenIntrospector introspectionClient = RestClientOpaqueTokenIntrospector
.withIntrospectionUri(introspectUri)
.clientId(CLIENT_ID)
.clientSecret(CLIENT_SECRET)
@@ -265,7 +265,7 @@ public class RestClientSpringOpaqueTokenIntrospectorTests {
try (MockWebServer server = new MockWebServer()) {
server.setDispatcher(requiresAuth(CLIENT_ID, CLIENT_SECRET, ACTIVE_RESPONSE));
String introspectUri = server.url("/introspect").toString();
- OpaqueTokenIntrospector introspectionClient = RestClientSpringOpaqueTokenIntrospector
+ OpaqueTokenIntrospector introspectionClient = RestClientOpaqueTokenIntrospector
.withIntrospectionUri(introspectUri)
.clientId(CLIENT_ID)
.clientSecret(CLIENT_SECRET)
@@ -282,8 +282,8 @@ public class RestClientSpringOpaqueTokenIntrospectorTests {
@Test
public void setRequestEntityConverterWhenConverterIsNullThenExceptionIsThrown() {
RestClient restClient = mock(RestClient.class);
- RestClientSpringOpaqueTokenIntrospector introspectionClient = new RestClientSpringOpaqueTokenIntrospector(
- INTROSPECTION_URL, restClient);
+ RestClientOpaqueTokenIntrospector introspectionClient = new RestClientOpaqueTokenIntrospector(INTROSPECTION_URL,
+ restClient);
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> introspectionClient.setRequestEntityConverter(null));
}
@@ -291,8 +291,8 @@ public class RestClientSpringOpaqueTokenIntrospectorTests {
@Test
public void setAuthenticationConverterWhenConverterIsNullThenExceptionIsThrown() {
RestClient restClient = mock(RestClient.class);
- RestClientSpringOpaqueTokenIntrospector introspectionClient = new RestClientSpringOpaqueTokenIntrospector(
- INTROSPECTION_URL, restClient);
+ RestClientOpaqueTokenIntrospector introspectionClient = new RestClientOpaqueTokenIntrospector(INTROSPECTION_URL,
+ restClient);
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> introspectionClient.setAuthenticationConverter(null));
}
@@ -311,7 +311,7 @@ public class RestClientSpringOpaqueTokenIntrospectorTests {
RestClient restClient = RestClient.builder()
.defaultHeaders((h) -> h.setBasicAuth("client%&1", "secret@$2"))
.build();
- OpaqueTokenIntrospector introspectionClient = new RestClientSpringOpaqueTokenIntrospector(introspectUri,
+ OpaqueTokenIntrospector introspectionClient = new RestClientOpaqueTokenIntrospector(introspectUri,
restClient);
assertThatExceptionOfType(OAuth2IntrospectionException.class)
.isThrownBy(() -> introspectionClient.introspect("token"));