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 安全提供类 LdapContextSource
和MultipleLdapAuthoritiesPopulator
允许在不同位置搜索角色。
现在这里是将导致如下所示错误的代码:
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
总结一下:我的凭据对于单个组库是正确的,无需使用 LdapContextSource
和 MultipleLdapAuthoritiesPopulator
。但是认证过程似乎没有为我的多组用户提供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)
;
您看到不再需要三个不同的节点,也不再需要转发自定义上下文对象,只需添加组搜索基础的父节点,让子树搜索完成剩下的工作。
自己想办法可能会很好,但是使用框架的集成解决方案肯定是更好的方法。
这个问题是关于如何使用多个组搜索库而不是一个。
我使用了 samaddico 提供的示例(简单 spring 安全 + LDAP 示例),使用提供的服务器/用户/LDAP 配置文本修改了它以用于单个组搜索库。它使用服务帐户连接到 ldap 和用户,然后尝试对某些简单网页进行身份验证。 这种方法有效,但无法从搜索树中的不同组收集成员资格/角色。
Spring 安全提供类 LdapContextSource
和MultipleLdapAuthoritiesPopulator
允许在不同位置搜索角色。
现在这里是将导致如下所示错误的代码:
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
总结一下:我的凭据对于单个组库是正确的,无需使用 LdapContextSource
和 MultipleLdapAuthoritiesPopulator
。但是认证过程似乎没有为我的多组用户提供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)
;
您看到不再需要三个不同的节点,也不再需要转发自定义上下文对象,只需添加组搜索基础的父节点,让子树搜索完成剩下的工作。
自己想办法可能会很好,但是使用框架的集成解决方案肯定是更好的方法。