本文共 7317 字,大约阅读时间需要 24 分钟。
这一周做LDAP做得头都大了。现在终于有点头绪了,记录一下,以备后用。
LDAP是什么?
LDAP是轻量级目录访问协议,英文全称是Lightweight Directory Access Protocol,一般都简称为LDAP.
一般用来构建集中的身份验证系统可以减少管理成本,增强安全性,避免数据复制的问题,并提高数据的一致性。
ActiveDirectory是什么?Active Directory存储了有关网络对象的信息,并且让管理员和用户能够轻松地查找和使用这些信息。Active Directory使用了一种结构化的数据存储方式,并以此作为基础对目录信息进行合乎逻辑的分层组织。①基础网络服务:包括DNS、WINS、DHCP、证书服务等。
②服务器及客户端计算机管理:管理服务器及客户端计算机账户,所有服务器及客户端计算机加入域管理并实施组策略。
③用户服务:管理用户域账户、用户信息、企业通讯录(与电子邮件系统集成)、用户组管理、用户身份认证、用户授权管理等,按省实施组管理策略。
④资源管理:管理打印机、文件共享服务等网络资源。
⑤桌面配置:系统管理员可以集中的配置各种桌面配置策略,如:界面功能的限制、应用程序执行特征限制、网络连接限制、安全配置限制等。
s⑥应用系统支撑:支持财务、人事、电子邮件、企业信息门户、办公自动化、补丁管理、防病毒系统等各种应用系统。
-------------------------------------------------------------------------------
概念都是搜出来的,不是一般的抽象。这也是我花了近一周时间才弄懂一点的原因所在。我的理解是可以把mirectory的ActiveDirectory当作一个LDAP服务器,提供LDAP验证服务。当然其他平台或公司也有自己的ldap服务器。如sun,ibm,等的。
我的需求是在EOS开发平台(基于EclipseJAVA工作流)上通过内嵌的开源ABFrame(权限管理系统)实现LDAP验证,进而实现SSO。找到了LDAP的配置文件后经过查找资料无论如何也通不过验证,还跟了很深的代码,JNDI的资料也查了很多,无果。
无奈,微软自己家东西,就试着用.net写了个程序,没有什么障碍,很简单就通过了登陆验证。代码如下:
ldap C# using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.DirectoryServices; using System.Configuration; using System.Text.RegularExpressions; namespace ldapcs{ class Program{ static void Main( string [] args){ string path = " LDAP://192.168.137.210:389/ou=pet,dc=abc,dc=com " ; string username = " uname " ; string pwd = " upwd " ; string domain = " abc.com " ;LdapAuthentication ldap = new LdapAuthentication(path);Console.WriteLine( ldap.IsAuthenticated(domain, username, pwd));Console.WriteLine(ldap.GetGroups());} public class LdapAuthentication{ private string _path; private string _filterAttribute; public LdapAuthentication( string path){ _path = path;} public bool IsAuthenticated( string domain, string username, string pwd){ string domainAndUsername = domain + @" \ " + username;DirectoryEntry entry = new DirectoryEntry(_path, username, pwd); try { // Bind to the native AdsObject to force authentication. object obj = entry.NativeObject;DirectorySearcher search = new DirectorySearcher(entry);search.Filter = " (SAMAccountName= " + username + " ) " ;search.PropertiesToLoad.Add( " cn " );SearchResult result = search.FindOne(); if ( null == result){ return false ;} // Update the new path to the user in the directory. _path = result.Path;_filterAttribute = ( string )result.Properties[ " cn " ][ 0 ];} catch (Exception ex){ throw new Exception( " Error authenticating user. " + ex.Message);} return true ;} public string GetGroups(){ DirectorySearcher search = new DirectorySearcher(_path);search.Filter = " (cn= " + _filterAttribute + " ) " ; // search.SearchRoot = "PET"; StringBuilder groupNames = new StringBuilder(); try { SearchResult result = search.FindOne(); int propertyCount = result.Properties[ " memberOf " ].Count; string dn; int equalsIndex, commaIndex; for ( int propertyCounter = 0 ; propertyCounter < propertyCount; propertyCounter ++ ){ dn = ( string )result.Properties[ " memberOf " ][propertyCounter];equalsIndex = dn.IndexOf( " = " , 1 );commaIndex = dn.IndexOf( " , " , 1 ); if ( - 1 == equalsIndex){ return null ;}groupNames.Append(dn.Substring((equalsIndex + 1 ), (commaIndex - equalsIndex) - 1 ));groupNames.Append( " | " );}} catch (Exception ex){ throw new Exception( " Error obtaining group names. " + ex.Message);} return groupNames.ToString();}} /// <summary> /// 验证AD用户是否登录成功 /// </summary> /// <param name="domain"></param> /// <param name="userName"></param> /// <param name="password"></param> /// <returns></returns> public static bool TryAuthenticate( string domain, string userName, string password){ bool isLogin = false ; try { DirectoryEntry entry = new DirectoryEntry( string .Format( " LDAP://{0} " , domain), userName, password);entry.RefreshCache();isLogin = true ;} catch { isLogin = false ;} return isLogin;}}}
再回头去用abframe的东西,还是没有结果。于是再找一个java验证的例子,还是可以通过验证
代码 /** ** @author icuit */ import java.util.Hashtable; import java.util.Enumeration; import javax.naming.Context; import javax.naming.NamingException; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; import javax.naming.directory.SearchControls ; import javax.naming.NamingEnumeration; import javax.naming.directory.SearchResult; public class LDAPtest { public static void main(String[] args) { LDAPtest ldap = new LDAPtest();ldap.init();} public void init(){ DirContext ctx = null ;Hashtable env = new Hashtable();env.put(Context.INITIAL_CONTEXT_FACTORY, " com.sun.jndi.ldap.LdapCtxFactory " );env.put(Context.PROVIDER_URL, " ldap://192.168.137.210:389/ " ); // 连接LDAP的URL和端口 // env.put(Context.SECURITY_AUTHENTICATION, "simple"); // 以simple方式发送 env.put(Context.SECURITY_PRINCIPAL, " cn=uname,ou=PET,DC=abc,DC=com " ); // 用户名 env.put(Context.SECURITY_CREDENTIALS, " upwd " ); // 密码 String baseDN = " ou=PET,DC=abc,DC=com " ; // 查询区域 String filter = " (&(objectClass=person)) " ; // 条件查询 try { ctx = new InitialDirContext(env); // 连接LDAP服务器 System.out.println( " Success " );SearchControls constraints = new SearchControls(); // 执行查询操作 constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);NamingEnumeration en = ctx.search(baseDN, filter, constraints); if (en == null ){ System.out.println( " There have no value " );} else { while (en.hasMoreElements()){ Object obj = en.nextElement(); if (obj instanceof SearchResult){ SearchResult sr = (SearchResult) obj;String cn = sr.getName();System.out.println( " cccccc: " + cn);}}}} catch (javax.naming.AuthenticationException e){ System.out.println(e.getMessage());} catch (Exception e){ System.out.println( " erro: " + e);}}} 于是又去跟abframe的代码,并重新检查文件,并查了一些关于LDAP验证参数的资料。终于可以验证,总结如下:
ldap验证有几个比较重要的参数:
ldap_base_provider_url,
ldap服务器的地址及端口,如: ldap://192.168.1.1:389/
ldap_security_principal,
用来查询验证ldap服务的用户
如 cn=uname,ou=pet,dc=abc,dc=com,或者有可能是cn=uadmin,cn=users,dc=abc,dc=com
这里是最最关键的地方,我也是在这方面花费了最多的时间,
如果服务器的域名是 abc.com 那么就要有 dc=abc,dc=com,其他情况以此类推
cn是指的用户名,但是这里有两种情况,一种是cn=uname,ou=pet,另一种是cn=uadmin,cn=users
我的猜测是如果在windows Active Directory的内建分组users下的用户则用第二种
如果是在windows Active Directory的自建分组,如组名为PET,则用第一种
dap_security_credentials,
用来查询验证ldap服务的密码,与ldap_security_principal配对 如 f34dgd
这里需要重点说明一下,ldap_security_principal与ldap_security_principal所指定的用户和密码并不是
最终要验证的用户,而是一个用来查询所要验证的用户是否存在的用户。
ldap_base_dn, ldap服务的验证基址,因为ldap是基于目录,也就有层次关系,如ou=PET,dc=intasect,dc=local
这里是需要验证的用户目录,至于参数的解释同ldap_security_principal
ldap_auth_search_filter
查询验证用户的搜索条件,一般是(objectClass=person),是什么意思我也没细去研究
ldap_auth_method
身份验证方式, bind 或 password-compare
bind 基于绑定用户身份检查,我这里采用的第一种,也许是因为windows AD是这一种,另一种无法通过
password-compare 基于加密算法,采用密码比较方法
ldap_auth_password_encryption_algorithm
密码加密方法 MD5,SHA等。
我用的是MD5
以上参数错一个可能就通不过验证,所以参数的正确性是关键。
这里留下一些参考的资料
1,LDAP验证常见的错误代码
javax.naming.AuthenticationException: [LDAP: error code 49 - 80090308: LdapErr: DSID-0C090334, comment: AcceptSecurityContext error, data 52e, vece
意思是用户名或密码错误
javax.naming.NamingException: [LDAP: error code 1 - 00000000: LdapErr: DSID-0C090AE2, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, vece
大概是查询的目录无效,应该是ou设置错误
2,参考网站
3,windows active directory在win2003上的安装方法
其实安装AD的过程也就是把此机器升级为域控制器的过程,有一点要提醒的是在升级域之前一定要备份自建账户信息
否则当降级为普通计算机时所有自建账户信息将丢失。切记。
4,在ActiveDirectory新建组,新建用户,配置域名
希望有其他朋友遇到同样问题时少走弯路。
转载地址:http://nalgb.baihongyu.com/