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刚上手的时候没有方便的工具会很费劲。我看了上“兔八哥”的文章,用JXplorer,感觉很不错。想看这篇文章,到上搜一下“兔八哥”,系列中No.12就是关于JXplorer的配置和使用。我的连接参数如下:Host:localhost//根据实际修改Port:7001Protocol:LDAP v3Base DN:dc=ldapdomain//根据实际修改Level:User+PasswordUser DN:cn=AdminPassword: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协议的支持。
