Spring 具有多个搜索库组的安全 5 失败,而具有相同凭据的单个组库则不会。我在这里想念什么?

Spring Security 5 with multiple searchbase groups fails while singel group base with same credentials does not. What do i miss here?

这个问题是关于如何使用多个组搜索库而不是一个。

我使用了 samaddico 提供的示例(简单 spring 安全 + LDAP 示例),使用提供的服务器/用户/LDAP 配置文本修改了它以用于单个组搜索库。它使用服务帐户连接到 ldap 和用户,然后尝试对某些简单网页进行身份验证。 这种方法有效,但无法从搜索树中的不同组收集成员资格/角色。

Spring 安全提供类 LdapContextSourceMultipleLdapAuthoritiesPopulator 允许在不同位置搜索角色。 现在这里是将导致如下所示错误的代码:

LDAP 配置:

* Create an implementation of org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator which can call 
multiple instances of LdapAuthoritiesPopulator.
 * Then create one LdapAuthoritiesPopulatorfor each 'groupSearchBase' that I wanted to query.

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

        LdapContextSource contextSource =   contextSource();

        MultipleLdapAuthoritiesPopulator multipleLdapAuthoritiesPopulator = new MultipleLdapAuthoritiesPopulator(
        new DefaultLdapAuthoritiesPopulator(contextSource, ldapGroupSearchBaseA),
        new DefaultLdapAuthoritiesPopulator(contextSource, ldapGroupSearchBaseB),
        new DefaultLdapAuthoritiesPopulator(contextSource, ldapGroupSearchBaseC));

        auth
            .ldapAuthentication()
            .contextSource(contextSource)
            .ldapAuthoritiesPopulator(multipleLdapAuthoritiesPopulator)
            .userSearchFilter(ldapUserSearchFilter)
            .userSearchBase(ldapUserSearchBase);
    }

    class MultipleLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator {
        private List<LdapAuthoritiesPopulator> authoritiesPopulators;

        public MultipleLdapAuthoritiesPopulator(LdapAuthoritiesPopulator...authoritiesPopulators) {
            this.authoritiesPopulators = Arrays.asList(authoritiesPopulators);
        }

        @Override
        public Collection<? extends GrantedAuthority> getGrantedAuthorities(DirContextOperations userData, String username) {
            List<GrantedAuthority> grantedAuthorities = authoritiesPopulators.stream()
                    .map(authPopulator -> authPopulator.getGrantedAuthorities(userData, username))
                    .flatMap(Collection::stream)
                    .collect(Collectors.toList());
            return grantedAuthorities;
        }
    }

    /**
     * Creates context source object instead of configuring it with AuthenticationBuilder
     * @return Context source object used for accessing ldap server
     */
    @Bean
    public LdapContextSource contextSource() {
        LdapContextSource contextSource= new LdapContextSource();
        contextSource.setUrl(ldapUrl);
        contextSource.setUserDn(ldapManagerDn);
        contextSource.setPassword(ldapManagerPassword);
        contextSource.afterPropertiesSet();
        return contextSource;
    }

会话配置:

/**
 * This is essential to make sure that the Spring Security session registry is notified when the session is destroyed.
 * @return
 */
@Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
    return new HttpSessionEventPublisher();
}

Spring 应用程序告诉我,我的服务帐户已成功连接到 LDAP 服务器。

DEBUG 17220 --- [nio-8080-exec-5] o.s.s.w.a.i.FilterSecurityInterceptor    : Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@c1e15be1: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@380f4: RemoteIpAddress: 127.0.0.1; SessionId: 0A82CE8FA4FB9EB248D756EEE8134CAE; Granted Authorities: ROLE_ANONYMOUS

当找到的用户正在尝试绑定时抛出错误:

DEBUG 17220 --- [nio-8080-exec-8] o.s.s.l.a.BindAuthenticator              : Failed to bind as CN=familyName\, name,OU=Group: org.springframework.ldap.AuthenticationException: [LDAP: error code 49 - 80090308: LdapErr: DSID-0C090453, comment: AcceptSecurityContext error, data 52e, v3839 ]; nested exception is javax.naming.AuthenticationException: [LDAP: error code 49 - 80090308: LdapErr: DSID-0C090453, comment: AcceptSecurityContext error, data 52e, v3839 ]
DEBUG 17220 --- [nio-8080-exec-8] w.a.UsernamePasswordAuthenticationFilter : Authentication request failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials

总结一下:我的凭据对于单个组库是正确的,无需使用 LdapContextSourceMultipleLdapAuthoritiesPopulator。但是认证过程似乎没有为我的多组用户提供enteret密码。

在花了一些时间找出解决方案后,我不得不承认没有有效的方法来创建解决方案,即使用覆盖方法或 类。

但我无意中发现了 spring 安全性的更改请求,正是针对需要检查多个组搜索基础的这个用例。 它从 Spring 安全版本 5.4.1(我相信)开始实现,或者在使用 Spring Starter 父版本 2.4.2 时包含。

只需将选项添加到您的身份验证方法:

.groupSearchSubtree(true)

完整的身份验证更新方法示例如下所示:

    @Override
@Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{   
    auth
            .ldapAuthentication()
            .contextSource()
            .url(ldapUrl)
            .managerDn(ldapManagerDn)
            .managerPassword(ldapManagerPassword)
       .and()
            .userSearchFilter(ldapUserSearchFilter)
            .userSearchBase(ldapUserSearchBase)
            .groupSearchFilter(ldapGroupSearchFilter)
            .groupSearchBase(ldapGroupSearchBase)
            .groupSearchSubtree(true)
    ;

您看到不再需要三个不同的节点,也不再需要转发自定义上下文对象,只需添加组搜索基础的父节点,让子树搜索完成剩下的工作。

自己想办法可能会很好,但是使用框架的集成解决方案肯定是更好的方法。