Polish #4904 Support GrantedAuthoritiesMapper @Bean for oauth2Login

This commit is contained in:
Joe Grandja 2018-01-22 22:21:15 -05:00
parent 444e2dade3
commit 84679a5d64
3 changed files with 97 additions and 93 deletions

View File

@ -66,7 +66,6 @@ dependencies {
testRuntime 'cglib:cglib-nodep' testRuntime 'cglib:cglib-nodep'
testRuntime 'org.hsqldb:hsqldb' testRuntime 'org.hsqldb:hsqldb'
testRuntime 'com.fasterxml.jackson.core:jackson-databind'
} }
test { test {

View File

@ -65,8 +65,6 @@ import org.springframework.security.web.context.HttpSessionSecurityContextReposi
import org.springframework.security.web.context.SecurityContextRepository; import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import javax.servlet.ServletException;
import java.io.IOException;
import java.time.Instant; import java.time.Instant;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -83,7 +81,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Kazuki Shimizu * @author Kazuki Shimizu
* @since 5.0.1 * @since 5.0.1
*/ */
public class OAuth2LoginConfigurerTest { public class OAuth2LoginConfigurerTests {
private static final ClientRegistration CLIENT_REGISTRATION = CommonOAuth2Provider.GOOGLE private static final ClientRegistration CLIENT_REGISTRATION = CommonOAuth2Provider.GOOGLE
.getBuilder("google").clientId("clientId").clientSecret("clientSecret") .getBuilder("google").clientId("clientId").clientSecret("clientSecret")
@ -93,8 +91,10 @@ public class OAuth2LoginConfigurerTest {
@Autowired @Autowired
private FilterChainProxy springSecurityFilterChain; private FilterChainProxy springSecurityFilterChain;
@Autowired @Autowired
private AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository; private AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository;
@Autowired @Autowired
SecurityContextRepository securityContextRepository; SecurityContextRepository securityContextRepository;
@ -120,23 +120,21 @@ public class OAuth2LoginConfigurerTest {
} }
@Test @Test
public void oauth2Login() throws IOException, ServletException { public void oauth2Login() throws Exception {
// setup application context // setup application context
loadConfig(OAuth2LoginConfig.class); loadConfig(OAuth2LoginConfig.class);
// setup authorization request // setup authorization request
OAuth2AuthorizationRequest authorizationRequest = createOAuth2AuthorizationRequest(); OAuth2AuthorizationRequest authorizationRequest = createOAuth2AuthorizationRequest();
this.authorizationRequestRepository.saveAuthorizationRequest(authorizationRequest, this.authorizationRequestRepository.saveAuthorizationRequest(
this.request, this.response); authorizationRequest, this.request, this.response);
// setup authentication parameters // setup authentication parameters
this.request.setParameter("code", "code123"); this.request.setParameter("code", "code123");
this.request.setParameter("state", authorizationRequest.getState()); this.request.setParameter("state", authorizationRequest.getState());
// perform test // perform test
this.springSecurityFilterChain.doFilter(this.request, this.response, this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
this.filterChain);
// assertions // assertions
Authentication authentication = this.securityContextRepository Authentication authentication = this.securityContextRepository
@ -148,24 +146,21 @@ public class OAuth2LoginConfigurerTest {
} }
@Test @Test
public void oauth2LoginCustomizeUsingConfigurerMethod() public void oauth2LoginCustomWithConfigurer() throws Exception {
throws IOException, ServletException {
// setup application context // setup application context
loadConfig(OAuth2LoginConfigCustomizeUsingConfigurerMethod.class); loadConfig(OAuth2LoginConfigCustomWithConfigurer.class);
// setup authorization request // setup authorization request
OAuth2AuthorizationRequest authorizationRequest = createOAuth2AuthorizationRequest(); OAuth2AuthorizationRequest authorizationRequest = createOAuth2AuthorizationRequest();
this.authorizationRequestRepository.saveAuthorizationRequest(authorizationRequest, this.authorizationRequestRepository.saveAuthorizationRequest(
this.request, this.response); authorizationRequest, this.request, this.response);
// setup authentication parameters // setup authentication parameters
this.request.setParameter("code", "code123"); this.request.setParameter("code", "code123");
this.request.setParameter("state", authorizationRequest.getState()); this.request.setParameter("state", authorizationRequest.getState());
// perform test // perform test
this.springSecurityFilterChain.doFilter(this.request, this.response, this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
this.filterChain);
// assertions // assertions
Authentication authentication = this.securityContextRepository Authentication authentication = this.securityContextRepository
@ -173,29 +168,25 @@ public class OAuth2LoginConfigurerTest {
.getAuthentication(); .getAuthentication();
assertThat(authentication.getAuthorities()).hasSize(2); assertThat(authentication.getAuthorities()).hasSize(2);
assertThat(authentication.getAuthorities()).first().hasToString("ROLE_USER"); assertThat(authentication.getAuthorities()).first().hasToString("ROLE_USER");
assertThat(authentication.getAuthorities()).last() assertThat(authentication.getAuthorities()).last().hasToString("ROLE_OAUTH2_USER");
.hasToString("ROLE_OAUTH2_USER");
} }
@Test @Test
public void oauth2LoginCustomizeUsingAutoDetection() public void oauth2LoginCustomWithBeanRegistration() throws Exception {
throws IOException, ServletException {
// setup application context // setup application context
loadConfig(OAuth2LoginConfigCustomizeUsingAutoDetection.class); loadConfig(OAuth2LoginConfigCustomWithBeanRegistration.class);
// setup authorization request // setup authorization request
OAuth2AuthorizationRequest authorizationRequest = createOAuth2AuthorizationRequest(); OAuth2AuthorizationRequest authorizationRequest = createOAuth2AuthorizationRequest();
this.authorizationRequestRepository.saveAuthorizationRequest(authorizationRequest, this.authorizationRequestRepository.saveAuthorizationRequest(
this.request, this.response); authorizationRequest, this.request, this.response);
// setup authentication parameters // setup authentication parameters
this.request.setParameter("code", "code123"); this.request.setParameter("code", "code123");
this.request.setParameter("state", authorizationRequest.getState()); this.request.setParameter("state", authorizationRequest.getState());
// perform test // perform test
this.springSecurityFilterChain.doFilter(this.request, this.response, this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
this.filterChain);
// assertions // assertions
Authentication authentication = this.securityContextRepository Authentication authentication = this.securityContextRepository
@ -203,30 +194,26 @@ public class OAuth2LoginConfigurerTest {
.getAuthentication(); .getAuthentication();
assertThat(authentication.getAuthorities()).hasSize(2); assertThat(authentication.getAuthorities()).hasSize(2);
assertThat(authentication.getAuthorities()).first().hasToString("ROLE_USER"); assertThat(authentication.getAuthorities()).first().hasToString("ROLE_USER");
assertThat(authentication.getAuthorities()).last() assertThat(authentication.getAuthorities()).last().hasToString("ROLE_OAUTH2_USER");
.hasToString("ROLE_OAUTH2_USER");
} }
@Test @Test
public void oidcLogin() throws IOException, ServletException { public void oidcLogin() throws Exception {
// setup application context // setup application context
loadConfig(OAuth2LoginConfig.class); loadConfig(OAuth2LoginConfig.class);
registerJwtDecoder(); registerJwtDecoder();
// setup authorization request // setup authorization request
OAuth2AuthorizationRequest authorizationRequest = createOAuth2AuthorizationRequest( OAuth2AuthorizationRequest authorizationRequest = createOAuth2AuthorizationRequest("openid");
"openid"); this.authorizationRequestRepository.saveAuthorizationRequest(
this.authorizationRequestRepository.saveAuthorizationRequest(authorizationRequest, authorizationRequest, this.request, this.response);
this.request, this.response);
// setup authentication parameters // setup authentication parameters
this.request.setParameter("code", "code123"); this.request.setParameter("code", "code123");
this.request.setParameter("state", authorizationRequest.getState()); this.request.setParameter("state", authorizationRequest.getState());
// perform test // perform test
this.springSecurityFilterChain.doFilter(this.request, this.response, this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
this.filterChain);
// assertions // assertions
Authentication authentication = this.securityContextRepository Authentication authentication = this.securityContextRepository
@ -238,26 +225,22 @@ public class OAuth2LoginConfigurerTest {
} }
@Test @Test
public void oidcLoginCustomizeUsingConfigurerMethod() public void oidcLoginCustomWithConfigurer() throws Exception {
throws IOException, ServletException {
// setup application context // setup application context
loadConfig(OAuth2LoginConfigCustomizeUsingConfigurerMethod.class); loadConfig(OAuth2LoginConfigCustomWithConfigurer.class);
registerJwtDecoder(); registerJwtDecoder();
// setup authorization request // setup authorization request
OAuth2AuthorizationRequest authorizationRequest = createOAuth2AuthorizationRequest( OAuth2AuthorizationRequest authorizationRequest = createOAuth2AuthorizationRequest("openid");
"openid"); this.authorizationRequestRepository.saveAuthorizationRequest(
this.authorizationRequestRepository.saveAuthorizationRequest(authorizationRequest, authorizationRequest, this.request, this.response);
this.request, this.response);
// setup authentication parameters // setup authentication parameters
this.request.setParameter("code", "code123"); this.request.setParameter("code", "code123");
this.request.setParameter("state", authorizationRequest.getState()); this.request.setParameter("state", authorizationRequest.getState());
// perform test // perform test
this.springSecurityFilterChain.doFilter(this.request, this.response, this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
this.filterChain);
// assertions // assertions
Authentication authentication = this.securityContextRepository Authentication authentication = this.securityContextRepository
@ -269,26 +252,22 @@ public class OAuth2LoginConfigurerTest {
} }
@Test @Test
public void oidcLoginCustomizeUsingAutoDetection() public void oidcLoginCustomWithBeanRegistration() throws Exception {
throws IOException, ServletException {
// setup application context // setup application context
loadConfig(OAuth2LoginConfigCustomizeUsingAutoDetection.class); loadConfig(OAuth2LoginConfigCustomWithBeanRegistration.class);
registerJwtDecoder(); registerJwtDecoder();
// setup authorization request // setup authorization request
OAuth2AuthorizationRequest authorizationRequest = createOAuth2AuthorizationRequest( OAuth2AuthorizationRequest authorizationRequest = createOAuth2AuthorizationRequest("openid");
"openid"); this.authorizationRequestRepository.saveAuthorizationRequest(
this.authorizationRequestRepository.saveAuthorizationRequest(authorizationRequest, authorizationRequest, this.request, this.response);
this.request, this.response);
// setup authentication parameters // setup authentication parameters
this.request.setParameter("code", "code123"); this.request.setParameter("code", "code123");
this.request.setParameter("state", authorizationRequest.getState()); this.request.setParameter("state", authorizationRequest.getState());
// perform test // perform test
this.springSecurityFilterChain.doFilter(this.request, this.response, this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
this.filterChain);
// assertions // assertions
Authentication authentication = this.securityContextRepository Authentication authentication = this.securityContextRepository
@ -318,42 +297,46 @@ public class OAuth2LoginConfigurerTest {
Collections.singletonMap("header1", "value1"), claims); Collections.singletonMap("header1", "value1"), claims);
}; };
this.springSecurityFilterChain.getFilters("/login/oauth2/code/google").stream() this.springSecurityFilterChain.getFilters("/login/oauth2/code/google").stream()
.filter(OAuth2LoginAuthenticationFilter.class::isInstance).findFirst() .filter(OAuth2LoginAuthenticationFilter.class::isInstance)
.findFirst()
.ifPresent(filter -> PropertyAccessorFactory.forDirectFieldAccess(filter) .ifPresent(filter -> PropertyAccessorFactory.forDirectFieldAccess(filter)
.setPropertyValue( .setPropertyValue(
"authenticationManager.providers[2].jwtDecoders['google']", "authenticationManager.providers[2].jwtDecoders['google']",
decoder)); decoder));
} }
private OAuth2AuthorizationRequest createOAuth2AuthorizationRequest( private OAuth2AuthorizationRequest createOAuth2AuthorizationRequest(String... scopes) {
String... scopes) {
return OAuth2AuthorizationRequest.authorizationCode() return OAuth2AuthorizationRequest.authorizationCode()
.authorizationUri( .authorizationUri(CLIENT_REGISTRATION.getProviderDetails().getAuthorizationUri())
CLIENT_REGISTRATION.getProviderDetails().getAuthorizationUri()) .clientId(CLIENT_REGISTRATION.getClientId())
.clientId(CLIENT_REGISTRATION.getClientId()).state("state123") .state("state123")
.redirectUri("http://localhost") .redirectUri("http://localhost")
.additionalParameters( .additionalParameters(
Collections.singletonMap(OAuth2ParameterNames.REGISTRATION_ID, Collections.singletonMap(
OAuth2ParameterNames.REGISTRATION_ID,
CLIENT_REGISTRATION.getRegistrationId())) CLIENT_REGISTRATION.getRegistrationId()))
.scope(scopes).build(); .scope(scopes)
.build();
} }
@EnableWebSecurity @EnableWebSecurity
static class OAuth2LoginConfig extends CommonWebSecurityConfigurerAdapter { static class OAuth2LoginConfig extends CommonWebSecurityConfigurerAdapter {
@Override @Override
protected void configure(HttpSecurity http) throws Exception { protected void configure(HttpSecurity http) throws Exception {
http.oauth2Login().clientRegistrationRepository( http
.oauth2Login()
.clientRegistrationRepository(
new InMemoryClientRegistrationRepository(CLIENT_REGISTRATION)); new InMemoryClientRegistrationRepository(CLIENT_REGISTRATION));
super.configure(http); super.configure(http);
} }
} }
@EnableWebSecurity @EnableWebSecurity
static class OAuth2LoginConfigCustomizeUsingConfigurerMethod static class OAuth2LoginConfigCustomWithConfigurer extends CommonWebSecurityConfigurerAdapter {
extends CommonWebSecurityConfigurerAdapter {
@Override @Override
protected void configure(HttpSecurity http) throws Exception { protected void configure(HttpSecurity http) throws Exception {
http.oauth2Login() http
.oauth2Login()
.clientRegistrationRepository( .clientRegistrationRepository(
new InMemoryClientRegistrationRepository(CLIENT_REGISTRATION)) new InMemoryClientRegistrationRepository(CLIENT_REGISTRATION))
.userInfoEndpoint() .userInfoEndpoint()
@ -363,11 +346,11 @@ public class OAuth2LoginConfigurerTest {
} }
@EnableWebSecurity @EnableWebSecurity
static class OAuth2LoginConfigCustomizeUsingAutoDetection static class OAuth2LoginConfigCustomWithBeanRegistration extends CommonWebSecurityConfigurerAdapter {
extends CommonWebSecurityConfigurerAdapter {
@Override @Override
protected void configure(HttpSecurity http) throws Exception { protected void configure(HttpSecurity http) throws Exception {
http.oauth2Login(); http
.oauth2Login();
super.configure(http); super.configure(http);
} }
@ -382,14 +365,19 @@ public class OAuth2LoginConfigurerTest {
} }
} }
private static abstract class CommonWebSecurityConfigurerAdapter private static abstract class CommonWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
extends WebSecurityConfigurerAdapter {
@Override @Override
protected void configure(HttpSecurity http) throws Exception { protected void configure(HttpSecurity http) throws Exception {
http.securityContext().securityContextRepository(securityContextRepository()) http
.and().oauth2Login().tokenEndpoint() .securityContext()
.securityContextRepository(securityContextRepository())
.and()
.oauth2Login()
.tokenEndpoint()
.accessTokenResponseClient(createOauth2AccessTokenResponseClient()) .accessTokenResponseClient(createOauth2AccessTokenResponseClient())
.and().userInfoEndpoint().userService(createOauth2UserService()) .and()
.userInfoEndpoint()
.userService(createOauth2UserService())
.oidcUserService(createOidcUserService()); .oidcUserService(createOidcUserService());
} }
@ -407,13 +395,13 @@ public class OAuth2LoginConfigurerTest {
private static OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> createOauth2AccessTokenResponseClient() { private static OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> createOauth2AccessTokenResponseClient() {
return request -> { return request -> {
Map<String, Object> additionalParameters = new HashMap<>(); Map<String, Object> additionalParameters = new HashMap<>();
if (request.getAuthorizationExchange().getAuthorizationRequest().getScopes() if (request.getAuthorizationExchange().getAuthorizationRequest().getScopes().contains("openid")) {
.contains("openid")) {
additionalParameters.put(OidcParameterNames.ID_TOKEN, "token123"); additionalParameters.put(OidcParameterNames.ID_TOKEN, "token123");
} }
return OAuth2AccessTokenResponse.withToken("accessToken123") return OAuth2AccessTokenResponse.withToken("accessToken123")
.tokenType(OAuth2AccessToken.TokenType.BEARER) .tokenType(OAuth2AccessToken.TokenType.BEARER)
.additionalParameters(additionalParameters).build(); .additionalParameters(additionalParameters)
.build();
}; };
} }
@ -426,8 +414,7 @@ public class OAuth2LoginConfigurerTest {
private static OAuth2UserService<OidcUserRequest, OidcUser> createOidcUserService() { private static OAuth2UserService<OidcUserRequest, OidcUser> createOidcUserService() {
OidcIdToken idToken = new OidcIdToken("token123", Instant.now(), OidcIdToken idToken = new OidcIdToken("token123", Instant.now(),
Instant.now().plusSeconds(3600), Instant.now().plusSeconds(3600), Collections.singletonMap(IdTokenClaimNames.SUB, "sub123"));
Collections.singletonMap(IdTokenClaimNames.SUB, "sub123"));
return request -> new DefaultOidcUser( return request -> new DefaultOidcUser(
Collections.singleton(new OidcUserAuthority(idToken)), idToken); Collections.singleton(new OidcUserAuthority(idToken)), idToken);
} }
@ -442,5 +429,4 @@ public class OAuth2LoginConfigurerTest {
return mappedAuthorities; return mappedAuthorities;
}; };
} }
} }

View File

@ -6912,6 +6912,25 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
} }
---- ----
Alternatively, you may register a `GrantedAuthoritiesMapper` `@Bean` to have it automatically applied to the configuration, as shown in the following example:
[source,java]
----
@EnableWebSecurity
public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.oauth2Login();
}
@Bean
public GrantedAuthoritiesMapper userAuthoritiesMapper() {
...
}
}
----
[[oauth2login-advanced-map-authorities-oauth2userservice]] [[oauth2login-advanced-map-authorities-oauth2userservice]]
===== Delegation-based strategy with `OAuth2UserService` ===== Delegation-based strategy with `OAuth2UserService`