parent
59cdfc7d6e
commit
0dc80aed40
|
@ -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;
|
||||
}
|
||||
|
||||
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.
|
||||
*
|
||||
* <pre class="code">
|
||||
* @Bean
|
||||
* public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
|
||||
* http
|
||||
* // ...
|
||||
* .oauth2()
|
||||
* .client()
|
||||
* .clientRegistrationRepository(clientRegistrationRepository)
|
||||
* .authorizedClientRepository(authorizedClientRepository);
|
||||
* return http.build();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* @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
|
||||
* <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;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
|
|
@ -95,8 +95,7 @@ public class OAuth2ClientSpecTests {
|
|||
@Bean
|
||||
SecurityWebFilterChain springSecurity(ServerHttpSecurity http) {
|
||||
http
|
||||
.oauth2()
|
||||
.client();
|
||||
.oauth2Client();
|
||||
return http.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -40,8 +40,7 @@ public class SecurityConfig {
|
|||
.and()
|
||||
.formLogin()
|
||||
.and()
|
||||
.oauth2()
|
||||
.client();
|
||||
.oauth2Client();
|
||||
return http.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue