Explorar o código

Disable device_code grant by default

Closes gh-17998
Joe Grandja hai 6 días
pai
achega
477a456d6c

+ 25 - 10
config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationServerConfigurer.java

@@ -255,8 +255,16 @@ public final class OAuth2AuthorizationServerConfigurer
 	 */
 	public OAuth2AuthorizationServerConfigurer deviceAuthorizationEndpoint(
 			Customizer<OAuth2DeviceAuthorizationEndpointConfigurer> deviceAuthorizationEndpointCustomizer) {
-		deviceAuthorizationEndpointCustomizer
-			.customize(getConfigurer(OAuth2DeviceAuthorizationEndpointConfigurer.class));
+		OAuth2DeviceAuthorizationEndpointConfigurer deviceAuthorizationEndpointConfigurer = getConfigurer(
+				OAuth2DeviceAuthorizationEndpointConfigurer.class);
+		if (deviceAuthorizationEndpointConfigurer == null) {
+			addConfigurer(OAuth2DeviceAuthorizationEndpointConfigurer.class,
+					new OAuth2DeviceAuthorizationEndpointConfigurer(this::postProcess));
+			deviceAuthorizationEndpointConfigurer = getConfigurer(OAuth2DeviceAuthorizationEndpointConfigurer.class);
+			deviceVerificationEndpoint((configurer) -> {
+			}); // Ensure the Device Verification Endpoint is enabled
+		}
+		deviceAuthorizationEndpointCustomizer.customize(deviceAuthorizationEndpointConfigurer);
 		return this;
 	}
 
@@ -268,7 +276,16 @@ public final class OAuth2AuthorizationServerConfigurer
 	 */
 	public OAuth2AuthorizationServerConfigurer deviceVerificationEndpoint(
 			Customizer<OAuth2DeviceVerificationEndpointConfigurer> deviceVerificationEndpointCustomizer) {
-		deviceVerificationEndpointCustomizer.customize(getConfigurer(OAuth2DeviceVerificationEndpointConfigurer.class));
+		OAuth2DeviceVerificationEndpointConfigurer deviceVerificationEndpointConfigurer = getConfigurer(
+				OAuth2DeviceVerificationEndpointConfigurer.class);
+		if (deviceVerificationEndpointConfigurer == null) {
+			addConfigurer(OAuth2DeviceVerificationEndpointConfigurer.class,
+					new OAuth2DeviceVerificationEndpointConfigurer(this::postProcess));
+			deviceVerificationEndpointConfigurer = getConfigurer(OAuth2DeviceVerificationEndpointConfigurer.class);
+			deviceAuthorizationEndpoint((configurer) -> {
+			}); // Ensure the Device Authorization Endpoint is enabled
+		}
+		deviceVerificationEndpointCustomizer.customize(deviceVerificationEndpointConfigurer);
 		return this;
 	}
 
@@ -386,9 +403,11 @@ public final class OAuth2AuthorizationServerConfigurer
 			preferredMatchers.add(getRequestMatcher(OAuth2TokenEndpointConfigurer.class));
 			preferredMatchers.add(getRequestMatcher(OAuth2TokenIntrospectionEndpointConfigurer.class));
 			preferredMatchers.add(getRequestMatcher(OAuth2TokenRevocationEndpointConfigurer.class));
-			preferredMatchers.add(getRequestMatcher(OAuth2DeviceAuthorizationEndpointConfigurer.class));
-			RequestMatcher preferredMatcher = getRequestMatcher(
-					OAuth2PushedAuthorizationRequestEndpointConfigurer.class);
+			RequestMatcher preferredMatcher = getRequestMatcher(OAuth2DeviceAuthorizationEndpointConfigurer.class);
+			if (preferredMatcher != null) {
+				preferredMatchers.add(preferredMatcher);
+			}
+			preferredMatcher = getRequestMatcher(OAuth2PushedAuthorizationRequestEndpointConfigurer.class);
 			if (preferredMatcher != null) {
 				preferredMatchers.add(preferredMatcher);
 			}
@@ -478,10 +497,6 @@ public final class OAuth2AuthorizationServerConfigurer
 				new OAuth2TokenIntrospectionEndpointConfigurer(this::postProcess));
 		configurers.put(OAuth2TokenRevocationEndpointConfigurer.class,
 				new OAuth2TokenRevocationEndpointConfigurer(this::postProcess));
-		configurers.put(OAuth2DeviceAuthorizationEndpointConfigurer.class,
-				new OAuth2DeviceAuthorizationEndpointConfigurer(this::postProcess));
-		configurers.put(OAuth2DeviceVerificationEndpointConfigurer.class,
-				new OAuth2DeviceVerificationEndpointConfigurer(this::postProcess));
 		return configurers;
 	}
 

+ 43 - 4
config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2DeviceCodeGrantTests.java

@@ -34,7 +34,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Import;
+import org.springframework.context.annotation.Configuration;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
@@ -47,8 +47,9 @@ 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.UsernamePasswordAuthenticationToken;
+import org.springframework.security.config.Customizer;
+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.SpringTestContext;
 import org.springframework.security.config.test.SpringTestContextExtension;
 import org.springframework.security.crypto.password.NoOpPasswordEncoder;
@@ -82,6 +83,7 @@ import org.springframework.security.oauth2.server.authorization.client.Registere
 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.settings.AuthorizationServerSettings;
+import org.springframework.security.web.SecurityFilterChain;
 import org.springframework.test.web.servlet.MockMvc;
 import org.springframework.test.web.servlet.MvcResult;
 import org.springframework.util.LinkedMultiValueMap;
@@ -645,9 +647,25 @@ public class OAuth2DeviceCodeGrantTests {
 	}
 
 	@EnableWebSecurity
-	@Import(OAuth2AuthorizationServerConfiguration.class)
+	@Configuration(proxyBeanMethods = false)
 	static class AuthorizationServerConfiguration {
 
+		// @formatter:off
+		@Bean
+		SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
+			http
+					.oauth2AuthorizationServer((authorizationServer) ->
+							authorizationServer
+									.deviceAuthorizationEndpoint(Customizer.withDefaults())
+									.deviceVerificationEndpoint(Customizer.withDefaults())
+					)
+					.authorizeHttpRequests((authorize) ->
+							authorize.anyRequest().authenticated()
+					);
+			return http.build();
+		}
+		// @formatter:on
+
 		@Bean
 		RegisteredClientRepository registeredClientRepository(JdbcOperations jdbcOperations) {
 			return new JdbcRegisteredClientRepository(jdbcOperations);
@@ -675,6 +693,11 @@ public class OAuth2DeviceCodeGrantTests {
 			return jwkSource;
 		}
 
+		@Bean
+		AuthorizationServerSettings authorizationServerSettings() {
+			return AuthorizationServerSettings.builder().build();
+		}
+
 		@Bean
 		PasswordEncoder passwordEncoder() {
 			return NoOpPasswordEncoder.getInstance();
@@ -683,9 +706,25 @@ public class OAuth2DeviceCodeGrantTests {
 	}
 
 	@EnableWebSecurity
-	@Import(OAuth2AuthorizationServerConfiguration.class)
+	@Configuration(proxyBeanMethods = false)
 	static class AuthorizationServerConfigurationWithMultipleIssuersAllowed extends AuthorizationServerConfiguration {
 
+		// @formatter:off
+		@Bean
+		SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
+			http
+					.oauth2AuthorizationServer((authorizationServer) ->
+							authorizationServer
+									.deviceAuthorizationEndpoint(Customizer.withDefaults())
+									.deviceVerificationEndpoint(Customizer.withDefaults())
+					)
+					.authorizeHttpRequests((authorize) ->
+							authorize.anyRequest().authenticated()
+					);
+			return http.build();
+		}
+		// @formatter:on
+
 		@Bean
 		AuthorizationServerSettings authorizationServerSettings() {
 			return AuthorizationServerSettings.builder().multipleIssuersAllowed(true).build();