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 OAuth2LoginSpec oauth2Login;
private OAuth2Spec oauth2; private OAuth2ResourceServerSpec resourceServer;
private OAuth2ClientSpec client;
private LogoutSpec logout = new LogoutSpec(); 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"> * <pre class="code">
* &#064;Bean * &#064;Bean
* public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { * public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
* http * http
* // ... * // ...
* .oauth2() * .oauth2Client()
* .resourceServer() * .clientRegistrationRepository(clientRegistrationRepository)
* .jwt() * .authorizedClientRepository(authorizedClientRepository);
* .jwkSetUri(jwkSetUri);
* return http.build(); * return http.build();
* } * }
* </pre> * </pre>
* *
* @return the {@link HttpBasicSpec} to customize *
* @return the {@link OAuth2ClientSpec} to customize
*/ */
public OAuth2Spec oauth2() { public OAuth2ClientSpec oauth2Client() {
if (this.oauth2 == null) { if (this.client == null) {
this.oauth2 = new OAuth2Spec(); 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 * Configures OAuth2 Resource Server Support
*
* @since 5.1
*/ */
public class OAuth2Spec { public class OAuth2ResourceServerSpec {
private OAuth2ResourceServerSpec resourceServer; private JwtSpec jwt;
private OAuth2ClientSpec client; public JwtSpec jwt() {
if (this.jwt == null) {
/** this.jwt = new JwtSpec();
* 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();
} }
return this.client; return this.jwt;
} }
public class OAuth2ClientSpec { protected void configure(ServerHttpSecurity http) {
private ReactiveClientRegistrationRepository clientRegistrationRepository; 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. * Configures the {@link ReactiveJwtDecoder} to use
* @param clientRegistrationRepository the repository to use * @param jwtDecoder the decoder to use
* @return the {@link OAuth2ClientSpec} to customize * @return the {@code JwtSpec} for additional configuration
*/ */
public OAuth2ClientSpec clientRegistrationRepository(ReactiveClientRegistrationRepository clientRegistrationRepository) { public JwtSpec jwtDecoder(ReactiveJwtDecoder jwtDecoder) {
this.clientRegistrationRepository = clientRegistrationRepository; this.jwtDecoder = jwtDecoder;
return this; return this;
} }
/** /**
* Configures the {@link ReactiveClientRegistrationRepository}. Default is to look the value up as a Bean. * Configures a {@link ReactiveJwtDecoder} that leverages the provided {@link RSAPublicKey}
* @param authorizedClientRepository the repository to use *
* @return the {@link OAuth2ClientSpec} to customize * @param publicKey the public key to use.
* @return the {@code JwtSpec} for additional configuration
*/ */
public OAuth2ClientSpec authorizedClientRepository(ServerOAuth2AuthorizedClientRepository authorizedClientRepository) { public JwtSpec publicKey(RSAPublicKey publicKey) {
this.authorizedClientRepository = authorizedClientRepository; this.jwtDecoder = new NimbusReactiveJwtDecoder(publicKey);
return this; 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 { public JwtSpec jwkSetUri(String jwkSetUri) {
private ReactiveJwtDecoder jwtDecoder; this.jwtDecoder = new NimbusReactiveJwtDecoder(jwkSetUri);
return this;
/**
* 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 OAuth2Spec and() { public OAuth2ResourceServerSpec and() {
return OAuth2Spec.this; 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() { public ServerHttpSecurity and() {
return ServerHttpSecurity.this; 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) { if (this.oauth2Login != null) {
this.oauth2Login.configure(this); this.oauth2Login.configure(this);
} }
if (this.oauth2 != null) { if (this.resourceServer != null) {
this.oauth2.configure(this); this.resourceServer.configure(this);
}
if (this.client != null) {
this.client.configure(this);
} }
this.loginPage.configure(this); this.loginPage.configure(this);
if(this.logout != null) { if(this.logout != null) {

View File

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

View File

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

View File

@ -45,10 +45,9 @@ public class SecurityConfig {
.authorizeExchange() .authorizeExchange()
.anyExchange().authenticated() .anyExchange().authenticated()
.and() .and()
.oauth2() .oauth2ResourceServer()
.resourceServer() .jwt()
.jwt() .jwkSetUri(jwkSetUri);
.jwkSetUri(jwkSetUri);
return http.build(); return http.build();
} }
@ -59,10 +58,9 @@ public class SecurityConfig {
.authorizeExchange() .authorizeExchange()
.anyExchange().authenticated() .anyExchange().authenticated()
.and() .and()
.oauth2() .oauth2ResourceServer()
.resourceServer() .jwt()
.jwt() .publicKey(publicKey());
.publicKey(publicKey());
return http.build(); return http.build();
} }