LDAP目录服务器介绍

前言

本文介绍LDAP目录服务器的简单概念以及如何使用Java操做LDAP做目录服务器java

正文

什么是目录服务器?

目录是一个专门为搜索和浏览而设计的数据库,它也支持简单的插入、删除、修改功能。你能够把它理解为咱们传统使用的关系型数据库,可是他与咱们的关系型数据库有着本质的区别,目录的存储结构相似于linux文件系统,他是一颗树(相似下图),因为它是为浏览和搜索而设计的,它的查询速度很快,相反插入速度较慢,它也不支持事务和回滚以及复杂的插入、更新功能。目录服务器可像关系型数据库同样对外提供数据服务,它能够是单机或集群式的。在集群式的架构中每一个机器都拥有一致的数据备份。linux

树中的每一个节点称之为条目(Entry),目录服务是以条目为基础的,在上图的树型结构中,每一个条目都有一个惟一的绝对名字Directory Name(DN)和相对名字rDN。每一个条目具备一组属性,每一个属性有一个key,每一个key对应一个或多个value。具体每一个条目有哪些属性由ObjectClass约束,也就是说每一个条目经过赋予ObjectClass来规定其必须拥有的属性。git

例如上图的babs条目中:数据库

DN:uid=babs,ou=people,dc=example,dc=combash

相对于ou=people,dc=example,dc=com 节点的rDN:uid=babs服务器

ObjectClass:Person架构

什么是LDAP?

LDAP全称为Lightweight Directory Access Protocol(轻量级目录访问协议),客户端与目录服务器遵循LDAP协议来发生交互,好比说新增一个节点,查询某个节点的属性等等。dom

常见的LDAP目录服务器

与关系型数据库同样,LDAP目录服务器是一个概念,包含许多具体实现的产品,好比关系型数据库常见的有MySQL,Oracle等等。LDAP目录服务器也有常见的具体实现,好比:OpenLDAP,Active Directory(Microsoft)。本文以OpenLDAP为例介绍Java如何操做LDAP服务器。gitlab

何时使用LDAP目录服务器?

看到目前为止,你可能会以为目录服务器貌似和关系型数据库服务器没有什么区别,到底何时该使用目录服务器呢?ui

使用目录服务器最多见的状况就是多系统间的集中用户管理,好比公司会使用OA,Confluence,gitlab,jira等等办公系统。若是每一个系统都须要咱们记住一个帐号密码,那无疑是很费力的。经过使用LDAP目录服务器将多个应用的用户集中管理起来,每一个应用都经过通用的LDAP协议与目录服务器通讯,达到用户信息集中管理的目的。事实上不少的开源项目都支持LDAP用户认证(例如SuperSet,Hue等等)

代码示例

package richstonedt.com;

import com.novell.ldap.*;
import com.novell.ldap.util.Base64;
import lombok.extern.slf4j.Slf4j;

import java.io.UnsupportedEncodingException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;


/**
 * 参考地址:http://www.micmiu.com/opensource/java-ldap-demo/
 */
@Slf4j
public class App {

    private static  String ldapHost = "192.168.x.x";
    private static int ldapPort = 389;
    private static String ldapBindDN = "cn=Manager,dc=my-domain,dc=com";
    private static String ldapPassword = "123456";
    private static int ldapVersion = LDAPConnection.LDAP_V3;

    /**
     * 获取链接
     *
     * @return A LDAP Connection
     * @throws LDAPException
     * @throws UnsupportedEncodingException
     */
    @SuppressWarnings("deprecation")
    private static LDAPConnection connection() throws UnsupportedEncodingException, LDAPException {
        try {
            LDAPConnection lc = new LDAPConnection();
            //获取链接
            lc.connect(ldapHost, ldapPort);
            //认证
            lc.bind(ldapVersion, ldapBindDN, ldapPassword.getBytes("UTF8"));
            log.info("链接LDAP服务器成功!");
            return lc;
        } catch (Exception e) {
            log.debug("LDAP服务器链接失败!");
            throw e;

        }
    }

    /**
     * 搜索某目录节点下全部节点及其属性
     * @param DN 目录节点名
     * @throws LDAPException
     * @throws UnsupportedEncodingException
     */
    public static void searchEntry(String DN) throws LDAPException, UnsupportedEncodingException {
        LDAPConnection conn = connection();
        try {
            LDAPSearchResults searchResults = conn.search(DN,
                    LDAPConnection.SCOPE_SUB, "objectClass=*", null, false);
            while (searchResults.hasMore()) {
                LDAPEntry nextEntry;
                try {
                    nextEntry = searchResults.next();
                } catch (LDAPException e) {
                    log.debug("Error: " + e);
                    if (e.getResultCode() == LDAPException.LDAP_TIMEOUT
                            || e.getResultCode() == LDAPException.CONNECT_ERROR) {
                        break;
                    } else {
                        continue;
                    }
                }
                log.info("DN :" + nextEntry.getDN());
                log.info("|---- Attributes list: ");
                LDAPAttributeSet attributeSet = nextEntry.getAttributeSet();
                Iterator<LDAPAttribute> allAttributes = attributeSet.iterator();
                while (allAttributes.hasNext()) {
                    LDAPAttribute attribute = allAttributes.next();
                    String attributeName = attribute.getName();

                    Enumeration<String> allValues = attribute.getStringValues();
                    if (null == allValues) {
                        continue;
                    }
                    while (allValues.hasMoreElements()) {
                        String value = allValues.nextElement();
                        if (!Base64.isLDIFSafe(value)) {
                            // base64 encode and then print out
                            value = Base64.encode(value.getBytes());
                        }
                        log.info("|---- ---- " + attributeName
                                + " = " + value);
                    }
                }
            }
        } finally {
            if (conn.isConnected()) {
                conn.disconnect();
            }
        }
    }

    /**
     * 新增一个目录节点
     * @param baseDN
     * @param rDN
     * @param attribute
     * @throws UnsupportedEncodingException
     * @throws LDAPException
     */
    public static void addEntry(String baseDN, String rDN, Map<String, String> attribute) throws UnsupportedEncodingException, LDAPException {
        LDAPConnection conn = connection();
        try {
            LDAPAttributeSet attributeSet = new LDAPAttributeSet();
            for (Map.Entry<String, String> entry : attribute.entrySet()) {
                attributeSet.add(new LDAPAttribute(entry.getKey(), entry.getValue()));
            }
            String DN = rDN + "," + baseDN;
            conn.add(new LDAPEntry(DN, attributeSet));
        } finally {
            if (conn.isConnected())
                conn.disconnect();
        }
    }

    /**
     * 删除一个目录节点
     * @param DN 目录节点名
     * @throws UnsupportedEncodingException
     * @throws LDAPException
     */
    public static void deleteEntry(String DN) throws UnsupportedEncodingException, LDAPException {
        LDAPConnection conn = connection();
        try {
            conn.delete(DN);
        } finally {
            if (conn.isConnected()) {
                conn.disconnect();
            }
        }

    }

    public static void main(String[] args) throws UnsupportedEncodingException, LDAPException {
        //新增节点
        Map<String, String> map = new HashMap<>();
        map.put("objectclass", "inetOrgPerson");
        map.put("cn", "liuruojing");
        map.put("sn", "liuruojing");
        addEntry("ou=userAccount,dc=my-domain,dc=com", "uid=liuruojing", map);

        //查询节点
        searchEntry("uid=liuruojing,ou=userAccount,dc=my-domain,dc=com");

        //删除节点
        deleteEntry("uid=liuruojing,ou=userAccount,dc=my-domain,dc=com");

    }


}
复制代码

注意:须要引入JLDAP的Maven依赖

<dependency>
      <groupId>com.novell.ldap</groupId>
      <artifactId>jldap</artifactId>
      <version>4.3</version>
      <type>jar</type>
      <scope>compile</scope>
</dependency>
复制代码