LDAP應用技術(shù)簡(jiǎn)述(轉)
LDAP應用技術(shù)簡(jiǎn)述
作者:fredeirck@daifusecure.com www.daifusecure.com (2005-05-12 14:54:03)
一、簡(jiǎn)介;
a) X500目錄服務(wù);
OSL X.500目錄是基于OSI網(wǎng)絡(luò )協(xié)議的目錄服務(wù)協(xié)議,也是LDAP的前身。但是X。500的缺點(diǎn)是不支持TCP/IP,而是支持OSI協(xié)議,顯然,在 Windows等個(gè)人電腦上不可以使用OSI協(xié)議,在此前提下,也就產(chǎn)生了訪(fǎng)問(wèn)X500目錄的網(wǎng)關(guān)--LDAP。
b) LDAP;
LDAP(Lightweight Directory Access Protocal, 輕型目錄訪(fǎng)問(wèn)協(xié)議),是針對以X500目錄為主的目錄服務(wù)的前端訪(fǎng)問(wèn)協(xié)議,是OSL X.500目錄訪(fǎng)問(wèn)網(wǎng)關(guān)。由于X500原來(lái)不是為T(mén)CP/IP網(wǎng)絡(luò )設計的,而目錄服務(wù)的最大使用者偏偏是TCP/IP客戶(hù),因此,LDAP就被設計成使用 TCP/IP訪(fǎng)問(wèn)OSI 目錄服務(wù)的服務(wù)協(xié)議,而隨著(zhù)互聯(lián)網(wǎng)成為網(wǎng)絡(luò )的主流,LDAP也成為一個(gè)具備目錄的大部分服務(wù)的協(xié)議。
LDAP主要解決目錄服務(wù)的前端訪(fǎng)問(wèn)形式,而不是對目錄服務(wù)本身制定的的協(xié)議,理論上,LDAP支持后臺的任何存儲形式,包括X500,關(guān)系數據庫,文本數據庫或文件目錄等。LDAP繼承了X500目錄的大部分定義,無(wú)論是訪(fǎng)問(wèn)樣式還是語(yǔ)法都與X500相似。
c) Active Directory 活動(dòng)目錄;
Active Directory (AD)是微軟為.net中的對象訪(fǎng)問(wèn)定義的目錄服務(wù),包括目錄服務(wù)本身,以及客戶(hù)端API(ADSI)。Ad并不是LDAP在.net中的實(shí)現,而是 X500在.net中的實(shí)現,但AD前端支持并主要以L(fǎng)DAP形式進(jìn)行訪(fǎng)問(wèn)。完整地說(shuō),AD是基于微軟自身定義的X500擴展的一系列Schema實(shí)現的 X500目錄服務(wù)及相關(guān)的訪(fǎng)問(wèn)控制工具的集合,其前端支持LDAP的查詢(xún),目的是對.net中涉及的所有網(wǎng)絡(luò )對象提供目錄服務(wù)。各個(gè)schema在一個(gè)樹(shù)森林中是唯一的。
普通的LDAP客戶(hù)端工具與AD并不兼容。WINDOWS2000自帶有一些LDAP客戶(hù)端工具,包括ldifde.exe, ldp.exe。并提供專(zhuān)門(mén)的LDAP程序接口A(yíng)SDI。同時(shí),可以在WINDOWS管理臺上添加AD管理snap-in,配合已有的AD基本管理工作。使用以上工具可以得到微軟樣式的詳情,但總的來(lái)說(shuō),WINDOWS2000原則上不鼓勵用戶(hù)在A(yíng)D的基礎上進(jìn)一步的開(kāi)發(fā),沒(méi)有開(kāi)發(fā)更多的資料。
WINDOWS2000中,訪(fǎng)問(wèn)AD記錄的API被集成到了內核,服務(wù)于WINDOWS2000從主機權限和對象管理,直接網(wǎng)絡(luò )的權限和對象管理,同時(shí)API細節沒(méi)有對外公開(kāi)。因此,某種程度上,AD是一個(gè)只對WINDOWS2000有用的目錄服務(wù),AD連同訪(fǎng)問(wèn)API,形成一個(gè)基于 X500-LDAP的孤島,從一開(kāi)始就沒(méi)有打算與其他廠(chǎng)商產(chǎn)品有兼容的余地,這也是微軟的一貫風(fēng)格。參考:
http://www.microsoft.com/windows2000/en/server/help/default.asp? url=/windows2000/en/server/help/sag_ADschema_Intro.htm
http://msdn.microsoft.com/library/default.asp? url=/library/en-us/netdir/ad/schema_implementation.asp
AD在WINDOWS2000中注冊表中的位置是:HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\NTDS\
使用AD時(shí),用戶(hù)可以自行在微軟樣式的基礎上添加新的類(lèi)和屬性,微軟稱(chēng)這個(gè)就是schema的增添,這與UNIX環(huán)境下有一些不同,用戶(hù)余地較少。如果真的需要添加,可以使用按:http://www.microsoft.com/ windows2000/techinfo/planning/activedirectory/adschemasteps.asp
的指示一步步做,也可以預先做好ldif文件,使用ldifde.exe一次性地進(jìn)行添加,效果是一樣的。 在默認的狀況下,WINDOWS2000的AD初始具備三個(gè)上下文對象:
dc=domainname; 微軟定義domainname必須是examples.com格式,即dc=example,dc=com;
cn=Configuration,dc=example,dc=com; 這一條目和上下文存儲設置信息;
cn=schema,cn=configuration,dc=example,dc=com;
二、服務(wù)器實(shí)現方式;
用戶(hù)可以選擇購買(mǎi)商業(yè)的LDAP服務(wù)器,如SUN的iplanet directory server;但在大部分情況下,使用openldap足以完成所需要的目錄服務(wù)工作。另外,包括windows 2000以及如domino6這樣的系統軟件中,通常也都集成了一個(gè)自身使用的LDAP服務(wù)器。
三、數據結構原理;
不少LDAP開(kāi)發(fā)人員喜歡把LDAP與關(guān)系數據庫相比,認為是另一種的存貯方式,然后在讀性能上進(jìn)行比較。實(shí)際上,這種對比的基礎是錯誤的。LDAP和關(guān)系數據庫是兩種不同層次的概念,后者是存貯方式(同一層次如網(wǎng)格數據庫,對象數據庫),前者是存貯模式和訪(fǎng)問(wèn)協(xié)議。LDAP是一個(gè)比關(guān)系數據庫抽象層次更高的存貯概念,與關(guān)系數據庫的查詢(xún)語(yǔ)言SQL屬同一級別。 LDAP是實(shí)現了指定的數據結構的存貯,它包括以下可以用關(guān)系數據庫實(shí)現的結構要求:樹(shù)狀組織、條目認證、類(lèi)型定義、許可樹(shù)形記錄拷貝。
a) 樹(shù)狀組織;
無(wú)論是X500還是LDAP都是采用樹(shù)狀方式進(jìn)行記錄。每一個(gè)樹(shù)目錄都有一個(gè)樹(shù)根的入口條目,子記錄全部是這一根條目的子孫。這是目錄與關(guān)系數據類(lèi)型最大的區別(關(guān)系數據庫的應用結構也可實(shí)現樹(shù)狀記錄)。因此,把目錄看作是更高級的樹(shù)狀數據庫也未嘗不可,只不過(guò)除此外,它不能實(shí)現關(guān)系存貯的重要功能。
b) 條目和條目認證;
LDAP是以條目作為認證的根據。ROOT的權限認證與目錄本身無(wú)關(guān),但除此外所有條目的認證權限由條目本身的密碼進(jìn)行認證。LDAP可以配置成各種各樣不同的父子條目權限繼承方式。
每一個(gè)條目相當于一個(gè)單一的平面文本記錄,由條目自身或指定的條目認證進(jìn)行訪(fǎng)問(wèn)控制。因此,LDAP定義的存貯結構等同于一批樹(shù)狀組織的平面數據庫,并提供相應的訪(fǎng)問(wèn)控制。
條目中的記錄以名-值對的形式存在,每一個(gè)名值對必須由數據樣式schema預定義。因此,LDAP可以看作是以規定的值類(lèi)型以名值對形式存貯在一系列以樹(shù)狀組織的平面數據庫的記錄的集合。
c) 數據樣式(schema);
數據樣式schema是針對不同的應用,由用戶(hù)指定(設計)類(lèi)和屬性類(lèi)型預定義,條目中的類(lèi)(objectclass)和屬性必須在在 LDAP服務(wù)器啟動(dòng)時(shí)載入內存的schema已有定義。因此,AD活動(dòng)目錄中的條目記錄就必須符合Active Directory的schema中。如果已提供的schema中的定義不夠用,用戶(hù)可以自行定義新的schema.
在這里 中可以看到常用的schema。
d) 類(lèi)型分類(lèi)(objectClass);
條目中的記錄通過(guò)objectclass實(shí)現分類(lèi),objectClass是一個(gè)繼承性的類(lèi)定義,每一個(gè)類(lèi)定義指定必須具備的屬性。如某一條目指定必須符合unit類(lèi)型,則它必須具備chinacfirm類(lèi)形指定的屬性,象法人代表什么的。
通過(guò)objectclass分類(lèi),分散的條目中的記錄就實(shí)際上建立了一個(gè)索引結構,為高速的讀查詢(xún)打下了基礎。Objectclass也是過(guò)濾器的主要查詢(xún)對象。
e) 過(guò)濾器和語(yǔ)法;
LDAP是一個(gè)查詢(xún)?yōu)橹鞯挠涗浗Y構,無(wú)論是何種查詢(xún)方式,最終都由過(guò)濾器缺點(diǎn)查詢(xún)的條件。過(guò)濾器相當于SQL中的WHERE子句。任何LDAP的類(lèi)過(guò)濾和字符串都必須放在括號內,如(objectclass=*),指列出所有類(lèi)型的記錄(不過(guò)分類(lèi))。
可以使用=,>=,<=,~=(約等于)進(jìn)行比較,如(number<=100)。合并條件是最怪的,必須把操作符放在兩個(gè)操作對象的前面而不是中間,單一操作對象用括號括起來(lái)。如
A與B,不是A&B,而是(&(A)(B))。
或使用"|"表示;
非使用"!"表示。
對于"與",或"或"在操作符后可以跟多個(gè)條件表達式,但非后則只參是單個(gè)表達式。
詳見(jiàn)RFC1558。
f) 樹(shù)移植;
LDAP最重要的特性和要求并不是讀性能,而是擴展性。這一特性是通過(guò)樹(shù)移植和樹(shù)復制實(shí)現的。按LDAP的RFC要求,LDAP目錄應該可以任意地在不同的目錄間連接、合并并實(shí)現自動(dòng)復制,及自動(dòng)性同步。這意味著(zhù)用戶(hù)可以在任一LDAP中訪(fǎng)問(wèn)條目,而不用管其中某一部分是否復制自全世界另一目錄中的記錄,同時(shí)另一目錄中的記錄同樣在正常運作。
這一特性如果在關(guān)系數據庫中實(shí)現,意味著(zhù)要使用程序化的非規范化預復制。類(lèi)似于匯總帳目的設計。
g) LDIF交換文件
LDIF是LDAP約定的記錄交換格式,以平面文本的形式存在,是大部分LDAP內容交換的基礎,如拷貝、添加、修改等操作,都是基于LDIF文件進(jìn)行操作。
f) JAVA或CORBA對象串行化存儲
網(wǎng)絡(luò )高效率的訪(fǎng)問(wèn)加上JAVA的跨平臺能力,當把JAVA或CORBA對象串行化后存儲到LDAP目錄上時(shí),可以產(chǎn)生非同一般的集成效果--實(shí)際上,這正是EJB和.NET的網(wǎng)絡(luò )定位基礎技術(shù)。
使用JAVA或CORBA對象存儲時(shí),必須首先讓LDAP服務(wù)支持該對象定義,也就是說(shuō)包含qmail.schema或corba.schema。
JAVA必須存儲在objectclass=javacontainer的條目中,而且必須帶有cn屬性,這意味著(zhù)除非該JAVA類(lèi)專(zhuān)門(mén)實(shí)現了DirContext接口,對于大多數JAVA類(lèi)來(lái)說(shuō),只能采用DirContext代替Context實(shí)現bind的添加操作。取出JAVA類(lèi)相對要簡(jiǎn)單得多,只需使用context.lookup()獲得該對象的句柄,然后強制造型成所需要的對象就可以了,如:
Person p=(Person)contex.lookup("cn=elvis,dc=daifu,dc=com");
這個(gè)句法在EJB的程序中,是經(jīng)常用到的。
使用CORBA的跨語(yǔ)言性質(zhì),使用CORBA存儲對象比JAVA更加誘人,這意味著(zhù)所存儲的對象可以被任何語(yǔ)言編寫(xiě)的客戶(hù)端訪(fǎng)問(wèn)。其實(shí),微軟的.net說(shuō)到底也非常簡(jiǎn)單,無(wú)非是把COM對象存儲到微軟自家的目錄ActiveDirectory里面,從而可以在網(wǎng)絡(luò )范圍內使用任何微軟平臺的語(yǔ)言進(jìn)行對象訪(fǎng)問(wèn)而已。眾所周知,COM就是與CORBA相對的微軟規范。
使用對象串行化技術(shù),可以把常用對象如某個(gè)打印機,某個(gè)客戶(hù)直接存儲到LDAP中,然后快速獲取該對象的引用,這樣,就比把對象信息存儲到關(guān)系數據庫中,分別取出屬性,然后再初始化對象操作的做法,效率要高得多了。這是LDAP目前比普通關(guān)系數據庫存儲要優(yōu)秀的地方,而對象數據庫還不成熟。
客戶(hù)端訪(fǎng)問(wèn)工具;
a) openldap命令行;
Openldap提供了在UNIX命令行下的訪(fǎng)問(wèn)工具集。包括ldapsearch,ldapadd,ldapmodify,ldappassword,ldapdelete等必要的工具。除了使用man獲得使用幫助外,還可以在http://www.tldp.org/HOWTO/LDAP-HOWTO/,及http://www.csis.gvsu.edu/GeneralInfo/Oracle/network.920/a96579/,獲得使用的支持。
例子:通過(guò)查詢(xún)根上下文判斷LDAP服務(wù)器是否正常工作:
$ ldapsearch -x -b "" -s base "objectclass=*" namingContexts
注:該命令查詢(xún)該當前服務(wù)器上的命令上下文,通常就是rootdn的上下文記錄。
-x 指該查詢(xún)使用目錄認證而不是使用SASL認證,;
-b “” 是查詢(xún)的起點(diǎn),即base,空指從根開(kāi)始查詢(xún);
-s base 指查詢(xún)范圍。有三種選項,one指一層,包括兄弟條目;base指當前條目,sub,子孫記錄。默認是sub.
“objectclass=*” 是過(guò)濾器,表示所有記錄類(lèi)型都加以選擇;
namingContexts是約定的特殊屬性,可以選擇其他屬性值進(jìn)行查詢(xún)。
$ ldapsearch -x -b "dc=daifu,dc=com" -s base "objectclass=organization" dn dc
注:
-b “dc=daifu,dc=com” 指查詢(xún)的是“dc=daifu,dc=com”的條目,需要注意的是,slapd.conf中指定rootdn為“dc=daifu,dc=com”,并不等同于目錄中已經(jīng)具有真實(shí)的“dc=daifu,dc=com”條目。
"objectclass=organization" 指查詢(xún)條件是organization類(lèi)的。
“dc dc”指只需列出dn,dc兩項屬性。
(ldapadd),ldapmodify的操作是基于LDIF文件的,所以必須先按規則生成LDIF文本文件,然后執行導入。要注意的是,新裝的LDAP具備一個(gè)上下文,并不等于在目錄中有相應的條目。如,OPENLDAP的slapd.conf中已經(jīng)定義了一個(gè)根“dc=daifu,dc=com”,并不等于可以把新的條目添加到”dc=daifu,dc=com”,因此實(shí)際上并沒(méi)有這一條目,必須先執行添加相應的條目,然后才可以添加后續條目。
其次,LDIF的格式文件非常嚴格,空間被認為是確定的字符,因此,需要特別注意每行后面不應帶有空格。
b) ldapbrowser;
ldapbrowser是開(kāi)源的LDAP瀏覽工具,并帶有不太強的條目編輯功能。Ldapbrowser是純JAVA的程序,可跨平臺運行,在開(kāi)源的程序中,是最優(yōu)秀的一個(gè)。缺點(diǎn)是不能瀏覽服務(wù)器端的schema對象,從而限制了條目編輯(添加)的能力。
其次,由于JAVA對LDAP的訪(fǎng)問(wèn)方式在添加時(shí),必須預先生成一個(gè)實(shí)現DirContext接口的類(lèi),因此,這也令訂制型的添加操作在JAVA實(shí)現時(shí)相當困難。
c) ldapadministrator;
ldapadministrator是一個(gè)windows的收費程序,試用一個(gè)月。Ldapadministrator除了具備ldapbrowser的功能外,在條目編輯上的功能大為增強。
但從另一個(gè)角度看,LDAP總是涉及到大量的條目,當需要編輯的條目急速增加時(shí),使用ldapadminstrator就不是輕松的事情,此時(shí)還是使用LDIF文件交 換為佳。
d) 瀏覽器;
根據rfc2255.txt的約定,可以使用URI定義LDAP查詢(xún),因此,理論上,只要瀏覽器內嵌支持,就可以作為L(cháng)DAP客戶(hù)端使用。 IE瀏覽器支持簡(jiǎn)單的LDAP查詢(xún)。此時(shí),IE把LDAP的URI看作是查詢(xún)的對象。但是IE以及Exchange server非常狹隘地把LDAP看作是純粹為EMAIL地址查詢(xún)服務(wù)的,只能以“圖形”的方式顯示查到的郵件地址什么的。因此,IE準確地說(shuō),是對LDAP存儲的郵件地址信息的查詢(xún)工具。
URI查詢(xún)語(yǔ)法是:
ldapurl = scheme "://" [hostport] ["/"
[dn ["?" [attributes] ["?" [scope]
["?" [filter] ["?" extensions]]]]]]
scheme = "ldap"
attributes = attrdesc *("," attrdesc)
scope = "base" / "one" / "sub"
dn = distinguishedName from Section 3 of [1]
hostport = hostport from Section 5 of RFC 1738 [5]
attrdesc = AttributeDeion from Section 4.1.5 of [2]
filter = filter from Section 4 of [4]
extensions = extension *("," extension)
extension = ["!"] extype ["=" ex]
extype = token / xtoken
ex = LDAPString from section 4.1.2 of [2]
token = oid from section 4.1 of [3]
xtoken = ("X-" / "x-") token
例:
類(lèi)似
#ldapsearch –x –h 192.168.0.2 –p 389 -b “dc=daifu,dc=com” –b “sub” “objectclass=qmailuser”
的URI查詢(xún)是:
ldap://192.168.0.2:389/dc=daifu,dc=com??sub?objectclass=qmailuser?
瀏覽器并不是完全的LDAP客戶(hù)工具。
e) ldapexplorer(PHP)
一個(gè)用PHP寫(xiě)的LDAP處理工具
二、 編寫(xiě)LDAP訪(fǎng)問(wèn)程序;
a) JAVA
i. JNDI(JAVA 命名及目錄接口)
JNDI是JAVA為命名及目錄服務(wù)訪(fǎng)問(wèn)制定的基礎接口標準,用于訪(fǎng)問(wèn)包括DNS,NIS,LDAP,文件系統等任何以樹(shù)目錄形式存在目標對象,并且基本上可保持訪(fǎng)問(wèn)方式的一致(意味著(zhù)代碼共用)。對于不同的目錄類(lèi)型,JNDI通過(guò)使用不同的目錄驅動(dòng),以保證訪(fǎng)問(wèn)方式的一致。
以下連接可獲得較詳細的講解和例程:http://java.sun.com/products/jndi/tutorial/
經(jīng)常使用的LDAP驅動(dòng)有JDK自帶的LDAP provider,還有IBM的PROVIDER,以及NOVEL的JNDI產(chǎn)品。需要提醒的是,JNDI中最重要的概念是上下文context,即定位從那一個(gè)入口開(kāi)始操作,相當于openldap命令行中的-D開(kāi)關(guān)的作用。其他的操作都是該上下文對象的調用。
LDAP通過(guò)JNDI添加條目是基于DirContext類(lèi)的操作。由于JAVA只能以對象方式向LDAP添加條目,因此,必須首先具備實(shí)現DirContext接口的類(lèi),或使用DirContext(擴充了context接口)代替context,然后才能通過(guò)ctx.bind()的方法把該類(lèi)添加到目錄中。
JAVA-LDAP-ADD的操作可以有三種方式:
Context.bind()或ctx.createSubcontext("name");
或DirContext.bind(“dn”,attrs,object)的方式。對于沒(méi)有預先編寫(xiě)實(shí)現DirContext接口的類(lèi)對象的添加,這是唯一的辦法。
ii. JLDAP
JLDAP是由novel開(kāi)發(fā)的,原是針對Novel的NDS目錄設計的JAVA訪(fǎng)問(wèn)工具。NOVEL的NDS和網(wǎng)景(NETSCAPE)的目錄是工具界最早的目錄產(chǎn)品。JLDAP并非JNDI的服務(wù)供應者,而是同一抽象層次下的訪(fǎng)問(wèn)工具集。與JNDI-LDAP相比,JLDAP更接近于類(lèi)關(guān)系數據庫的訪(fǎng)問(wèn)方式。
NDS是遵守LDAP協(xié)議的并進(jìn)行了擴展的類(lèi)MAD產(chǎn)品。而NOVEL也已把JLDAP捐獻給了OPENLDAP開(kāi)源項目,可以世界范圍內自由使用。與JNDI相比,JLDAP無(wú)須繼承DirContext才能實(shí)現添加,也無(wú)需預先生成添加的類(lèi),可以象普通數據訪(fǎng)問(wèn)那樣,生成連接,然后使用::add方法添加。這樣,添加的靈活性要強于JNDI。
但由于JLDAP目前是訪(fǎng)問(wèn)NDS,因此,它不具備JNDI完全面向對象存儲的能力,對于高級的LDAP應用,JLDAP不是合適的選擇。
例:
import com.novell.ldap.*;
public class AddEntry
{
public static void main( String[] args )
{
if (args.length != 4) {
System.err.println("Usage: java AddEntry <host name> <login dn>"
+ " <password> <container>");
System.err.println("Example: java AddEntry Acme.com"
+ " \"cn=admin,o=Acme\" secret \"ou=Sales,o=Acme\"");
System.exit(1);
}
int ldapPort = LDAPConnection.DEFAULT_PORT;
int ldapVersion = LDAPConnection.LDAP_V3;
String ldapHost = args[0];
String loginDN = args[1];
String password = args[2];
String containerName = args[3];
LDAPConnection lc = new LDAPConnection();
LDAPAttribute attribute = null;
LDAPAttributeSet attributeSet = new LDAPAttributeSet();
/* To Add an entry to the directory,
* -- Create the attributes of the entry and add them to an attribute set
* -- Specify the DN of the entry to be created
* -- Create an LDAPEntry object with the DN and the attribute set
* -- Call the LDAPConnection add method to add it to the directory
*/
String objectclass_s[] = { "inetOrgPerson" };
attribute = new LDAPAttribute( "objectclass", objectclass_s );
attributeSet.add( attribute );
String cn_s[] = { "James Smith", "Jim Smith", "Jimmy Smith" };
attribute = new LDAPAttribute( "cn", cn_s );
attributeSet.add( attribute );
String givenname_s[] = { "James", "Jim", "Jimmy" };
attribute = new LDAPAttribute( "givenname", givenname_s );
attributeSet.add( attribute );
attributeSet.add( new LDAPAttribute( "sn", "Smith" ) );
attributeSet.add( new LDAPAttribute( "telephonenumber",
"1 801 555 1212" ) );
attributeSet.add( new LDAPAttribute( "mail", "JSmith@Acme.com" ) );
String dn = "cn=JSmith," + containerName;
LDAPEntry newEntry = new LDAPEntry( dn, attributeSet );
try {
// connect to the server
lc.connect( ldapHost, ldapPort );
// authenticate to the server
lc.bind( ldapVersion, loginDN, password );
lc.add( newEntry );
System.out.println( "\nAdded object: " + dn + " successfully." );
// disconnect with the server
lc.disconnect();
}
catch( LDAPException e ) {
System.out.println( "Error: " + e.toString());
}
System.exit(0);
}
}
iii. JdbcLDAP
JDBCLDAP是OcterString提供的,能過(guò)類(lèi)SQL實(shí)現LDAP訪(fǎng)問(wèn)的工具。JDBCLDAP是針對大量熟悉SQL而對LDAP欠缺了解的程序員而設計的,可以完成簡(jiǎn)單的LDAP查詢(xún)、插入、更新、刪除這樣的工作。
JdbcLDAP使用LDAP-JDBC驅動(dòng)訪(fǎng)問(wèn)“LDAP數據庫”:
Class.forName("com.octetstring.jdbcLdap.sql.JdbcLdapDriver");
連接時(shí)使用各個(gè)DN的具體權限建立連接:
String ldapConnectString = "jdbc:ldap://localhost:389/dc=examples,dc=com?SEARCH_SCOPE:=subTreeScope";
java.sql.Connection con;
con = DriverManager.getConnection(ldapConnectString,"cn=Admin","manager");
連接字符串遵從標準的LDAP-URL格式,(RFC2255)。
SQL操作時(shí),將每一個(gè)目錄ENTRY看作是一個(gè)統一表的一行,然后把屬性看作列,如:
String SQL = "INSERT INTO cn,ou (objectClass,objectClass,objectClass,ou,sn,cn) " +
"S (top,person,organizationalPerson,Product Development,Boorshtein," +
"Marc Boorshtein)";
Statement insert = con.createStatement();
int count = insert.executeUpdate(SQL);
if (count < 1) {
System.out.println("Insert Failed");
} else {
System.out.println("Insert Succeeded");
}
Ou,sn,cn是新條目的入口標識。
Jdbc-LDAP不可以完成串行化binding,因此,只適宜對已有的LDAP進(jìn)行臨時(shí)訪(fǎng)問(wèn)(如程序員不熟悉,或保持舊程序,僅修改必要的連接項),不宜把整個(gè)項目建筑在JDBC-LDAP上。實(shí)際上,LDAP本身就是一種訪(fǎng)問(wèn)的前端協(xié)議,硬要把SQL再作為前端使用,是完全沒(méi)有必要的。
b) C語(yǔ)言:
包括openldap,netscape(sun),mozilla, novell,ibm等,都提供了LDAP的C SDK和接口函數。作為RFC標準的LDAP結構,struct LDAP是定義為對用戶(hù)隱藏的,并在各個(gè)實(shí)現函數中各自定義,以便適應不同的LDAP訪(fǎng)問(wèn)。
#typedef struct ldap LDAP在ldap.h中定義;在2.0版以后,struct LDAP改為隱藏,只能能過(guò)函數ldap_set_option 和ldap_get_option訪(fǎng)問(wèn)。(draft-ldapext-ldap-c-api-xx.txt)
使用時(shí):
如:
LDAP *Ld=null; //聲明并初始化LDAP類(lèi)型的變量指針 *ld;
Ld =ldap_init( ldaphost, ldapport ); //獲取LDAP的會(huì )話(huà);
獲得會(huì )話(huà)后,調用ldap_simple_bind_s獲得訪(fǎng)問(wèn)LDAP的權限,然后就可以調用不同的函數,如
ldap_search_ext( ld, base, scope, filter, attrs, attrsonly,
sctrls, cctrls, timeout, sizelimit, &msgid );
即可完成相關(guān)的操作。
即步驟為:1。獲得會(huì )話(huà);2。綁定對象;3。執行操作。
連接例子:
#i nclude <stdio.h>
#i nclude "ldap.h"
/* Adjust these setting for your own LDAP server */
#define HOSTNAME "localhost"
#define PORT_NUMBERLDAP_PORT
#define FIND_DN "uid=bjensen, ou=People, o=Airius.com"
int
main( int argc, char **argv )
{
LDAP*ld;
LDAPMessage*result, *e;
BerElement*ber;
char*a;
char**vals;
int i, rc;
/* Get a handle to an LDAP connection. */
if ( (ld = ldap_init( HOSTNAME, PORT_NUMBER )) == NULL ) {
perror( "ldap_init" );
return( 1 );
}
/* Bind anonymously to the LDAP server. */
rc = ldap_simple_bind_s( ld, NULL, NULL );
if ( rc != LDAP_SUCCESS ) {
fprintf(stderr, "ldap_simple_bind_s: %s\n", ldap_err2string(rc));
return( 1 );
}
/* Search for the entry. */
if ( ( rc = ldap_search_ext_s( ld, FIND_DN, LDAP_SCOPE_BASE,
"(objectclass=*)", NULL, 0, NULL, NULL, LDAP_NO_LIMIT,
LDAP_NO_LIMIT, &result ) ) != LDAP_SUCCESS ) {
fprintf(stderr, "ldap_search_ext_s: %s\n", ldap_err2string(rc));
return( 1 );
}
/* Since we are doing a base search, there should be only
one matching entry. */
e = ldap_first_entry( ld, result );
if ( e != NULL ) {
printf( "\nFound %s:\n\n", FIND_DN );
/* Iterate through each attribute in the entry. */
for ( a = ldap_first_attribute( ld, e, &ber );
a != NULL; a = ldap_next_attribute( ld, e, ber ) ) {
/* For each attribute, print the attribute name and s. */
if ((vals = ldap_get_s( ld, e, a)) != NULL ) {
for ( i = 0; vals[i] != NULL; i++ ) {
printf( "%s: %s\n", a, vals[i] );
}
ldap__free( vals );
}
ldap_memfree( a );
}
if ( ber != NULL ) {
ber_free( ber, 0 );
}
}
ldap_msgfree( result );
ldap_unbind( ld );
return( 0 );
}
i. Novell函數庫:
Novel提供了基于普通LDAP函數庫的擴展,主要包括兩個(gè)部分:針對Novel eDirectory服務(wù)器產(chǎn)品的擴展,其次是對如ldapsearch等常用函數的擴展。詳情可從:http://developer.novell.com/ndk/qstart/opensource.htm#ldapc 獲得幫助;
ii. Netscape函數庫;
Netscape一度是企業(yè)級目錄服務(wù)提供者,許多LDAP的C例子,實(shí)際上都是基于Netscape服務(wù)器的。但在Netscape被收購后,其目錄服務(wù)成了iPlanet和SUN eDirectory產(chǎn)品的一部分,出于支持JAVA和iplanet產(chǎn)品的緣故,SUN對該產(chǎn)品和相關(guān)庫的支持遠不夠積極,特別是對linux的支持不夠充分,估計也與保護solaris產(chǎn)品有關(guān)。
iii. Mozilla函數庫:
Mozilla可以看作是Netscape的另一個(gè)分支。準確地說(shuō),Netscape本來(lái)就是源于Mozilla。Mozilla是也是一個(gè)開(kāi)源的項目,提供完整的C-SDK,缺點(diǎn)是對linux的支持不夠充分。
c) Perl接口
Perl 的NET::LDAP模塊中包括有完整的LDAP目錄訪(fǎng)問(wèn)函數,只要安裝NET::LDAP就可以完成正常的LDAP目錄訪(fǎng)問(wèn);但在安裝NET::LDAP模塊前,必須先安裝Convert::ASN1模塊,該模塊可以從CPAN下載。
例:
#!/usr/bin/perl
use warnings;
use strict;
use Net::LDAP;
use Net::LDAP::Util qw(ldap_error_text);
my $server = "localhost";
my $ldap = new Net::LDAP($server) ||
die("failed to connect to server.$!\n");
my $mesg = $ldap->bind("cn=Manager,dc=daifu,dc=com", password => "secret");
die ("bind failed with ",ldap_error_text($mesg->code()),"\n")
if $mesg->code();
$mesg = $ldap->search(base => "dc=daifu,dc=com", scope => "sub",
filter => "sn=*",);
die ("search failed with ",ldap_error_text($mesg->code()),"\n")
if $mesg->code();
print "Count is ",$mesg->count(),"\n";
while (my $entry = $mesg->shift_entry()) {
print "dn:",$entry->dn(),"\n";
for my $attr($entry->attributes()) {
for my $val($entry->get_($attr)) {
print "$attr:$val\n";
}
}
print "\n";
}
操作過(guò)程實(shí)際上與C和JAVA是一樣的。
(http://www.fanqiang.com)
原文鏈接:http://www.daifusecure.com/articles/ldap.php