Polish gh-630
This commit is contained in:
@@ -33,7 +33,6 @@ import com.nimbusds.jose.jwk.source.JWKSource;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||
@@ -44,14 +43,11 @@ import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.oauth2.core.OAuth2Token;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;
|
||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenIntrospectionAuthenticationProvider;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
|
||||
import org.springframework.security.oauth2.server.authorization.config.ProviderSettings;
|
||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;
|
||||
import org.springframework.security.oauth2.server.authorization.web.NimbusJwkSetEndpointFilter;
|
||||
import org.springframework.security.oauth2.server.authorization.web.OAuth2AuthorizationServerMetadataEndpointFilter;
|
||||
import org.springframework.security.oauth2.server.authorization.web.OAuth2TokenIntrospectionEndpointFilter;
|
||||
import org.springframework.security.oauth2.server.authorization.web.OAuth2TokenRevocationEndpointFilter;
|
||||
import org.springframework.security.oauth2.server.authorization.web.ProviderContextFilter;
|
||||
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
|
||||
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
|
||||
@@ -78,13 +74,12 @@ import org.springframework.util.Assert;
|
||||
* @see OAuth2ClientAuthenticationConfigurer
|
||||
* @see OAuth2AuthorizationEndpointConfigurer
|
||||
* @see OAuth2TokenEndpointConfigurer
|
||||
* @see OAuth2TokenIntrospectionEndpointConfigurer
|
||||
* @see OAuth2TokenRevocationEndpointConfigurer
|
||||
* @see OidcConfigurer
|
||||
* @see RegisteredClientRepository
|
||||
* @see OAuth2AuthorizationService
|
||||
* @see OAuth2AuthorizationConsentService
|
||||
* @see OAuth2TokenIntrospectionEndpointFilter
|
||||
* @see OAuth2TokenRevocationEndpointFilter
|
||||
* @see NimbusJwkSetEndpointFilter
|
||||
* @see OAuth2AuthorizationServerMetadataEndpointFilter
|
||||
*/
|
||||
@@ -92,15 +87,14 @@ public final class OAuth2AuthorizationServerConfigurer<B extends HttpSecurityBui
|
||||
extends AbstractHttpConfigurer<OAuth2AuthorizationServerConfigurer<B>, B> {
|
||||
|
||||
private final Map<Class<? extends AbstractOAuth2Configurer>, AbstractOAuth2Configurer> configurers = createConfigurers();
|
||||
private RequestMatcher tokenIntrospectionEndpointMatcher;
|
||||
private RequestMatcher jwkSetEndpointMatcher;
|
||||
private RequestMatcher authorizationServerMetadataEndpointMatcher;
|
||||
private final RequestMatcher endpointsMatcher = (request) ->
|
||||
getRequestMatcher(OAuth2AuthorizationEndpointConfigurer.class).matches(request) ||
|
||||
getRequestMatcher(OAuth2TokenEndpointConfigurer.class).matches(request) ||
|
||||
getRequestMatcher(OAuth2TokenIntrospectionEndpointConfigurer.class).matches(request) ||
|
||||
getRequestMatcher(OAuth2TokenRevocationEndpointConfigurer.class).matches(request) ||
|
||||
getRequestMatcher(OidcConfigurer.class).matches(request) ||
|
||||
getRequestMatcher(OAuth2TokenIntrospectionConfigurer.class).matches(request) ||
|
||||
this.jwkSetEndpointMatcher.matches(request) ||
|
||||
this.authorizationServerMetadataEndpointMatcher.matches(request);
|
||||
|
||||
@@ -198,6 +192,18 @@ public final class OAuth2AuthorizationServerConfigurer<B extends HttpSecurityBui
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the OAuth 2.0 Token Introspection Endpoint.
|
||||
*
|
||||
* @param tokenIntrospectionEndpointCustomizer the {@link Customizer} providing access to the {@link OAuth2TokenIntrospectionEndpointConfigurer}
|
||||
* @return the {@link OAuth2AuthorizationServerConfigurer} for further configuration
|
||||
* @since 0.2.3
|
||||
*/
|
||||
public OAuth2AuthorizationServerConfigurer<B> tokenIntrospectionEndpoint(Customizer<OAuth2TokenIntrospectionEndpointConfigurer> tokenIntrospectionEndpointCustomizer) {
|
||||
tokenIntrospectionEndpointCustomizer.customize(getConfigurer(OAuth2TokenIntrospectionEndpointConfigurer.class));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the OAuth 2.0 Token Revocation Endpoint.
|
||||
*
|
||||
@@ -221,19 +227,6 @@ public final class OAuth2AuthorizationServerConfigurer<B extends HttpSecurityBui
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the OAuth 2.0 Token Introspection Endpoint.
|
||||
*
|
||||
* @param tokenIntrospectionEndpointCustomizer the {@link Customizer} providing access to the {@link OAuth2TokenIntrospectionConfigurer}
|
||||
* @return the {@link OAuth2AuthorizationServerConfigurer} for further configuration
|
||||
* @since 0.2.3
|
||||
*/
|
||||
public OAuth2AuthorizationServerConfigurer<B> tokenIntrospectionEndpoint(Customizer<OAuth2TokenIntrospectionConfigurer> tokenIntrospectionEndpointCustomizer) {
|
||||
tokenIntrospectionEndpointCustomizer.customize(getConfigurer(OAuth2TokenIntrospectionConfigurer.class));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a {@link RequestMatcher} for the authorization server endpoints.
|
||||
*
|
||||
@@ -251,20 +244,14 @@ public final class OAuth2AuthorizationServerConfigurer<B extends HttpSecurityBui
|
||||
|
||||
this.configurers.values().forEach(configurer -> configurer.init(builder));
|
||||
|
||||
OAuth2TokenIntrospectionAuthenticationProvider tokenIntrospectionAuthenticationProvider =
|
||||
new OAuth2TokenIntrospectionAuthenticationProvider(
|
||||
OAuth2ConfigurerUtils.getRegisteredClientRepository(builder),
|
||||
OAuth2ConfigurerUtils.getAuthorizationService(builder));
|
||||
builder.authenticationProvider(postProcess(tokenIntrospectionAuthenticationProvider));
|
||||
|
||||
ExceptionHandlingConfigurer<B> exceptionHandling = builder.getConfigurer(ExceptionHandlingConfigurer.class);
|
||||
if (exceptionHandling != null) {
|
||||
exceptionHandling.defaultAuthenticationEntryPointFor(
|
||||
new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED),
|
||||
new OrRequestMatcher(
|
||||
getRequestMatcher(OAuth2TokenEndpointConfigurer.class),
|
||||
getRequestMatcher(OAuth2TokenRevocationEndpointConfigurer.class),
|
||||
this.tokenIntrospectionEndpointMatcher)
|
||||
getRequestMatcher(OAuth2TokenIntrospectionEndpointConfigurer.class),
|
||||
getRequestMatcher(OAuth2TokenRevocationEndpointConfigurer.class))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -362,8 +349,8 @@ public final class OAuth2AuthorizationServerConfigurer<B extends HttpSecurityBui
|
||||
|
||||
List<RequestMatcher> requestMatchers = new ArrayList<>();
|
||||
requestMatchers.add(getRequestMatcher(OAuth2TokenEndpointConfigurer.class));
|
||||
requestMatchers.add(getRequestMatcher(OAuth2TokenIntrospectionEndpointConfigurer.class));
|
||||
requestMatchers.add(getRequestMatcher(OAuth2TokenRevocationEndpointConfigurer.class));
|
||||
requestMatchers.add(OAuth2AuthorizationServerConfigurer.this.tokenIntrospectionEndpointMatcher);
|
||||
return new OrRequestMatcher(requestMatchers);
|
||||
}
|
||||
|
||||
@@ -395,7 +382,6 @@ public final class OAuth2AuthorizationServerConfigurer<B extends HttpSecurityBui
|
||||
this.configurers.values().forEach(configurer -> configurer.configure(builder));
|
||||
|
||||
ProviderSettings providerSettings = OAuth2ConfigurerUtils.getProviderSettings(builder);
|
||||
AuthenticationManager authenticationManager = builder.getSharedObject(AuthenticationManager.class);
|
||||
|
||||
ProviderContextFilter providerContextFilter = new ProviderContextFilter(providerSettings);
|
||||
builder.addFilterAfter(postProcess(providerContextFilter), SecurityContextPersistenceFilter.class);
|
||||
@@ -417,9 +403,9 @@ public final class OAuth2AuthorizationServerConfigurer<B extends HttpSecurityBui
|
||||
configurers.put(OAuth2ClientAuthenticationConfigurer.class, new OAuth2ClientAuthenticationConfigurer(this::postProcess));
|
||||
configurers.put(OAuth2AuthorizationEndpointConfigurer.class, new OAuth2AuthorizationEndpointConfigurer(this::postProcess));
|
||||
configurers.put(OAuth2TokenEndpointConfigurer.class, new OAuth2TokenEndpointConfigurer(this::postProcess));
|
||||
configurers.put(OAuth2TokenIntrospectionEndpointConfigurer.class, new OAuth2TokenIntrospectionEndpointConfigurer(this::postProcess));
|
||||
configurers.put(OAuth2TokenRevocationEndpointConfigurer.class, new OAuth2TokenRevocationEndpointConfigurer(this::postProcess));
|
||||
configurers.put(OidcConfigurer.class, new OidcConfigurer(this::postProcess));
|
||||
configurers.put(OAuth2TokenIntrospectionConfigurer.class, new OAuth2TokenIntrospectionConfigurer(this::postProcess));
|
||||
return configurers;
|
||||
}
|
||||
|
||||
@@ -433,8 +419,6 @@ public final class OAuth2AuthorizationServerConfigurer<B extends HttpSecurityBui
|
||||
}
|
||||
|
||||
private void initEndpointMatchers(ProviderSettings providerSettings) {
|
||||
this.tokenIntrospectionEndpointMatcher = new AntPathRequestMatcher(
|
||||
providerSettings.getTokenIntrospectionEndpoint(), HttpMethod.POST.name());
|
||||
this.jwkSetEndpointMatcher = new AntPathRequestMatcher(
|
||||
providerSettings.getJwkSetEndpoint(), HttpMethod.GET.name());
|
||||
this.authorizationServerMetadataEndpointMatcher = new AntPathRequestMatcher(
|
||||
|
||||
@@ -15,13 +15,20 @@
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationGrantAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenIntrospectionAuthenticationProvider;
|
||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenIntrospectionAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.authorization.config.ProviderSettings;
|
||||
@@ -34,41 +41,37 @@ import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Configurer for OAuth 2.0 Token Introspection.
|
||||
* Configurer for the OAuth 2.0 Token Introspection Endpoint.
|
||||
*
|
||||
* @author Gaurav Tiwari
|
||||
* @since 0.2.3
|
||||
* @see OAuth2AuthorizationServerConfigurer#tokenIntrospectionEndpoint(Customizer)
|
||||
* @see OAuth2TokenIntrospectionEndpointFilter
|
||||
*/
|
||||
public class OAuth2TokenIntrospectionConfigurer extends AbstractOAuth2Configurer {
|
||||
|
||||
public final class OAuth2TokenIntrospectionEndpointConfigurer extends AbstractOAuth2Configurer {
|
||||
private RequestMatcher requestMatcher;
|
||||
private AuthenticationConverter accessTokenRequestConverter;
|
||||
private AuthenticationConverter introspectionRequestConverter;
|
||||
private final List<AuthenticationProvider> authenticationProviders = new LinkedList<>();
|
||||
private AuthenticationSuccessHandler tokenIntrospectionResponseHandler;
|
||||
private AuthenticationSuccessHandler introspectionResponseHandler;
|
||||
private AuthenticationFailureHandler errorResponseHandler;
|
||||
|
||||
/**
|
||||
* Restrict for internal use only.
|
||||
*/
|
||||
OAuth2TokenIntrospectionConfigurer(ObjectPostProcessor<Object> objectPostProcessor) {
|
||||
OAuth2TokenIntrospectionEndpointConfigurer(ObjectPostProcessor<Object> objectPostProcessor) {
|
||||
super(objectPostProcessor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link AuthenticationConverter} used when attempting to extract an Access Token Request from {@link HttpServletRequest}
|
||||
* to an instance of {@link OAuth2AuthorizationGrantAuthenticationToken} used for authenticating the authorization grant.
|
||||
* Sets the {@link AuthenticationConverter} used when attempting to extract an Introspection Request from {@link HttpServletRequest}
|
||||
* to an instance of {@link OAuth2TokenIntrospectionAuthenticationToken} used for authenticating the request.
|
||||
*
|
||||
* @param accessTokenRequestConverter the {@link AuthenticationConverter} used when attempting to extract an Access Token Request from {@link HttpServletRequest}
|
||||
* @return the {@link OAuth2TokenIntrospectionConfigurer} for further configuration
|
||||
* @param introspectionRequestConverter the {@link AuthenticationConverter} used when attempting to extract an Introspection Request from {@link HttpServletRequest}
|
||||
* @return the {@link OAuth2TokenIntrospectionEndpointConfigurer} for further configuration
|
||||
*/
|
||||
public OAuth2TokenIntrospectionConfigurer accessTokenRequestConverter(AuthenticationConverter accessTokenRequestConverter) {
|
||||
this.accessTokenRequestConverter = accessTokenRequestConverter;
|
||||
public OAuth2TokenIntrospectionEndpointConfigurer introspectionRequestConverter(AuthenticationConverter introspectionRequestConverter) {
|
||||
this.introspectionRequestConverter = introspectionRequestConverter;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -76,9 +79,9 @@ public class OAuth2TokenIntrospectionConfigurer extends AbstractOAuth2Configurer
|
||||
* Adds an {@link AuthenticationProvider} used for authenticating a type of {@link OAuth2TokenIntrospectionAuthenticationToken}.
|
||||
*
|
||||
* @param authenticationProvider an {@link AuthenticationProvider} used for authenticating a type of {@link OAuth2TokenIntrospectionAuthenticationToken}
|
||||
* @return the {@link OAuth2TokenIntrospectionConfigurer} for further configuration
|
||||
* @return the {@link OAuth2TokenIntrospectionEndpointConfigurer} for further configuration
|
||||
*/
|
||||
public OAuth2TokenIntrospectionConfigurer authenticationProvider(AuthenticationProvider authenticationProvider) {
|
||||
public OAuth2TokenIntrospectionEndpointConfigurer authenticationProvider(AuthenticationProvider authenticationProvider) {
|
||||
Assert.notNull(authenticationProvider, "authenticationProvider cannot be null");
|
||||
this.authenticationProviders.add(authenticationProvider);
|
||||
return this;
|
||||
@@ -87,22 +90,22 @@ public class OAuth2TokenIntrospectionConfigurer extends AbstractOAuth2Configurer
|
||||
/**
|
||||
* Sets the {@link AuthenticationSuccessHandler} used for handling an {@link OAuth2TokenIntrospectionAuthenticationToken}.
|
||||
*
|
||||
* @param tokenIntrospectionResponseHandler the {@link AuthenticationSuccessHandler} used for handling an {@link OAuth2TokenIntrospectionAuthenticationToken}
|
||||
* @return the {@link OAuth2TokenEndpointConfigurer} for further configuration
|
||||
* @param introspectionResponseHandler the {@link AuthenticationSuccessHandler} used for handling an {@link OAuth2TokenIntrospectionAuthenticationToken}
|
||||
* @return the {@link OAuth2TokenIntrospectionEndpointConfigurer} for further configuration
|
||||
*/
|
||||
public OAuth2TokenIntrospectionConfigurer accessTokenResponseHandler(AuthenticationSuccessHandler tokenIntrospectionResponseHandler) {
|
||||
this.tokenIntrospectionResponseHandler = tokenIntrospectionResponseHandler;
|
||||
public OAuth2TokenIntrospectionEndpointConfigurer introspectionResponseHandler(AuthenticationSuccessHandler introspectionResponseHandler) {
|
||||
this.introspectionResponseHandler = introspectionResponseHandler;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link AuthenticationFailureHandler} used for handling an {@link org.springframework.security.oauth2.core.OAuth2AuthenticationException}
|
||||
* Sets the {@link AuthenticationFailureHandler} used for handling an {@link OAuth2AuthenticationException}
|
||||
* and returning the {@link OAuth2Error Error Response}.
|
||||
*
|
||||
* @param errorResponseHandler the {@link AuthenticationFailureHandler} used for handling an {@link org.springframework.security.oauth2.core.OAuth2AuthenticationException}
|
||||
* @return the {@link OAuth2TokenIntrospectionConfigurer} for further configuration
|
||||
* @param errorResponseHandler the {@link AuthenticationFailureHandler} used for handling an {@link OAuth2AuthenticationException}
|
||||
* @return the {@link OAuth2TokenIntrospectionEndpointConfigurer} for further configuration
|
||||
*/
|
||||
public OAuth2TokenIntrospectionConfigurer errorResponseHandler(AuthenticationFailureHandler errorResponseHandler) {
|
||||
public OAuth2TokenIntrospectionEndpointConfigurer errorResponseHandler(AuthenticationFailureHandler errorResponseHandler) {
|
||||
this.errorResponseHandler = errorResponseHandler;
|
||||
return this;
|
||||
}
|
||||
@@ -113,8 +116,12 @@ public class OAuth2TokenIntrospectionConfigurer extends AbstractOAuth2Configurer
|
||||
this.requestMatcher = new AntPathRequestMatcher(
|
||||
providerSettings.getTokenIntrospectionEndpoint(), HttpMethod.POST.name());
|
||||
|
||||
List<AuthenticationProvider> authenticationProviders = this.authenticationProviders.isEmpty() ? createDefaultAuthenticationProviders(builder) : this.authenticationProviders;
|
||||
authenticationProviders.forEach(authenticationProvider -> builder.authenticationProvider(postProcess(authenticationProvider)));
|
||||
List<AuthenticationProvider> authenticationProviders =
|
||||
!this.authenticationProviders.isEmpty() ?
|
||||
this.authenticationProviders :
|
||||
createDefaultAuthenticationProviders(builder);
|
||||
authenticationProviders.forEach(authenticationProvider ->
|
||||
builder.authenticationProvider(postProcess(authenticationProvider)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -123,20 +130,17 @@ public class OAuth2TokenIntrospectionConfigurer extends AbstractOAuth2Configurer
|
||||
ProviderSettings providerSettings = OAuth2ConfigurerUtils.getProviderSettings(builder);
|
||||
|
||||
OAuth2TokenIntrospectionEndpointFilter introspectionEndpointFilter =
|
||||
new OAuth2TokenIntrospectionEndpointFilter(authenticationManager, providerSettings.getTokenIntrospectionEndpoint());
|
||||
|
||||
if (accessTokenRequestConverter != null) {
|
||||
introspectionEndpointFilter.setAuthenticationConverter(this.accessTokenRequestConverter);
|
||||
new OAuth2TokenIntrospectionEndpointFilter(
|
||||
authenticationManager, providerSettings.getTokenIntrospectionEndpoint());
|
||||
if (this.introspectionRequestConverter != null) {
|
||||
introspectionEndpointFilter.setAuthenticationConverter(this.introspectionRequestConverter);
|
||||
}
|
||||
|
||||
if (this.tokenIntrospectionResponseHandler != null) {
|
||||
introspectionEndpointFilter.setAuthenticationSuccessHandler(this.tokenIntrospectionResponseHandler);
|
||||
if (this.introspectionResponseHandler != null) {
|
||||
introspectionEndpointFilter.setAuthenticationSuccessHandler(this.introspectionResponseHandler);
|
||||
}
|
||||
|
||||
if (this.errorResponseHandler != null) {
|
||||
introspectionEndpointFilter.setAuthenticationFailureHandler(this.errorResponseHandler);
|
||||
}
|
||||
|
||||
builder.addFilterAfter(postProcess(introspectionEndpointFilter), FilterSecurityInterceptor.class);
|
||||
}
|
||||
|
||||
@@ -148,15 +152,13 @@ public class OAuth2TokenIntrospectionConfigurer extends AbstractOAuth2Configurer
|
||||
private <B extends HttpSecurityBuilder<B>> List<AuthenticationProvider> createDefaultAuthenticationProviders(B builder) {
|
||||
List<AuthenticationProvider> authenticationProviders = new ArrayList<>();
|
||||
|
||||
OAuth2TokenIntrospectionAuthenticationProvider tokenIntrospectionAuthenticationProvider
|
||||
= new OAuth2TokenIntrospectionAuthenticationProvider(
|
||||
OAuth2ConfigurerUtils.getRegisteredClientRepository(builder),
|
||||
OAuth2ConfigurerUtils.getAuthorizationService(builder)
|
||||
);
|
||||
|
||||
OAuth2TokenIntrospectionAuthenticationProvider tokenIntrospectionAuthenticationProvider =
|
||||
new OAuth2TokenIntrospectionAuthenticationProvider(
|
||||
OAuth2ConfigurerUtils.getRegisteredClientRepository(builder),
|
||||
OAuth2ConfigurerUtils.getAuthorizationService(builder));
|
||||
authenticationProviders.add(tokenIntrospectionAuthenticationProvider);
|
||||
|
||||
return authenticationProviders;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -34,7 +34,6 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Gerardo Roza
|
||||
* @author Joe Grandja
|
||||
* @author Gaurav Tiwari
|
||||
* @since 0.1.1
|
||||
* @see OAuth2TokenIntrospectionClaimAccessor
|
||||
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc7662#section-2.2">Section 2.2 Introspection Response</a>
|
||||
@@ -258,28 +257,6 @@ public final class OAuth2TokenIntrospection implements OAuth2TokenIntrospectionC
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds custom claims if corresponding keys don't exist in present set of claims.
|
||||
*
|
||||
* @since 0.2.3
|
||||
* @param presentedClaims map of all claims
|
||||
* @return the {@link Builder} for further configuration
|
||||
*/
|
||||
public Builder withCustomClaims(Map<String, Object> presentedClaims) {
|
||||
|
||||
if (presentedClaims != null && !presentedClaims.isEmpty()) {
|
||||
|
||||
presentedClaims.keySet().forEach(key -> {
|
||||
if (!this.claims.containsKey(key)) {
|
||||
this.claim(key, presentedClaims.get(key));
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides access to every {@link #claim(String, Object)} declared so far with
|
||||
* the possibility to add, replace, or remove.
|
||||
@@ -335,6 +312,15 @@ public final class OAuth2TokenIntrospection implements OAuth2TokenIntrospectionC
|
||||
((List<String>) this.claims.get(name)).add(value);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void acceptClaimValues(String name, Consumer<List<String>> valuesConsumer) {
|
||||
Assert.hasText(name, "name cannot be empty");
|
||||
Assert.notNull(valuesConsumer, "valuesConsumer cannot be null");
|
||||
this.claims.computeIfAbsent(name, k -> new LinkedList<String>());
|
||||
List<String> values = (List<String>) this.claims.get(name);
|
||||
valuesConsumer.accept(values);
|
||||
}
|
||||
|
||||
private static void validateURL(Object url, String errorMessage) {
|
||||
if (URL.class.isAssignableFrom(url.getClass())) {
|
||||
return;
|
||||
@@ -346,14 +332,5 @@ public final class OAuth2TokenIntrospection implements OAuth2TokenIntrospectionC
|
||||
throw new IllegalArgumentException(errorMessage, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void acceptClaimValues(String name, Consumer<List<String>> valuesConsumer) {
|
||||
Assert.hasText(name, "name cannot be empty");
|
||||
Assert.notNull(valuesConsumer, "valuesConsumer cannot be null");
|
||||
this.claims.computeIfAbsent(name, k -> new LinkedList<String>());
|
||||
List<String> values = (List<String>) this.claims.get(name);
|
||||
valuesConsumer.accept(values);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,23 +16,25 @@
|
||||
package org.springframework.security.oauth2.server.authorization.authentication;
|
||||
|
||||
import java.net.URL;
|
||||
import java.time.Instant;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.oauth2.core.AbstractOAuth2Token;
|
||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenClaimAccessor;
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenIntrospection;
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenIntrospectionClaimNames;
|
||||
import org.springframework.security.oauth2.core.converter.ClaimConversionService;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthenticationProviderUtils.getAuthenticatedClientElseThrowInvalidClient;
|
||||
|
||||
@@ -41,7 +43,6 @@ import static org.springframework.security.oauth2.server.authorization.authentic
|
||||
*
|
||||
* @author Gerardo Roza
|
||||
* @author Joe Grandja
|
||||
* @author Gaurav Tiwari
|
||||
* @since 0.1.1
|
||||
* @see OAuth2TokenIntrospectionAuthenticationToken
|
||||
* @see RegisteredClientRepository
|
||||
@@ -49,6 +50,9 @@ import static org.springframework.security.oauth2.server.authorization.authentic
|
||||
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc7662#section-2.1">Section 2.1 Introspection Request</a>
|
||||
*/
|
||||
public final class OAuth2TokenIntrospectionAuthenticationProvider implements AuthenticationProvider {
|
||||
private static final TypeDescriptor OBJECT_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(Object.class);
|
||||
private static final TypeDescriptor LIST_STRING_TYPE_DESCRIPTOR =
|
||||
TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(String.class));
|
||||
private final RegisteredClientRepository registeredClientRepository;
|
||||
private final OAuth2AuthorizationService authorizationService;
|
||||
|
||||
@@ -103,8 +107,15 @@ public final class OAuth2TokenIntrospectionAuthenticationProvider implements Aut
|
||||
private static OAuth2TokenIntrospection withActiveTokenClaims(
|
||||
OAuth2Authorization.Token<AbstractOAuth2Token> authorizedToken, RegisteredClient authorizedClient) {
|
||||
|
||||
OAuth2TokenIntrospection.Builder tokenClaims = OAuth2TokenIntrospection.builder(true)
|
||||
.clientId(authorizedClient.getClientId());
|
||||
OAuth2TokenIntrospection.Builder tokenClaims;
|
||||
if (!CollectionUtils.isEmpty(authorizedToken.getClaims())) {
|
||||
Map<String, Object> claims = convertClaimsIfNecessary(authorizedToken.getClaims());
|
||||
tokenClaims = OAuth2TokenIntrospection.withClaims(claims).active(true);
|
||||
} else {
|
||||
tokenClaims = OAuth2TokenIntrospection.builder(true);
|
||||
}
|
||||
|
||||
tokenClaims.clientId(authorizedClient.getClientId());
|
||||
|
||||
// TODO Set "username"
|
||||
|
||||
@@ -118,34 +129,43 @@ public final class OAuth2TokenIntrospectionAuthenticationProvider implements Aut
|
||||
|
||||
if (OAuth2AccessToken.class.isAssignableFrom(token.getClass())) {
|
||||
OAuth2AccessToken accessToken = (OAuth2AccessToken) token;
|
||||
tokenClaims.scopes(scopes -> scopes.addAll(accessToken.getScopes()));
|
||||
tokenClaims.tokenType(accessToken.getTokenType().getValue());
|
||||
|
||||
if (!CollectionUtils.isEmpty(authorizedToken.getClaims())) {
|
||||
OAuth2TokenClaimAccessor accessTokenClaims = authorizedToken::getClaims;
|
||||
|
||||
Instant notBefore = accessTokenClaims.getNotBefore();
|
||||
if (notBefore != null) {
|
||||
tokenClaims.notBefore(notBefore);
|
||||
}
|
||||
tokenClaims.subject(accessTokenClaims.getSubject());
|
||||
List<String> audience = accessTokenClaims.getAudience();
|
||||
if (!CollectionUtils.isEmpty(audience)) {
|
||||
tokenClaims.audiences(audiences -> audiences.addAll(audience));
|
||||
}
|
||||
URL issuer = accessTokenClaims.getIssuer();
|
||||
if (issuer != null) {
|
||||
tokenClaims.issuer(issuer.toExternalForm());
|
||||
}
|
||||
String jti = accessTokenClaims.getId();
|
||||
if (StringUtils.hasText(jti)) {
|
||||
tokenClaims.id(jti);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tokenClaims.withCustomClaims(authorizedToken.getClaims());
|
||||
|
||||
return tokenClaims.build();
|
||||
}
|
||||
|
||||
private static Map<String, Object> convertClaimsIfNecessary(Map<String, Object> claims) {
|
||||
Map<String, Object> convertedClaims = new HashMap<>(claims);
|
||||
|
||||
Object value = claims.get(OAuth2TokenIntrospectionClaimNames.ISS);
|
||||
if (value != null && !(value instanceof URL)) {
|
||||
URL convertedValue = ClaimConversionService.getSharedInstance()
|
||||
.convert(value, URL.class);
|
||||
if (convertedValue != null) {
|
||||
convertedClaims.put(OAuth2TokenIntrospectionClaimNames.ISS, convertedValue);
|
||||
}
|
||||
}
|
||||
|
||||
value = claims.get(OAuth2TokenIntrospectionClaimNames.SCOPE);
|
||||
if (value != null && !(value instanceof List)) {
|
||||
Object convertedValue = ClaimConversionService.getSharedInstance()
|
||||
.convert(value, OBJECT_TYPE_DESCRIPTOR, LIST_STRING_TYPE_DESCRIPTOR);
|
||||
if (convertedValue != null) {
|
||||
convertedClaims.put(OAuth2TokenIntrospectionClaimNames.SCOPE, convertedValue);
|
||||
}
|
||||
}
|
||||
|
||||
value = claims.get(OAuth2TokenIntrospectionClaimNames.AUD);
|
||||
if (value != null && !(value instanceof List)) {
|
||||
Object convertedValue = ClaimConversionService.getSharedInstance()
|
||||
.convert(value, OBJECT_TYPE_DESCRIPTOR, LIST_STRING_TYPE_DESCRIPTOR);
|
||||
if (convertedValue != null) {
|
||||
convertedClaims.put(OAuth2TokenIntrospectionClaimNames.AUD, convertedValue);
|
||||
}
|
||||
}
|
||||
|
||||
return convertedClaims;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -70,12 +70,12 @@ public final class OAuth2TokenIntrospectionEndpointFilter extends OncePerRequest
|
||||
|
||||
private final AuthenticationManager authenticationManager;
|
||||
private final RequestMatcher tokenIntrospectionEndpointMatcher;
|
||||
private AuthenticationConverter tokenIntrospectionAuthenticationConverter =
|
||||
private AuthenticationConverter authenticationConverter =
|
||||
new DefaultTokenIntrospectionAuthenticationConverter();
|
||||
private final HttpMessageConverter<OAuth2TokenIntrospection> tokenIntrospectionHttpResponseConverter =
|
||||
new OAuth2TokenIntrospectionHttpMessageConverter();
|
||||
private final HttpMessageConverter<OAuth2Error> errorHttpResponseConverter = new OAuth2ErrorHttpMessageConverter();
|
||||
private AuthenticationSuccessHandler authenticationSuccessHandler = this::sendTokenIntrospectionResponse;;
|
||||
private AuthenticationSuccessHandler authenticationSuccessHandler = this::sendIntrospectionResponse;
|
||||
private AuthenticationFailureHandler authenticationFailureHandler = this::sendErrorResponse;
|
||||
|
||||
/**
|
||||
@@ -112,14 +112,10 @@ public final class OAuth2TokenIntrospectionEndpointFilter extends OncePerRequest
|
||||
}
|
||||
|
||||
try {
|
||||
OAuth2TokenIntrospectionAuthenticationToken tokenIntrospectionAuthentication =
|
||||
(OAuth2TokenIntrospectionAuthenticationToken) this.tokenIntrospectionAuthenticationConverter.convert(request);
|
||||
|
||||
OAuth2TokenIntrospectionAuthenticationToken tokenIntrospectionAuthenticationResult =
|
||||
(OAuth2TokenIntrospectionAuthenticationToken) this.authenticationManager.authenticate(tokenIntrospectionAuthentication);
|
||||
|
||||
Authentication tokenIntrospectionAuthentication = this.authenticationConverter.convert(request);
|
||||
Authentication tokenIntrospectionAuthenticationResult =
|
||||
this.authenticationManager.authenticate(tokenIntrospectionAuthentication);
|
||||
this.authenticationSuccessHandler.onAuthenticationSuccess(request, response, tokenIntrospectionAuthenticationResult);
|
||||
|
||||
} catch (OAuth2AuthenticationException ex) {
|
||||
SecurityContextHolder.clearContext();
|
||||
this.authenticationFailureHandler.onAuthenticationFailure(request, response, ex);
|
||||
@@ -127,50 +123,52 @@ public final class OAuth2TokenIntrospectionEndpointFilter extends OncePerRequest
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link AuthenticationConverter} used when attempting to extract a Token Introspection Request from
|
||||
* {@link HttpServletRequest} to an instance of {@link OAuth2TokenIntrospectionAuthenticationToken} used for authenticating the request.
|
||||
* Sets the {@link AuthenticationConverter} used when attempting to extract an Introspection Request from {@link HttpServletRequest}
|
||||
* to an instance of {@link OAuth2TokenIntrospectionAuthenticationToken} used for authenticating the request.
|
||||
*
|
||||
* @param authenticationConverter the {@link AuthenticationConverter} used when attempting to extract a Token Introspection Request from {@link HttpServletRequest}
|
||||
* @param authenticationConverter the {@link AuthenticationConverter} used when attempting to extract an Introspection Request from {@link HttpServletRequest}
|
||||
* @since 0.2.3
|
||||
*/
|
||||
public void setAuthenticationConverter(AuthenticationConverter authenticationConverter) {
|
||||
Assert.notNull(authenticationConverter, "authenticationConverter cannot be null.");
|
||||
this.tokenIntrospectionAuthenticationConverter = authenticationConverter;
|
||||
Assert.notNull(authenticationConverter, "authenticationConverter cannot be null");
|
||||
this.authenticationConverter = authenticationConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link AuthenticationSuccessHandler} used for handling an {@link OAuth2TokenIntrospectionAuthenticationToken}
|
||||
* Sets the {@link AuthenticationSuccessHandler} used for handling an {@link OAuth2TokenIntrospectionAuthenticationToken}.
|
||||
*
|
||||
* @param authenticationSuccessHandler the {@link AuthenticationSuccessHandler} used for handling an {@link OAuth2TokenIntrospectionAuthenticationToken}
|
||||
* @since 0.2.3
|
||||
*/
|
||||
public void setAuthenticationSuccessHandler(AuthenticationSuccessHandler authenticationSuccessHandler) {
|
||||
Assert.notNull(authenticationSuccessHandler, "authenticationSuccessHandler cannot be null.");
|
||||
Assert.notNull(authenticationSuccessHandler, "authenticationSuccessHandler cannot be null");
|
||||
this.authenticationSuccessHandler = authenticationSuccessHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link AuthenticationFailureHandler} used for handling an {@link OAuth2AuthenticationException} and
|
||||
* returning {@link OAuth2Error Error Resonse}.
|
||||
* Sets the {@link AuthenticationFailureHandler} used for handling an {@link OAuth2AuthenticationException}
|
||||
* and returning the {@link OAuth2Error Error Resonse}.
|
||||
*
|
||||
* @param authenticationFailureHandler the {@link .AuthenticationFailureHandler} used for handling {@link OAuth2AuthenticationException}
|
||||
* @param authenticationFailureHandler the {@link AuthenticationFailureHandler} used for handling an {@link OAuth2AuthenticationException}
|
||||
* @since 0.2.3
|
||||
*/
|
||||
public void setAuthenticationFailureHandler(AuthenticationFailureHandler authenticationFailureHandler) {
|
||||
Assert.notNull(authenticationFailureHandler, "authenticationFailureHandler cannot be null.");
|
||||
Assert.notNull(authenticationFailureHandler, "authenticationFailureHandler cannot be null");
|
||||
this.authenticationFailureHandler = authenticationFailureHandler;
|
||||
}
|
||||
|
||||
private void sendTokenIntrospectionResponse(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
|
||||
|
||||
OAuth2TokenIntrospectionAuthenticationToken tokenIntrospectionAuthenticationResult = (OAuth2TokenIntrospectionAuthenticationToken) authentication;
|
||||
OAuth2TokenIntrospection tokenClaims = tokenIntrospectionAuthenticationResult.getTokenClaims();
|
||||
private void sendIntrospectionResponse(HttpServletRequest request, HttpServletResponse response,
|
||||
Authentication authentication) throws IOException {
|
||||
|
||||
OAuth2TokenIntrospectionAuthenticationToken tokenIntrospectionAuthentication =
|
||||
(OAuth2TokenIntrospectionAuthenticationToken) authentication;
|
||||
OAuth2TokenIntrospection tokenClaims = tokenIntrospectionAuthentication.getTokenClaims();
|
||||
ServletServerHttpResponse httpResponse = new ServletServerHttpResponse(response);
|
||||
this.tokenIntrospectionHttpResponseConverter.write(tokenClaims, null, httpResponse);
|
||||
}
|
||||
|
||||
private void sendErrorResponse(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException {
|
||||
private void sendErrorResponse(HttpServletRequest request, HttpServletResponse response,
|
||||
AuthenticationException exception) throws IOException {
|
||||
OAuth2Error error = ((OAuth2AuthenticationException) exception).getError();
|
||||
ServletServerHttpResponse httpResponse = new ServletServerHttpResponse(response);
|
||||
httpResponse.setStatusCode(HttpStatus.BAD_REQUEST);
|
||||
@@ -179,7 +177,7 @@ public final class OAuth2TokenIntrospectionEndpointFilter extends OncePerRequest
|
||||
|
||||
private static void throwError(String errorCode, String parameterName) {
|
||||
OAuth2Error error = new OAuth2Error(errorCode, "OAuth 2.0 Token Introspection Parameter: " + parameterName,
|
||||
"https://tools.ietf.org/html/rfc7662#section-2.1");
|
||||
"https://datatracker.ietf.org/doc/html/rfc7662#section-2.1");
|
||||
throw new OAuth2AuthenticationException(error);
|
||||
}
|
||||
|
||||
@@ -217,5 +215,7 @@ public final class OAuth2TokenIntrospectionEndpointFilter extends OncePerRequest
|
||||
return new OAuth2TokenIntrospectionAuthenticationToken(
|
||||
token, clientPrincipal, tokenTypeHint, additionalParameters);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,9 +26,6 @@ import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import com.nimbusds.jose.jwk.JWKSet;
|
||||
import com.nimbusds.jose.jwk.source.JWKSource;
|
||||
import com.nimbusds.jose.proc.SecurityContext;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
@@ -49,34 +46,38 @@ import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
|
||||
import org.springframework.mock.http.client.MockClientHttpResponse;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
|
||||
import org.springframework.security.config.test.SpringTestRule;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.oauth2.core.AbstractOAuth2Token;
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthorizationCode;
|
||||
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
|
||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenClaimsSet;
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenFormat;
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenIntrospection;
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenIntrospectionClaimNames;
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenType;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||
import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter;
|
||||
import org.springframework.security.oauth2.core.http.converter.OAuth2TokenIntrospectionHttpMessageConverter;
|
||||
import org.springframework.security.oauth2.jose.TestJwks;
|
||||
import org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationConsentService;
|
||||
import org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenClaimsContext;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2TokenCustomizer;
|
||||
import org.springframework.security.oauth2.server.authorization.TestOAuth2Authorizations;
|
||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenIntrospectionAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository;
|
||||
import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository.RegisteredClientParametersMapper;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
||||
@@ -85,14 +86,24 @@ import org.springframework.security.oauth2.server.authorization.client.TestRegis
|
||||
import org.springframework.security.oauth2.server.authorization.config.ProviderSettings;
|
||||
import org.springframework.security.oauth2.server.authorization.config.TokenSettings;
|
||||
import org.springframework.security.oauth2.server.authorization.jackson2.TestingAuthenticationTokenMixin;
|
||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenClaimsContext;
|
||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenClaimsSet;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.AuthenticationConverter;
|
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@@ -104,9 +115,12 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
*/
|
||||
public class OAuth2TokenIntrospectionTests {
|
||||
private static EmbeddedDatabase db;
|
||||
private static JWKSource<SecurityContext> jwkSource;
|
||||
private static ProviderSettings providerSettings;
|
||||
private static OAuth2TokenCustomizer<OAuth2TokenClaimsContext> accessTokenCustomizer;
|
||||
private static AuthenticationConverter authenticationConverter;
|
||||
private static AuthenticationProvider authenticationProvider;
|
||||
private static AuthenticationSuccessHandler authenticationSuccessHandler;
|
||||
private static AuthenticationFailureHandler authenticationFailureHandler;
|
||||
private static final HttpMessageConverter<OAuth2TokenIntrospection> tokenIntrospectionHttpResponseConverter =
|
||||
new OAuth2TokenIntrospectionHttpMessageConverter();
|
||||
private static final HttpMessageConverter<OAuth2AccessTokenResponse> accessTokenHttpResponseConverter =
|
||||
@@ -129,9 +143,11 @@ public class OAuth2TokenIntrospectionTests {
|
||||
|
||||
@BeforeClass
|
||||
public static void init() {
|
||||
JWKSet jwkSet = new JWKSet(TestJwks.DEFAULT_RSA_JWK);
|
||||
jwkSource = (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
|
||||
providerSettings = ProviderSettings.builder().tokenIntrospectionEndpoint("/test/introspect").build();
|
||||
authenticationConverter = mock(AuthenticationConverter.class);
|
||||
authenticationProvider = mock(AuthenticationProvider.class);
|
||||
authenticationSuccessHandler = mock(AuthenticationSuccessHandler.class);
|
||||
authenticationFailureHandler = mock(AuthenticationFailureHandler.class);
|
||||
accessTokenCustomizer = mock(OAuth2TokenCustomizer.class);
|
||||
db = new EmbeddedDatabaseBuilder()
|
||||
.generateUniqueName(true)
|
||||
@@ -175,6 +191,7 @@ public class OAuth2TokenIntrospectionTests {
|
||||
.issuedAt(issuedAt)
|
||||
.notBefore(issuedAt)
|
||||
.expiresAt(expiresAt)
|
||||
.claim(OAuth2TokenIntrospectionClaimNames.SCOPE, accessToken.getScopes())
|
||||
.id("id")
|
||||
.build();
|
||||
// @formatter:on
|
||||
@@ -314,6 +331,43 @@ public class OAuth2TokenIntrospectionTests {
|
||||
assertThat(tokenIntrospectionResponse.getId()).isEqualTo(accessTokenClaims.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenTokenIntrospectionEndpointCustomizedThenUsed() throws Exception {
|
||||
this.spring.register(AuthorizationServerConfigurationCustomTokenIntrospectionEndpoint.class).autowire();
|
||||
|
||||
RegisteredClient introspectRegisteredClient = TestRegisteredClients.registeredClient2().build();
|
||||
this.registeredClientRepository.save(introspectRegisteredClient);
|
||||
|
||||
RegisteredClient authorizedRegisteredClient = TestRegisteredClients.registeredClient().build();
|
||||
this.registeredClientRepository.save(authorizedRegisteredClient);
|
||||
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(authorizedRegisteredClient).build();
|
||||
this.authorizationService.save(authorization);
|
||||
|
||||
OAuth2AccessToken accessToken = authorization.getAccessToken().getToken();
|
||||
|
||||
Authentication clientPrincipal = new OAuth2ClientAuthenticationToken(
|
||||
introspectRegisteredClient, ClientAuthenticationMethod.CLIENT_SECRET_BASIC, introspectRegisteredClient.getClientSecret());
|
||||
OAuth2TokenIntrospectionAuthenticationToken tokenIntrospectionAuthentication =
|
||||
new OAuth2TokenIntrospectionAuthenticationToken(
|
||||
accessToken.getTokenValue(), clientPrincipal, null, null);
|
||||
|
||||
when(authenticationConverter.convert(any())).thenReturn(tokenIntrospectionAuthentication);
|
||||
when(authenticationProvider.supports(eq(OAuth2TokenIntrospectionAuthenticationToken.class))).thenReturn(true);
|
||||
when(authenticationProvider.authenticate(any())).thenReturn(tokenIntrospectionAuthentication);
|
||||
|
||||
// @formatter:off
|
||||
this.mvc.perform(post(providerSettings.getTokenIntrospectionEndpoint())
|
||||
.params(getTokenIntrospectionRequestParameters(accessToken, OAuth2TokenType.ACCESS_TOKEN))
|
||||
.header(HttpHeaders.AUTHORIZATION, getAuthorizationHeader(introspectRegisteredClient)))
|
||||
.andExpect(status().isOk());
|
||||
// @formatter:on
|
||||
|
||||
verify(authenticationConverter).convert(any());
|
||||
verify(authenticationProvider).authenticate(eq(tokenIntrospectionAuthentication));
|
||||
verify(authenticationSuccessHandler).onAuthenticationSuccess(any(), any(), eq(tokenIntrospectionAuthentication));
|
||||
}
|
||||
|
||||
private static MultiValueMap<String, String> getTokenIntrospectionRequestParameters(AbstractOAuth2Token token,
|
||||
OAuth2TokenType tokenType) {
|
||||
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
|
||||
@@ -420,4 +474,35 @@ public class OAuth2TokenIntrospectionTests {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class AuthorizationServerConfigurationCustomTokenIntrospectionEndpoint extends AuthorizationServerConfiguration {
|
||||
|
||||
// @formatter:off
|
||||
@Bean
|
||||
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
|
||||
OAuth2AuthorizationServerConfigurer<HttpSecurity> authorizationServerConfigurer =
|
||||
new OAuth2AuthorizationServerConfigurer<>();
|
||||
authorizationServerConfigurer
|
||||
.tokenIntrospectionEndpoint(tokenIntrospectionEndpoint ->
|
||||
tokenIntrospectionEndpoint
|
||||
.introspectionRequestConverter(authenticationConverter)
|
||||
.authenticationProvider(authenticationProvider)
|
||||
.introspectionResponseHandler(authenticationSuccessHandler)
|
||||
.errorResponseHandler(authenticationFailureHandler));
|
||||
RequestMatcher endpointsMatcher = authorizationServerConfigurer.getEndpointsMatcher();
|
||||
|
||||
http
|
||||
.requestMatcher(endpointsMatcher)
|
||||
.authorizeRequests(authorizeRequests ->
|
||||
authorizeRequests.anyRequest().authenticated()
|
||||
)
|
||||
.csrf(csrf -> csrf.ignoringRequestMatchers(endpointsMatcher))
|
||||
.apply(authorizationServerConfigurer);
|
||||
return http.build();
|
||||
}
|
||||
// @formatter:on
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,15 +31,16 @@ import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
|
||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenClaimNames;
|
||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenClaimsSet;
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenIntrospection;
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenIntrospectionClaimNames;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
||||
import org.springframework.security.oauth2.server.authorization.TestOAuth2Authorizations;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
|
||||
import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients;
|
||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenClaimNames;
|
||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenClaimsSet;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
@@ -54,7 +55,6 @@ import static org.mockito.Mockito.when;
|
||||
*
|
||||
* @author Gerardo Roza
|
||||
* @author Joe Grandja
|
||||
* @author Gaurav Tiwari
|
||||
*/
|
||||
public class OAuth2TokenIntrospectionAuthenticationProviderTests {
|
||||
private RegisteredClientRepository registeredClientRepository;
|
||||
@@ -227,6 +227,8 @@ public class OAuth2TokenIntrospectionAuthenticationProviderTests {
|
||||
.notBefore(issuedAt)
|
||||
.expiresAt(expiresAt)
|
||||
.id("id")
|
||||
.claim(OAuth2TokenIntrospectionClaimNames.SCOPE, accessToken.getScopes())
|
||||
.claim("custom-claim", "custom-value")
|
||||
.build();
|
||||
// @formatter:on
|
||||
|
||||
@@ -253,68 +255,14 @@ public class OAuth2TokenIntrospectionAuthenticationProviderTests {
|
||||
assertThat(tokenClaims.getClientId()).isEqualTo(authorizedClient.getClientId());
|
||||
assertThat(tokenClaims.getIssuedAt()).isEqualTo(accessToken.getIssuedAt());
|
||||
assertThat(tokenClaims.getExpiresAt()).isEqualTo(accessToken.getExpiresAt());
|
||||
assertThat(tokenClaims.getScopes()).containsExactlyInAnyOrderElementsOf(accessToken.getScopes());
|
||||
assertThat(tokenClaims.getTokenType()).isEqualTo(accessToken.getTokenType().getValue());
|
||||
assertThat(tokenClaims.getNotBefore()).isEqualTo(claimsSet.getNotBefore());
|
||||
assertThat(tokenClaims.getSubject()).isEqualTo(claimsSet.getSubject());
|
||||
assertThat(tokenClaims.getAudience()).containsExactlyInAnyOrderElementsOf(claimsSet.getAudience());
|
||||
assertThat(tokenClaims.getIssuer()).isEqualTo(claimsSet.getIssuer());
|
||||
assertThat(tokenClaims.getId()).isEqualTo(claimsSet.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenValidAccessTokenAndCustomClaimThenActiveAndCustomClaimInResponse() {
|
||||
RegisteredClient authorizedClient = TestRegisteredClients.registeredClient().build();
|
||||
Instant issuedAt = Instant.now();
|
||||
Instant expiresAt = issuedAt.plus(Duration.ofHours(1));
|
||||
OAuth2AccessToken accessToken = new OAuth2AccessToken(
|
||||
OAuth2AccessToken.TokenType.BEARER, "access-token", issuedAt, expiresAt,
|
||||
new HashSet<>(Arrays.asList("scope1", "scope2")));
|
||||
|
||||
// @formatter:off
|
||||
OAuth2TokenClaimsSet claimsSet = OAuth2TokenClaimsSet.builder()
|
||||
.issuer("https://provider.com")
|
||||
.subject("subject")
|
||||
.audience(Collections.singletonList(authorizedClient.getClientId()))
|
||||
.issuedAt(issuedAt)
|
||||
.notBefore(issuedAt)
|
||||
.expiresAt(expiresAt)
|
||||
.claim("custom-claim", "custom-claim-value")
|
||||
.id("id")
|
||||
.build();
|
||||
// @formatter:on
|
||||
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations
|
||||
.authorization(authorizedClient, accessToken, claimsSet.getClaims())
|
||||
.build();
|
||||
when(this.authorizationService.findByToken(eq(accessToken.getTokenValue()), isNull()))
|
||||
.thenReturn(authorization);
|
||||
when(this.registeredClientRepository.findById(eq(authorizedClient.getId()))).thenReturn(authorizedClient);
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient2().build();
|
||||
OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(
|
||||
registeredClient, ClientAuthenticationMethod.CLIENT_SECRET_BASIC, registeredClient.getClientSecret());
|
||||
|
||||
OAuth2TokenIntrospectionAuthenticationToken authentication = new OAuth2TokenIntrospectionAuthenticationToken(
|
||||
accessToken.getTokenValue(), clientPrincipal, null, null);
|
||||
OAuth2TokenIntrospectionAuthenticationToken authenticationResult =
|
||||
(OAuth2TokenIntrospectionAuthenticationToken) this.authenticationProvider.authenticate(authentication);
|
||||
|
||||
verify(this.authorizationService).findByToken(eq(authentication.getToken()), isNull());
|
||||
verify(this.registeredClientRepository).findById(eq(authorizedClient.getId()));
|
||||
assertThat(authenticationResult.isAuthenticated()).isTrue();
|
||||
OAuth2TokenIntrospection tokenClaims = authenticationResult.getTokenClaims();
|
||||
assertThat(tokenClaims.isActive()).isTrue();
|
||||
assertThat(tokenClaims.getClientId()).isEqualTo(authorizedClient.getClientId());
|
||||
assertThat(tokenClaims.getIssuedAt()).isEqualTo(accessToken.getIssuedAt());
|
||||
assertThat(tokenClaims.getExpiresAt()).isEqualTo(accessToken.getExpiresAt());
|
||||
assertThat(tokenClaims.getScopes()).containsExactlyInAnyOrderElementsOf(accessToken.getScopes());
|
||||
assertThat(tokenClaims.getTokenType()).isEqualTo(accessToken.getTokenType().getValue());
|
||||
assertThat(tokenClaims.getNotBefore()).isEqualTo(claimsSet.getNotBefore());
|
||||
assertThat(tokenClaims.getSubject()).isEqualTo(claimsSet.getSubject());
|
||||
assertThat(tokenClaims.getAudience()).containsExactlyInAnyOrderElementsOf(claimsSet.getAudience());
|
||||
assertThat(tokenClaims.getIssuer()).isEqualTo(claimsSet.getIssuer());
|
||||
assertThat(tokenClaims.getId()).isEqualTo(claimsSet.getId());
|
||||
assertThat((String) tokenClaims.getClaim("custom-claim")).isEqualTo("custom-claim-value");
|
||||
assertThat(tokenClaims.<String>getClaim("custom-claim")).isEqualTo("custom-value");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020-2021 the original author or authors.
|
||||
* Copyright 2020-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -40,6 +40,7 @@ import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenIntrospection;
|
||||
@@ -51,6 +52,9 @@ import org.springframework.security.oauth2.server.authorization.authentication.O
|
||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenIntrospectionAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
||||
import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients;
|
||||
import org.springframework.security.web.authentication.AuthenticationConverter;
|
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
@@ -101,6 +105,27 @@ public class OAuth2TokenIntrospectionEndpointFilterTests {
|
||||
.hasMessage("tokenIntrospectionEndpointUri cannot be empty");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAuthenticationConverterWhenNullThenThrowIllegalArgumentException() {
|
||||
assertThatThrownBy(() -> this.filter.setAuthenticationConverter(null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("authenticationConverter cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAuthenticationSuccessHandlerWhenNullThenThrowIllegalArgumentException() {
|
||||
assertThatThrownBy(() -> this.filter.setAuthenticationSuccessHandler(null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("authenticationSuccessHandler cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAuthenticationFailureHandlerWhenNullThenThrowIllegalArgumentException() {
|
||||
assertThatThrownBy(() -> this.filter.setAuthenticationFailureHandler(null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("authenticationFailureHandler cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenNotTokenIntrospectionRequestThenNotProcessed() throws Exception {
|
||||
String requestUri = "/path";
|
||||
@@ -231,6 +256,100 @@ public class OAuth2TokenIntrospectionEndpointFilterTests {
|
||||
assertThat(tokenIntrospectionResponse.getId()).isEqualTo(tokenClaims.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenCustomAuthenticationConverterThenUsed() throws Exception {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
Authentication clientPrincipal = new OAuth2ClientAuthenticationToken(
|
||||
registeredClient, ClientAuthenticationMethod.CLIENT_SECRET_BASIC, registeredClient.getClientSecret());
|
||||
OAuth2AccessToken accessToken = new OAuth2AccessToken(
|
||||
OAuth2AccessToken.TokenType.BEARER, "token",
|
||||
Instant.now(), Instant.now().plus(Duration.ofHours(1)),
|
||||
new HashSet<>(Arrays.asList("scope1", "scope2")));
|
||||
OAuth2TokenIntrospectionAuthenticationToken tokenIntrospectionAuthentication =
|
||||
new OAuth2TokenIntrospectionAuthenticationToken(
|
||||
accessToken.getTokenValue(), clientPrincipal, OAuth2TokenType.ACCESS_TOKEN.getValue(), null);
|
||||
|
||||
AuthenticationConverter authenticationConverter = mock(AuthenticationConverter.class);
|
||||
when(authenticationConverter.convert(any())).thenReturn(tokenIntrospectionAuthentication);
|
||||
this.filter.setAuthenticationConverter(authenticationConverter);
|
||||
|
||||
when(this.authenticationManager.authenticate(any())).thenReturn(tokenIntrospectionAuthentication);
|
||||
|
||||
SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
|
||||
securityContext.setAuthentication(clientPrincipal);
|
||||
SecurityContextHolder.setContext(securityContext);
|
||||
|
||||
MockHttpServletRequest request = createTokenIntrospectionRequest(
|
||||
accessToken.getTokenValue(), OAuth2TokenType.ACCESS_TOKEN.getValue());
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
FilterChain filterChain = mock(FilterChain.class);
|
||||
|
||||
this.filter.doFilter(request, response, filterChain);
|
||||
|
||||
verify(authenticationConverter).convert(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenCustomAuthenticationSuccessHandlerThenUsed() throws Exception {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
Authentication clientPrincipal = new OAuth2ClientAuthenticationToken(
|
||||
registeredClient, ClientAuthenticationMethod.CLIENT_SECRET_BASIC, registeredClient.getClientSecret());
|
||||
OAuth2AccessToken accessToken = new OAuth2AccessToken(
|
||||
OAuth2AccessToken.TokenType.BEARER, "token",
|
||||
Instant.now(), Instant.now().plus(Duration.ofHours(1)),
|
||||
new HashSet<>(Arrays.asList("scope1", "scope2")));
|
||||
OAuth2TokenIntrospectionAuthenticationToken tokenIntrospectionAuthentication =
|
||||
new OAuth2TokenIntrospectionAuthenticationToken(
|
||||
accessToken.getTokenValue(), clientPrincipal, OAuth2TokenType.ACCESS_TOKEN.getValue(), null);
|
||||
|
||||
AuthenticationSuccessHandler authenticationSuccessHandler = mock(AuthenticationSuccessHandler.class);
|
||||
this.filter.setAuthenticationSuccessHandler(authenticationSuccessHandler);
|
||||
|
||||
when(this.authenticationManager.authenticate(any())).thenReturn(tokenIntrospectionAuthentication);
|
||||
|
||||
SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
|
||||
securityContext.setAuthentication(clientPrincipal);
|
||||
SecurityContextHolder.setContext(securityContext);
|
||||
|
||||
MockHttpServletRequest request = createTokenIntrospectionRequest(
|
||||
accessToken.getTokenValue(), OAuth2TokenType.ACCESS_TOKEN.getValue());
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
FilterChain filterChain = mock(FilterChain.class);
|
||||
|
||||
this.filter.doFilter(request, response, filterChain);
|
||||
|
||||
verify(authenticationSuccessHandler).onAuthenticationSuccess(any(), any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenCustomAuthenticationFailureHandlerThenUsed() throws Exception {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
Authentication clientPrincipal = new OAuth2ClientAuthenticationToken(
|
||||
registeredClient, ClientAuthenticationMethod.CLIENT_SECRET_BASIC, registeredClient.getClientSecret());
|
||||
OAuth2AccessToken accessToken = new OAuth2AccessToken(
|
||||
OAuth2AccessToken.TokenType.BEARER, "token",
|
||||
Instant.now(), Instant.now().plus(Duration.ofHours(1)),
|
||||
new HashSet<>(Arrays.asList("scope1", "scope2")));
|
||||
|
||||
AuthenticationFailureHandler authenticationFailureHandler = mock(AuthenticationFailureHandler.class);
|
||||
this.filter.setAuthenticationFailureHandler(authenticationFailureHandler);
|
||||
|
||||
when(this.authenticationManager.authenticate(any())).thenThrow(OAuth2AuthenticationException.class);
|
||||
|
||||
SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
|
||||
securityContext.setAuthentication(clientPrincipal);
|
||||
SecurityContextHolder.setContext(securityContext);
|
||||
|
||||
MockHttpServletRequest request = createTokenIntrospectionRequest(
|
||||
accessToken.getTokenValue(), OAuth2TokenType.ACCESS_TOKEN.getValue());
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
FilterChain filterChain = mock(FilterChain.class);
|
||||
|
||||
this.filter.doFilter(request, response, filterChain);
|
||||
|
||||
verify(authenticationFailureHandler).onAuthenticationFailure(any(), any(), any());
|
||||
}
|
||||
|
||||
private void doFilterWhenTokenIntrospectionRequestInvalidParameterThenError(String parameterName, String errorCode,
|
||||
MockHttpServletRequest request) throws Exception {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user