OAuth2ResourceServerConfigurer.java
/*
* Copyright 2004-present 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers.oauth2.server.resource;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Supplier;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.context.ApplicationContext;
import org.springframework.core.convert.converter.Converter;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationManagerResolver;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;
import org.springframework.security.config.annotation.web.configurers.ExceptionHandlingConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.FactorGrantedAuthority;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.oauth2.server.resource.OAuth2ProtectedResourceMetadata;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider;
import org.springframework.security.oauth2.server.resource.authentication.OpaqueTokenAuthenticationProvider;
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;
import org.springframework.security.oauth2.server.resource.introspection.SpringOpaqueTokenIntrospector;
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint;
import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver;
import org.springframework.security.oauth2.server.resource.web.OAuth2ProtectedResourceMetadataFilter;
import org.springframework.security.oauth2.server.resource.web.access.BearerTokenAccessDeniedHandler;
import org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
import org.springframework.security.web.access.DelegatingAccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationConverter;
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
import org.springframework.security.web.csrf.CsrfException;
import org.springframework.security.web.util.matcher.AndRequestMatcher;
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.web.accept.ContentNegotiationStrategy;
import org.springframework.web.accept.HeaderContentNegotiationStrategy;
/**
*
* An {@link AbstractHttpConfigurer} for OAuth 2.0 Resource Server Support.
*
* By default, this wires a {@link BearerTokenAuthenticationFilter}, which can be used to
* parse the request for bearer tokens and make an authentication attempt.
*
* <p>
* The following configuration options are available:
*
* <ul>
* <li>{@link #accessDeniedHandler(AccessDeniedHandler)}</li> - customizes how access
* denied errors are handled
* <li>{@link #authenticationEntryPoint(AuthenticationEntryPoint)}</li> - customizes how
* authentication failures are handled
* <li>{@link #bearerTokenResolver(BearerTokenResolver)} - customizes how to resolve a
* bearer token from the request</li>
* <li>{@link #jwt(Customizer)} - enables Jwt-encoded bearer token support</li>
* <li>{@link #opaqueToken(Customizer)} - enables opaque bearer token support</li>
* </ul>
*
* <p>
* When using {@link #jwt(Customizer)}, either
*
* <ul>
* <li>supply a Jwk Set Uri via {@link JwtConfigurer#jwkSetUri}, or</li>
* <li>supply a {@link JwtDecoder} instance via {@link JwtConfigurer#decoder}, or</li>
* <li>expose a {@link JwtDecoder} bean</li>
* </ul>
*
* Also with {@link #jwt(Customizer)} consider
*
* <ul>
* <li>customizing the conversion from a {@link Jwt} to an
* {@link org.springframework.security.core.Authentication} with
* {@link JwtConfigurer#jwtAuthenticationConverter(Converter)}</li>
* </ul>
*
* <p>
* When using {@link #opaqueToken(Customizer)}, supply an introspection endpoint with its
* client credentials and an OpaqueTokenAuthenticationConverter
* </p>
*
* <h2>Security Filters</h2>
*
* The following {@code Filter}s are populated when {@link #jwt(Customizer)} is
* configured:
*
* <ul>
* <li>{@link BearerTokenAuthenticationFilter}</li>
* </ul>
*
* <h2>Shared Objects Created</h2>
*
* The following shared objects are populated:
*
* <ul>
* <li>{@link SessionCreationPolicy} (optional)</li>
* </ul>
*
* <h2>Shared Objects Used</h2>
*
* The following shared objects are used:
*
* <ul>
* <li>{@link AuthenticationManager}</li>
* </ul>
*
* @author Josh Cummings
* @author Evgeniy Cheban
* @author Jerome Wacongne <ch4mp@c4-soft.com>
* @since 5.1
* @see BearerTokenAuthenticationFilter
* @see JwtAuthenticationProvider
* @see NimbusJwtDecoder
* @see AbstractHttpConfigurer
*/
public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<OAuth2ResourceServerConfigurer<H>, H> {
private static final boolean dPoPAuthenticationAvailable;
static {
ClassLoader classLoader = OAuth2ResourceServerConfigurer.class.getClassLoader();
dPoPAuthenticationAvailable = ClassUtils
.isPresent("org.springframework.security.oauth2.jwt.DPoPProofJwtDecoderFactory", classLoader);
}
private static final RequestHeaderRequestMatcher X_REQUESTED_WITH = new RequestHeaderRequestMatcher(
"X-Requested-With", "XMLHttpRequest");
private final ApplicationContext context;
private AuthenticationManagerResolver<HttpServletRequest> authenticationManagerResolver;
private AuthenticationConverter authenticationConverter;
private JwtConfigurer jwtConfigurer;
private OpaqueTokenConfigurer opaqueTokenConfigurer;
private final ProtectedResourceMetadataConfigurer protectedResourceMetadataConfigurer = new ProtectedResourceMetadataConfigurer();
private AccessDeniedHandler accessDeniedHandler = new DelegatingAccessDeniedHandler(
new LinkedHashMap<>(Map.of(CsrfException.class, new AccessDeniedHandlerImpl())),
new BearerTokenAccessDeniedHandler());
private AuthenticationEntryPoint authenticationEntryPoint = new BearerTokenAuthenticationEntryPoint();
private BearerTokenRequestMatcher requestMatcher = new BearerTokenRequestMatcher();
public OAuth2ResourceServerConfigurer(ApplicationContext context) {
Assert.notNull(context, "context cannot be null");
this.context = context;
}
public OAuth2ResourceServerConfigurer<H> accessDeniedHandler(AccessDeniedHandler accessDeniedHandler) {
Assert.notNull(accessDeniedHandler, "accessDeniedHandler cannot be null");
this.accessDeniedHandler = accessDeniedHandler;
return this;
}
public OAuth2ResourceServerConfigurer<H> authenticationEntryPoint(AuthenticationEntryPoint entryPoint) {
Assert.notNull(entryPoint, "entryPoint cannot be null");
this.authenticationEntryPoint = entryPoint;
return this;
}
public OAuth2ResourceServerConfigurer<H> authenticationManagerResolver(
AuthenticationManagerResolver<HttpServletRequest> authenticationManagerResolver) {
Assert.notNull(authenticationManagerResolver, "authenticationManagerResolver cannot be null");
this.authenticationManagerResolver = authenticationManagerResolver;
return this;
}
public OAuth2ResourceServerConfigurer<H> bearerTokenResolver(BearerTokenResolver bearerTokenResolver) {
Assert.notNull(bearerTokenResolver, "bearerTokenResolver cannot be null");
this.authenticationConverter = new BearerTokenResolverHoldingAuthenticationConverter(bearerTokenResolver);
return this;
}
/**
* Sets the {@link AuthenticationConverter} to use.
* @param authenticationConverter the authentication converter
* @return the {@link OAuth2ResourceServerConfigurer} for further configuration
* @since 7.0
*/
public OAuth2ResourceServerConfigurer<H> authenticationConverter(AuthenticationConverter authenticationConverter) {
Assert.notNull(authenticationConverter, "authenticationConverter cannot be null");
this.authenticationConverter = authenticationConverter;
return this;
}
/**
* Enables Jwt-encoded bearer token support.
* @param jwtCustomizer the {@link Customizer} to provide more options for the
* {@link JwtConfigurer}
* @return the {@link OAuth2ResourceServerConfigurer} for further customizations
*/
public OAuth2ResourceServerConfigurer<H> jwt(Customizer<JwtConfigurer> jwtCustomizer) {
if (this.jwtConfigurer == null) {
this.jwtConfigurer = new JwtConfigurer(this.context);
}
jwtCustomizer.customize(this.jwtConfigurer);
return this;
}
/**
* Enables opaque bearer token support.
* @param opaqueTokenCustomizer the {@link Customizer} to provide more options for the
* {@link OpaqueTokenConfigurer}
* @return the {@link OAuth2ResourceServerConfigurer} for further customizations
*/
public OAuth2ResourceServerConfigurer<H> opaqueToken(Customizer<OpaqueTokenConfigurer> opaqueTokenCustomizer) {
if (this.opaqueTokenConfigurer == null) {
this.opaqueTokenConfigurer = new OpaqueTokenConfigurer(this.context);
}
opaqueTokenCustomizer.customize(this.opaqueTokenConfigurer);
return this;
}
/**
* Configure OAuth 2.0 Protected Resource Metadata.
* @param protectedResourceMetadataCustomizer the {@link Customizer} to provide more
* options for the {@link ProtectedResourceMetadataConfigurer}
* @return the {@link OAuth2ResourceServerConfigurer} for further customizations
*/
public OAuth2ResourceServerConfigurer<H> protectedResourceMetadata(
Customizer<ProtectedResourceMetadataConfigurer> protectedResourceMetadataCustomizer) {
protectedResourceMetadataCustomizer.customize(this.protectedResourceMetadataConfigurer);
return this;
}
@Override
public void init(H http) {
validateConfiguration();
registerDefaultAccessDeniedHandler(http);
registerDefaultEntryPoint(http);
registerDefaultCsrfOverride(http);
AuthenticationProvider authenticationProvider = getAuthenticationProvider();
if (authenticationProvider != null) {
http.authenticationProvider(authenticationProvider);
}
}
@Override
public void configure(H http) {
AuthenticationManagerResolver resolver = this.authenticationManagerResolver;
if (resolver == null) {
AuthenticationManager authenticationManager = getAuthenticationManager(http);
resolver = (request) -> authenticationManager;
}
AuthenticationConverter converter = getAuthenticationConverter();
this.requestMatcher.setAuthenticationConverter(converter);
BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(resolver, converter);
filter.setAuthenticationEntryPoint(this.authenticationEntryPoint);
filter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
filter = postProcess(filter);
http.addFilter(filter);
if (dPoPAuthenticationAvailable) {
DPoPAuthenticationConfigurer<H> dPoPAuthenticationConfigurer = new DPoPAuthenticationConfigurer<>();
dPoPAuthenticationConfigurer.configure(http);
}
OAuth2ProtectedResourceMetadataFilter protectedResourceMetadataFilter = new OAuth2ProtectedResourceMetadataFilter();
if (this.protectedResourceMetadataConfigurer.protectedResourceMetadataCustomizer != null) {
protectedResourceMetadataFilter.setProtectedResourceMetadataCustomizer(
this.protectedResourceMetadataConfigurer.protectedResourceMetadataCustomizer);
}
protectedResourceMetadataFilter = postProcess(protectedResourceMetadataFilter);
http.addFilterBefore(protectedResourceMetadataFilter, AbstractPreAuthenticatedProcessingFilter.class);
}
private void validateConfiguration() {
if (this.authenticationManagerResolver == null) {
Assert.state(this.jwtConfigurer != null || this.opaqueTokenConfigurer != null,
"Jwt and Opaque Token are the only supported formats for bearer tokens "
+ "in Spring Security and neither was found. Make sure to configure JWT "
+ "via http.oauth2ResourceServer().jwt() or Opaque Tokens via "
+ "http.oauth2ResourceServer().opaqueToken().");
Assert.state(this.jwtConfigurer == null || this.opaqueTokenConfigurer == null,
"Spring Security only supports JWTs or Opaque Tokens, not both at the " + "same time.");
}
else {
Assert.state(this.jwtConfigurer == null && this.opaqueTokenConfigurer == null,
"If an authenticationManagerResolver() is configured, then it takes "
+ "precedence over any jwt() or opaqueToken() configuration.");
}
}
private void registerDefaultAccessDeniedHandler(H http) {
ExceptionHandlingConfigurer<H> exceptionHandling = http.getConfigurer(ExceptionHandlingConfigurer.class);
if (exceptionHandling != null) {
exceptionHandling.defaultAccessDeniedHandlerFor(this.accessDeniedHandler, this.requestMatcher);
}
}
private void registerDefaultEntryPoint(H http) {
ExceptionHandlingConfigurer<H> exceptionHandling = http.getConfigurer(ExceptionHandlingConfigurer.class);
if (exceptionHandling != null) {
ContentNegotiationStrategy contentNegotiationStrategy = http
.getSharedObject(ContentNegotiationStrategy.class);
if (contentNegotiationStrategy == null) {
contentNegotiationStrategy = new HeaderContentNegotiationStrategy();
}
MediaTypeRequestMatcher restMatcher = new MediaTypeRequestMatcher(contentNegotiationStrategy,
MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_JSON,
MediaType.APPLICATION_OCTET_STREAM, MediaType.APPLICATION_XML, MediaType.MULTIPART_FORM_DATA,
MediaType.TEXT_XML);
restMatcher.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL));
MediaTypeRequestMatcher allMatcher = new MediaTypeRequestMatcher(contentNegotiationStrategy, MediaType.ALL);
allMatcher.setUseEquals(true);
RequestMatcher notHtmlMatcher = new NegatedRequestMatcher(
new MediaTypeRequestMatcher(contentNegotiationStrategy, MediaType.TEXT_HTML));
RequestMatcher restNotHtmlMatcher = new AndRequestMatcher(Arrays.asList(notHtmlMatcher, restMatcher));
RequestMatcher preferredMatcher = new OrRequestMatcher(
Arrays.asList(this.requestMatcher, X_REQUESTED_WITH, restNotHtmlMatcher, allMatcher));
exceptionHandling.defaultAuthenticationEntryPointFor(this.authenticationEntryPoint, preferredMatcher);
exceptionHandling.defaultDeniedHandlerForMissingAuthority(
(ep) -> ep.addEntryPointFor(this.authenticationEntryPoint, preferredMatcher),
FactorGrantedAuthority.BEARER_AUTHORITY);
}
}
private void registerDefaultCsrfOverride(H http) {
CsrfConfigurer<H> csrf = http.getConfigurer(CsrfConfigurer.class);
if (csrf != null) {
csrf.ignoringRequestMatchers(this.requestMatcher);
}
}
AuthenticationProvider getAuthenticationProvider() {
if (this.jwtConfigurer != null) {
return this.jwtConfigurer.getAuthenticationProvider();
}
if (this.opaqueTokenConfigurer != null) {
return this.opaqueTokenConfigurer.getAuthenticationProvider();
}
return null;
}
AuthenticationManager getAuthenticationManager(H http) {
if (this.jwtConfigurer != null) {
return this.jwtConfigurer.getAuthenticationManager(http);
}
if (this.opaqueTokenConfigurer != null) {
return this.opaqueTokenConfigurer.getAuthenticationManager(http);
}
return http.getSharedObject(AuthenticationManager.class);
}
AuthenticationManagerResolver<HttpServletRequest> getAuthenticationManagerResolver() {
return this.authenticationManagerResolver;
}
AuthenticationConverter getAuthenticationConverter() {
if (this.authenticationConverter != null) {
return this.authenticationConverter;
}
if (this.context.getBeanNamesForType(AuthenticationConverter.class).length > 0) {
this.authenticationConverter = this.context.getBean(AuthenticationConverter.class);
}
else if (this.context.getBeanNamesForType(BearerTokenResolver.class).length > 0) {
BearerTokenResolver bearerTokenResolver = this.context.getBean(BearerTokenResolver.class);
this.authenticationConverter = new BearerTokenResolverHoldingAuthenticationConverter(bearerTokenResolver);
}
else {
this.authenticationConverter = new BearerTokenAuthenticationConverter();
}
return this.authenticationConverter;
}
BearerTokenResolver getBearerTokenResolver() {
AuthenticationConverter authenticationConverter = getAuthenticationConverter();
if (authenticationConverter instanceof OAuth2ResourceServerConfigurer.BearerTokenResolverHoldingAuthenticationConverter bearer) {
return bearer.bearerTokenResolver;
}
return null;
}
public class JwtConfigurer {
private final ApplicationContext context;
private AuthenticationManager authenticationManager;
private JwtDecoder decoder;
private Converter<Jwt, ? extends AbstractAuthenticationToken> jwtAuthenticationConverter;
JwtConfigurer(ApplicationContext context) {
this.context = context;
}
public JwtConfigurer authenticationManager(AuthenticationManager authenticationManager) {
Assert.notNull(authenticationManager, "authenticationManager cannot be null");
this.authenticationManager = authenticationManager;
return this;
}
public JwtConfigurer decoder(JwtDecoder decoder) {
this.decoder = decoder;
return this;
}
public JwtConfigurer jwkSetUri(String uri) {
this.decoder = NimbusJwtDecoder.withJwkSetUri(uri).build();
return this;
}
public JwtConfigurer jwtAuthenticationConverter(
Converter<Jwt, ? extends AbstractAuthenticationToken> jwtAuthenticationConverter) {
this.jwtAuthenticationConverter = jwtAuthenticationConverter;
return this;
}
Converter<Jwt, ? extends AbstractAuthenticationToken> getJwtAuthenticationConverter() {
if (this.jwtAuthenticationConverter == null) {
if (this.context.getBeanNamesForType(JwtAuthenticationConverter.class).length > 0) {
this.jwtAuthenticationConverter = this.context.getBean(JwtAuthenticationConverter.class);
}
else {
this.jwtAuthenticationConverter = new JwtAuthenticationConverter();
}
}
return this.jwtAuthenticationConverter;
}
JwtDecoder getJwtDecoder() {
if (this.decoder == null) {
return this.context.getBean(JwtDecoder.class);
}
return this.decoder;
}
AuthenticationProvider getAuthenticationProvider() {
if (this.authenticationManager != null) {
return null;
}
JwtDecoder decoder = getJwtDecoder();
Converter<Jwt, ? extends AbstractAuthenticationToken> jwtAuthenticationConverter = getJwtAuthenticationConverter();
JwtAuthenticationProvider provider = new JwtAuthenticationProvider(decoder);
provider.setJwtAuthenticationConverter(jwtAuthenticationConverter);
return postProcess(provider);
}
AuthenticationManager getAuthenticationManager(H http) {
if (this.authenticationManager != null) {
return this.authenticationManager;
}
return http.getSharedObject(AuthenticationManager.class);
}
}
public class OpaqueTokenConfigurer {
private final ApplicationContext context;
private AuthenticationManager authenticationManager;
private String introspectionUri;
private String clientId;
private String clientSecret;
private Supplier<OpaqueTokenIntrospector> introspector;
private OpaqueTokenAuthenticationConverter authenticationConverter;
OpaqueTokenConfigurer(ApplicationContext context) {
this.context = context;
}
public OpaqueTokenConfigurer authenticationManager(AuthenticationManager authenticationManager) {
Assert.notNull(authenticationManager, "authenticationManager cannot be null");
this.authenticationManager = authenticationManager;
return this;
}
public OpaqueTokenConfigurer introspectionUri(String introspectionUri) {
Assert.notNull(introspectionUri, "introspectionUri cannot be null");
this.introspectionUri = introspectionUri;
this.introspector = () -> new SpringOpaqueTokenIntrospector(this.introspectionUri, this.clientId,
this.clientSecret);
return this;
}
public OpaqueTokenConfigurer introspectionClientCredentials(String clientId, String clientSecret) {
Assert.notNull(clientId, "clientId cannot be null");
Assert.notNull(clientSecret, "clientSecret cannot be null");
this.clientId = clientId;
this.clientSecret = clientSecret;
this.introspector = () -> new SpringOpaqueTokenIntrospector(this.introspectionUri, this.clientId,
this.clientSecret);
return this;
}
public OpaqueTokenConfigurer introspector(OpaqueTokenIntrospector introspector) {
Assert.notNull(introspector, "introspector cannot be null");
this.introspector = () -> introspector;
return this;
}
public OpaqueTokenConfigurer authenticationConverter(
OpaqueTokenAuthenticationConverter authenticationConverter) {
Assert.notNull(authenticationConverter, "authenticationConverter cannot be null");
this.authenticationConverter = authenticationConverter;
return this;
}
OpaqueTokenIntrospector getIntrospector() {
if (this.introspector != null) {
return this.introspector.get();
}
return this.context.getBean(OpaqueTokenIntrospector.class);
}
OpaqueTokenAuthenticationConverter getAuthenticationConverter() {
if (this.authenticationConverter != null) {
return this.authenticationConverter;
}
if (this.context.getBeanNamesForType(OpaqueTokenAuthenticationConverter.class).length > 0) {
return this.context.getBean(OpaqueTokenAuthenticationConverter.class);
}
return null;
}
AuthenticationProvider getAuthenticationProvider() {
if (this.authenticationManager != null) {
return null;
}
OpaqueTokenIntrospector introspector = getIntrospector();
OpaqueTokenAuthenticationProvider opaqueTokenAuthenticationProvider = new OpaqueTokenAuthenticationProvider(
introspector);
OpaqueTokenAuthenticationConverter authenticationConverter = getAuthenticationConverter();
if (authenticationConverter != null) {
opaqueTokenAuthenticationProvider.setAuthenticationConverter(authenticationConverter);
}
return opaqueTokenAuthenticationProvider;
}
AuthenticationManager getAuthenticationManager(H http) {
if (this.authenticationManager != null) {
return this.authenticationManager;
}
return http.getSharedObject(AuthenticationManager.class);
}
}
public static final class ProtectedResourceMetadataConfigurer {
private Consumer<OAuth2ProtectedResourceMetadata.Builder> protectedResourceMetadataCustomizer;
private ProtectedResourceMetadataConfigurer() {
}
/**
* Sets the {@code Consumer} providing access to the
* {@link OAuth2ProtectedResourceMetadata.Builder} allowing the ability to
* customize the claims of the Resource Server's configuration.
* @param protectedResourceMetadataCustomizer the {@code Consumer} providing
* access to the {@link OAuth2ProtectedResourceMetadata.Builder}
* @return the {@link ProtectedResourceMetadataConfigurer} for further
* configuration
*/
public ProtectedResourceMetadataConfigurer protectedResourceMetadataCustomizer(
Consumer<OAuth2ProtectedResourceMetadata.Builder> protectedResourceMetadataCustomizer) {
this.protectedResourceMetadataCustomizer = protectedResourceMetadataCustomizer;
return this;
}
}
private static final class BearerTokenRequestMatcher implements RequestMatcher {
private AuthenticationConverter authenticationConverter;
@Override
public boolean matches(HttpServletRequest request) {
try {
return this.authenticationConverter.convert(request) != null;
}
catch (OAuth2AuthenticationException ex) {
return false;
}
}
void setAuthenticationConverter(AuthenticationConverter authenticationConverter) {
Assert.notNull(authenticationConverter, "authenticationConverter cannot be null");
this.authenticationConverter = authenticationConverter;
}
}
private static final class BearerTokenResolverHoldingAuthenticationConverter implements AuthenticationConverter {
private final BearerTokenResolver bearerTokenResolver;
private final AuthenticationConverter authenticationConverter;
BearerTokenResolverHoldingAuthenticationConverter(BearerTokenResolver bearerTokenResolver) {
this.bearerTokenResolver = bearerTokenResolver;
BearerTokenAuthenticationConverter authenticationConverter = new BearerTokenAuthenticationConverter();
authenticationConverter.setBearerTokenResolver(bearerTokenResolver);
this.authenticationConverter = authenticationConverter;
}
@Override
public Authentication convert(HttpServletRequest request) {
return this.authenticationConverter.convert(request);
}
}
}