|
@@ -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.
|
|
|
*
|
|
|
* <pre class="code">
|
|
|
* @Bean
|
|
|
* public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
|
|
|
* http
|
|
|
* // ...
|
|
|
- * .oauth2()
|
|
|
- * .resourceServer()
|
|
|
- * .jwt()
|
|
|
- * .jwkSetUri(jwkSetUri);
|
|
|
+ * .oauth2Client()
|
|
|
+ * .clientRegistrationRepository(clientRegistrationRepository)
|
|
|
+ * .authorizedClientRepository(authorizedClientRepository);
|
|
|
* return http.build();
|
|
|
* }
|
|
|
* </pre>
|
|
|
*
|
|
|
- * @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;
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Configures OAuth2 Support
|
|
|
- *
|
|
|
- * @since 5.1
|
|
|
- */
|
|
|
- public class OAuth2Spec {
|
|
|
- private OAuth2ResourceServerSpec resourceServer;
|
|
|
+ public class OAuth2ClientSpec {
|
|
|
+ private ReactiveClientRegistrationRepository clientRegistrationRepository;
|
|
|
|
|
|
- private OAuth2ClientSpec client;
|
|
|
+ private ServerOAuth2AuthorizedClientRepository authorizedClientRepository;
|
|
|
|
|
|
/**
|
|
|
- * Configures the OAuth2 client.
|
|
|
- *
|
|
|
- * <pre class="code">
|
|
|
- * @Bean
|
|
|
- * public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
|
|
|
- * http
|
|
|
- * // ...
|
|
|
- * .oauth2()
|
|
|
- * .client()
|
|
|
- * .clientRegistrationRepository(clientRegistrationRepository)
|
|
|
- * .authorizedClientRepository(authorizedClientRepository);
|
|
|
- * return http.build();
|
|
|
- * }
|
|
|
- * </pre>
|
|
|
- *
|
|
|
- *
|
|
|
+ * 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 client() {
|
|
|
- if (this.client == null) {
|
|
|
- this.client = new OAuth2ClientSpec();
|
|
|
- }
|
|
|
- return this.client;
|
|
|
+ public OAuth2ClientSpec clientRegistrationRepository(ReactiveClientRegistrationRepository clientRegistrationRepository) {
|
|
|
+ this.clientRegistrationRepository = clientRegistrationRepository;
|
|
|
+ return this;
|
|
|
}
|
|
|
|
|
|
- public class OAuth2ClientSpec {
|
|
|
- private ReactiveClientRegistrationRepository clientRegistrationRepository;
|
|
|
-
|
|
|
- private ServerOAuth2AuthorizedClientRepository authorizedClientRepository;
|
|
|
+ /**
|
|
|
+ * 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;
|
|
|
+ }
|
|
|
|
|
|
- /**
|
|
|
- * 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;
|
|
|
- }
|
|
|
+ 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);
|
|
|
+ }
|
|
|
|
|
|
- /**
|
|
|
- * 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;
|
|
|
+ private ReactiveClientRegistrationRepository getClientRegistrationRepository() {
|
|
|
+ if (this.clientRegistrationRepository != null) {
|
|
|
+ return this.clientRegistrationRepository;
|
|
|
}
|
|
|
+ return getBeanOrNull(ReactiveClientRegistrationRepository.class);
|
|
|
+ }
|
|
|
|
|
|
- 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 ServerOAuth2AuthorizedClientRepository getAuthorizedClientRepository() {
|
|
|
+ if (this.authorizedClientRepository != null) {
|
|
|
+ return this.authorizedClientRepository;
|
|
|
}
|
|
|
-
|
|
|
- private ReactiveClientRegistrationRepository getClientRegistrationRepository() {
|
|
|
- if (this.clientRegistrationRepository != null) {
|
|
|
- return this.clientRegistrationRepository;
|
|
|
+ ServerOAuth2AuthorizedClientRepository result = getBeanOrNull(ServerOAuth2AuthorizedClientRepository.class);
|
|
|
+ if (result == null) {
|
|
|
+ ReactiveOAuth2AuthorizedClientService authorizedClientService = getAuthorizedClientService();
|
|
|
+ if (authorizedClientService != null) {
|
|
|
+ result = new AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository(
|
|
|
+ authorizedClientService);
|
|
|
}
|
|
|
- return getBeanOrNull(ReactiveClientRegistrationRepository.class);
|
|
|
}
|
|
|
+ return result;
|
|
|
+ }
|
|
|
|
|
|
- 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 ReactiveOAuth2AuthorizedClientService getAuthorizedClientService() {
|
|
|
- ReactiveOAuth2AuthorizedClientService service = getBeanOrNull(ReactiveOAuth2AuthorizedClientService.class);
|
|
|
- if (service == null) {
|
|
|
- service = new InMemoryReactiveOAuth2AuthorizedClientService(getClientRegistrationRepository());
|
|
|
- }
|
|
|
- return service;
|
|
|
- }
|
|
|
+ private OAuth2ClientSpec() {}
|
|
|
+ }
|
|
|
|
|
|
- private OAuth2ClientSpec() {}
|
|
|
+ public OAuth2ResourceServerSpec oauth2ResourceServer() {
|
|
|
+ if (this.resourceServer == null) {
|
|
|
+ this.resourceServer = new OAuth2ResourceServerSpec();
|
|
|
}
|
|
|
+ return this.resourceServer;
|
|
|
+ }
|
|
|
|
|
|
- public OAuth2ResourceServerSpec resourceServer() {
|
|
|
- if (this.resourceServer == null) {
|
|
|
- this.resourceServer = new OAuth2ResourceServerSpec();
|
|
|
+ /**
|
|
|
+ * 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);
|
|
|
}
|
|
|
- return this.resourceServer;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Configures OAuth2 Resource Server Support
|
|
|
+ * Configures JWT Resource Server Support
|
|
|
*/
|
|
|
- public class OAuth2ResourceServerSpec {
|
|
|
- private JwtSpec jwt;
|
|
|
+ public class JwtSpec {
|
|
|
+ private ReactiveJwtDecoder jwtDecoder;
|
|
|
|
|
|
- public JwtSpec jwt() {
|
|
|
- if (this.jwt == null) {
|
|
|
- this.jwt = new JwtSpec();
|
|
|
- }
|
|
|
- return this.jwt;
|
|
|
+ /**
|
|
|
+ * 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;
|
|
|
}
|
|
|
|
|
|
- protected void configure(ServerHttpSecurity http) {
|
|
|
- if (this.jwt != null) {
|
|
|
- this.jwt.configure(http);
|
|
|
- }
|
|
|
+ /**
|
|
|
+ * 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 JWT Resource Server Support
|
|
|
+ * Configures a {@link ReactiveJwtDecoder} using
|
|
|
+ * <a target="_blank" href="https://tools.ietf.org/html/rfc7517">JSON Web Key (JWK)</a> 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
|
|
|
- * <a target="_blank" href="https://tools.ietf.org/html/rfc7517">JSON Web Key (JWK)</a> 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;
|
|
|
- }
|
|
|
+ public JwtSpec jwkSetUri(String jwkSetUri) {
|
|
|
+ this.jwtDecoder = new NimbusReactiveJwtDecoder(jwkSetUri);
|
|
|
+ return 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 OAuth2ResourceServerSpec and() {
|
|
|
+ return OAuth2ResourceServerSpec.this;
|
|
|
}
|
|
|
|
|
|
- public OAuth2Spec and() {
|
|
|
- return OAuth2Spec.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) {
|