LDAP快速入門

1. LDAP簡介

  LDAP(輕量級目錄訪問協議,Lightweight Directory Access Protocol)是實現提供被稱爲目錄服務的信息服務。目錄服務是一種特殊的數據庫系統,其專門針對讀取,瀏覽和搜索操作進行了特定的優化。目錄一般用來包含描述性的,基於屬性的信息並支持精細複雜的過濾能力。目錄一般不支持通用數據庫針對大量更新操作操作需要的複雜的事務管理或回捲策略。而目錄服務的更新則一般都非常簡單。這種目錄可以存儲包括個人信息、web鏈結、jpeg圖像等各種信息。爲了訪問存儲在目錄中的信息,就需要使用運行在TCP/IP 之上的訪問協議—LDAP。


  LDAP目錄中的信息是是按照樹型結構組織,具體信息存儲在條目(entry)的數據結構中。條目相當於關係數據庫中表的記錄;條目是具有區別名DN (Distinguished Name)的屬性(Attribute),DN是用來引用條目的,DN相當於關係數據庫表中的關鍵字(Primary Key)。屬性由類型(Type)和一個或多個值(Values)組成,相當於關係數據庫中的字段(Field)由字段名和數據類型組成,只是爲了方便檢索的需要,LDAP中的Type可以有多個Value,而不是關係數據庫中爲降低數據的冗餘性要求實現的各個域必須是不相關的。LDAP中條目的組織一般按照地理位置和組織關係進行組織,非常的直觀。LDAP把數據存放在文件中,爲提高效率可以使用基於索引的文件數據庫,而不是關係數據庫。類型的一個例子就是mail,其值將是一個電子郵件地址。


LDAP的信息是以樹型結構存儲的,在樹根一般定義國家(c=CN)或域名(dc=com),在其下則往往定義一個或多個組織 (organization)(o=Acme)或組織單元(organizational units) (ou=People)。一個組織單元可能包含諸如所有僱員、大樓內的所有打印機等信息。此外,LDAP支持對條目能夠和必須支持哪些屬性進行控制,這是有一個特殊的稱爲對象類別(objectClass)的屬性來實現的。該屬性的值決定了該條目必須遵循的一些規則,其規定了該條目能夠及至少應該包含哪些屬性。例如:inetorgPerson對象類需要支持sn(surname)和cn(common name)屬性,但也可以包含可選的如郵件,電話號碼等屬性。


2. LDAP簡稱對應

  1. o– organization(組織-公司)

  2. ou – organization unit(組織單元-部門)

  3. c - countryName(國家)

  4. dc - domainComponent(域名)

  5. sn – suer name(真實名稱)

  6. cn - common name(常用名稱)


3. 目錄設計

設計目錄結構是LDAP最重要的方面之一。下面我們將通過一個簡單的例子來說明如何設計合理的目錄結構。該例子將通過Netscape地址薄來訪文。假設有一個位於美國US(c=US)而且跨越多個州的名爲Acme(o=Acme)的公司。Acme希望爲所有的僱員實現一個小型的地址薄服務器。


  我們從一個簡單的組織DN開始: 

    dn: o=Acme, c=US


  Acme所有的組織分類和屬性將存儲在該DN之下,這個DN在該存儲在該服務器的目錄是唯一的。Acme希望將其僱員的信息分爲兩類:管理者(ou= Managers)和普通僱員(ou=Employees),這種分類產生的相對區別名(RDN,relative distinguished names。表示相對於頂點DN)就shi :


    dn: ou=Managers, o=Acme, c=US

    dn: ou=Employees, o=Acme, c=US


  在下面我們將會看到分層結構的組成:頂點是US的Acme,下面是管理者組織單元和僱員組織單元。因此包括Managers和Employees的DN組成爲:

    dn: cn=Jason H. Smith, ou=Managers, o=Acme, c=US

    dn: cn=Ray D. Jones, ou=Employees, o=Acme, c=US

    dn: cn=Eric S. Woods, ou=Employees, o=Acme, c=US


  爲了引用Jason H. Smith的通用名(common name )條目,LDAP將採用cn=Jason H. Smith的RDN。然後將前面的父條目結合在一起就形成如下的樹型結構:


    cn=Jason H. Smith

        + ou=Managers

            + o=Acme

                + c=US

                               -> dn: cn=Jason H. Smith,ou=Managers,o=Acme,c=US



  現在已經定義好了目錄結構,下一步就需要導入目錄信息數據。目錄信息數據將被存放在LDIF文件中,其是導入目錄信息數據的默認存放文件。用戶可以方便的編寫Perl腳本來從例如/etc/passwd、NIS等系統文件中自動創建LDIF文件。


  下面的實例保存目錄信息數據爲testdate.ldif文件,該文件的格式說明將可以在man ldif中得到。

  在添加任何組織單元以前,必須首先定義Acme DN: 

    dn: o=Acme, c=US

    objectClass: organization


  這裏o屬性是必須的

    o: Acme


  下面是管理組單元的DN,在添加任何管理者信息以前,必須先定義該條目。

    dn: ou=Managers, o=Acme, c=US

    objectClass: organizationalUnit

這裏ou屬性是必須的。


ou: Managers

  第一個管理者DN:

    dn: cn=Jason H. Smith, ou=Managers, o=Acme, c=US

    objectClass: inetOrgPerson

  cn和sn都是必須的屬性:

    cn: Jason H. Smith

    sn: Smith

  但是還可以定義一些可選的屬性:

    telephoneNumber: 111-222-9999

    mail: [email protected]

    localityName: Houston


  可以定義另外一個組織單元:

    dn: ou=Employees, o=Acme, c=US

    objectClass: organizationalUnit

    ou: Employees


  並添加僱員信息如下:

    dn: cn=Ray D. Jones, ou=Employees, o=Acme, c=US

    objectClass: inetOrgPerson

    cn: Ray D. Jones

    sn: Jones

    telephoneNumber: 444-555-6767

    mail: [email protected]

    localityName: Houston

    dn: cn=Eric S. Woods, ou=Employees, o=Acme, c=US

    objectClass: inetOrgPerson

    cn: Eric S. Woods

    sn: Woods

    telephoneNumber: 444-555-6768

    mail: [email protected]

    localityName: Houston


4. 配置OpenLDAP

本文實踐了在 Windows 下安裝配 openldap,並添加一個條目,LdapBrowser 瀏覽,及 Java 程序連接 openldap 的全過程。


1. 下載安裝 openldap for windows,當前版本2.2.29下載地址:http://download.bergmans.us/openldap/openldap-2.2.29/openldap-2.2.29-db-4.3.29-openssl-0.9.8a-win32_Setup.exe

   相關鏈接:http://lucas.bergmans.us/hacks/openldap/

  安裝很簡單,一路 next 即可,假設我們安裝在 c:\openldap


2. 配置 openldap,編輯 sldap.conf 文件

  1) 打開 c:\openldap\sldap.conf,找到

   include  C:/openldap/etc/schema/core.schema,在它後面添加

   include  C:/openldap/etc/schema/cosine.schema

   include  C:/openldap/etc/schema/inetorgperson.schema


   接下來的例子只需要用到以上三個 schema,當然,如果你覺得需要的話,你可以把其他的 schema 全部添加進來

   include  C:/openldap/etc/schema/corba.schema

   include  C:/openldap/etc/schema/dyngroup.schema

   include  C:/openldap/etc/schema/java.schema

   include  C:/openldap/etc/schema/misc.schema

   include  C:/openldap/etc/schema/nis.schema

   include  C:/openldap/etc/schema/openldap.schema


  2) 還是在 sldap.conf 文件中,找到

   suffix  "dc=my-domain,dc=com"

   rootdn  "cn=Manager,dc=my-domain,dc=com"

   把這兩行改爲

   suffix "o=teemlink,c=cn"

   rootdn "cn=Manager,o=teemlink,dc=cn"


   suffix 就是看自己如何定義了,後面步驟的 ldif 文件就必須與它定義了。還要注意到這個配置文件中有一個 rootpw  secret,這個 secret 是 cn=Manager 的密碼,以後會用到,不過這裏是明文密碼,你可以用命令: slappasswd -h {MD5} -s secret 算出加密的密碼 {MD5}Xr4ilOzQ4PCOq3aQ0qbuaQ== 取代配置中的 secret。


3. 啓動 openldap

   CMD 進入到 c:\openldap 下,運行命令 sldapd -d 1

   用可以看到控制檯下打印一片信息,openldap 默認是用的 Berkeley DB 數據庫存儲目錄數據的。


4. 建立條目,編輯導入 ldif 文件

  1) 新建一個 ldif(LDAP Data Interchanged Format) 文件(純文本格式),例如 test.ldif,文件內容如下:


dn: o=teemlink

objectclass: top

objectclass: organization

o: develop


  2) 執行命令:ldapadd -l test.ldif


5. 使用LDAP Browser進行訪問

      5.1安裝LDAP Browser2.6軟件,進行如下操作:

2010082814190153.jpg

2010082814200667.jpg


5.2顯示效果

2010082814363213.jpg


5. Java操作LDAP


5.1 用JNDI進訪問

複製代碼
package cn.myapps.test;

import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;

publicclass LdapTest {
publicvoid JNDILookup() {
       String root
="o=teemlink,c=cn";
       Hashtable env
=new Hashtable();
       env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
       env.put(Context.PROVIDER_URL,
"ldap://192.168.0.30/"+ root);
       env.put(Context.SECURITY_AUTHENTICATION,
"simple");
       env.put(Context.SECURITY_PRINCIPAL,
"cn=Nicholas,ou=產品,o=teemlink,c=cn");
       env.put(Context.SECURITY_CREDENTIALS,
"123456");
       DirContext ctx
=null;

try {
           ctx
=new InitialDirContext(env);
           Attributes attrs
= ctx.getAttributes("cn=Nicholas,ou=產品");
           System.out.println(
"Last Name: "+ attrs.get("sn").get());
           System.out.println(
"認證成功");
       }
catch (javax.naming.AuthenticationException e) {
           e.printStackTrace();
           System.out.println(
"認證失敗");
       }
catch (Exception e) {
           System.out.println(
"認證出錯:");
           e.printStackTrace();
       }
if (ctx !=null) {
try {
               ctx.close();
           }
catch (NamingException e) {
// ignore
           }
       }
   }

publicstaticvoid main(String[] args) {
       LdapTest LDAPTest
=new LdapTest();
       LDAPTest.JNDILookup();
   }
}
複製代碼


5.2 用JLDAP進訪問

訪問地址:http://www.openldap.org/jldap/ 並下載相關lib


複製代碼
import com.novell.ldap.*;

import java.io.UnsupportedEncodingException;

publicclass List

{

publicstaticvoid main(String[] args)

   {
int ldapPort = LDAPConnection.DEFAULT_PORT;
int searchScope = LDAPConnection.SCOPE_ONE;
int ldapVersion = LDAPConnection.LDAP_V3;
boolean attributeOnly =false;
       String attrs[]
=null;
       String ldapHost
="192.168.0.30";
       String loginDN
="cn=Manager,o=teemlink,c=cn";
       String password
="secret";
       String searchBase
="ou=develop,o=teemlink,c=cn";
       String searchFilter
="objectClass=*";

       LDAPConnection lc
=new LDAPConnection();
try {
// connect to the server
           lc.connect(ldapHost, ldapPort);

// bind to the server
           lc.bind(ldapVersion, loginDN, password.getBytes("UTF8"));

           LDAPSearchResults searchResults
=

           lc.search(searchBase,
// container to search
                   searchScope, // search scope
                   searchFilter, // search filter
                   attrs, // "1.1" returns entry name only
                   attributeOnly); // no attributes are returned

// print out all the objects
while (searchResults.hasMore()) {
               LDAPEntry nextEntry
=null;
try {
                   nextEntry
= searchResults.next();
                   System.out.println(
"\n"+ nextEntry.getDN());
                   System.out.println(nextEntry.getAttributeSet());
               }
catch (LDAPException e) {
                   System.out.println(
"Error: "+ e.toString());
// Exception is thrown, go for next entry
continue;
               }
           }

// disconnect with the server
           lc.disconnect();

       }
catch (LDAPException e) {
           System.out.println(
"Error: "+ e.toString());
       }
catch (UnsupportedEncodingException e) {
           System.out.println(
"Error: "+ e.toString());
       }
       System.exit(
0);
   }
}
複製代碼


5.3 用JDBC-LDAP進訪問

訪問地址:http://www.openldap.org/jdbcldap/ 並下載相關lib


複製代碼
package jdbcldap;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

publicclass JdbcLdap {

/**
    *
@param args
    *
@throws Exception
*/
publicstaticvoid main(String[] args) throws Exception {
       Class.forName(
"com.octetstring.jdbcLdap.sql.JdbcLdapDriver");
       String ldapConnectString
="jdbc:ldap://192.168.0.30/o=teemlink,c=cn?SEARCH_SCOPE:=subTreeScope";
       Connection con
= DriverManager.getConnection(ldapConnectString, "cn=Manager,o=teemlink,c=cn", "secret");

       String sql
="SELECT * FROM ou=develop,o=teemlink,c=cn";

       Statement sat
= con.createStatement();
       ResultSet rs
= sta.executeQuery(sql);
while (rs.next()) {
           System.out.println(rs.getString(
1));
       }

if (con !=null)
           con.close();
   }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章