Lotus的JAVA与DOMINO通过LDAP集成方法

来源:互联网 发布:如何开通手机淘宝花呗 编辑:程序博客网 时间:2024/05/16 02:20

Lotus的JAVA与DOMINO通过LDAP集成方法!

JAVA, DOMINO, Lotus, LDAP
摘要:LDAP是标准轻量目录访问协议(Lightweight Directory Access Protocol),通过LDAP,你可以访问目录中的用户信息,进行用户验证。DominoR5/6支持标准的LDAP v3目录服务。本文通过描述使用JNDI访问Domino目录的过程,为大家介绍如何充分利用机构中已有的Domino目录资源。本文所述的方法也适用于其他支持LDAP v3的目录服务器。
为什么目录服务如此重要
随着企业中应用程序的增加,我们不得不面对日益增长的各类用户数据。这些用户数据分布在企业各处,带来了很大管理和维护上的麻烦。为了解决这个问题,我们通常需要在企业中构建标准的目录基础设施。同时,在实施EAI(企业应用集成)时,我们还经常会遇到用户需要单点登录(SSO)的情况,而成功实施SSO的基础是我们有一个好的目录基础。
目前,在很多的机构中都实施了基于Domino的应用,例如:办公、邮件、审批等。做为一个兼容各种标准的优秀平台,Domino也提供了对LDAP v3的良好支持。
那么,对于已经架设Domino基础设施的机构,是否考虑从现有的投资中获得更多的回报呢?下面,我们通过两个范例来了解如何充分利用这些保存在Domino中的目录资源。
准备工作
1、 了解JNDI
JNDI(Java Naming And Directory Interface)是在Java中访问各种命名和目录服务的规范。它通过一组扩展的API:javax.naming.*来提供对命名和目录服务的访问。
使用JNDI前,你必须确保你拥有jndi.jar,并且在当前ClassPath中包含它。如果你还没有jndi.jar,可通过参考资料处下载。
2、 配置Domino服务器
在使用下列范例前,你必须先启动你的Domino服务器(我使用R6版本)中,并且启用LDAP服务。
由于我们不需要使用任何特殊的选项,我们无须对Domino的LDAP配置做出任何修改,仅须确认已加载了LDAP服务(在Domino Console上输入:show tasks来查看是否加载了LDAP服务)。如果还没有加载LDAP服务,你可以通过在Domino的服务器控制台上输入:load ldap来加载它。
读取目录信息
下面的代码从目录中读取给定用户的邮件地址。
package net.eservice4you.ldap;
import javax.naming.Context;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.DirContext;
import javax.naming.directory.Attributes;
import javax.naming.NamingException;
import java.util.Hashtable;
class Getattr {
    public static void main(String[] args) {
// Identify service provider to use
//将初始化的信息放到一个hashtable中去
Hashtable env = new Hashtable(11);
env.put(Context.INITIAL_CONTEXT_FACTORY,
    "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=BJCHP");
// 你需要将localhost改为domino服务器的全称或IP,并且,将O=改为你的Domino组织名称
try {
// Create the initial directory context
    DirContext ctx = new InitialDirContext(env);
    // Ask for all attributes of the object
    // 你需要将xinxibu改为服务上已有的注册用户
    Attributes attrs = ctx.getAttributes("cn=xinxibu");
    // Find the mail address and print it
System.out.println("Mail: " + attrs.get("mail").get());
    // Close the context when we're done
    ctx.close();
} catch (NamingException e) {
    System.err.println("Problem getting attribute: " + e);
}
    }
}
从代码中,我们看到读取目录信息的过程:
1. 设置所使用的Service Provider 和Service URI到Hashtable中。
2. 初始化一个DirContext。
3. 使用Context.getAttributes来获取指定用户的所有属性信息。
4. 使用attrs.get(“xxx”)来获得属性信息。
5. 关闭Context的连接。
注:在Domino LDAP目录默认只允许查找部分用户信息。你可以查看Domino Administrator Help中“Domino目录/Domino LDAP服务”一节,加入更多的属性到列表中。
验证用户身份
下面的代码通过请求LDAP用户登录,来验证用户的身份。
package net.eservice4you.ldap;
import javax.naming.Context;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.DirContext;
import javax.naming.NamingException;
import javax.naming.AuthenticationException;
import java.util.Hashtable;
class AuthUser {
    public static void main(String[] args) {
// Identify service provider to use
Hashtable env = new Hashtable(11);
env.put(Context.INITIAL_CONTEXT_FACTORY,
    "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=BJCHP");
   // 你需要将localhost改为domino服务器的全称或IP,并且,将O=改为你的Domino组织名称
// Authenticate as xinxibu and password "1234"
   env.put(Context.SECURITY_AUTHENTICATION, "simple");
   env.put(Context.SECURITY_PRINCIPAL, "cn=xinxibu,o=BJCHP");
   env.put(Context.SECURITY_CREDENTIALS, "1234");
try {
// Create the initial directory context
    DirContext ctx = new InitialDirContext(env);
    System.out.println("Authentication Ok!");
    ctx.close();
}catch (AuthenticationException e){
// 如果捕捉到AuthenticationException,表示验证失败
System.err.println("Authentication Fail:"+e);
} catch (NamingException e) {
    System.err.println("Nameing Exception: " + e);
}
    }
}
我们可以看到,要验证用户,我们需要做以下几件事:
1. 设置所使用的Service Provider 和URL到Hashtable中。
2. 设置验证方式,用户名和密码(对于simple)。
3. 初始化一个DirContext。如果捕捉到AuthenticationException异常,表示验证失败。
4. 关闭Context的连接。
除了我们刚才使用的simple方式外,还可以使用Digest-MD5, Kerberos V5和X.509等方式来验证。你可以查看参考资料来了解具体的细节。
总结
如果你的机构中已使用了Domino,如果你需要应用集成,是时候考虑LDAP!
本文所述的方法,同样适用于IBM Directory Server和OpenLDAP等其他目录服务器。我在JDK 1.4.1+ Domino 6下测试通过了这些代码。你也可以使用Domino 5,它同样可以工作的很好。
参考资料
** 下载范例代码:jndiExample.jar
** 访问java.sun.com/products/jndi可以了解有关JNDI的最新情况,下载JNDI API。你还看看JNDI Tutorial : java.sun.com/products/jndi/tutorial/index.html。
** 关于LDAP,你可以访问 LDAPman RFC 页面来了解LDAP RFC。在developer works上,你还可以找到一篇关于如何构建LDAP地址本的教学:http://www-900.ibm.com/developer ... tutorial/index.html。

 

 

JNDI(Java Naming and Directory Interface,Java命名和目录接口)是为了Java程序访问命名服务和目录服务而提供的统一API。

        命名服务,说白了就是提供一个名称键值对的管理,即Key-Value对,Key代表一个资源的名称,Value代表资源的真实地址,命名服务允许大家通过唯一的名称找到对应的对象或资源。这样程序只需要知道某种资源的名称,就可以通过JNDI来访问到它,而不需要知道这个资源真实的物理地址。这有点类似于DNS服务,DNS服务将域名解析成IP地址,这样大家只需要在浏览器中输入网站的唯一名称(即域名)就可以访问到该网站,而不需要记住这个网站真实的IP地址。

        目录服务,提供的也是一种公共资源的管理服务。目录服务是一种特殊类型的数据库,它按照一定的数据结构,比如树型结构,把各种公共资源组织并保存起来。这种特殊数据库与传统关系型数据库的区别在于,它对查询作了优化,其数据结构允许大家非常快速的找到想要的资源,即保障了一种快速查找能力,不过这种设计也牺牲了其他方面的效率,比如它的更新效率就要低得多。

        目录服务中管理的也是名称键值对,不过其键值是具有层次结构的,像一棵树,即通过一个名称或一个带层次结构的名称,你可以定位到一颗子树,而不只是一个属性。由此可见,目录服务将命名服务的概念进一步引申为提供具有层次结构的信息库。一个目录服务通常拥有一个命名服务,但是一个命名服务不必具有一个目录服务。

        目前,有许多不同厂商提供目录服务产品如NIS、NDS、Active Directory、或者完全的LDAP目录服务,类似于不同数据库厂商的数据库产品,这些目录服务产品的实现是不一样的,各有各的特点。但他们的前端访问都支持LDAP协议。

        LDAP(lightweight directory access protocol,轻量级目录访问协议)是在20世纪90年代早期作为标准目录协议进行开发的。它是目前最流行的目录协议,与厂商、具体平台无关。LDAP用统一的方式定义了如何访问目录服务中的内容,比如增加、修改、删除一个条目。每个具体的目录服务厂商都会向外界提供LDAP协议访问本产品的接口,这样,我们只需要统一关心如何使用LDAP协议就可以了。

        JNDI则是Java中用于访问LDAP的API,开发人员使用JNDI完成与LDAP服务器之间的通信,即用JNDI来访问LDAP,而不需要和具体的目录服务产品特性打交道。这样通过LDAP、JNDI两层抽象,使Java程序对目录服务的访问做到了平台无关性。

        JNDI API是J2SE中的标准API,是通用的API。JNDI中包括5个包:javax.naming,javax.naming.directory,javax.naming.event,javax.naming.ldap,javax.naming.spi。

        常用的JNDI操作有:bind,unbind,lookup,rename,NamingEnumeration listBindings,NamingEnumeration list。

        使用JNDI来访问命名服务或目录服务,操作步骤如下:

        1、建立一个HashTable,包含定义所希望使用的JNDI服务的属性,所希望连接的LDAP服务器IP地址以及端口;

        2、将与认证成用户登录有关的任何信息添加到散列表中;

        3、创建初始context对象。如果访问命名服务,则使用InitialContext类,如果访问目录服务,则要使用InitialDirContext类;

        4、使用刚才得到的context对象执行所需的操作,如添加新的条目或者搜索条目;

        5、完成操作后关闭context对象。

 

以下代码,实测可用:

 

import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.NamingEnumeration;
import javax.naming.directory.*;

public class findUseBindObj {

public static void main(String[]args){

         //创建Hashtable以存储JNDI将用于连接目录服务的环境变量
       Hashtable hs = new Hashtable();

        //设置连接Ldap的实现工厂
        hs.put(Context.INITIAL_CONTEXT_FACTORY,

                       "com.sun.jndi.ldap.LdapCtxFactory");

        // 指定LDAP服务器IP地址为本机及端口号为389
        hs.put(Context.PROVIDER_URL, "ldap://testoa.dgoa.cn:389");

        try {

           // 得到初始目录环境的一个引用
           DirContext ctx = new InitialDirContext(hs);

          //利用lookup查找返回指定DN的条目对象
           //persons pers =(persons)ctx.lookup("cn=辉,o=东莞市");

           // 利用远程对象调用远程方法,返回Age变量的值
           //String  age    =  pers.getAge();

           // 利用远程对象调用远程方法,返回Name变量的值
           //String  name  =  pers.getName();

           //输出Name的值
       //System.out.println("name is :" +  name );

       /*根据结点的DN来查找它的所有属性, 然后再从属性中得到所有的值,注意一个属性可
           以有多个值*/
       Attributes attrs=ctx.getAttributes("cn=辉,o=东莞市");

       //循环获取并输出这个属性的所有属性值
       for(NamingEnumeration ae = attrs.getAll();ae.hasMore();){

           //获取一个属性
           Attribute attr = (Attribute)ae.next();
           System.out.println("Attribute : " + attr.getID());

                      //循环取得输出这个属性的所有属性值
            for(NamingEnumeration ve = attr.getAll();ve.hasMore();){
                        System.out.println("  Value : " + ve.next());
        }

        }
        //成功打印提示信息
        System.out.println("find object success " );

        //调用该对象的函数
       //pers.toString();       

       //关闭初始目录环境
       ctx.close();

    } catch (NamingException ex) {
       System.err.println(ex.toString());
    }   

  }

 

原创粉丝点击