I have a oauth2 client spring-boot application with dependencies: - spring-boot 1.2.0.RC1 - spring-security-oauth2 2.0.4.RELEASE - spring-security 3.2.5.RELEASE
The client authenticates, the authentication is set in the SecurityContextHolder but when the request is redirected to the original url the filter chain starts processing again. I noticed that in the SecurityContextPersistenceFilter the contextBeforeChainExecution and contextAfterChainExecution both have a null authentication.
I have based some of the code on [1]Spring Security OAuth2 (google) web app in redirect loop
Any ideas as to why the redirect loop? Thank you in advance.
[Logs snippet]https://gist.github.com/yterradas/61da3f6eccc683b3a086
Below is the config for security.
@Configuration
public class SecurityConfig {
@Configuration
@EnableWebMvcSecurity
protected static class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private OAuth2ClientAuthenticationProcessingFilter oAuth2ClientAuthenticationProcessingFilter;
@Autowired
private LoginUrlAuthenticationEntryPoint vaultAuthenticationEntryPoint;
@SuppressWarnings({"SpringJavaAutowiringInspection"})
@Autowired
private OAuth2ClientContextFilter oAuth2ClientContextFilter;
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.antMatchers("/**").authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(vaultAuthenticationEntryPoint)
.and()
.addFilterAfter(oAuth2ClientContextFilter, ExceptionTranslationFilter.class)
.addFilterBefore(oAuth2ClientAuthenticationProcessingFilter, FilterSecurityInterceptor.class)
.anonymous().disable();
// @formatter:on
}
@Override
public void configure(WebSecurity web) throws Exception {
// @formatter:off
web
/* TODO:
disable debug in production
*/
.debug(true);
// @formatter:on
}
}
@Configuration
@EnableOAuth2Client
protected static class ClientSecurityConfig {
@Value("${app.name}") private String appId;
@Value("${app.clientId}") private String appClientId;
@Value("${app.clientSecret}") private String appClientSecret;
@Value("${app.redirectUrl}") private String appRedirectUrl;
@Value("${vault.accessTokenUrl}") private String vaultAccessTokenUrl;
@Value("${vault.userAuthorizationUrl}") private String vaultUserAuthorizationUrl;
@Value("${vault.checkTokenUrl}") private String vaultCheckTokenUrl;
@SuppressWarnings({"SpringJavaAutowiringInspection"})
@Resource
@Qualifier("oauth2ClientContext")
private OAuth2ClientContext oAuth2ClientContext;
@Autowired
@Qualifier("securityDataSource")
private DataSource securityDataSource;
@Autowired
private MappingJackson2HttpMessageConverter jackson2HttpMessageConverter;
@Bean
public OAuth2RestOperations oAuth2RestOperations() {
AccessTokenProviderChain provider = new AccessTokenProviderChain(
Arrays.asList(new AuthorizationCodeAccessTokenProvider())
);
provider.setClientTokenServices(new JdbcClientTokenServices(securityDataSource));
OAuth2RestTemplate template = new OAuth2RestTemplate(oAuth2Resource(), oAuth2ClientContext);
template.setAccessTokenProvider(provider);
template.setMessageConverters(Arrays.asList(jackson2HttpMessageConverter));
return template;
}
@Bean
OAuth2ProtectedResourceDetails oAuth2Resource() {
AuthorizationCodeResourceDetails resource = new AuthorizationCodeResourceDetails();
resource.setId(appId);
resource.setAuthenticationScheme(AuthenticationScheme.query);
resource.setAccessTokenUri(vaultAccessTokenUrl);
resource.setUserAuthorizationUri(vaultUserAuthorizationUrl);
resource.setUseCurrentUri(false);
resource.setPreEstablishedRedirectUri(appRedirectUrl);
resource.setClientId(appClientId);
resource.setClientSecret(appClientSecret);
resource.setClientAuthenticationScheme(AuthenticationScheme.form);
return resource;
}
@Bean
ResourceServerTokenServices oAuth2RemoteTokenServices() {
VaultTokenServices tokenServices = new VaultTokenServices();
RestTemplate restOperations = new RestTemplate();
restOperations.setMessageConverters(Arrays.asList(jackson2HttpMessageConverter));
tokenServices.setRestTemplate(restOperations);
tokenServices.setClientId(appClientId);
tokenServices.setClientSecret(appClientSecret);
tokenServices.setCheckTokenEndpointUrl(vaultCheckTokenUrl);
return tokenServices;
}
@Bean
LoginUrlAuthenticationEntryPoint oAuth2AuthenticationEntryPoint() {
return new LoginUrlAuthenticationEntryPoint("/vaultLogin");
}
@Bean
OAuth2ClientAuthenticationProcessingFilter oAuth2ClientAuthenticationProcessingFilter() {
OAuth2ClientAuthenticationProcessingFilter filter =
new OAuth2ClientAuthenticationProcessingFilter("/vaultLogin");
filter.setRestTemplate(oAuth2RestOperations());
filter.setTokenServices(oAuth2RemoteTokenServices());
return filter;
}
}
}