【问题标题】:Is it possible to use two different AuthenticationProvider's with WebSecurityConfigurerAdapter?是否可以将两个不同的 AuthenticationProvider 与 WebSecurityConfigurerAdapter 一起使用?
【发布时间】:2016-01-12 14:33:09
【问题描述】:

我有一个基于 SpringBoot 的应用程序,具有多个端点。由于将访问端点的不同客户端,我希望有不同的身份验证提供程序来保护它们。某些端点将受 Kerberos 保护(KerberosServiceAuthenticationProvider -- http://docs.spring.io/autorepo/docs/spring-security-kerberos/1.0.0.RC1/reference/htmlsingle/)。一些端点会受到 AD/LDAP (ActiveDirectoryLdapAuthenticationProvider) 的保护。

我目前使用 Kerberos 或 LDAP,但不能同时使用:

@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
protected class ApplicationSecurity extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

//For Kerberos
        auth.authenticationProvider(kerberosAuthenticationProvider())
            .authenticationProvider(kerberosServiceAuthenticationProvider());
//For LDAP  
        //auth.authenticationProvider(customAuthenticationProvider());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
            http
                .authorizeRequests()
                    .antMatchers(HttpMethod.GET, APPLICATION_ADMIN_ENDPOINTS)
                    .permitAll()
                    .and()
                .authorizeRequests()
                    .antMatchers(HttpMethod.PUT, APPLICATION_ADMIN_ENDPOINTS)
                    .hasAnyAuthority(AUTHENTICATED_APPLICATION_ADMIN_AUTHORITIES)
                    .and()
                .authorizeRequests()
                    .antMatchers(HttpMethod.DELETE, APPLICATION_ADMIN_ENDPOINTS)
                    .hasAnyAuthority(AUTHENTICATED_APPLICATION_ADMIN_AUTHORITIES)
                    .and()
                .authorizeRequests()
                    .antMatchers(CLIENT_ENDPOINTS)
                    .permitAll()
                    .and()
                .authorizeRequests()
                    .antMatchers(SWAGGER_ENDPOINTS)
                    .permitAll()
                    .and()
                .authorizeRequests()
                    .antMatchers(MANAGER_ENDPOINTS)
                    .hasAnyAuthority(AUTHENTICATED_MANAGER_AUTHORITIES)
                    .and()
                .authorizeRequests()
                    .antMatchers(TRUSTED_AGENT_ENDPOINTS)
                    .hasAnyAuthority(AUTHENTICATED_TRUSTED_AGENT_AUTHORITIES)
                    .and()
                .authorizeRequests()
                    .antMatchers("/kerb/**")
                    .hasAnyAuthority(AUTHENTICATED_APPLICATION_ADMIN_AUTHORITIES)
                    .and()
                .addFilterBefore(spnegoAuthenticationProcessingFilter(authenticationManagerBean()), BasicAuthenticationFilter.class)
                .httpBasic()
                    .and()
                .csrf()
                    .disable();
    }
}

@Bean
public AuthenticationProvider customAuthenticationProvider() {
    ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(
            ldapDomain, ldapUrl);
    SimpleCaseAndWhitespaceMitigatingAuthoritiesMapper authoritiesMapper = new SimpleCaseAndWhitespaceMitigatingAuthoritiesMapper();
    provider.setAuthoritiesMapper(authoritiesMapper);
    provider.setConvertSubErrorCodesToExceptions(true);
    return provider;
}

@Bean
public KerberosAuthenticationProvider kerberosAuthenticationProvider() {
    KerberosAuthenticationProvider provider = new KerberosAuthenticationProvider();
    SunJaasKerberosClient client = new SunJaasKerberosClient();
    client.setDebug(true);
    provider.setKerberosClient(client);
    provider.setUserDetailsService(kerberosUserService());
    return provider;
}

@Bean
public KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider() {
    KerberosServiceAuthenticationProvider provider = new KerberosServiceAuthenticationProvider();
    provider.setTicketValidator(sunJaasKerberosTicketValidator());
    provider.setUserDetailsService(kerberosUserService());
    return provider;
}

@Bean
public SunJaasKerberosTicketValidator sunJaasKerberosTicketValidator() {
    SunJaasKerberosTicketValidator ticketValidator = new SunJaasKerberosTicketValidator();
    ticketValidator.setServicePrincipal(kerberosPrincipal);
    File f = new File(keytabFile);
    try {
        LOG.info(String.format("Absolute: %s, Canonical: %s", f.getAbsolutePath(), f.getCanonicalPath()));
        if(f.exists()){
            LOG.info("File exists.");
        }
        else{
            LOG.info("File DOES NOT exist.");
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    ticketValidator.setKeyTabLocation(new FileSystemResource(f));
    ticketValidator.setDebug(true);
    return ticketValidator;
}

@Bean
public SpnegoAuthenticationProcessingFilter spnegoAuthenticationProcessingFilter(AuthenticationManager authenticationManager) {
    SpnegoAuthenticationProcessingFilter filter = new SpnegoAuthenticationProcessingFilter();
    filter.setAuthenticationManager(authenticationManager);
    return filter;
}

@Bean
public KerberosUserDetailsService kerberosUserService() {
    return new KerberosUserDetailsService();
}

无论如何要让这对双方都有效?我正在考虑制作一个可以处理请求的自定义身份验证提供程序,但不确定这是否可行。

【问题讨论】:

  • 你到底想做什么?是否某些端点使用 kerberos 而其他端点使用您的自定义 AD 身份验证,或者两者都在所有端点上可用?一起使用时遇到了什么错误,例如auth.authenticationProvider(kerberosAuthenticationProvider()).authenticationProvider(kerberosServiceAuthenticationProvider()).authenticationProvider(customAuthenticationProvider());

标签: spring-security spring-security-kerberos


【解决方案1】:

最简单的想法是必须在你的Web.xml 中基于url 映射SpringDistpatcherServlets。然后每个 url 映射都在不同的 spring 上下文中。然后每个 spring 上下文都可以有自己的安全性。

【讨论】:

    【解决方案2】:
     public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(kerberosAuthenticationProvider());
    auth.authenticationProvider(kerberosServiceAuthenticationProvider());
        auth.authenticationProvider(customAuthenticationProvider());
    }
    

    【讨论】:

    【解决方案3】:

    您正在做的是将 Kerberos 的 authenticationProviders 和您自定义的 AuthenticationManagerBuilder 添加到 AuthenticationManagerBuilder。这应该注册所有这些。

    运行时会发生什么:

    有一个ProviderManager 处理您所有注册的AuthenticationProvider 和一个内建。

    • 首先它尝试以匿名用户身份进行身份验证。如果请求的 URL 设置为 permitAll,这就是故事的结尾
    • 然后ProviderManager 按照您提供的顺序遍历您的所有AuthenticationProvider。它检查他们是否支持身份验证并尝试与他们进行身份验证。如果失败,它会移动到下一个(如果有异常则保存异常)
    • 终于有一个DaoAuthenticationProvider 处理正常的用户名-密码-凭据
    • 如果任何提供者成功,则用户登录,否则抛出保存的异常。

    结论: 如果不是您想要的,您所做的应该非常接近。对于受 Kerberos 保护的端点,它将使用 kerberos AuthenticationProvider。对于其他端点,它会尝试使 Kerberos 失败并继续使用您的自定义提供程序。

    如果仍然无法正常工作,我建议在 org.springframework.security.authentication.ProviderManager 类中设置一个断点,看看它是如何处理您的提供者的。

    【讨论】:

      猜你喜欢
      • 2019-08-04
      • 2011-04-15
      • 2019-01-17
      • 2021-11-12
      • 2016-04-01
      • 2011-01-20
      • 2018-08-11
      • 2021-08-05
      • 2019-03-18
      相关资源
      最近更新 更多