|
23 | 23 | import java.util.function.Supplier;
|
24 | 24 |
|
25 | 25 | import jakarta.servlet.http.HttpServletRequest;
|
| 26 | +import org.apache.commons.logging.Log; |
| 27 | +import org.apache.commons.logging.LogFactory; |
26 | 28 |
|
27 | 29 | import org.springframework.context.ApplicationContext;
|
28 | 30 | import org.springframework.core.convert.converter.Converter;
|
|
37 | 39 | import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;
|
38 | 40 | import org.springframework.security.config.annotation.web.configurers.ExceptionHandlingConfigurer;
|
39 | 41 | import org.springframework.security.config.http.SessionCreationPolicy;
|
| 42 | +import org.springframework.security.core.Authentication; |
40 | 43 | import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
41 | 44 | import org.springframework.security.oauth2.jwt.Jwt;
|
42 | 45 | import org.springframework.security.oauth2.jwt.JwtDecoder;
|
43 | 46 | import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
|
| 47 | +import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken; |
44 | 48 | import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
|
45 | 49 | import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider;
|
46 | 50 | import org.springframework.security.oauth2.server.resource.authentication.OpaqueTokenAuthenticationProvider;
|
|
49 | 53 | import org.springframework.security.oauth2.server.resource.introspection.SpringOpaqueTokenIntrospector;
|
50 | 54 | import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint;
|
51 | 55 | import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver;
|
52 |
| -import org.springframework.security.oauth2.server.resource.web.DefaultBearerTokenResolver; |
53 | 56 | import org.springframework.security.oauth2.server.resource.web.access.BearerTokenAccessDeniedHandler;
|
| 57 | +import org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationConverter; |
54 | 58 | import org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter;
|
55 | 59 | import org.springframework.security.web.AuthenticationEntryPoint;
|
56 | 60 | import org.springframework.security.web.access.AccessDeniedHandler;
|
57 | 61 | import org.springframework.security.web.access.AccessDeniedHandlerImpl;
|
58 | 62 | import org.springframework.security.web.access.DelegatingAccessDeniedHandler;
|
| 63 | +import org.springframework.security.web.authentication.AuthenticationConverter; |
59 | 64 | import org.springframework.security.web.csrf.CsrfException;
|
60 | 65 | import org.springframework.security.web.util.matcher.AndRequestMatcher;
|
61 | 66 | import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
|
|
64 | 69 | import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher;
|
65 | 70 | import org.springframework.security.web.util.matcher.RequestMatcher;
|
66 | 71 | import org.springframework.util.Assert;
|
| 72 | +import org.springframework.util.StringUtils; |
67 | 73 | import org.springframework.web.accept.ContentNegotiationStrategy;
|
68 | 74 | import org.springframework.web.accept.HeaderContentNegotiationStrategy;
|
69 | 75 |
|
@@ -156,7 +162,7 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
156 | 162 |
|
157 | 163 | private AuthenticationManagerResolver<HttpServletRequest> authenticationManagerResolver;
|
158 | 164 |
|
159 |
| - private BearerTokenResolver bearerTokenResolver; |
| 165 | + private AuthenticationConverter authenticationConverter; |
160 | 166 |
|
161 | 167 | private JwtConfigurer jwtConfigurer;
|
162 | 168 |
|
@@ -194,9 +200,25 @@ public OAuth2ResourceServerConfigurer<H> authenticationManagerResolver(
|
194 | 200 | return this;
|
195 | 201 | }
|
196 | 202 |
|
| 203 | + /** |
| 204 | + * @deprecated please use {@link #authenticationConverter} instead |
| 205 | + */ |
| 206 | + @Deprecated |
197 | 207 | public OAuth2ResourceServerConfigurer<H> bearerTokenResolver(BearerTokenResolver bearerTokenResolver) {
|
198 | 208 | Assert.notNull(bearerTokenResolver, "bearerTokenResolver cannot be null");
|
199 |
| - this.bearerTokenResolver = bearerTokenResolver; |
| 209 | + this.authenticationConverter = new BearerTokenResolverAuthenticationConverterAdapter(bearerTokenResolver); |
| 210 | + return this; |
| 211 | + } |
| 212 | + |
| 213 | + /** |
| 214 | + * Sets the {@link AuthenticationConverter} to use. |
| 215 | + * @param authenticationConverter the authentication converter |
| 216 | + * @return the {@link OAuth2ResourceServerConfigurer} for further configuration |
| 217 | + * @since 6.5 |
| 218 | + */ |
| 219 | + public OAuth2ResourceServerConfigurer<H> authenticationConverter(AuthenticationConverter authenticationConverter) { |
| 220 | + Assert.notNull(authenticationConverter, "authenticationConverter cannot be null"); |
| 221 | + this.authenticationConverter = authenticationConverter; |
200 | 222 | return this;
|
201 | 223 | }
|
202 | 224 |
|
@@ -271,16 +293,16 @@ public void init(H http) {
|
271 | 293 |
|
272 | 294 | @Override
|
273 | 295 | public void configure(H http) {
|
274 |
| - BearerTokenResolver bearerTokenResolver = getBearerTokenResolver(); |
275 |
| - this.requestMatcher.setBearerTokenResolver(bearerTokenResolver); |
276 | 296 | AuthenticationManagerResolver resolver = this.authenticationManagerResolver;
|
277 | 297 | if (resolver == null) {
|
278 | 298 | AuthenticationManager authenticationManager = getAuthenticationManager(http);
|
279 | 299 | resolver = (request) -> authenticationManager;
|
280 | 300 | }
|
281 | 301 |
|
282 | 302 | BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(resolver);
|
283 |
| - filter.setBearerTokenResolver(bearerTokenResolver); |
| 303 | + AuthenticationConverter converter = getAuthenticationConverter(); |
| 304 | + this.requestMatcher.setAuthenticationConverter(converter); |
| 305 | + filter.setAuthenticationConverter(converter); |
284 | 306 | filter.setAuthenticationEntryPoint(this.authenticationEntryPoint);
|
285 | 307 | filter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
|
286 | 308 | filter = postProcess(filter);
|
@@ -363,16 +385,29 @@ AuthenticationManager getAuthenticationManager(H http) {
|
363 | 385 | return http.getSharedObject(AuthenticationManager.class);
|
364 | 386 | }
|
365 | 387 |
|
| 388 | + AuthenticationConverter getAuthenticationConverter() { |
| 389 | + if (this.authenticationConverter != null) { |
| 390 | + return this.authenticationConverter; |
| 391 | + } |
| 392 | + if (this.context.getBeanNamesForType(AuthenticationConverter.class).length > 0) { |
| 393 | + this.authenticationConverter = this.context.getBean(AuthenticationConverter.class); |
| 394 | + } |
| 395 | + else if (this.context.getBeanNamesForType(BearerTokenResolver.class).length > 0) { |
| 396 | + BearerTokenResolver bearerTokenResolver = this.context.getBean(BearerTokenResolver.class); |
| 397 | + this.authenticationConverter = new BearerTokenResolverAuthenticationConverterAdapter(bearerTokenResolver); |
| 398 | + } |
| 399 | + else { |
| 400 | + this.authenticationConverter = new BearerTokenAuthenticationConverter(); |
| 401 | + } |
| 402 | + return this.authenticationConverter; |
| 403 | + } |
| 404 | + |
366 | 405 | BearerTokenResolver getBearerTokenResolver() {
|
367 |
| - if (this.bearerTokenResolver == null) { |
368 |
| - if (this.context.getBeanNamesForType(BearerTokenResolver.class).length > 0) { |
369 |
| - this.bearerTokenResolver = this.context.getBean(BearerTokenResolver.class); |
370 |
| - } |
371 |
| - else { |
372 |
| - this.bearerTokenResolver = new DefaultBearerTokenResolver(); |
373 |
| - } |
| 406 | + AuthenticationConverter authenticationConverter = getAuthenticationConverter(); |
| 407 | + if (authenticationConverter instanceof BearerTokenResolverAuthenticationConverterAdapter bearer) { |
| 408 | + return bearer.bearerTokenResolver; |
374 | 409 | }
|
375 |
| - return this.bearerTokenResolver; |
| 410 | + return null; |
376 | 411 | }
|
377 | 412 |
|
378 | 413 | public class JwtConfigurer {
|
@@ -560,21 +595,43 @@ AuthenticationManager getAuthenticationManager(H http) {
|
560 | 595 |
|
561 | 596 | private static final class BearerTokenRequestMatcher implements RequestMatcher {
|
562 | 597 |
|
563 |
| - private BearerTokenResolver bearerTokenResolver; |
| 598 | + private AuthenticationConverter authenticationConverter; |
564 | 599 |
|
565 | 600 | @Override
|
566 | 601 | public boolean matches(HttpServletRequest request) {
|
567 | 602 | try {
|
568 |
| - return this.bearerTokenResolver.resolve(request) != null; |
| 603 | + return this.authenticationConverter.convert(request) != null; |
569 | 604 | }
|
570 | 605 | catch (OAuth2AuthenticationException ex) {
|
571 | 606 | return false;
|
572 | 607 | }
|
573 | 608 | }
|
574 | 609 |
|
575 |
| - void setBearerTokenResolver(BearerTokenResolver tokenResolver) { |
576 |
| - Assert.notNull(tokenResolver, "resolver cannot be null"); |
577 |
| - this.bearerTokenResolver = tokenResolver; |
| 610 | + void setAuthenticationConverter(AuthenticationConverter authenticationConverter) { |
| 611 | + Assert.notNull(authenticationConverter, "authenticationConverter cannot be null"); |
| 612 | + this.authenticationConverter = authenticationConverter; |
| 613 | + } |
| 614 | + |
| 615 | + } |
| 616 | + |
| 617 | + private static final class BearerTokenResolverAuthenticationConverterAdapter implements AuthenticationConverter { |
| 618 | + |
| 619 | + private final Log logger = LogFactory.getLog(BearerTokenResolverAuthenticationConverterAdapter.class); |
| 620 | + |
| 621 | + private final BearerTokenResolver bearerTokenResolver; |
| 622 | + |
| 623 | + BearerTokenResolverAuthenticationConverterAdapter(BearerTokenResolver bearerTokenResolver) { |
| 624 | + this.bearerTokenResolver = bearerTokenResolver; |
| 625 | + } |
| 626 | + |
| 627 | + @Override |
| 628 | + public Authentication convert(HttpServletRequest request) { |
| 629 | + String token = this.bearerTokenResolver.resolve(request); |
| 630 | + if (!StringUtils.hasText(token)) { |
| 631 | + this.logger.trace("Did not process request since did not find bearer token"); |
| 632 | + return null; |
| 633 | + } |
| 634 | + return new BearerTokenAuthenticationToken(token); |
578 | 635 | }
|
579 | 636 |
|
580 | 637 | }
|
|
0 commit comments