?? LDAP的英文全稱是Lightweight Directory Access Protocol,即輕量級目錄訪問協議.我們
知道,人們對計算機網絡的使用和管理涉及了各種龐雜的資源,信息.為了提高性能,便于使
用,有效管理分布式應用的服務,資源,用戶及別的對象信息,這些信息需要清晰,一致地組
織起來.基于這樣的需求,描述各種用戶,應用,文件,打印機和其它可從網絡訪問的資源的
信息被集中到一個特殊的數據庫中,這種數據庫被稱為目錄.目錄存放對象的公開或非公開的
信息,這些信息以某種順序組織,描述了每個對象的細節.電話簿,圖書館藏書卡片目錄就是
常見的目錄.
???? LDAP是基于X.500標準的,訪問 X.500 目錄需要某種協議,例如:目錄訪問協議 (DAP).
然而,DAP 需要大量的系統資源和支持機制來處理復雜的協議.LDAP 僅通過使用原始 X.500
目錄存取協議 (DAP) 的功能子集而減少了所需的系統資源消耗,而且可以根據需要定制.此
外,與X.500不同,LDAP支持TCP/IP,這對訪問Internet是必須的.
??? 為了能對LDAP協議進行更好的理解,我們需要對以下概念有初步的認識:
目錄:Directory,存放對象的信息,這些信息以某種順序組織,詳細描述每個對象.
目錄信息樹:DIT,Directory Information Tree,目錄條目的集合構成了目錄信息樹.
條目:Entry,目錄信息樹中的一個結點,是一個對象信息的集合,是目錄信息中最基本的
單位,包含該對象的一系列屬性.
屬性:Attribute,屬性描述對象的特征.一個屬性由屬性類型(type)和一個或多個屬性值
(values)構成.
相對標識名:RDN,Relative Distinguished Name,條目的名字.
唯一標識名:DN,Distinguished Name,在一個目錄信息樹中唯一標識一個條目的名字.
??? 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,其值將是一個電子郵件地址。
WebLogic的內置的LDAP Server支持IETF LDAP為LDAPv3制定的控制訪問模型。下面這個片斷將講述在內置的LDAP
Server中怎樣實現控制訪問。可以通過編輯訪問控制文件來將這些規則直接應用到目錄的入口。
WebLogic中的訪問控制文件是acls.prop。在Server的lib中可以找到這個文件。
這個文件的所有訪問控制規則都被注釋掉了,如果想更改這些規則,你要手工更改這個文件。
注意:WebLogic Server內置的LDAP Server在默認的情況下只允許Admin帳號訪問,WebLogic Server的security providers
只使用Admin帳號訪問內置的LDAP Server。如果你不想使用外部的LDAP Brower訪問WebLogic Server的內置的LDAP Server,
或者你只想使用Admin帳號訪問內置的LDAP Server,你不需要編輯acls.prop文件,
訪問控制文件(The Access Control File)
訪問控制文件(acls.prop)包含內置的LDAP Server的整個目錄的完整的訪問控制列表(ACL)。
這個文件中的每一行都包含一個訪問控制規則。一個訪問控制規則由下面接個部分組成:
??? 訪問控制位置(Access Control Location)
?????? 每個訪問控制規則都應用于LDAP目錄中的一個給定的位置。這個位置通常是一個區別命名(DN),但有一個例外,這就是[root],如果訪問控制規則應用到整個目錄,則只需要指定位置為[root]就可以了!
?????? 如果被訪問或更改的入口的位置與訪問控制規則指定的位置不相等,或在訪問控制規則指定的位置的下級,則這個訪問控制規則將不會被執行。
?? 訪問控制范圍(Access Control Scope)
?????? 訪問控制范圍有2種:
?????? Entry-一個Entry范圍的訪問控制列表只在下面的情況下被執行:
?????? LDAP目錄的入口的DN與訪問控制規則指定的位置相同。這樣的規則對于包含了比并行和副入口更敏感信息的單獨入口非常有用。
?????? Subtree-意味著訪問控制規則指定的位置及子樹都可以適用這條規則。
??????? 如果Entry與Subtree在訪問控制規則中有沖突,則Entry要優先于Subtree。
?? 訪問權限(Access Rights)
??????? 訪問權限應用于整個對象或對象的屬性,有2個值:grant(準許)或deny(拒絕)。訪問權限指定了LDAP操作的類型。
??
?? 許可(grant或deny)
?? 應用規則的屬性(attribute)
?? 允許或拒絕訪問的主題(subject)
?? 在weblogic可以編寫程序來訪問LDAP.上手時可以選擇JXplorer工具。
?? 1.LDAP Server及LDAP Browser:
????? 對于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:
注意,該文件中這些行之間,以及其他行之間不能有空行,否則啟動WLS會報錯的。修改好之后就可以啟動WLS了,
啟動后進入Console里修改Ldap Server的密碼。密碼修改完后需要再重新啟動一次WLS。
LDAP剛上手的時候沒有方便的工具會很費勁。我看了CSDN上“兔八哥”的文章,用JXplorer,感覺很不錯。
想看這篇文章,到CSDN上搜一下“兔八哥”,系列中No.12就是關于JXplorer的配置和使用。我的連接參數如下:
Host:localhost//根據實際修改
Port:7001
Protocol:LDAP v3
Base DN:dc=ldapdomain//根據實際修改
Level:User+Password
User DN:cn=Admin
Password:weblogic//根據實際修改
.編程操作LDAP Server。
?下面四個JAVA方法,分別用于初始化,查詢,添加,刪除,修改,關閉連接。
?記得每次都需要先大概連接,操作,然后關閉連接。和使用數據庫差不多。
?
?????? 首先是需要用到的頭文件:
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;
然后是一個類域,用于保存上下文:
?
DirContext ctx = null;
?
然后是初始化:
?
??? public void init(){
??????? String account="Admin";//操作LDAP的帳戶。默認就是Admin。
??????? String password="weblogic";//帳戶Admin的密碼。
??????? String root="dc=ldapdomain"; //所操作的WLS域。也就是LDAP的根節點的DC
??????? Hashtable env = new Hashtable();
??????? env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");//必須這樣寫,無論用什么LDAP服務器。
??????? env.put(Context.PROVIDER_URL, "ldap://localhost:7001/" + root);//LDAP服務器的地址:端口。對WLS端口就是7001
??????? env.put(Context.SECURITY_AUTHENTICATION, "none");//授權界別,可以有三種授權級別,但是如果設為另外兩種都無法登錄,我也不知道為啥,但是只能設成這個值"none"。
??????? env.put(Context.SECURITY_PRINCIPAL, "cn=" + account + "," + root);//載入登陸帳戶和登錄密碼
??????? env.put(Context.SECURITY_CREDENTIALS, password);
??????? try{
??????????? ctx = new InitialDirContext(env);//初始化上下文
??????????? System.out.println("認證成功");//這里可以改成異常拋出。
??????? }catch(javax.naming.AuthenticationException e){
??????????? System.out.println("認證失敗");
??????? }catch(Exception e){
??????????? System.out.println("認證出錯:"+e);
??????? }
?}
查詢操作:
?
?public void search(){//我只能按照某些屬性查找節點,偶還不會怎么查找一個目錄或按照更復雜的正則式查找特定節點/目錄
? 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的節點
?? if(en == null){
??? System.out.println("Have no NamingEnumeration.");
?? }
?? if(!en.hasMoreElements()){
??? System.out.println("Have no element.");
?? }
?? while (en != null && en.hasMoreElements()){//可以查出多個元素
?????? 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();){//獲得該節點的所有屬性
?????? Attribute attr = (Attribute) ae.next();//下一屬性
?????? String attrId = attr.getID();//獲得該屬性的屬性名
?????? for (Enumeration vals = attr.getAll();vals.hasMoreElements();){//獲得一個屬性中的所有屬性值
?????????? 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);? //添加一個節點,我還不會添加目錄
? }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);??? //執行修改操作
? }catch(Exception e){
?? System.out.println("Exception in edit():"+e);
? }
??? }
刪除節點操作:
?
??? public void delete(){
???? try{
?? String uid = "stella";
?? ctx.destroySubcontext("uid=" + uid);? //按照UID刪除某個節點。我還不會刪除一個目錄。
?? }catch(Exception e){
??? System.out.println("Exception in edit():"+e);
?? }
??? }
關閉連接:
?
??? public void close(){
??????? if(ctx != null)
??????? {
??????????? try
??????????? {
??????????????? ctx.close();
??????????? }
??????????? catch (NamingException e)
??????????? {
??????????????? System.out.println("NamingException in close():"+e);
??????????? }
??????? }???
??? }
我對LDAP的理解:它是用于對資源的管理和服務的訪問協議,在Weblogic平臺上的JNDI(包含EJB和DataSource)都是提供它來提供的。
正是JNDI的服務和RMI結合就形成J2EE平臺上分布式的應用,因此說到底層,還是LDAP協議的支持。
posted on 2006-12-27 15:00
李大嘴 閱讀(544)
評論(0) 編輯 收藏