標籤:
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簡稱對應
- o– organization(組織-公司)
- ou – organization unit(組織單元-部門)
- c - countryName(國家)
- dc - domainComponent(網域名稱)
- sn – suer name(真實名稱)
- 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軟體,進行如下操作:
5.2顯示效果
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;
public class LdapTest {
public void 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
}
}
}
public static void 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;
public class List
{
public static void 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;
public class JdbcLdap {
/**
* @param args
* @throws Exception
*/
public static void 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();
}
}
原創人員:Nicholas
[轉]LDAP快速入門