有關(guān)LDAP協(xié)議的整理(轉(zhuǎn))
LDAP的英文全稱是Lightweight Directory Access Protocol,即輕量級(jí)目錄訪問協(xié)議.我們知道,人們對(duì)計(jì)算機(jī)網(wǎng)絡(luò)的使用和管理涉及了各種龐雜的資源,信息.為了提高性能,便于使用,有效管理分布式應(yīng)用的服務(wù),資源,用戶及別的對(duì)象信息,這些信息需要清晰,一致地組織起來.基于這樣的需求,描述各種用戶,應(yīng)用,文件,打印機(jī)和其它可從網(wǎng)絡(luò)訪問的資源的信息被集中到一個(gè)特殊的數(shù)據(jù)庫中,這種數(shù)據(jù)庫被稱為目錄.目錄存放對(duì)象的公開或非公開的信息,這些信息以某種順序組織,描述了每個(gè)對(duì)象的細(xì)節(jié).電話簿,圖書館藏書卡片目錄就是常見的目錄. LDAP是基于X.500標(biāo)準(zhǔn)的,訪問 X.500 目錄需要某種協(xié)議,例如:目錄訪問協(xié)議 (DAP).然而,DAP 需要大量的系統(tǒng)資源和支持機(jī)制來處理復(fù)雜的協(xié)議.LDAP 僅通過使用原始 X.500目錄存取協(xié)議 (DAP) 的功能子集而減少了所需的系統(tǒng)資源消耗,而且可以根據(jù)需要定制.此外,與X.500不同,LDAP支持TCP/IP,這對(duì)訪問Internet是必須的. 為了能對(duì)LDAP協(xié)議進(jìn)行更好的理解,我們需要對(duì)以下概念有初步的認(rèn)識(shí):目錄:Directory,存放對(duì)象的信息,這些信息以某種順序組織,詳細(xì)描述每個(gè)對(duì)象.目錄信息樹:DIT,Directory Information Tree,目錄條目的集合構(gòu)成了目錄信息樹.條目:Entry,目錄信息樹中的一個(gè)結(jié)點(diǎn),是一個(gè)對(duì)象信息的集合,是目錄信息中最基本的單位,包含該對(duì)象的一系列屬性.屬性:Attribute,屬性描述對(duì)象的特征.一個(gè)屬性由屬性類型(type)和一個(gè)或多個(gè)屬性值(values)構(gòu)成.相對(duì)標(biāo)識(shí)名:RDN,Relative Distinguished Name,條目的名字.唯一標(biāo)識(shí)名:DN,Distinguished Name,在一個(gè)目錄信息樹中唯一標(biāo)識(shí)一個(gè)條目的名字. LDAP(輕量級(jí)目錄訪問協(xié)議,Lightweight Directory Access Protocol)是實(shí)現(xiàn)提供被稱為目錄服務(wù)的信息服務(wù)。 目錄服務(wù)是一種特殊的數(shù)據(jù)庫系統(tǒng),其專門針對(duì)讀取,瀏覽和搜索操作進(jìn)行了特定的優(yōu)化。目錄一般用來包含描 述性的,基于屬性的信息并支持精細(xì)復(fù)雜的過濾能力。目錄一般不支持通用數(shù)據(jù)庫針對(duì)大量更新操作操作需要的 復(fù)雜的事務(wù)管理或回卷策略。而目錄服務(wù)的更新則一般都非常簡單。這種目錄可以存儲(chǔ)包括個(gè)人信息、web鏈結(jié)、 jpeg圖像等各種信息。為了訪問存儲(chǔ)在目錄中的信息,就需要使用運(yùn)行在TCP/IP之上的訪問協(xié)議—LDAP。
LDAP目錄中的信息是是按照樹型結(jié)構(gòu)組織,具體信息存儲(chǔ)在條目(entry)的數(shù)據(jù)結(jié)構(gòu)中。條目相當(dāng)于關(guān)系數(shù)據(jù)庫中 表的記錄;條目是具有區(qū)別名DN(Distinguished Name)的屬性(Attribute),DN是用來引用條目的,DN相當(dāng)于 關(guān)系數(shù)據(jù)庫表中的關(guān)鍵字(Primary Key)。屬性由類型(Type)和一個(gè)或多個(gè)值(Values)組成,相當(dāng)于關(guān)系數(shù) 據(jù)庫中的字段(Field)由字段名和數(shù)據(jù)類型組成,只是為了方便檢索的需要,LDAP中的Type可以有多個(gè)Value, 而不是關(guān)系數(shù)據(jù)庫中為降低數(shù)據(jù)的冗余性要求實(shí)現(xiàn)的各個(gè)域必須是不相關(guān)的。LDAP中條目的組織一般按照地理位置 和組織關(guān)系進(jìn)行組織,非常的直觀。LDAP把數(shù)據(jù)存放在文件中,為提高效率可以使用基于索引的文件數(shù)據(jù)庫,而不 是關(guān)系數(shù)據(jù)庫。類型的一個(gè)例子就是mail,其值將是一個(gè)電子郵件地址。
WebLogic的內(nèi)置的LDAP Server支持IETF LDAP為LDAPv3制定的控制訪問模型。下面這個(gè)片斷將講述在內(nèi)置的LDAP Server中怎樣實(shí)現(xiàn)控制訪問。可以通過編輯訪問控制文件來將這些規(guī)則直接應(yīng)用到目錄的入口。WebLogic中的訪問控制文件是acls.prop。在Server的lib中可以找到這個(gè)文件。這個(gè)文件的所有訪問控制規(guī)則都被注釋掉了,如果想更改這些規(guī)則,你要手工更改這個(gè)文件。注意:WebLogic Server內(nèi)置的LDAP Server在默認(rèn)的情況下只允許Admin帳號(hào)訪問,WebLogic Server的security providers只使用Admin帳號(hào)訪問內(nèi)置的LDAP Server。如果你不想使用外部的LDAP Brower訪問WebLogic Server的內(nèi)置的LDAP Server,或者你只想使用Admin帳號(hào)訪問內(nèi)置的LDAP Server,你不需要編輯acls.prop文件,訪問控制文件(The Access Control File)
訪問控制文件(acls.prop)包含內(nèi)置的LDAP Server的整個(gè)目錄的完整的訪問控制列表(ACL)。這個(gè)文件中的每一行都包含一個(gè)訪問控制規(guī)則。一個(gè)訪問控制規(guī)則由下面接個(gè)部分組成: 訪問控制位置(Access Control Location) 每個(gè)訪問控制規(guī)則都應(yīng)用于LDAP目錄中的一個(gè)給定的位置。這個(gè)位置通常是一個(gè)區(qū)別命名(DN),但有一個(gè)例外,這就是[root],如果訪問控制規(guī)則應(yīng)用到整個(gè)目錄,則只需要指定位置為[root]就可以了! 如果被訪問或更改的入口的位置與訪問控制規(guī)則指定的位置不相等,或在訪問控制規(guī)則指定的位置的下級(jí),則這個(gè)訪問控制規(guī)則將不會(huì)被執(zhí)行。
訪問控制范圍(Access Control Scope) 訪問控制范圍有2種: Entry-一個(gè)Entry范圍的訪問控制列表只在下面的情況下被執(zhí)行: LDAP目錄的入口的DN與訪問控制規(guī)則指定的位置相同。這樣的規(guī)則對(duì)于包含了比并行和副入口更敏感信息的單獨(dú)入口非常有用。 Subtree-意味著訪問控制規(guī)則指定的位置及子樹都可以適用這條規(guī)則。 如果Entry與Subtree在訪問控制規(guī)則中有沖突,則Entry要優(yōu)先于Subtree。
訪問權(quán)限(Access Rights) 訪問權(quán)限應(yīng)用于整個(gè)對(duì)象或?qū)ο蟮膶傩裕?個(gè)值:grant(準(zhǔn)許)或deny(拒絕)。訪問權(quán)限指定了LDAP操作的類型。 許可(grant或deny)
應(yīng)用規(guī)則的屬性(attribute)
允許或拒絕訪問的主題(subject) 在weblogic可以編寫程序來訪問LDAP.上手時(shí)可以選擇JXplorer工具。 1.LDAP Server及LDAP Browser: 對(duì)于WLS LDAP為理解起來簡單,去掉限制的方法是修改bea\weblogic81\server\lib\acls.prop文件后。修改方法:在該文件最后添加以下幾行。[root]|entry#grant:s,r,o,w,c,m#[all]#public[root]|subtree#grant:s,r,o,w,c,m#[all]#public:[root]|subtree#grant:a,d,e,i,n,b,t#[entry]#public:cn=schema|entry#grant:s,r,o,w,c,m#[all]#public:cn=schema|entry#grant:a,d,e,i,n,b,t#[entry]#public:注意,該文件中這些行之間,以及其他行之間不能有空行,否則啟動(dòng)WLS會(huì)報(bào)錯(cuò)的。修改好之后就可以啟動(dòng)WLS了,啟動(dòng)后進(jìn)入Console里修改Ldap Server的密碼。密碼修改完后需要再重新啟動(dòng)一次WLS。
LDAP剛上手的時(shí)候沒有方便的工具會(huì)很費(fèi)勁。我看了CSDN上“兔八哥”的文章,用JXplorer,感覺很不錯(cuò)。想看這篇文章,到CSDN上搜一下“兔八哥”,系列中No.12就是關(guān)于JXplorer的配置和使用。我的連接參數(shù)如下:Host:localhost//根據(jù)實(shí)際修改Port:7001Protocol:LDAP v3Base DN:dc=ldapdomain//根據(jù)實(shí)際修改Level:User PasswordUser DN:cn=AdminPassword:weblogic//根據(jù)實(shí)際修改.編程操作LDAP Server。 下面四個(gè)JAVA方法,分別用于初始化,查詢,添加,刪除,修改,關(guān)閉連接。 記得每次都需要先大概連接,操作,然后關(guān)閉連接。和使用數(shù)據(jù)庫差不多。 首先是需要用到的頭文件:import java.util.Hashtable;import java.util.Enumeration;import javax.naming.Context;import javax.naming.NamingException;import javax.naming.directory.DirContext;import javax.naming.directory.InitialDirContext;import javax.naming.directory.SearchControls ;import javax.naming.NamingEnumeration;import javax.naming.directory.SearchResult;import javax.naming.directory.Attributes ;import javax.naming.directory.Attribute;import javax.naming.directory.BasicAttributes;import javax.naming.directory.BasicAttribute;import javax.naming.directory.ModificationItem;import java.lang.reflect.Method;import java.io.BufferedReader;import java.io.InputStreamReader;
然后是一個(gè)類域,用于保存上下文: DirContext ctx = null; 然后是初始化: public void init(){ String account="Admin";//操作LDAP的帳戶。默認(rèn)就是Admin。 String password="weblogic";//帳戶Admin的密碼。 String root="dc=ldapdomain"; //所操作的WLS域。也就是LDAP的根節(jié)點(diǎn)的DC Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");//必須這樣寫,無論用什么LDAP服務(wù)器。 env.put(Context.PROVIDER_URL, "ldap://localhost:7001/" root);//LDAP服務(wù)器的地址:端口。對(duì)WLS端口就是7001 env.put(Context.SECURITY_AUTHENTICATION, "none");//授權(quán)界別,可以有三種授權(quán)級(jí)別,但是如果設(shè)為另外兩種都無法登錄,我也不知道為啥,但是只能設(shè)成這個(gè)值"none"。 env.put(Context.SECURITY_PRINCIPAL, "cn=" account "," root);//載入登陸帳戶和登錄密碼 env.put(Context.SECURITY_CREDENTIALS, password); try{ ctx = new InitialDirContext(env);//初始化上下文 System.out.println("認(rèn)證成功");//這里可以改成異常拋出。 }catch(javax.naming.AuthenticationException e){ System.out.println("認(rèn)證失敗"); }catch(Exception e){ System.out.println("認(rèn)證出錯(cuò):" e); } }
查詢操作: public void search(){//我只能按照某些屬性查找節(jié)點(diǎn),偶還不會(huì)怎么查找一個(gè)目錄或按照更復(fù)雜的正則式查找特定節(jié)點(diǎn)/目錄 try{ SearchControls constraints = new SearchControls(); constraints.setSearchScope(SearchControls.SUBTREE_SCOPE); System.out.print("what would you want to search:"); BufferedReader bd=new BufferedReader(new InputStreamReader(System.in)); String s=bd.readLine(); NamingEnumeration en = ctx.search("", "uid=" s, constraints); //要查詢的UID。如果是*則可以查到所有UID的節(jié)點(diǎn) if(en == null){ System.out.println("Have no NamingEnumeration."); } if(!en.hasMoreElements()){ System.out.println("Have no element."); } while (en != null && en.hasMoreElements()){//可以查出多個(gè)元素 Object obj = en.nextElement(); if(obj instanceof SearchResult){ SearchResult si = (SearchResult) obj; System.out.println("\tname: " si.getName()); Attributes attrs = si.getAttributes(); if (attrs == null){ System.out.println("\tNo attributes"); }else{ for (NamingEnumeration ae = attrs.getAll(); ae.hasMoreElements();){//獲得該節(jié)點(diǎn)的所有屬性 Attribute attr = (Attribute) ae.next();//下一屬性 String attrId = attr.getID();//獲得該屬性的屬性名 for (Enumeration vals = attr.getAll();vals.hasMoreElements();){//獲得一個(gè)屬性中的所有屬性值 System.out.print("\t\t" attrId ": "); Object o = vals.nextElement();//下一屬性值 if(o instanceof byte[]) System.out.println(new String((byte[])o)); else System.out.println(o); } } } } else{ System.out.println(obj); } System.out.println(); } }catch(Exception e){ System.out.println("Exception in search():" e); } } 添加操作: public void add(){ try{ String newUserName = "stella"; BasicAttributes attrs = new BasicAttributes(); BasicAttribute objclassSet = new BasicAttribute("objectclass"); objclassSet.add("person"); objclassSet.add("top"); objclassSet.add("organizationalPerson");
objclassSet.add("inetOrgPerson"); objclassSet.add("wlsUser"); attrs.put(objclassSet); attrs.put("sn", newUserName); attrs.put("uid", newUserName); attrs.put("cn", newUserName); ctx.createSubcontext("uid=" newUserName ",ou=people,ou=myrealm", attrs); //添加一個(gè)節(jié)點(diǎn),我還不會(huì)添加目錄 }catch(Exception e){ System.out.println("Exception in add():" e); } }
修改操作: public void edit(){ try{ String account = "stella";//修改以前舊的值 String sn = "stella sn";//修改以后新的值 ModificationItem modificationItem[] = new ModificationItem[1]; modificationItem[0] = new ModificationItem( DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("sn", sn));//所修改的屬性 ctx.modifyAttributes("uid=" account, modificationItem); //執(zhí)行修改操作 }catch(Exception e){ System.out.println("Exception in edit():" e); } }
刪除節(jié)點(diǎn)操作: public void delete(){ try{ String uid = "stella"; ctx.destroySubcontext("uid=" uid); //按照UID刪除某個(gè)節(jié)點(diǎn)。我還不會(huì)刪除一個(gè)目錄。 }catch(Exception e){ System.out.println("Exception in edit():" e); } }
關(guān)閉連接: public void close(){ if(ctx != null) { try { ctx.close(); } catch (NamingException e) { System.out.println("NamingException in close():" e); } } }我對(duì)LDAP的理解:它是用于對(duì)資源的管理和服務(wù)的訪問協(xié)議,在Weblogic平臺(tái)上的JNDI(包含EJB和DataSource)都是提供它來提供的。正是JNDI的服務(wù)和RMI結(jié)合就形成J2EE平臺(tái)上分布式的應(yīng)用,因此說到底層,還是LDAP協(xié)議的支持。
部分資料參考:http://www.aygfsteel.com/kapok/archive/2005/05/05/4034.html
http://www.blogdriver.com/goblinize/250559.html
posted on 2007-06-04 09:36 junky 閱讀(833) 評(píng)論(0) 編輯 收藏 所屬分類: database