Java Spring LDAP 身份验证:总是失败但在 Nodejs 中测试类似配置时工作正常
Java Spring LDAP Auth: always failed but works fine for testing similar configurations in Nodejs
我对 Java/Spring 很陌生。如果需要更多信息,请随时指出。
首先,我在 Javascript(nodejs) 中测试了以下代码 ,它工作正常。
var ldap = require('ldapjs');
var client = ldap.createClient({
url: 'ldap://xx.xx.xx.xx:389'
});
client.bind('domain\user1', 'user1_password', function (err) {
if (err) {
throw err;
return
}
var opts = {
filter: '(sAMAccountName=user2)',
scope: 'sub',
attributes: ['l', 'sn', 'cn', 'mail', 'displayName', 'postalCode', 'physicalDeliveryOfficeName', 'telephoneNumber' ]
};
client.search('dc=aaa,dc=bbb,dc=ccc', opts, function(err, res) {
res.on('searchEntry', function(entry) {
Object.entries(entry.object).forEach(([key, value]) => {
console.log('Found Attribute: ', key, '; value:', value)
})
});
});
然后按照本指南进行操作:
我把和上面一样的配置应用到spring/security.xml,比如:
<bean id="customUserContextMapper" class="com.my.own.util.CustomUserDetailsMapper"/>
<sec:authentication-manager>
<sec:ldap-authentication-provider
user-search-base="dc=aaa,dc=bbb,dc=ccc"
user-search-filter="(sAMAccountName={0})"
user-context-mapper-ref="customUserContextMapper"
/>
</sec:authentication-manager>
<sec:ldap-server url="ldap://xx.xx.xx.xx:389/"
manager-dn="domain\user1"
manager-password="user1_password"
/>
但是它失败了。
如果提交 (http-post) 一个表单(用户名使用 domain\username)像 username=domain%5Cuser1&password=user1_password&submit=Login
,它returned 原因:凭据错误
如果像 username=user1&password=user1_password&submit=Login
一样提交 (http-post) 一个表单(用户名不包含域 ),它 returned 500 错误:
org.springframework.ldap.NameNotFoundException:[LDAP:错误代码 32 - 0000208D:NameErr:DSID-031001E5,问题 2001 (NO_OBJECT),数据 0,最佳匹配:
''
];嵌套异常是 javax.naming.NameNotFoundException:[LDAP:错误代码 32 - 0000208D:NameErr:DSID-031001E5,问题 2001 (NO_OBJECT),数据 0,最佳匹配:
''
];剩余姓名 ''
对于第一种情况,条目似乎存在但未能验证密码。所以 return 凭据错误 .
对于第二种情况,错误似乎是说搜索过滤器是错误的(正如CAS AD LDAP 32 error所指出的)
但我确定我输入了正确的用户名和密码,并且搜索过滤器与已经在 nodejs 中测试过的相同。
这个问题已经纠结很久了,一直找不到解决办法。
感谢任何建议和解决方案。
注意:我在class=com.my.own.util.CustomUserDetailsMapper
的入口处设置了断点,但是一直没有触发,所以没有附上它的代码。
最后,我发现下面的配置运行良好。
下面<bean id="ldapAuthProvider">
构造两个参数,
第一个参数: 会验证终端用户在前端填写的用户名和密码
第二个参数:一旦成功通过验证器,它将调用我们自己的填充器(<bean class="com.my.own.util.MyCustomLdapAuthPopulator">
)来分配适当的角色或做其他事情你'我喜欢。
<sec:authentication-manager>
<sec:authentication-provider
ref="ldapAuthProvider"
>
</sec:authentication-provider>
</sec:authentication-manager>
<bean id="ldapAuthProvider"
class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider" >
<constructor-arg>
<bean id="authenticator"
class="org.springframework.security.ldap.authentication.BindAuthenticator">
<constructor-arg ref="contextSource" />
<property name="userSearch">
<bean
class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
<constructor-arg value="dc=aaa,dc=bbb,dc=ccc" />
<constructor-arg value="(sAMAccountName={0})" />
<constructor-arg ref="contextSource" />
</bean>
</property>
</bean>
</constructor-arg>
<constructor-arg>
<bean class="com.my.own.util.MyCustomLdapAuthPopulator">
<constructor-arg ref="contextSource" />
<constructor-arg value="dc=aaa,dc=bbb,dc=ccc" />
<property name="searchSubtree" value="true" />
<property name="ignorePartialResultException" value="true" />
<property name="groupSearchFilter" value="(member={0})" />
</bean>
</constructor-arg>
</bean>
<bean id="contextSource"
class="org.springframework.security.ldap.DefaultSpringSecurityContextSource" >
<constructor-arg value="ldap://xx.xx.xx.xx:389/" />
<property name="userDn" value="domain\user1" />
<property name="password" value="user1_password" />
</bean>
下面是我们自己的填充器的一个简单实现。
import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator;
public class MyCustomLdapAuthPopulator extends DefaultLdapAuthoritiesPopulator {
@Autowired
public MyCustomLdapAuthPopulator(ContextSource contextSource, String groupSearchBase) {
super(contextSource, groupSearchBase);
// TODO Auto-generated constructor stub
}
@Override
protected Set<GrantedAuthority> getAdditionalRoles(DirContextOperations user, String username) {
Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
authorities.add((new SimpleGrantedAuthority("ROLE_XXX")));
return authorities;
}
}
我对 Java/Spring 很陌生。如果需要更多信息,请随时指出。
首先,我在 Javascript(nodejs) 中测试了以下代码 ,它工作正常。
var ldap = require('ldapjs');
var client = ldap.createClient({
url: 'ldap://xx.xx.xx.xx:389'
});
client.bind('domain\user1', 'user1_password', function (err) {
if (err) {
throw err;
return
}
var opts = {
filter: '(sAMAccountName=user2)',
scope: 'sub',
attributes: ['l', 'sn', 'cn', 'mail', 'displayName', 'postalCode', 'physicalDeliveryOfficeName', 'telephoneNumber' ]
};
client.search('dc=aaa,dc=bbb,dc=ccc', opts, function(err, res) {
res.on('searchEntry', function(entry) {
Object.entries(entry.object).forEach(([key, value]) => {
console.log('Found Attribute: ', key, '; value:', value)
})
});
});
然后按照本指南进行操作:
我把和上面一样的配置应用到spring/security.xml,比如:
<bean id="customUserContextMapper" class="com.my.own.util.CustomUserDetailsMapper"/>
<sec:authentication-manager>
<sec:ldap-authentication-provider
user-search-base="dc=aaa,dc=bbb,dc=ccc"
user-search-filter="(sAMAccountName={0})"
user-context-mapper-ref="customUserContextMapper"
/>
</sec:authentication-manager>
<sec:ldap-server url="ldap://xx.xx.xx.xx:389/"
manager-dn="domain\user1"
manager-password="user1_password"
/>
但是它失败了。
如果提交 (http-post) 一个表单(用户名使用 domain\username)像
username=domain%5Cuser1&password=user1_password&submit=Login
,它returned 原因:凭据错误如果像
username=user1&password=user1_password&submit=Login
一样提交 (http-post) 一个表单(用户名不包含域 ),它 returned 500 错误:org.springframework.ldap.NameNotFoundException:[LDAP:错误代码 32 - 0000208D:NameErr:DSID-031001E5,问题 2001 (NO_OBJECT),数据 0,最佳匹配: '' ];嵌套异常是 javax.naming.NameNotFoundException:[LDAP:错误代码 32 - 0000208D:NameErr:DSID-031001E5,问题 2001 (NO_OBJECT),数据 0,最佳匹配: '' ];剩余姓名 ''
对于第一种情况,条目似乎存在但未能验证密码。所以 return 凭据错误 .
对于第二种情况,错误似乎是说搜索过滤器是错误的(正如CAS AD LDAP 32 error所指出的)
但我确定我输入了正确的用户名和密码,并且搜索过滤器与已经在 nodejs 中测试过的相同。
这个问题已经纠结很久了,一直找不到解决办法。
感谢任何建议和解决方案。
注意:我在class=com.my.own.util.CustomUserDetailsMapper
的入口处设置了断点,但是一直没有触发,所以没有附上它的代码。
最后,我发现下面的配置运行良好。
下面<bean id="ldapAuthProvider">
构造两个参数,
第一个参数: 会验证终端用户在前端填写的用户名和密码
第二个参数:一旦成功通过验证器,它将调用我们自己的填充器(<bean class="com.my.own.util.MyCustomLdapAuthPopulator">
)来分配适当的角色或做其他事情你'我喜欢。
<sec:authentication-manager>
<sec:authentication-provider
ref="ldapAuthProvider"
>
</sec:authentication-provider>
</sec:authentication-manager>
<bean id="ldapAuthProvider"
class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider" >
<constructor-arg>
<bean id="authenticator"
class="org.springframework.security.ldap.authentication.BindAuthenticator">
<constructor-arg ref="contextSource" />
<property name="userSearch">
<bean
class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
<constructor-arg value="dc=aaa,dc=bbb,dc=ccc" />
<constructor-arg value="(sAMAccountName={0})" />
<constructor-arg ref="contextSource" />
</bean>
</property>
</bean>
</constructor-arg>
<constructor-arg>
<bean class="com.my.own.util.MyCustomLdapAuthPopulator">
<constructor-arg ref="contextSource" />
<constructor-arg value="dc=aaa,dc=bbb,dc=ccc" />
<property name="searchSubtree" value="true" />
<property name="ignorePartialResultException" value="true" />
<property name="groupSearchFilter" value="(member={0})" />
</bean>
</constructor-arg>
</bean>
<bean id="contextSource"
class="org.springframework.security.ldap.DefaultSpringSecurityContextSource" >
<constructor-arg value="ldap://xx.xx.xx.xx:389/" />
<property name="userDn" value="domain\user1" />
<property name="password" value="user1_password" />
</bean>
下面是我们自己的填充器的一个简单实现。
import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator;
public class MyCustomLdapAuthPopulator extends DefaultLdapAuthoritiesPopulator {
@Autowired
public MyCustomLdapAuthPopulator(ContextSource contextSource, String groupSearchBase) {
super(contextSource, groupSearchBase);
// TODO Auto-generated constructor stub
}
@Override
protected Set<GrantedAuthority> getAdditionalRoles(DirContextOperations user, String username) {
Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
authorities.add((new SimpleGrantedAuthority("ROLE_XXX")));
return authorities;
}
}