|
@@ -23,6 +23,8 @@ import java.util.Map;
|
|
|
import java.util.function.Supplier;
|
|
|
|
|
|
import jakarta.servlet.http.HttpServletRequest;
|
|
|
+import org.apache.commons.logging.Log;
|
|
|
+import org.apache.commons.logging.LogFactory;
|
|
|
|
|
|
import org.springframework.context.ApplicationContext;
|
|
|
import org.springframework.core.convert.converter.Converter;
|
|
@@ -37,10 +39,12 @@ import org.springframework.security.config.annotation.web.configurers.AbstractHt
|
|
|
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.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.authentication.BearerTokenAuthenticationToken;
|
|
|
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;
|
|
@@ -49,13 +53,14 @@ import org.springframework.security.oauth2.server.resource.introspection.OpaqueT
|
|
|
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.DefaultBearerTokenResolver;
|
|
|
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.csrf.CsrfException;
|
|
|
import org.springframework.security.web.util.matcher.AndRequestMatcher;
|
|
|
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
|
|
@@ -64,6 +69,7 @@ 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.StringUtils;
|
|
|
import org.springframework.web.accept.ContentNegotiationStrategy;
|
|
|
import org.springframework.web.accept.HeaderContentNegotiationStrategy;
|
|
|
|
|
@@ -156,7 +162,7 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
|
|
|
|
|
private AuthenticationManagerResolver<HttpServletRequest> authenticationManagerResolver;
|
|
|
|
|
|
- private BearerTokenResolver bearerTokenResolver;
|
|
|
+ private AuthenticationConverter authenticationConverter;
|
|
|
|
|
|
private JwtConfigurer jwtConfigurer;
|
|
|
|
|
@@ -194,9 +200,25 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * @deprecated please use {@link #authenticationConverter} instead
|
|
|
+ */
|
|
|
+ @Deprecated
|
|
|
public OAuth2ResourceServerConfigurer<H> bearerTokenResolver(BearerTokenResolver bearerTokenResolver) {
|
|
|
Assert.notNull(bearerTokenResolver, "bearerTokenResolver cannot be null");
|
|
|
- this.bearerTokenResolver = bearerTokenResolver;
|
|
|
+ this.authenticationConverter = new BearerTokenResolverAuthenticationConverterAdapter(bearerTokenResolver);
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Sets the {@link AuthenticationConverter} to use.
|
|
|
+ * @param authenticationConverter the authentication converter
|
|
|
+ * @return the {@link OAuth2ResourceServerConfigurer} for further configuration
|
|
|
+ * @since 6.5
|
|
|
+ */
|
|
|
+ public OAuth2ResourceServerConfigurer<H> authenticationConverter(AuthenticationConverter authenticationConverter) {
|
|
|
+ Assert.notNull(authenticationConverter, "authenticationConverter cannot be null");
|
|
|
+ this.authenticationConverter = authenticationConverter;
|
|
|
return this;
|
|
|
}
|
|
|
|
|
@@ -271,8 +293,6 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
|
|
|
|
|
@Override
|
|
|
public void configure(H http) {
|
|
|
- BearerTokenResolver bearerTokenResolver = getBearerTokenResolver();
|
|
|
- this.requestMatcher.setBearerTokenResolver(bearerTokenResolver);
|
|
|
AuthenticationManagerResolver resolver = this.authenticationManagerResolver;
|
|
|
if (resolver == null) {
|
|
|
AuthenticationManager authenticationManager = getAuthenticationManager(http);
|
|
@@ -280,7 +300,9 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
|
|
}
|
|
|
|
|
|
BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(resolver);
|
|
|
- filter.setBearerTokenResolver(bearerTokenResolver);
|
|
|
+ AuthenticationConverter converter = getAuthenticationConverter();
|
|
|
+ this.requestMatcher.setAuthenticationConverter(converter);
|
|
|
+ filter.setAuthenticationConverter(converter);
|
|
|
filter.setAuthenticationEntryPoint(this.authenticationEntryPoint);
|
|
|
filter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
|
|
|
filter = postProcess(filter);
|
|
@@ -363,16 +385,29 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
|
|
return http.getSharedObject(AuthenticationManager.class);
|
|
|
}
|
|
|
|
|
|
+ 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 BearerTokenResolverAuthenticationConverterAdapter(bearerTokenResolver);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ this.authenticationConverter = new BearerTokenAuthenticationConverter();
|
|
|
+ }
|
|
|
+ return this.authenticationConverter;
|
|
|
+ }
|
|
|
+
|
|
|
BearerTokenResolver getBearerTokenResolver() {
|
|
|
- if (this.bearerTokenResolver == null) {
|
|
|
- if (this.context.getBeanNamesForType(BearerTokenResolver.class).length > 0) {
|
|
|
- this.bearerTokenResolver = this.context.getBean(BearerTokenResolver.class);
|
|
|
- }
|
|
|
- else {
|
|
|
- this.bearerTokenResolver = new DefaultBearerTokenResolver();
|
|
|
- }
|
|
|
+ AuthenticationConverter authenticationConverter = getAuthenticationConverter();
|
|
|
+ if (authenticationConverter instanceof BearerTokenResolverAuthenticationConverterAdapter bearer) {
|
|
|
+ return bearer.bearerTokenResolver;
|
|
|
}
|
|
|
- return this.bearerTokenResolver;
|
|
|
+ return null;
|
|
|
}
|
|
|
|
|
|
public class JwtConfigurer {
|
|
@@ -560,21 +595,43 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
|
|
|
|
|
private static final class BearerTokenRequestMatcher implements RequestMatcher {
|
|
|
|
|
|
- private BearerTokenResolver bearerTokenResolver;
|
|
|
+ private AuthenticationConverter authenticationConverter;
|
|
|
|
|
|
@Override
|
|
|
public boolean matches(HttpServletRequest request) {
|
|
|
try {
|
|
|
- return this.bearerTokenResolver.resolve(request) != null;
|
|
|
+ return this.authenticationConverter.convert(request) != null;
|
|
|
}
|
|
|
catch (OAuth2AuthenticationException ex) {
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- void setBearerTokenResolver(BearerTokenResolver tokenResolver) {
|
|
|
- Assert.notNull(tokenResolver, "resolver cannot be null");
|
|
|
- this.bearerTokenResolver = tokenResolver;
|
|
|
+ void setAuthenticationConverter(AuthenticationConverter authenticationConverter) {
|
|
|
+ Assert.notNull(authenticationConverter, "authenticationConverter cannot be null");
|
|
|
+ this.authenticationConverter = authenticationConverter;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ private static final class BearerTokenResolverAuthenticationConverterAdapter implements AuthenticationConverter {
|
|
|
+
|
|
|
+ private final Log logger = LogFactory.getLog(BearerTokenResolverAuthenticationConverterAdapter.class);
|
|
|
+
|
|
|
+ private final BearerTokenResolver bearerTokenResolver;
|
|
|
+
|
|
|
+ BearerTokenResolverAuthenticationConverterAdapter(BearerTokenResolver bearerTokenResolver) {
|
|
|
+ this.bearerTokenResolver = bearerTokenResolver;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Authentication convert(HttpServletRequest request) {
|
|
|
+ String token = this.bearerTokenResolver.resolve(request);
|
|
|
+ if (!StringUtils.hasText(token)) {
|
|
|
+ this.logger.trace("Did not process request since did not find bearer token");
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return new BearerTokenAuthenticationToken(token);
|
|
|
}
|
|
|
|
|
|
}
|