Flatten ServerHttpSecurity.oauth2()

Fixes: gh-5712
This commit is contained in:
Rob Winch 2018-08-21 15:48:21 -05:00
parent 59cdfc7d6e
commit 0dc80aed40
4 changed files with 156 additions and 207 deletions

View File

@ -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">
* &#064;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">
* &#064;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) {

View File

@ -95,8 +95,7 @@ public class OAuth2ClientSpecTests {
@Bean
SecurityWebFilterChain springSecurity(ServerHttpSecurity http) {
http
.oauth2()
.client();
.oauth2Client();
return http.build();
}

View File

@ -40,8 +40,7 @@ public class SecurityConfig {
.and()
.formLogin()
.and()
.oauth2()
.client();
.oauth2Client();
return http.build();
}

View File

@ -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();
}