您的位置:首页 > 编程语言 > Java开发

JAVA实现:使用sAMAccountName作为登录名通过LDAP目录库验证

2009-09-08 16:24 841 查看
(转载请注明出处为本博客)

(2-2009至6-2009)要做一套对项目开发、跟踪、管理、多服务器同步备份的系统集成。主要结合svn、apache、tomcat、bugzilla、sendmail、openSSL、LDAP这些开源优秀软件在ubuntu下实现。其中涉及到JAVA EE的WEB开发,EMAIL、NDS应用模块的配置和结合,数据加密,项目管理过程设计,SVN数据的备份与恢复等等。而我和几个teammates主要负责开发一个web应用程序,对svn中各个库的用户权限进行详细管理。

Linux下这些软件的结合是由一位Linux高手用了两个月时间,一步一步的配置起来,间中遇到的各种各样问题,在大家的努力下,终于把整个系统搭建起来。

因为公司原来就已经组建了一个非常完善的LDAP目录库,LDAP目录库,就像一个通信录,里面已经存放了所以公司人员的基本信息(如姓名,邮箱,职位等等)。这里有一个前提:所有的公司员工作为用户都可以登录这个web应用程序,登录后,系统则再根据那些SVN库对于这个用户是否有开放访问权限,如果有,则展现给用户。所以我们可以充分利用这个LDAP目录库,非常方便的管理这个WEB应用程序的使用用户。

现在不谈整个验证过程,就谈谈登录时,如何匹配LDAP目录库的信息,从而通过登录验证。匹配LDAP目录库记录时,要求要提供以下信息:LDAP目录库地址,基准DN,个人的CN,登录密码。如下面的一个例子:

LDAP目录库地址: ldap://10.67.10.2:3268/
基准DN: DC=corp,DC=sb
个人的CN: CN=Xiaopeng Deng,OU=HR,DC=CN,DC=corp,DC=sb
登录密码: 123456

sAMAccountName是个人的CN结点中的一个属性,例如上述的个人的CN的sAMAccountName的值为:xdeng。我命名它为shortname,即短名。在外国非常流行于使用shortname作为个人在公司中的称号,包括用于各种系统的登录。现在这个web应用程序也要使用这个sAMAccountName作为登录名登录。查了JAVA操作LDAP库的包,解决方法还是有的:

1,用户提供了sAMAccountName和密码,想登录系统。

2,首先要使用一个已知个人的CN及其密码,登录到LDAP目录库。登录成功后,这里会返回一个LDAP上下文类:InitialLdapContext。

3,利用这个上下文类中的方法:SearchControls,可以根据搜索条件字符串返回一个枚举类:NamingEnumeration,这时的搜索条件就可以指定sAMAccountName的值为用户输入的shortname。

4,如果搜索返回的枚举类中有值,则可以从这个对象中获取得它的 CN值。没有,则说明不存在这个用户

5,再根据这个CN值,和用户提供的密码,进行LDAP目录库的登录验证匹配过程。

目的其实非常单纯:先用一个已知的CN及其密码通过LDAP目录库验证,然后就可以查找到用户提供的shortname的对应CN是什么,最后就利用这个CN和用户提供的密码验证。最重要就是获得用户shortname的对应CN!

具体的类代码分享出来:(其中部分经过了我老大的修改后,更加完善,老大厉害!)

使用单态模式

代码中的bindDN,bindPassword变量值就是首先知道的CN及其密码,值放在资源文件中。

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.Hashtable;
import java.util.Properties;

import javax.naming.Context;
import javax.naming.NameClassPair;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.ldap.Control;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
import javax.naming.ldap.SortControl;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.util.Constant;

/**
* LDAP Connector seems like JDBC, supposed to interface with AD.
*
* Use singleton pattern to prevent multi-instances.
*
*/
public class LDAPConnector {
/** Logger for this class and subclasses */
protected final Log log = LogFactory.getLog(getClass());
private static LDAPConnector instance;
private String url;
private String baseDN;
private String bindDN;
private String bindPassword;
private final Hashtable<String, String> env = new Hashtable<String, String>();
private final Control[] sortConnCtls = new SortControl[1];

{
try {
sortConnCtls[0] = new SortControl("sAMAccountName", Control.CRITICAL);
} catch (IOException ex) {
}
}

private LDAPConnector() {
try {
URL fileUrl = getClass().getClassLoader().getResource(Constant.FILE_LDAP_CONFIG);
File resource = new File(fileUrl.getFile());
Properties properties = new Properties();
properties.load(new FileInputStream(resource));
url = properties.getProperty("url");
baseDN = properties.getProperty("baseDN");
bindDN = properties.getProperty("bindDN");
bindPassword = properties.getProperty("bindPassword");
// set up environment for creating initial context
env.put(Context.PROVIDER_URL, url + baseDN);
env.put(Context.SECURITY_PRINCIPAL, bindDN);
env.put(Context.SECURITY_CREDENTIALS, bindPassword);
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put("java.naming.batchsize", "50");
env.put("com.sun.jndi.ldap.connect.timeout", "3000");
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put("com.sun.jndi.ldap.connect.pool", "true");
// the following pool parameters doesn't work
// must setup as java init parameters
env.put("com.sun.jndi.ldap.connect.pool.maxsize", "3");
env.put("com.sun.jndi.ldap.connect.pool.prefsize", "1");
env.put("com.sun.jndi.ldap.connect.pool.timeout", "300000");
env.put("com.sun.jndi.ldap.connect.pool.initsize", "1");
env.put("com.sun.jndi.ldap.connect.pool.authentication", "simple");

} catch (Exception e) {
// ignore error
e.printStackTrace();
}
}

public static LDAPConnector getInstance() {
if (instance == null)
instance = new LDAPConnector();
return instance;
}

public boolean validateUser(String username, String password) {
boolean passed = false;
LdapContext dirContext = null;
try {
// create initial context
dirContext = new InitialLdapContext(env, sortConnCtls);
dirContext.setRequestControls(sortConnCtls);
SearchControls controls = new SearchControls();
controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
String filter = "(sAMAccountName=" + username + ")";
NamingEnumeration<?> answer = dirContext.search("", filter, controls);
String userDN = null;
while (answer.hasMore()) {
userDN = ((NameClassPair) answer.nextElement()).getName();
}
// set up environment for creating initial context
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.PROVIDER_URL, url + baseDN);
env.put(Context.SECURITY_PRINCIPAL, userDN + "," + baseDN);
env.put(Context.SECURITY_CREDENTIALS, password);
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put("com.sun.jndi.ldap.connect.timeout", "1000");
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");

// create initial context
DirContext context = new InitialDirContext(env);
passed = true;
context.close();
} catch (NamingException e) {
// ignore error
// e.printStackTrace();
} finally {
if (dirContext != null) {
try {
dirContext.close();
} catch (NamingException e) {
e.printStackTrace();
}
}

}
return passed;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: