소스 검색

Load ReactiveJwtAuthenticationConverter bean in OAuth2 Resource Server config

When a bean of type ReactiveJwtAuthenticationConverter is defined,
the OAuth2 Resource Server configuration will use it automatically
when no other converter is defined through the DSL.

Closes gh-9698
Thomas Vitale 4 년 전
부모
커밋
b44d0fb319

+ 19 - 5
config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java

@@ -91,10 +91,9 @@ import org.springframework.security.oauth2.jwt.Jwt;
 import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder;
 import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
 import org.springframework.security.oauth2.jwt.ReactiveJwtDecoderFactory;
-import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
 import org.springframework.security.oauth2.server.resource.authentication.JwtReactiveAuthenticationManager;
 import org.springframework.security.oauth2.server.resource.authentication.OpaqueTokenReactiveAuthenticationManager;
-import org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverterAdapter;
+import org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverter;
 import org.springframework.security.oauth2.server.resource.introspection.NimbusReactiveOpaqueTokenIntrospector;
 import org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenIntrospector;
 import org.springframework.security.oauth2.server.resource.web.access.server.BearerTokenServerAccessDeniedHandler;
@@ -1497,6 +1496,13 @@ public class ServerHttpSecurity {
 		return null;
 	}
 
+	private <T> String[] getBeanNamesForTypeOrEmpty(Class<T> beanClass) {
+		if (this.context == null) {
+			return new String[0];
+		}
+		return this.context.getBeanNamesForType(beanClass);
+	}
+
 	protected void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
 		this.context = applicationContext;
 	}
@@ -3813,8 +3819,7 @@ public class ServerHttpSecurity {
 
 			private ReactiveJwtDecoder jwtDecoder;
 
-			private Converter<Jwt, ? extends Mono<? extends AbstractAuthenticationToken>> jwtAuthenticationConverter = new ReactiveJwtAuthenticationConverterAdapter(
-					new JwtAuthenticationConverter());
+			private Converter<Jwt, ? extends Mono<? extends AbstractAuthenticationToken>> jwtAuthenticationConverter;
 
 			/**
 			 * Configures the {@link ReactiveAuthenticationManager} to use
@@ -3892,7 +3897,16 @@ public class ServerHttpSecurity {
 			}
 
 			protected Converter<Jwt, ? extends Mono<? extends AbstractAuthenticationToken>> getJwtAuthenticationConverter() {
-				return this.jwtAuthenticationConverter;
+				if (this.jwtAuthenticationConverter != null) {
+					return this.jwtAuthenticationConverter;
+				}
+
+				if (getBeanNamesForTypeOrEmpty(ReactiveJwtAuthenticationConverter.class).length > 0) {
+					return getBean(ReactiveJwtAuthenticationConverter.class);
+				}
+				else {
+					return new ReactiveJwtAuthenticationConverter();
+				}
 			}
 
 			private ReactiveAuthenticationManager getAuthenticationManager() {

+ 54 - 1
config/src/test/java/org/springframework/security/config/web/server/OAuth2ResourceServerSpecTests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2019 the original author or authors.
+ * Copyright 2002-2021 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.
@@ -64,6 +64,7 @@ import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
 import org.springframework.security.oauth2.jwt.TestJwts;
 import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
 import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
+import org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverter;
 import org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverterAdapter;
 import org.springframework.security.web.server.SecurityWebFilterChain;
 import org.springframework.security.web.server.authentication.HttpStatusServerEntryPoint;
@@ -478,6 +479,58 @@ public class OAuth2ResourceServerSpecTests {
 		assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> jwt.getJwtDecoder());
 	}
 
+	@Test
+	public void getJwtAuthenticationConverterWhenBeanWiredAndDslWiredThenDslTakesPrecedence() {
+		GenericWebApplicationContext context = autowireWebServerGenericWebApplicationContext();
+		ServerHttpSecurity http = new ServerHttpSecurity();
+		http.setApplicationContext(context);
+		ReactiveJwtAuthenticationConverter beanWiredJwtAuthenticationConverter = new ReactiveJwtAuthenticationConverter();
+		ReactiveJwtAuthenticationConverter dslWiredJwtAuthenticationConverter = new ReactiveJwtAuthenticationConverter();
+		context.registerBean(ReactiveJwtAuthenticationConverter.class, () -> beanWiredJwtAuthenticationConverter);
+		ServerHttpSecurity.OAuth2ResourceServerSpec.JwtSpec jwt = http.oauth2ResourceServer().jwt();
+		jwt.jwtAuthenticationConverter(dslWiredJwtAuthenticationConverter);
+		assertThat(jwt.getJwtAuthenticationConverter()).isEqualTo(dslWiredJwtAuthenticationConverter);
+	}
+
+	@Test
+	public void getJwtAuthenticationConverterWhenTwoBeansWiredAndDslWiredThenDslTakesPrecedence() {
+		GenericWebApplicationContext context = autowireWebServerGenericWebApplicationContext();
+		ServerHttpSecurity http = new ServerHttpSecurity();
+		http.setApplicationContext(context);
+		ReactiveJwtAuthenticationConverter beanWiredJwtAuthenticationConverter = new ReactiveJwtAuthenticationConverter();
+		ReactiveJwtAuthenticationConverter dslWiredJwtAuthenticationConverter = new ReactiveJwtAuthenticationConverter();
+		context.registerBean("firstJwtAuthenticationConverter", ReactiveJwtAuthenticationConverter.class,
+				() -> beanWiredJwtAuthenticationConverter);
+		context.registerBean("secondJwtAuthenticationConverter", ReactiveJwtAuthenticationConverter.class,
+				() -> beanWiredJwtAuthenticationConverter);
+		ServerHttpSecurity.OAuth2ResourceServerSpec.JwtSpec jwt = http.oauth2ResourceServer().jwt();
+		jwt.jwtAuthenticationConverter(dslWiredJwtAuthenticationConverter);
+		assertThat(jwt.getJwtAuthenticationConverter()).isEqualTo(dslWiredJwtAuthenticationConverter);
+	}
+
+	@Test
+	public void getJwtAuthenticationConverterWhenTwoBeansWiredThenThrowsWiringException() {
+		GenericWebApplicationContext context = autowireWebServerGenericWebApplicationContext();
+		ServerHttpSecurity http = new ServerHttpSecurity();
+		http.setApplicationContext(context);
+		ReactiveJwtAuthenticationConverter beanWiredJwtAuthenticationConverter = new ReactiveJwtAuthenticationConverter();
+		context.registerBean("firstJwtAuthenticationConverter", ReactiveJwtAuthenticationConverter.class,
+				() -> beanWiredJwtAuthenticationConverter);
+		context.registerBean("secondJwtAuthenticationConverter", ReactiveJwtAuthenticationConverter.class,
+				() -> beanWiredJwtAuthenticationConverter);
+		ServerHttpSecurity.OAuth2ResourceServerSpec.JwtSpec jwt = http.oauth2ResourceServer().jwt();
+		assertThatExceptionOfType(NoUniqueBeanDefinitionException.class).isThrownBy(jwt::getJwtAuthenticationConverter);
+	}
+
+	@Test
+	public void getJwtAuthenticationConverterWhenNoBeansAndNoDslWiredThenDefaultConverter() {
+		GenericWebApplicationContext context = autowireWebServerGenericWebApplicationContext();
+		ServerHttpSecurity http = new ServerHttpSecurity();
+		http.setApplicationContext(context);
+		ServerHttpSecurity.OAuth2ResourceServerSpec.JwtSpec jwt = http.oauth2ResourceServer().jwt();
+		assertThat(jwt.getJwtAuthenticationConverter()).isInstanceOf(ReactiveJwtAuthenticationConverter.class);
+	}
+
 	@Test
 	public void introspectWhenValidThenReturnsOk() {
 		this.spring.register(IntrospectionConfig.class, RootController.class).autowire();