java实现LDAP目录登陆验证

(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及其密码,值放在资源文件中。

  1. import java.io.File; 
  2. import java.io.FileInputStream; 
  3. import java.io.IOException; 
  4. import java.net.URL; 
  5. import java.util.Hashtable; 
  6. import java.util.Properties; 
  7.  
  8. import javax.naming.Context; 
  9. import javax.naming.NameClassPair; 
  10. import javax.naming.NamingEnumeration; 
  11. import javax.naming.NamingException; 
  12. import javax.naming.directory.DirContext; 
  13. import javax.naming.directory.InitialDirContext; 
  14. import javax.naming.directory.SearchControls; 
  15. import javax.naming.ldap.Control; 
  16. import javax.naming.ldap.InitialLdapContext; 
  17. import javax.naming.ldap.LdapContext; 
  18. import javax.naming.ldap.SortControl; 
  19.  
  20. import org.apache.commons.logging.Log; 
  21. import org.apache.commons.logging.LogFactory; 
  22.  
  23. import com.util.Constant; 
  24.  
  25. /**
  26. * LDAP Connector seems like JDBC, supposed to interface with AD.
  27. *
  28. * Use singleton pattern to prevent multi-instances.
  29. *
  30. */ 
  31. public class LDAPConnector { 
  32.     /** Logger for this class and subclasses */ 
  33.     protected final Log log = LogFactory.getLog(getClass()); 
  34.     private static LDAPConnector instance; 
  35.     private String url; 
  36.     private String baseDN; 
  37.     private String bindDN; 
  38.     private String bindPassword; 
  39.     private final Hashtable<String, String> env =new Hashtable<String, String>(); 
  40.     private final Control[] sortConnCtls =new SortControl[1]; 
  41.  
  42.     { 
  43.         try
  44.             sortConnCtls[0] = new SortControl("sAMAccountName", Control.CRITICAL); 
  45.         } catch (IOException ex) { 
  46.         } 
  47.     } 
  48.  
  49.     private LDAPConnector() { 
  50.         try
  51.             URL fileUrl = getClass().getClassLoader().getResource(Constant.FILE_LDAP_CONFIG); 
  52.             File resource = new File(fileUrl.getFile()); 
  53.             Properties properties = new Properties(); 
  54.             properties.load(new FileInputStream(resource)); 
  55.             url = properties.getProperty("url"); 
  56.             baseDN = properties.getProperty("baseDN"); 
  57.             bindDN = properties.getProperty("bindDN"); 
  58.             bindPassword = properties.getProperty("bindPassword"); 
  59.             // set up environment for creating initial context 
  60.             env.put(Context.PROVIDER_URL, url + baseDN); 
  61.             env.put(Context.SECURITY_PRINCIPAL, bindDN); 
  62.             env.put(Context.SECURITY_CREDENTIALS, bindPassword); 
  63.             env.put(Context.SECURITY_AUTHENTICATION, "simple"); 
  64.             env.put("java.naming.batchsize","50"); 
  65.             env.put("com.sun.jndi.ldap.connect.timeout","3000"); 
  66.             env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); 
  67.             env.put("com.sun.jndi.ldap.connect.pool","true"); 
  68.             // the following pool parameters doesn't work 
  69.             // must setup as java init parameters 
  70.             env.put("com.sun.jndi.ldap.connect.pool.maxsize","3"); 
  71.             env.put("com.sun.jndi.ldap.connect.pool.prefsize","1"); 
  72.             env.put("com.sun.jndi.ldap.connect.pool.timeout","300000"); 
  73.             env.put("com.sun.jndi.ldap.connect.pool.initsize","1"); 
  74.             env.put("com.sun.jndi.ldap.connect.pool.authentication","simple"); 
  75.  
  76.         } catch (Exception e) { 
  77.             // ignore error 
  78.             e.printStackTrace(); 
  79.         } 
  80.     } 
  81.  
  82.     public static LDAPConnector getInstance() { 
  83.         if (instance == null
  84.             instance = new LDAPConnector(); 
  85.         return instance; 
  86.     } 
  87.  
  88.     public boolean validateUser(String username, String password) { 
  89.         boolean passed =false
  90.         LdapContext dirContext = null
  91.         try
  92.             // create initial context 
  93.             dirContext = new InitialLdapContext(env, sortConnCtls); 
  94.             dirContext.setRequestControls(sortConnCtls); 
  95.             SearchControls controls = new SearchControls(); 
  96.             controls.setSearchScope(SearchControls.SUBTREE_SCOPE); 
  97.             String filter = "(sAMAccountName=" + username +")"
  98.             NamingEnumeration<?> answer = dirContext.search("", filter, controls); 
  99.             String userDN = null
  100.             while (answer.hasMore()) { 
  101.                 userDN = ((NameClassPair) answer.nextElement()).getName(); 
  102.             } 
  103.             // set up environment for creating initial context 
  104.             Hashtable<String, String> env = new Hashtable<String, String>(); 
  105.             env.put(Context.PROVIDER_URL, url + baseDN); 
  106.             env.put(Context.SECURITY_PRINCIPAL, userDN + "," + baseDN); 
  107.             env.put(Context.SECURITY_CREDENTIALS, password); 
  108.             env.put(Context.SECURITY_AUTHENTICATION, "simple"); 
  109.             env.put("com.sun.jndi.ldap.connect.timeout","1000"); 
  110.             env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); 
  111.  
  112.             // create initial context 
  113.             DirContext context = new InitialDirContext(env); 
  114.             passed = true
  115.             context.close(); 
  116.         } catch (NamingException e) { 
  117.             // ignore error 
  118.             // e.printStackTrace(); 
  119.         } finally
  120.             if (dirContext != null) { 
  121.                 try
  122.                     dirContext.close(); 
  123.                 } catch (NamingException e) { 
  124.                     e.printStackTrace(); 
  125.                 } 
  126.             } 
  127.  
  128.         } 
  129.         return passed; 
  130.     } 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值