通常在根据LDAP进行身份验证时会采取以下三种方法:
1、利用一个LDAP用户的用户名和密码绑定到LDAP服务器。
2、在LDAP中检索一个用户的条目,然后将提供的密码和检索到的LDAP记录中的密码属性相比较。
3、“两次绑定”验证方法。
基于LDAP进行身份验证,最好也是最通用的方法就是 “两次绑定”。这种方法的步骤以及优点可参看我的另一篇博客:基于LDAP进行验证-方法和问题
当前Shiro只支持了第一种方法,即使用用户名和密码到LDAP服务器中进行绑定来判断合法性。
我自己写了一个认证类,实现了“两次绑定”验证。同时解决了目前做LDAP认证时没有区分错误情况,返回的错误提示信息不够准确的问题。
配置信息:
- [main]
- ldapRealm = main.java.name.peter.shiro.realm.ldap.LdapAuthenticator
- ldapRealm.rootDN = dc=example,dc=com
- ldapRealm.contextFactory.url = ldap://localhost:389
- ldapRealm.contextFactory.systemUsername = cn=Manager,dc=example,dc=com
- ldapRealm.contextFactory.systemPassword = secret
认证类:
- /***
- * 基于Ldap进行身份认证,二次绑定方式.
- *
- * @author wanghao
- *
- */
- public class LdapAuthenticator extends JndiLdapRealm {
-
- private static final Logger log = LoggerFactory
- .getLogger(LdapAuthenticator.class);
- private String rootDN;
-
- public LdapAuthenticator() {
- super();
- }
-
- public String getRootDN() {
- return rootDN;
- }
-
- public void setRootDN(String rootDN) {
- this.rootDN = rootDN;
- }
-
- @Override
- /***
- * 认证
- */
- protected AuthenticationInfo doGetAuthenticationInfo(
- AuthenticationToken token) throws AuthenticationException {
- AuthenticationInfo info;
- try {
- info = queryForAuthenticationInfo(token, getContextFactory());
- } catch (AuthenticationNotSupportedException e) {
- String msg = "Unsupported configured authentication mechanism";
- throw new UnsupportedAuthenticationMechanismException(msg, e);
- } catch (javax.naming.AuthenticationException e) {
- String msg = "LDAP authentication failed.";
- throw new AuthenticationException(msg, e);
- } catch (NamingException e) {
- String msg = "LDAP naming error while attempting to authenticate user.";
- throw new AuthenticationException(msg, e);
- } catch (UnknownAccountException e) {
- String msg = "UnknownAccountException";
- throw new UnknownAccountException(msg, e);
- } catch (IncorrectCredentialsException e) {
- String msg = "IncorrectCredentialsException";
- throw new IncorrectCredentialsException(msg, e);
- }
-
- return info;
- }
-
- @Override
- protected AuthenticationInfo queryForAuthenticationInfo(
- AuthenticationToken token, LdapContextFactory ldapContextFactory)
- throws NamingException {
-
- Object principal = token.getPrincipal();
- Object credentials = token.getCredentials();
-
- LdapContext systemCtx = null;
- LdapContext ctx = null;
- try {
- systemCtx = ldapContextFactory.getSystemLdapContext();
-
- SearchControls constraints = new SearchControls();
- constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
- NamingEnumeration results = systemCtx.search(rootDN, "cn="
- + principal, constraints);
- if (results != null && !results.hasMore()) {
- throw new UnknownAccountException();
- } else {
- while (results.hasMore()) {
- SearchResult si = (SearchResult) results.next();
- principal = si.getName() + "," + rootDN;
- }
- log.info("DN="+principal);
- try {
- ctx = ldapContextFactory.getLdapContext(principal,
- credentials);
- } catch (NamingException e) {
- throw new IncorrectCredentialsException();
- }
- return createAuthenticationInfo(token, principal, credentials,
- ctx);
- }
- } finally {
- LdapUtils.closeContext(systemCtx);
- LdapUtils.closeContext(ctx);
- }
- }
- }
|