(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
2. import
3. import
4. import
5. import
6. import
7.   
8. import
9. import
10. import
11. import
12. import
13. import
14. import
15. import
16. import
17. import
18. import
19.   
20. import
21. import
22.   
23. import
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
32. /** Logger for this class and subclasses */
33. protected final
34. private static
35. private
36. private
37. private
38. private
39. private final Hashtable<String, String> env =new
40. private final Control[] sortConnCtls =new SortControl[1]; 
41.   
42.     {  
43. try
44. 0] =  new SortControl("sAMAccountName", Control.CRITICAL); 
45. catch
46.         }  
47.     }  
48.   
49. private
50. try
51.             URL fileUrl = getClass().getClassLoader().getResource(Constant.FILE_LDAP_CONFIG); 
52. new
53. new
54. new
55. "url"); 
56. "baseDN"); 
57. "bindDN"); 
58. "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.  "simple");  
64. "java.naming.batchsize","50");  
65. "com.sun.jndi.ldap.connect.timeout","3000");  
66.  "com.sun.jndi.ldap.LdapCtxFactory");  
67. "com.sun.jndi.ldap.connect.pool","true");  
68. // the following pool parameters doesn't work
69. // must setup as java init parameters
70. "com.sun.jndi.ldap.connect.pool.maxsize","3");  
71. "com.sun.jndi.ldap.connect.pool.prefsize","1");  
72. "com.sun.jndi.ldap.connect.pool.timeout","300000");  
73. "com.sun.jndi.ldap.connect.pool.initsize","1");  
74. "com.sun.jndi.ldap.connect.pool.authentication","simple");  
75.   
76. catch
77. // ignore error
78.             e.printStackTrace();  
79.         }  
80.     }  
81.   
82. public static
83. if (instance ==  null)  
84. new
85. return
86.     }  
87.   
88. public boolean
89. boolean passed =false;  
90. null; 
91. try
92. // create initial context
93. new
94.             dirContext.setRequestControls(sortConnCtls);  
95.  new
96.             controls.setSearchScope(SearchControls.SUBTREE_SCOPE);   
97. "(sAMAccountName=" + username +")";  
98. "", filter, controls); 
99. null; 
100. while
101.                 userDN = ((NameClassPair) answer.nextElement()).getName(); 
102.             }  
103. // set up environment for creating initial context
104. new
105.             env.put(Context.PROVIDER_URL, url + baseDN);   
106.  ","
107.             env.put(Context.SECURITY_CREDENTIALS, password); 
108.  "simple");  
109. "com.sun.jndi.ldap.connect.timeout","1000");  
110.  "com.sun.jndi.ldap.LdapCtxFactory");  
111.   
112. // create initial context
113. new
114. true;  
115.             context.close();  
116. catch
117. // ignore error
118. // e.printStackTrace();
119. finally
120. if (dirContext !=  null) {  
121. try
122.                     dirContext.close();  
123. catch
124.                     e.printStackTrace();  
125.                 }  
126.             }  
127.   
128.         }  
129. return
130.     }  
131. }