mirror of
https://github.com/spring-projects/spring-security.git
synced 2026-03-05 03:04:31 +00:00
Add postProcessr support to RestClientOpaqueTokenIntrospector
Signed-off-by: Andrey Litvitski <andrey1010102008@gmail.com>
This commit is contained in:
parent
bafd4034a0
commit
a5c0113ff0
@ -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
|
||||
* <p>
|
||||
* Sets the {@link Converter Converter<OAuth2TokenIntrospectionClaimAccessor,
|
||||
* OAuth2AuthenticatedPrincipal>} to use. Defaults to
|
||||
* {@link RestClientSpringOpaqueTokenIntrospector#defaultAuthenticationConverter}.
|
||||
* {@link RestClientOpaqueTokenIntrospector#defaultAuthenticationConverter}.
|
||||
* </p>
|
||||
* <p>
|
||||
* Use if you need a custom mapping of OAuth 2.0 token claims to the authenticated
|
||||
* principal.
|
||||
* </p>
|
||||
* @param authenticationConverter the converter
|
||||
* @since 7.1
|
||||
*/
|
||||
public void setAuthenticationConverter(
|
||||
Converter<OAuth2TokenIntrospectionClaimAccessor, ? extends OAuth2AuthenticatedPrincipal> 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<Consumer<RestClientOpaqueTokenIntrospector>> 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<RestClientOpaqueTokenIntrospector> 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;
|
||||
}
|
||||
|
||||
}
|
||||
@ -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"));
|
||||
Loading…
x
Reference in New Issue
Block a user