(转)JNDI/LDAP Active Directory验证第五部分 Simple

一份 pdf 文件的文章,来源于 www.diybl.com 这个网站,本想直接找到原始出处,但是发现网站关闭了,pdf 文件又不方便随时查阅,所以把文章内容复制到这里,供查阅参考。

JNDI, Active Directory and Authentication (part 5) —–Simple

笔者最近接触到一些通过JNDI/LDAP来访问Microsoft Active Directory的知识,虽然也可以通过JNI来调用C++或者其他Microsoft的编程工具编译完成的DLL来调用一些特定的功能,例如通过使用C++调用ADSI接口来进
行用户的验证。

但是这就造成了平台依赖,如果目录服务换成了Sun Directory Service或者openldap,那么系统就不能调用DLL来实现对应的功能了,所以应该使用JNDI/LDAP的方式,因为无论是什么目录服务,都实现了LDAP标准,所以针对接口进行编程即可。

笔者需要完成这样一个功能,通过JNDI/LDAP编程的方式来实现Microsoft Active Directory的用户验证。

本文描述了使用Simple方式来进行验证。

很多开发者使用LDAP目录作为一个验证服务。但是LDAP作为一个目录协议,主要被设计用来搜索,添加,删除以及修改存储在目录中的实体,协议中暗含了通过使用一系列验证方法来验证LDAP连接。这些验证方法包括Simple(明文)、HTTP-DIGEST、X.509客户端证书以及Kerberos(通过GSS-API)。

在本系列文章的第二、三、四篇中讲述了使用JAAS和GSSAPI并利用Kerberos作为验证协议来访问Active Directory、使用SSL通信方式来保证传输的安全性、描述了使用DIGEST-MD5方式来保证传输的数据完整性和机密性、以及
使用SASL EXTERNAL方式进行Active Directory验证。

当使用LDAP目录作为简单的验证服务时,典型的方法是获取用户的验证信息(用户名和密码),然后与存储在Active Directory中的用户名和密码相比较进行验证。

由于众所周知的安全原因,Active Directory不允许读取Windows密码(unicodePassword)属性,以此来防止攻击者获取密码或者以脱机方式破解密码。因此验证用户信息的唯一方式就是实现LDAP绑定。

通常情况下,当Active Directory验证一个用户的时候,它收集所有的验证数据和创建一个包含所有用户安全标志的Windows安全标记(组、成员、权限、…)。这适用于在Windows网络中验证用户,但是由可能导致
额外的性能需求,不一定适用于许多企业内部或者外部的情况,在这些情况下只需要简单的校验用户名和密码。

Windows Server 2003介绍了一个LDAP连接控制来支持这种简单的情况,减少信息的收集。详细信息参考:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ldap/ldap/ldap_server_fast_bind_oid.asp

为了在Java&JNDI中使用Active Directory LDAP Fast Bind Control,只需要在连接请求时请求控制。在下面这个应用程序的服务器端代码中,LdapContext通过连接控制来进行初始化,后续的验证通过调用Context.reconnect方法。

package com.sun.auth.simple;
/**
 * ldapfastbind.java
 *
 * Sample JNDI application to use Active Directory LDAP_SERVER_FAST_BIND connection control
 *
 */
import java.util.Hashtable;
import javax.naming.AuthenticationException;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.ldap.Control;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;

class FastBindConnectionControl implements Control {
    public byte[] getEncodedValue() {
        return null;
    }
    public String getID() {
        return "1.2.840.113556.1.4.1781";
    }
    public boolean isCritical() {
        return true;
    }
}

public class LdapFastBind {

    public Hashtable env = null;
    public LdapContext ctx = null;
    public Control[] connCtls = null;

    public LdapFastBind(String ldapurl) {

        env = new Hashtable();
        env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.SECURITY_AUTHENTICATION,"simple");
        env.put(Context.PROVIDER_URL,ldapurl);
        connCtls = new Control[] {new FastBindConnectionControl()};

        //first time we initialize the context, no credentials are supplied
        //therefore it is an anonymous bind. 
        try {
            ctx = new InitialLdapContext(env,connCtls);
        }
        catch (NamingException e) {
            System.out.println("Naming exception " + e);
        }
    }

    public boolean Authenticate(String username, String password) {
        try {
            ctx.addToEnvironment(Context.SECURITY_PRINCIPAL,username);
            ctx.addToEnvironment(Context.SECURITY_CREDENTIALS,password);
            ctx.reconnect(connCtls);
            System.out.println(username + " is authenticated");
            return true;
        }
        catch (AuthenticationException e) {
            System.out.println(username + " is not authenticated");
            return false;
        }
        catch (NamingException e) {
            System.out.println(username + " is not authenticated");
            return false;
        }
    }

    public void finito() {
        try {
            ctx.close();
            System.out.println("Context is closed");
        }
        catch (NamingException e) {
            System.out.println("Context close failure " + e);
        }
    }
}

客户端代码只是简单的初始化SimpleSearch类,然后通过设置不同的用户来调用authenticate方法。

package com.sun.auth.simple;
/**
* fastbindclient.java
*
* Sample JNDI application to use LDAP_SERVER_FAST_BIND connection control
*
* This is just a test harness to invoke the ldapfastbind methods
*/
class FastBindClient {

    public static void main(String[] args) {
        // Could also use ldaps over port 636 to protect the communication to
        // the
        // Active Directory domain controller. Would also need to add
        // env.put(Context.SECURITY_PROTOCOL,"ssl") to the "server" code
        String ldapurl = "ldap://mydc.antipodes.com:389";
        boolean IsAuthenticated = false;
        LdapFastBind ctx = new LdapFastBind(ldapurl);

        IsAuthenticated = ctx.Authenticate("ANTIPODES\\alberte", "GoodPassword");
        IsAuthenticated = ctx.Authenticate("ANTIPODES\\alberte", "BadPassword");
        IsAuthenticated = ctx.Authenticate("ANTIPODES\\charlesd","GoodPassword");

        IsAuthenticated = ctx.Authenticate("ANTIPODES\\charlesd", "BadPassword");
        IsAuthenticated = ctx.Authenticate("ANTIPODES\\isaacn", "GoodPassword");
        IsAuthenticated = ctx.Authenticate("ANTIPODES\\isaacn", "BadPassword");

        ctx.finito();
    }
}

至此,本系列文章告一段落,但是会继续发表一些关于LDAP和AD的文章。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值