Browse Source

Register SecurityFilterChain instead of WebSecurityConfigurerAdapter

Closes gh-163
Joe Grandja 4 năm trước cách đây
mục cha
commit
d97235d0bb

+ 28 - 4
oauth2-authorization-server/src/main/java/org/springframework/security/config/annotation/web/configuration/OAuth2AuthorizationServerConfiguration.java

@@ -17,21 +17,45 @@ package org.springframework.security.config.annotation.web.configuration;
 
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
-import org.springframework.security.config.annotation.web.builders.WebSecurity;
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization.OAuth2AuthorizationServerConfigurer;
+import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.security.web.util.matcher.OrRequestMatcher;
+import org.springframework.security.web.util.matcher.RequestMatcher;
 
 /**
  * {@link Configuration} for OAuth 2.0 Authorization Server support.
  *
  * @author Joe Grandja
  * @since 0.0.1
+ * @see OAuth2AuthorizationServerConfigurer
  */
 @Configuration(proxyBeanMethods = false)
 public class OAuth2AuthorizationServerConfiguration {
 
 	@Bean
-	public WebSecurityConfigurer<WebSecurity> defaultOAuth2AuthorizationServerSecurity() {
-		return new OAuth2AuthorizationServerSecurity();
+	@Order(Ordered.HIGHEST_PRECEDENCE)
+	public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
+		applyDefaultSecurity(http);
+		return http.build();
 	}
 
+	// @formatter:off
+	public static void applyDefaultSecurity(HttpSecurity http) throws Exception {
+		OAuth2AuthorizationServerConfigurer<HttpSecurity> authorizationServerConfigurer =
+				new OAuth2AuthorizationServerConfigurer<>();
+		RequestMatcher[] endpointMatchers = authorizationServerConfigurer
+				.getEndpointMatchers().toArray(new RequestMatcher[0]);
+
+		http
+			.requestMatcher(new OrRequestMatcher(endpointMatchers))
+			.authorizeRequests(authorizeRequests ->
+				authorizeRequests.anyRequest().authenticated()
+			)
+			.csrf(csrf -> csrf.ignoringRequestMatchers(endpointMatchers))
+			.apply(authorizationServerConfigurer);
+	}
+	// @formatter:on
 }

+ 0 - 58
oauth2-authorization-server/src/main/java/org/springframework/security/config/annotation/web/configuration/OAuth2AuthorizationServerSecurity.java

@@ -1,58 +0,0 @@
-/*
- * Copyright 2020 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.configuration;
-
-import org.springframework.core.Ordered;
-import org.springframework.core.annotation.Order;
-import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization.OAuth2AuthorizationServerConfigurer;
-import org.springframework.security.web.util.matcher.OrRequestMatcher;
-import org.springframework.security.web.util.matcher.RequestMatcher;
-
-import static org.springframework.security.config.Customizer.withDefaults;
-
-/**
- * {@link WebSecurityConfigurerAdapter} providing default security configuration for OAuth 2.0 Authorization Server.
- *
- * @author Joe Grandja
- * @since 0.0.1
- */
-@Order(Ordered.HIGHEST_PRECEDENCE)
-public class OAuth2AuthorizationServerSecurity extends WebSecurityConfigurerAdapter {
-
-	@Override
-	protected void configure(HttpSecurity http) throws Exception {
-		applyDefaultConfiguration(http);
-	}
-
-	// @formatter:off
-	public static void applyDefaultConfiguration(HttpSecurity http) throws Exception {
-		OAuth2AuthorizationServerConfigurer<HttpSecurity> authorizationServerConfigurer =
-				new OAuth2AuthorizationServerConfigurer<>();
-		RequestMatcher[] endpointMatchers = authorizationServerConfigurer
-				.getEndpointMatchers().toArray(new RequestMatcher[0]);
-
-		http
-			.requestMatcher(new OrRequestMatcher(endpointMatchers))
-			.authorizeRequests(authorizeRequests ->
-					authorizeRequests.anyRequest().authenticated()
-			)
-			.formLogin(withDefaults())
-			.csrf(csrf -> csrf.ignoringRequestMatchers(endpointMatchers))
-			.apply(authorizationServerConfigurer);
-	}
-	// @formatter:on
-}

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

@@ -39,9 +39,13 @@ import org.springframework.security.oauth2.server.authorization.web.OAuth2Author
 import org.springframework.security.oauth2.server.authorization.web.OAuth2ClientAuthenticationFilter;
 import org.springframework.security.oauth2.server.authorization.web.OAuth2TokenEndpointFilter;
 import org.springframework.security.oauth2.server.authorization.web.OAuth2TokenRevocationEndpointFilter;
+import org.springframework.security.web.AuthenticationEntryPoint;
 import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
+import org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint;
 import org.springframework.security.web.authentication.HttpStatusEntryPoint;
+import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
 import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
+import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
 import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
 import org.springframework.security.web.util.matcher.OrRequestMatcher;
 import org.springframework.security.web.util.matcher.RequestMatcher;
@@ -49,6 +53,7 @@ import org.springframework.util.Assert;
 import org.springframework.util.StringUtils;
 
 import java.util.Arrays;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -163,10 +168,19 @@ public final class OAuth2AuthorizationServerConfigurer<B extends HttpSecurityBui
 
 		ExceptionHandlingConfigurer<B> exceptionHandling = builder.getConfigurer(ExceptionHandlingConfigurer.class);
 		if (exceptionHandling != null) {
-			// Register the default AuthenticationEntryPoint for the token endpoint and token revocation endpoint
-			exceptionHandling.defaultAuthenticationEntryPointFor(
-					new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED),
-					new OrRequestMatcher(this.tokenEndpointMatcher, this.tokenRevocationEndpointMatcher));
+			LinkedHashMap<RequestMatcher, AuthenticationEntryPoint> entryPoints = new LinkedHashMap<>();
+			entryPoints.put(
+					new OrRequestMatcher(this.tokenEndpointMatcher, this.tokenRevocationEndpointMatcher),
+					new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED));
+			DelegatingAuthenticationEntryPoint authenticationEntryPoint =
+					new DelegatingAuthenticationEntryPoint(entryPoints);
+
+			// TODO This needs to change as the login page could be customized with a different URL
+			authenticationEntryPoint.setDefaultEntryPoint(
+					new LoginUrlAuthenticationEntryPoint(
+							DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL));
+
+			exceptionHandling.authenticationEntryPoint(authenticationEntryPoint);
 		}
 	}
 

+ 13 - 6
oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configuration/OAuth2AuthorizationServerSecurityTests.java → oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configuration/OAuth2AuthorizationServerConfigurationTests.java

@@ -18,22 +18,29 @@ package org.springframework.security.config.annotation.web.configuration;
 import org.junit.Test;
 import org.springframework.core.Ordered;
 import org.springframework.core.annotation.OrderUtils;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.util.ClassUtils;
+
+import java.lang.reflect.Method;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 /**
- * Tests for {@link OAuth2AuthorizationServerSecurity}.
+ * Tests for {@link OAuth2AuthorizationServerConfiguration}.
  *
  * @author Joe Grandja
  */
-public class OAuth2AuthorizationServerSecurityTests {
+public class OAuth2AuthorizationServerConfigurationTests {
 
 	@Test
 	public void assertOrderHighestPrecedence() {
-		Integer authorizationServerSecurityOrder = OrderUtils.getOrder(OAuth2AuthorizationServerSecurity.class);
-		Integer defaultSecurityOrder = OrderUtils.getOrder(WebSecurityConfigurerAdapter.class);
-		assertThat(authorizationServerSecurityOrder).isNotEqualTo(defaultSecurityOrder);
-		assertThat(authorizationServerSecurityOrder).isEqualTo(Ordered.HIGHEST_PRECEDENCE);
+		Method authorizationServerSecurityFilterChainMethod =
+				ClassUtils.getMethod(
+						OAuth2AuthorizationServerConfiguration.class,
+						"authorizationServerSecurityFilterChain",
+						HttpSecurity.class);
+		Integer order = OrderUtils.getOrder(authorizationServerSecurityFilterChainMethod);
+		assertThat(order).isEqualTo(Ordered.HIGHEST_PRECEDENCE);
 	}
 
 }

+ 2 - 18
samples/boot/oauth2-integration/authorizationserver/src/main/java/sample/config/AuthorizationServerConfig.java

@@ -16,12 +16,9 @@
 package sample.config;
 
 import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Import;
-import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 import org.springframework.security.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
-import org.springframework.security.core.userdetails.User;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.core.userdetails.UserDetailsService;
 import org.springframework.security.crypto.key.CryptoKeySource;
 import org.springframework.security.crypto.key.StaticKeyGeneratingCryptoKeySource;
 import org.springframework.security.oauth2.core.AuthorizationGrantType;
@@ -29,7 +26,6 @@ import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
 import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository;
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
-import org.springframework.security.provisioning.InMemoryUserDetailsManager;
 
 import java.util.UUID;
 
@@ -37,7 +33,7 @@ import java.util.UUID;
  * @author Joe Grandja
  * @since 0.0.1
  */
-@EnableWebSecurity
+@Configuration(proxyBeanMethods = false)
 @Import(OAuth2AuthorizationServerConfiguration.class)
 public class AuthorizationServerConfig {
 
@@ -63,16 +59,4 @@ public class AuthorizationServerConfig {
 	public CryptoKeySource keySource() {
 		return new StaticKeyGeneratingCryptoKeySource();
 	}
-
-	// @formatter:off
-	@Bean
-	public UserDetailsService users() {
-		UserDetails user = User.withDefaultPasswordEncoder()
-				.username("user1")
-				.password("password")
-				.roles("USER")
-				.build();
-		return new InMemoryUserDetailsManager(user);
-	}
-	// @formatter:on
 }

+ 60 - 0
samples/boot/oauth2-integration/authorizationserver/src/main/java/sample/config/DefaultSecurityConfig.java

@@ -0,0 +1,60 @@
+/*
+ * Copyright 2020 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 sample.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.provisioning.InMemoryUserDetailsManager;
+import org.springframework.security.web.SecurityFilterChain;
+
+import static org.springframework.security.config.Customizer.withDefaults;
+
+/**
+ * @author Joe Grandja
+ * @since 0.1.0
+ */
+@EnableWebSecurity
+public class DefaultSecurityConfig {
+
+	// formatter:off
+	@Bean
+	SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
+		http
+			.authorizeRequests(authorizeRequests ->
+				authorizeRequests.anyRequest().authenticated()
+			)
+			.formLogin(withDefaults());
+		return http.build();
+	}
+	// formatter:on
+
+	// @formatter:off
+	@Bean
+	UserDetailsService users() {
+		UserDetails user = User.withDefaultPasswordEncoder()
+				.username("user1")
+				.password("password")
+				.roles("USER")
+				.build();
+		return new InMemoryUserDetailsManager(user);
+	}
+	// @formatter:on
+
+}