Spring Security OAuth2重定向循环

时间:2014-11-14 20:31:29

标签: spring-security spring-boot spring-security-oauth2

我有一个带依赖关系的oauth2客户端spring-boot应用程序:   - spring-boot 1.2.0.RC1   - spring-security-oauth2 2.0.4.RELEASE   - spring-security 3.2.5.RELEASE

客户端进行身份验证,身份验证在SecurityContextHolder中设置,但是当请求重定向到原始URL时,过滤器链会再次开始处理。我注意到在SecurityContextPersistenceFilter contextBeforeChainExecution和contextAfterChainExecution都有一个空认证。

我基于[1] Spring Security OAuth2 (google) web app in redirect loop

的一些代码

关于为什么重定向循环的任何想法?先感谢您。

[Logs snippet] https://gist.github.com/yterradas/61da3f6eccc683b3a086

以下是安全配置。

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

  }
}

3 个答案:

答案 0 :(得分:2)

我认为你有2 OAuth2ClientContextFilters(一个是@EnableOAuth2Client添加的,你已经手动添加了另一个到Spring Security过滤器链)。您应该能够删除添加的那个。

答案 1 :(得分:0)

我找到了一个平庸的解决方案,它需要从SecurityFilterChain中删除几乎所有的过滤器。不幸的是,我没有我工作的应用程序的工作副本。但是,通过在打破应用程序之前删除尽可能多的过滤器然后只添加必要的过滤器来复制解决方案应该很容易。如果内存为我提供服务,那么罪魁祸首就是SecurityContextPersistenceFilter或RequestCacheAwareFilter。

答案 2 :(得分:0)

对于其他可能遇到同样问题的人 - 使用Spring Security oAuth时的重定向循环。我有这个,因为我在阻止任何直接访问Internet的防火墙后面,我的Spring Boot + Security应用程序需要调用位于Internet上的IdP的userinfo端点,例如Okta,Google等您可以通过在本地运行配置中配置代理来修复它,如下所示:

-Dhttp.proxyHost=yourhttpproxy.company.com 
-Dhttp.proxyPort=yourhttproxyport
-Dhttp.nonProxyHosts=”localhost|*.yourintranetdomain1.com|*.yourintranetdomain2.com|etc” 
-Dhttps.proxyHost=yourhttpsproxy.company.com
-Dhttps.proxyPort=yourhttpsproxyport 
-Dhttps.nonProxyHosts=”localhost|*.yourintranetdomain1.com|*.yourintranetdomain2.com|etc”

我希望这会有所帮助。