美文网首页程序员
Java 中 LDAP 的使用与整理

Java 中 LDAP 的使用与整理

作者: 58bc06151329 | 来源:发表于2018-01-10 21:45 被阅读2888次

    文前说明

    作为码农中的一员,需要不断的学习,我工作之余将一些分析总结和学习笔记写成博客与大家一起交流,也希望采用这种方式记录自己的学习之旅。

    本文仅供学习交流使用,侵权必删。
    不用于商业目的,转载请注明出处。

    LDAP 是轻量 目录访问协议,英文全称是 Lightweight Directory Access Protocol,一般都简称为 LDAP。LDAP 基于 X.500 标准的,但简单了许多并且可以根据需要进行定制。与 X.500 不同,LDAP 支持 TCP/IP。LDAP 的核心规范在 RFC 中都有定义,所有与 LDAP 相关的RFC 都可以在 LDAPman RFC 网页中找到。

    目录结构

    • LDAP 目录以树状的层次结构来存储数据。
    • 象 DNS 的 主机名,LDAP 目录记录的标识名(Distinguished Name,简称 DN)用来读取单个记录,以及回溯到树的顶部。
    • LDAP 目录树的最顶部就是根,也就是所谓的 " 基准DN "。
    • 基准 DN 通常使用三种格式之一
      • 以 X.500 格式表示的基准 DN,例如 o=xxxx, c=CN
      • 用公司的 Internet 地址表示的基准 DN,例如 o=xxxx.com
      • 用 DNS 域名的不同部分组成的基准 DN,例如 dc=xxxx, dc=com
      • 如果使用活动目录(Active Directory),Microsoft 限制必须使用 DNS 域名格式。

    组织数据

    • 在根目录下,数据从逻辑上区分开。
    • 大多数 LDAP 目录用 OU 从逻辑上把数据分开来。OU 表示
      Organization Unit ,在 X.500 协议中用来表示公司内部机构:销售部、财务部等等。
    • 现在 LDAP 还保留 ou= 这样的命名规则,但是扩展了分类的范围,可以分类为:ou=people, ou=groups, ou=devices 等等。
    • 更低一级的 OU 有时用来做更细的归类。

    单独记录

    • DN 是 LDAP 记录项的名字。
    • 在 LDAP 目录中的所有记录项都有一个唯一的 Distinguished Name,也就是 DN。
    • 每一个 LDAP 记录项的 DN 是由两个部分组成的
      • 相对DN(RDN)
      • 记录在 LDAP 目录中的位置。
    • RDN 是 DN 中与目录树的结构无关的部分。
    • 在 LDAP 目录中存储的记录项都要有一个名字,通常存在 cn(Common Name)属性里。
    • 在 LDAP 中存储的对象都用 cn 值作为 RDN 的基础。
    • 为公司的员工设置一个 DN

    基于登录名(uid (User ID)与 unix 的 uid 完全不同)

    uid=abc123, ou=xxxx, dc=xxxx, dc=com
    

    基于姓名(cn)

    cn=abc, ou=xxxx, dc=xxxx, dc=com
    
    • 这种格式有明显的缺点,名字发生改变,LDAP 的记录就要从一个 DN 转移到另一个 DN。

    定制对象

    • LDAP 目录可以定制成存储任何文本或二进制数据。
    • LDAP 目录用对象类型(object classes)的概念来定义运行哪一类的对象使用什么属性。
    • LDAP 目录以一系列 " 属性对 " 的形式来存储记录项,每一个记录项包括属性类型和属性值(这与关系型数据库用行和列来存取数据有根本的不同)。
    • LDAP 目录被设计成为一个属性保存多个值的,而不是在每一个属性的后面用逗号把一系列值分开。这样的方式存储数据,数据库有很大的灵活性,不必为加入一些新的数据就重新创建表和索引。
    • LDAP 目录不必花费内存或硬盘空间处理 " 空 " 域,也就是说,实际上不使用可选择的域也不会花费任何资源。
    • 记录项的格式是 LDIF,用来导入和导出 LDAP 目录的记录项。
    • 属性的值在保存的时候是保留大小写的,但是在默认情况下搜索的时候是不区分大小写的。
    • 某些特殊的属性(例如,password)在搜索的时候需要区分大小写。
    属性名称 含义 备注
    OU Organizational Unit(组织单元) 最多可以有四级,每级最长 32 个字符,可以为中文。
    DC Domain Component(域名) dc=xxxx,dc=com
    CN Common Name(用户名或服务器名) 最长可以到 80 个字符,可以为中文。
    O Organization(组织名称) 可以 3~64 个字符长度。
    C Country(国家名) 可选,为 2 个字符长度。
    SN
    UID 用户ID
    DN 唯一标识 类似于 Linux 文件系统的绝对路径,每个对象都有一个唯一的名称。

    Java 中 LDAP 的基本操作

    LDAP 连接
    Hashtable env = new Hashtable();
    String LDAP_URL = "ldap://<IP>:389"; // LDAP 访问地址
    String adminName = "example\\user"; // 注意用户名的写法:domain\User 或 cn=user
    String adminPassword = "userpassword"; // 密码
    env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
    env.put(Context.PROVIDER_URL, LDAP_URL);
    env.put(Context.SECURITY_AUTHENTICATION, "simple");
    env.put(Context.SECURITY_PRINCIPAL, adminName);
    env.put(Context.SECURITY_CREDENTIALS, adminPassword);
    try {
         dc = new InitialDirContext(env);// 初始化上下文
         System.out.println("认证成功");
    } catch (javax.naming.AuthenticationException e) {
         System.out.println("认证失败");
    } catch (Exception e) {
         System.out.println("认证出错:" + e);
    }
    
    LDAP 增加记录
    String root = "dc=example,dc=com"; // LDAP的根节点的DC
    
    BasicAttributes attrs = new BasicAttributes();
    BasicAttribute objclassSet = new BasicAttribute("objectClass");
    objclassSet.add("sAMAccountName");
    objclassSet.add("employeeID");
    objclassSet.add("sAMAccountName");
    objclassSet.add("employeeID");
    attrs.put(objclassSet);
    attrs.put("ou", newUserName);
    dc.createSubcontext("ou=" + newUserName + "," + root, attrs);
    
    LDAP 删除记录
    try {
         dc.destroySubcontext(dn);
    } catch (Exception e) {
         e.printStackTrace();
         System.out.println("Exception in delete():" + e);
    }
    
    LDAP 重命名节点
    try {
          dc.rename(oldDN, newDN);
          return true;
    } catch (NamingException ne) {
          System.err.println("Error: " + ne.getMessage());
          return false;
    }
    
    LDAP 修改
    try {
          ModificationItem[] mods = new ModificationItem[1];
          /* 修改属性 */
          // Attribute attr0 = new BasicAttribute("employeeID", "test");
          // mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, attr0);
          /* 删除属性 */
          // Attribute attr0 = new BasicAttribute("description", "test");
          // mods[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, attr0);
          /* 添加属性 */
          Attribute attr0 = new BasicAttribute("employeeID", employeeID);
          mods[0] = new ModificationItem(DirContext.ADD_ATTRIBUTE, attr0);
          /* 修改 */
          dc.modifyAttributes(dn + ",dc=example,dc=com", mods);
          return true;
    } catch (NamingException e) {
          e.printStackTrace();
          System.err.println("Error: " + e.getMessage());
          return false;
    }
    
    LDAP 查询
    // 创建搜索控件
    SearchControls searchCtls = new SearchControls();
    // 设置搜索范围
    searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
    // 设置搜索过滤条件
    String searchFilter = "sAMAccountName=" + userName;
    // 设置搜索域节点
    String searchBase = "DC=example,DC=COM";
    // 定制返回属性
    String returnedAtts[] = { "url", "whenChanged", "employeeID", "name", "userPrincipalName", "physicalDeliveryOfficeName", "departmentNumber", "telephoneNumber", "homePhone", "mobile", "department", "sAMAccountName", "whenChanged", "mail" };
    // 不定制属性,返回所有的属性集
    // searchCtls.setReturningAttributes(null);
    int totalResults = 0;
    try {
         NamingEnumeration answer = dc.search(searchBase, searchFilter, searchCtls);
         while (answer.hasMoreElements()) {
               SearchResult sr = (SearchResult) answer.next();
               Attributes Attrs = sr.getAttributes();
               if (Attrs != null) {
                     try {
                            for (NamingEnumeration ne = Attrs.getAll(); ne.hasMore();) {
                                    Attribute Attr = (Attribute) ne.next();
                                    // 读取属性值
                                    for (NamingEnumeration e = Attr.getAll(); e.hasMore(); totalResults++) {
                                             // 接受循环遍历读取的userPrincipalName用户属性
                                             String user = e.next().toString();
                                    }
                                    // 读取属性值
                                    // Enumeration values = Attr.getAll();
                                    // if (values != null) {
                                    //          while (values.hasMoreElements()) {
                                    //                   System.out.println(" 2AttributeValues=" + values.nextElement());
                                    //          }
                                    // }
                            }
                     } catch (NamingException e) {
                            System.err.println("Throw Exception : " + e);
                     }
               }
         }
    } catch (Exception e) {
          e.printStackTrace();
          System.err.println("Throw Exception : " + e);
    }
    
    • 搜索范围包含
      • 本节点:SearchControls.OBJECT_SCOPE
      • 单层:SearchControls.ONELEVEL_SCOPE
      • 遍历:SearchControls.SUBTREE_SCOPE
    LDAP 关闭
    if (dc != null) {
         try {
             dc.close();
         } catch (NamingException e) {
             System.out.println("NamingException in close():" + e);
         }
    }
    

    相关文章

      网友评论

        本文标题:Java 中 LDAP 的使用与整理

        本文链接:https://www.haomeiwen.com/subject/erbnnxtx.html