diff --git a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java index d305b4939b..71ace7dac2 100644 --- a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java +++ b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java @@ -207,7 +207,9 @@ public class ServerHttpSecurity { private OAuth2LoginSpec oauth2Login; - private OAuth2Spec oauth2; + private OAuth2ResourceServerSpec resourceServer; + + private OAuth2ClientSpec client; private LogoutSpec logout = new LogoutSpec(); @@ -573,240 +575,188 @@ public class ServerHttpSecurity { } /** - * Configures OAuth2 support. An example configuration is provided below: + * Configures the OAuth2 client. * *
 	 *  @Bean
 	 *  public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
 	 *      http
 	 *          // ...
-	 *          .oauth2()
-	 *              .resourceServer()
-	 *                  .jwt()
-	 *                      .jwkSetUri(jwkSetUri);
+	 *          .oauth2Client()
+	 *              .clientRegistrationRepository(clientRegistrationRepository)
+	 *              .authorizedClientRepository(authorizedClientRepository);
 	 *      return http.build();
 	 *  }
 	 * 
* - * @return the {@link HttpBasicSpec} to customize + * + * @return the {@link OAuth2ClientSpec} to customize */ - public OAuth2Spec oauth2() { - if (this.oauth2 == null) { - this.oauth2 = new OAuth2Spec(); + public OAuth2ClientSpec oauth2Client() { + if (this.client == null) { + this.client = new OAuth2ClientSpec(); } - return this.oauth2; + return this.client; + } + + public class OAuth2ClientSpec { + private ReactiveClientRegistrationRepository clientRegistrationRepository; + + private ServerOAuth2AuthorizedClientRepository authorizedClientRepository; + + /** + * Configures the {@link ReactiveClientRegistrationRepository}. Default is to look the value up as a Bean. + * @param clientRegistrationRepository the repository to use + * @return the {@link OAuth2ClientSpec} to customize + */ + public OAuth2ClientSpec clientRegistrationRepository(ReactiveClientRegistrationRepository clientRegistrationRepository) { + this.clientRegistrationRepository = clientRegistrationRepository; + return this; + } + + /** + * Configures the {@link ReactiveClientRegistrationRepository}. Default is to look the value up as a Bean. + * @param authorizedClientRepository the repository to use + * @return the {@link OAuth2ClientSpec} to customize + */ + public OAuth2ClientSpec authorizedClientRepository(ServerOAuth2AuthorizedClientRepository authorizedClientRepository) { + this.authorizedClientRepository = authorizedClientRepository; + return this; + } + + protected void configure(ServerHttpSecurity http) { + ReactiveClientRegistrationRepository clientRegistrationRepository = getClientRegistrationRepository(); + ServerOAuth2AuthorizedClientRepository authorizedClientRepository = getAuthorizedClientRepository(); + ReactiveAuthenticationManager authenticationManager = new OAuth2AuthorizationCodeReactiveAuthenticationManager(new WebClientReactiveAuthorizationCodeTokenResponseClient()); + OAuth2AuthorizationCodeGrantWebFilter codeGrantWebFilter = new OAuth2AuthorizationCodeGrantWebFilter(authenticationManager, + clientRegistrationRepository, + authorizedClientRepository); + + OAuth2AuthorizationRequestRedirectWebFilter oauthRedirectFilter = new OAuth2AuthorizationRequestRedirectWebFilter( + clientRegistrationRepository); + http.addFilterAt(codeGrantWebFilter, SecurityWebFiltersOrder.AUTHENTICATION); + http.addFilterAt(oauthRedirectFilter, SecurityWebFiltersOrder.HTTP_BASIC); + } + + private ReactiveClientRegistrationRepository getClientRegistrationRepository() { + if (this.clientRegistrationRepository != null) { + return this.clientRegistrationRepository; + } + return getBeanOrNull(ReactiveClientRegistrationRepository.class); + } + + private ServerOAuth2AuthorizedClientRepository getAuthorizedClientRepository() { + if (this.authorizedClientRepository != null) { + return this.authorizedClientRepository; + } + ServerOAuth2AuthorizedClientRepository result = getBeanOrNull(ServerOAuth2AuthorizedClientRepository.class); + if (result == null) { + ReactiveOAuth2AuthorizedClientService authorizedClientService = getAuthorizedClientService(); + if (authorizedClientService != null) { + result = new AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository( + authorizedClientService); + } + } + return result; + } + + private ReactiveOAuth2AuthorizedClientService getAuthorizedClientService() { + ReactiveOAuth2AuthorizedClientService service = getBeanOrNull(ReactiveOAuth2AuthorizedClientService.class); + if (service == null) { + service = new InMemoryReactiveOAuth2AuthorizedClientService(getClientRegistrationRepository()); + } + return service; + } + + private OAuth2ClientSpec() {} + } + + public OAuth2ResourceServerSpec oauth2ResourceServer() { + if (this.resourceServer == null) { + this.resourceServer = new OAuth2ResourceServerSpec(); + } + return this.resourceServer; } /** - * Configures OAuth2 Support - * - * @since 5.1 + * Configures OAuth2 Resource Server Support */ - public class OAuth2Spec { - private OAuth2ResourceServerSpec resourceServer; + public class OAuth2ResourceServerSpec { + private JwtSpec jwt; - private OAuth2ClientSpec client; - - /** - * Configures the OAuth2 client. - * - *
-		 *  @Bean
-		 *  public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
-		 *      http
-		 *          // ...
-		 *          .oauth2()
-		 *              .client()
-		 *                  .clientRegistrationRepository(clientRegistrationRepository)
-		 *                  .authorizedClientRepository(authorizedClientRepository);
-		 *      return http.build();
-		 *  }
-		 * 
- * - * - * @return the {@link OAuth2ClientSpec} to customize - */ - public OAuth2ClientSpec client() { - if (this.client == null) { - this.client = new OAuth2ClientSpec(); + public JwtSpec jwt() { + if (this.jwt == null) { + this.jwt = new JwtSpec(); } - return this.client; + return this.jwt; } - public class OAuth2ClientSpec { - private ReactiveClientRegistrationRepository clientRegistrationRepository; + protected void configure(ServerHttpSecurity http) { + if (this.jwt != null) { + this.jwt.configure(http); + } + } - private ServerOAuth2AuthorizedClientRepository authorizedClientRepository; + /** + * Configures JWT Resource Server Support + */ + public class JwtSpec { + private ReactiveJwtDecoder jwtDecoder; /** - * Configures the {@link ReactiveClientRegistrationRepository}. Default is to look the value up as a Bean. - * @param clientRegistrationRepository the repository to use - * @return the {@link OAuth2ClientSpec} to customize + * Configures the {@link ReactiveJwtDecoder} to use + * @param jwtDecoder the decoder to use + * @return the {@code JwtSpec} for additional configuration */ - public OAuth2ClientSpec clientRegistrationRepository(ReactiveClientRegistrationRepository clientRegistrationRepository) { - this.clientRegistrationRepository = clientRegistrationRepository; + public JwtSpec jwtDecoder(ReactiveJwtDecoder jwtDecoder) { + this.jwtDecoder = jwtDecoder; return this; } /** - * Configures the {@link ReactiveClientRegistrationRepository}. Default is to look the value up as a Bean. - * @param authorizedClientRepository the repository to use - * @return the {@link OAuth2ClientSpec} to customize + * Configures a {@link ReactiveJwtDecoder} that leverages the provided {@link RSAPublicKey} + * + * @param publicKey the public key to use. + * @return the {@code JwtSpec} for additional configuration */ - public OAuth2ClientSpec authorizedClientRepository(ServerOAuth2AuthorizedClientRepository authorizedClientRepository) { - this.authorizedClientRepository = authorizedClientRepository; + public JwtSpec publicKey(RSAPublicKey publicKey) { + this.jwtDecoder = new NimbusReactiveJwtDecoder(publicKey); return this; } - protected void configure(ServerHttpSecurity http) { - ReactiveClientRegistrationRepository clientRegistrationRepository = getClientRegistrationRepository(); - ServerOAuth2AuthorizedClientRepository authorizedClientRepository = getAuthorizedClientRepository(); - ReactiveAuthenticationManager authenticationManager = new OAuth2AuthorizationCodeReactiveAuthenticationManager(new WebClientReactiveAuthorizationCodeTokenResponseClient()); - OAuth2AuthorizationCodeGrantWebFilter codeGrantWebFilter = new OAuth2AuthorizationCodeGrantWebFilter(authenticationManager, - clientRegistrationRepository, - authorizedClientRepository); - - OAuth2AuthorizationRequestRedirectWebFilter oauthRedirectFilter = new OAuth2AuthorizationRequestRedirectWebFilter( - clientRegistrationRepository); - http.addFilterAt(codeGrantWebFilter, SecurityWebFiltersOrder.AUTHENTICATION); - http.addFilterAt(oauthRedirectFilter, SecurityWebFiltersOrder.HTTP_BASIC); - } - - private ReactiveClientRegistrationRepository getClientRegistrationRepository() { - if (this.clientRegistrationRepository != null) { - return this.clientRegistrationRepository; - } - return getBeanOrNull(ReactiveClientRegistrationRepository.class); - } - - private ServerOAuth2AuthorizedClientRepository getAuthorizedClientRepository() { - if (this.authorizedClientRepository != null) { - return this.authorizedClientRepository; - } - ServerOAuth2AuthorizedClientRepository result = getBeanOrNull(ServerOAuth2AuthorizedClientRepository.class); - if (result == null) { - ReactiveOAuth2AuthorizedClientService authorizedClientService = getAuthorizedClientService(); - if (authorizedClientService != null) { - result = new AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository( - authorizedClientService); - } - } - return result; - } - - private ReactiveOAuth2AuthorizedClientService getAuthorizedClientService() { - ReactiveOAuth2AuthorizedClientService service = getBeanOrNull(ReactiveOAuth2AuthorizedClientService.class); - if (service == null) { - service = new InMemoryReactiveOAuth2AuthorizedClientService(getClientRegistrationRepository()); - } - return service; - } - - private OAuth2ClientSpec() {} - } - - public OAuth2ResourceServerSpec resourceServer() { - if (this.resourceServer == null) { - this.resourceServer = new OAuth2ResourceServerSpec(); - } - return this.resourceServer; - } - - /** - * Configures OAuth2 Resource Server Support - */ - public class OAuth2ResourceServerSpec { - private JwtSpec jwt; - - public JwtSpec jwt() { - if (this.jwt == null) { - this.jwt = new JwtSpec(); - } - return this.jwt; - } - - protected void configure(ServerHttpSecurity http) { - if (this.jwt != null) { - this.jwt.configure(http); - } - } - /** - * Configures JWT Resource Server Support + * Configures a {@link ReactiveJwtDecoder} using + * JSON Web Key (JWK) URL + * @param jwkSetUri the URL to use. + * @return the {@code JwtSpec} for additional configuration */ - public class JwtSpec { - private ReactiveJwtDecoder jwtDecoder; - - /** - * Configures the {@link ReactiveJwtDecoder} to use - * @param jwtDecoder the decoder to use - * @return the {@code JwtSpec} for additional configuration - */ - public JwtSpec jwtDecoder(ReactiveJwtDecoder jwtDecoder) { - this.jwtDecoder = jwtDecoder; - return this; - } - - /** - * Configures a {@link ReactiveJwtDecoder} that leverages the provided {@link RSAPublicKey} - * - * @param publicKey the public key to use. - * @return the {@code JwtSpec} for additional configuration - */ - public JwtSpec publicKey(RSAPublicKey publicKey) { - this.jwtDecoder = new NimbusReactiveJwtDecoder(publicKey); - return this; - } - - /** - * Configures a {@link ReactiveJwtDecoder} using - * JSON Web Key (JWK) URL - * @param jwkSetUri the URL to use. - * @return the {@code JwtSpec} for additional configuration - */ - public JwtSpec jwkSetUri(String jwkSetUri) { - this.jwtDecoder = new NimbusReactiveJwtDecoder(jwkSetUri); - return this; - } - - public OAuth2ResourceServerSpec and() { - return OAuth2ResourceServerSpec.this; - } - - protected void configure(ServerHttpSecurity http) { - BearerTokenServerAuthenticationEntryPoint entryPoint = new BearerTokenServerAuthenticationEntryPoint(); - JwtReactiveAuthenticationManager authenticationManager = new JwtReactiveAuthenticationManager( - this.jwtDecoder); - AuthenticationWebFilter oauth2 = new AuthenticationWebFilter(authenticationManager); - oauth2.setServerAuthenticationConverter(new ServerBearerTokenAuthenticationConverter()); - oauth2.setAuthenticationFailureHandler(new ServerAuthenticationEntryPointFailureHandler(entryPoint)); - http - .exceptionHandling() - .authenticationEntryPoint(entryPoint) - .and() - .addFilterAt(oauth2, SecurityWebFiltersOrder.AUTHENTICATION); - } + public JwtSpec jwkSetUri(String jwkSetUri) { + this.jwtDecoder = new NimbusReactiveJwtDecoder(jwkSetUri); + return this; } - public OAuth2Spec and() { - return OAuth2Spec.this; + public OAuth2ResourceServerSpec and() { + return OAuth2ResourceServerSpec.this; + } + + protected void configure(ServerHttpSecurity http) { + BearerTokenServerAuthenticationEntryPoint entryPoint = new BearerTokenServerAuthenticationEntryPoint(); + JwtReactiveAuthenticationManager authenticationManager = new JwtReactiveAuthenticationManager( + this.jwtDecoder); + AuthenticationWebFilter oauth2 = new AuthenticationWebFilter(authenticationManager); + oauth2.setServerAuthenticationConverter(new ServerBearerTokenAuthenticationConverter()); + oauth2.setAuthenticationFailureHandler(new ServerAuthenticationEntryPointFailureHandler(entryPoint)); + http + .exceptionHandling() + .authenticationEntryPoint(entryPoint) + .and() + .addFilterAt(oauth2, SecurityWebFiltersOrder.AUTHENTICATION); } } public ServerHttpSecurity and() { return ServerHttpSecurity.this; } - - protected void configure(ServerHttpSecurity http) { - if (this.resourceServer != null) { - this.resourceServer.configure(http); - } - if (this.client != null) { - this.client.configure(http); - } - } - - private OAuth2Spec() {} } /** @@ -1009,8 +959,11 @@ public class ServerHttpSecurity { if (this.oauth2Login != null) { this.oauth2Login.configure(this); } - if (this.oauth2 != null) { - this.oauth2.configure(this); + if (this.resourceServer != null) { + this.resourceServer.configure(this); + } + if (this.client != null) { + this.client.configure(this); } this.loginPage.configure(this); if(this.logout != null) { diff --git a/config/src/test/java/org/springframework/security/config/web/server/OAuth2ClientSpecTests.java b/config/src/test/java/org/springframework/security/config/web/server/OAuth2ClientSpecTests.java index cae98a8934..af97a25c2e 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/OAuth2ClientSpecTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/OAuth2ClientSpecTests.java @@ -95,8 +95,7 @@ public class OAuth2ClientSpecTests { @Bean SecurityWebFilterChain springSecurity(ServerHttpSecurity http) { http - .oauth2() - .client(); + .oauth2Client(); return http.build(); } diff --git a/samples/boot/authcodegrant-webflux/src/main/java/sample/config/SecurityConfig.java b/samples/boot/authcodegrant-webflux/src/main/java/sample/config/SecurityConfig.java index f7a0406cbe..400d9008e4 100644 --- a/samples/boot/authcodegrant-webflux/src/main/java/sample/config/SecurityConfig.java +++ b/samples/boot/authcodegrant-webflux/src/main/java/sample/config/SecurityConfig.java @@ -40,8 +40,7 @@ public class SecurityConfig { .and() .formLogin() .and() - .oauth2() - .client(); + .oauth2Client(); return http.build(); } diff --git a/samples/boot/oauth2resourceserver-webflux/src/main/java/sample/SecurityConfig.java b/samples/boot/oauth2resourceserver-webflux/src/main/java/sample/SecurityConfig.java index f8ce3b3de0..16de4e2977 100644 --- a/samples/boot/oauth2resourceserver-webflux/src/main/java/sample/SecurityConfig.java +++ b/samples/boot/oauth2resourceserver-webflux/src/main/java/sample/SecurityConfig.java @@ -45,10 +45,9 @@ public class SecurityConfig { .authorizeExchange() .anyExchange().authenticated() .and() - .oauth2() - .resourceServer() - .jwt() - .jwkSetUri(jwkSetUri); + .oauth2ResourceServer() + .jwt() + .jwkSetUri(jwkSetUri); return http.build(); } @@ -59,10 +58,9 @@ public class SecurityConfig { .authorizeExchange() .anyExchange().authenticated() .and() - .oauth2() - .resourceServer() - .jwt() - .publicKey(publicKey()); + .oauth2ResourceServer() + .jwt() + .publicKey(publicKey()); return http.build(); }