• 通过LDAP验证Active Directory服务


    这一周做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
    {
    staticvoid 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());
    }

    publicclass LdapAuthentication
    {
    privatestring _path;
    privatestring _filterAttribute;

    public LdapAuthentication(string path)
    {
    _path
    = path;
    }

    publicbool 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)
    {
    returnfalse;
    }

    //Update the new path to the user in the directory.
    _path = result.Path;
    _filterAttribute
    = (string)result.Properties["cn"][0];
    }
    catch (Exception ex)
    {
    thrownew Exception("Error authenticating user. "+ ex.Message);
    }

    returntrue;
    }

    publicstring 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)
    {
    returnnull;
    }
    groupNames.Append(dn.Substring((equalsIndex
    +1), (commaIndex - equalsIndex) -1));
    groupNames.Append(
    "|");
    }
    }
    catch (Exception ex)
    {
    thrownew 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>
    publicstaticbool 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;




    publicclass LDAPtest {


    publicstaticvoid main(String[] args) {
    LDAPtest ldap
    =new LDAPtest();
    ldap.init();
    }
    publicvoid 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,参考网站
    http://java.sun.com/products/jndi/tutorial/ldap/security/ldap.html
    http://new.qzone.qq.com/416276265
    http://blogger.org.cn/blog/more.asp?name=gecko&id=9149

    3,windows active directory在win2003上的安装方法
    其实安装AD的过程也就是把此机器升级为域控制器的过程,有一点要提醒的是在升级域之前一定要备份自建账户信息
    否则当降级为普通计算机时所有自建账户信息将丢失。切记。
    http://book.51cto.com/art/200805/72120.htm

    4,在ActiveDirectory新建组,新建用户,配置域名

    希望有其他朋友遇到同样问题时少走弯路。

  • 相关阅读:
    dig命令不能使用(-bash: dig: command not found)
    linux系统中的一些典型问题汇总
    Django运行项目时候出现DisallowedHost at / Invalid HTTP_HOST header:
    Grafana添加Zabbix为数据源(二)
    Grafana添加Zabbix为数据源(一)
    linux go环境安装
    centos6里面装zabbix(五)
    centos6里面装zabbix(二)
    HTTP状态码分类及异常状态码处理
    超详细 Linux 下编译安装Redis 以及php配套使用
  • 原文地址:https://www.cnblogs.com/icuit/p/1755575.html
Copyright © 2020-2023  润新知