如何在你的系統里集成LDAP統一認證


一、為什么需要統一認證

日常辦公經常會有多套系統,如果各個系統各自維護一套用戶認證,用戶需要記住多個用戶名密碼。 系統各自管理用戶認證的方式,不但會有重復建設的問題,用戶體驗也會差,經常會有用戶忘記密碼的情況。

二、LDAP統一認證是什么

LDAP是Light weight Directory Access Protocol(輕量級目錄訪問協議)的縮寫,它是基於X.500標准的輕量組播目錄訪問協議。 

目錄是一個為查詢、瀏覽和搜索而優化的數據庫,它成樹狀結構組織數據。目錄數據庫和關系數據庫不同,它有優異的讀性能,但寫性能很差,沒有事務處理、回滾等復雜操作,不適合存儲修改頻繁的數據。適合存儲人員組織、電話簿和地址簿等信息。

三、LDAP的基本模型

3.1 信息模型

LDAP中信息以樹狀方式組織,數據的基本單元是條目,每個條目由屬性構成,屬性中存儲有屬性值。

3.2 命名模型

LDAP中的命名模型,也即LDAP中條目的定位方式。

每個條目有自己的DN,DN是該條目在整個樹中的唯一名稱標識,如同文件系統中帶路徑的文件名。

3.3 功能模型

LDAP中支持四類操作: 查詢類操作、更新類操作、認證類操作和其它操作;

3.4 安全模型

LDAP的安全模型主要通過身份認證、安全通道和訪問控制來實現。

四、LDAP認證的過程

4.1 訪問LDAP認證服務架構圖

4.2 身份驗證的步驟

LDAP利用登錄名和密碼進行驗證,進行身份驗證通常需要以下步驟:

  • 1、通過用戶登錄獲取用戶名密碼。
  • 2、匿名或默認用戶綁定LDAP服務器,綁定成功后執行下面步聚。
  • 3、根據輸入的登錄名,執行一個搜索。請求參數形如:"(|(uid={login})(mail={login}))“,請求如果返回一個entry,可以通過該entry得到DN,后面步聚使用。如果返回多個或沒有返回,說明用戶輸入用戶名有誤,驗證失敗。
  • 4、如果上一步驗證成功,得到用戶信息所在entry的DN,使用這個DN和用戶輸入password重新綁定LDAP服務器。如果綁定成功,說明驗證成功。綁定失敗,返回密碼錯誤的信息。 

4.3 為什么需要兩次綁定

為什么基於LDAP進行驗證需要“兩次”綁定? 為什么不能直接取出密碼進行比較?

主要是出於安全考慮,LDAP服務器對於password屬性一般是不可讀的。 

4.4 LDAP搜索參數表達式

  • & 與(列表中所有項必須為true)
  • | 或(列表中至少一個必須為true)
  • ! 非(求反的項不能為true)
  • = 相等(根據屬性的匹配規則)
  • ~= 近似等於(根據屬性的匹配規則)
  • >= 大於(根據屬性的匹配規則)
  • <= 小於(根據屬性的匹配規則)
  • =* 存在(條目中必須有這個屬性,但值不做限制)
  • * 通配符(表示這個位置可以有一個或多個字符),當指定屬性值時用到
  • \ 轉義符(當遇到“*”,“(”,“)”時進行轉義)

五、如何在系統中集成LDAP認證

LDAP認證服務是跨平台,同時支持TCP/IP協議。在系統中兩次綁定LDAP服務器成功,代表登錄成功,否則登錄失敗。 

下面以Java語言為例演示兩次綁定的過程:

首先添加依賴:

 <dependency>
  <groupId>com.novell.ldap</groupId>
  <artifactId>jldap</artifactId>
  <version>4.3</version>
</dependency>

兩次綁定代碼:

public string bind(String username, String password) {

    LDAPConnection ldapConnection = new LDAPConnection();
    ldapConnection.connect(Constants.LDAP_HOST, Constants.LDAP_PORT);
    ldapConnection.bind(LDAPConnection.LDAP_V3, Constants.LDAP_BIND_DN, Constants.LDAP_BIND_PASSWORD.getBytes("UTF8"));
    try {
        String filter = String.format("(|(mail=%s)(uid=%s))", username, username);
        LDAPSearchResults results = ldapConnection.search(Constants.LDAP_BIND_BASE, LDAPConnection.SCOPE_SUB, filter, null, false);
        LDAPEntry nextEntry, nextUserEntry;
        while (results.hasMore()) {
            try {
                nextEntry = results.next();
            } catch (LDAPException e) {
                if (e.getResultCode() == LDAPException.LDAP_TIMEOUT || e.getResultCode() == LDAPException.CONNECT_ERROR) {
                    break;
                } else {
                    continue;
                }
            }
            String dn = nextEntry.getDN();
            ldapConnection.bind(LDAPConnection.LDAP_V3, dn, password.getBytes("UTF8"));
            LDAPSearchResults userResults = ldapConnection.search(Constants.LDAP_BIND_BASE, LDAPConnection.SCOPE_SUB, String.format("(|(mail=%s)(uid=%s))", username, username), null, false);
            while (userResults.hasMore()) {
                try {
                    nextUserEntry = userResults.next();
                } catch (LDAPException e) {
                    if (e.getResultCode() == LDAPException.LDAP_TIMEOUT || e.getResultCode() == LDAPException.CONNECT_ERROR) {
                        break;
                    } else {
                        continue;
                    }
                }
                if (nextUserEntry == null) {
                    continue;
                }
                String userDn = nextUserEntry.getDN();
                if (!Strings.isNullOrEmpty(userDn) && userDn.equals(dn)) {
                    //登錄成功
                }
            }
        }
    } catch (LDAPException e) {
        logger.warn("get LDAPException:", e);
    } catch (UnsupportedEncodingException e) {
        logger.warn("get UnsupportedEncodingException:", e);
    } finally {
        ldapConnection.disconnect();
    }
    return null;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM