LDAP作为一种普遍使用的认证服务,可以通过模拟登录的方式来监测服务的可用性。今天写了一个服务来轮询模拟LDAP登录,下面是主要的代码。
LDAP的原理是先用一个admin用户去认证,认证通过后,使用应登录的用户的用户名及密码去登录。
1.常量设置
public class Constants {
/**
* LDAP服务端地址URL(端口默认389)
*/
public static final String ldapURL= "ldap://xxx.xxx.xxx.xxx/";
/**
* LDAP根
*/
public static final String ldapBasedn= "ou=ldaptest,dc=ldaptest,dc=com";
/**
* LDAP登陆账号(注:特殊字符\需要进行转义)
*/
public static final String ldapPrincipal= "ldapadmin";
/**
* LDAP登陆密码
*/
public static final String ldapCredentials= "ldappassword";
/**
* <B>LDAP查询Filter <br/>#arg在代码中可替换为实际查找用户的用户账号<b/>
*/
public static final String ldapFilter= "(&(objectClass=user)(sAMAccountName=#arg))";
}
2.LDAPAuthentication
package com.system.ldap;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.Control;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
public class LDAPAuthentication implements Runnable {
private final String BASEDN = Constants.ldapBasedn;
private final String FACTORY = "com.sun.jndi.ldap.LdapCtxFactory";
private LdapContext ctx = null;
private final Control[] connCtls = null;
//private Log log = null;
public void LDAP_connect(){
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, FACTORY);
env.put(Context.PROVIDER_URL, Constants.ldapURL);
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, Constants.ldapPrincipal);
env.put(Context.SECURITY_CREDENTIALS, Constants.ldapCredentials);
try {
ctx = new InitialLdapContext(env, connCtls);
wirte("认证LDAP服务器(" + Constants.ldapURL + ")成功!");
} catch (javax.naming.AuthenticationException e) {
wirte("认证LDAP服务器(" + Constants.ldapURL + ")失败,原因:"+e.toString());
//throw new Exception();
} catch (Exception e) {
wirte("认证LDAP服务器(" + Constants.ldapURL + ")失败,原因 :"+e.toString());
}
}
public static void wirte(String msg){
FileWriter fileWriter;
try {
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
fileWriter = new FileWriter("D:\\log\\ldap.log",true);
String s = new String( "["+sf.format(new Date())+"]"+msg);
fileWriter.write("\r\n");
fileWriter.write(s);
fileWriter.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private String getUserDN(String uid) {
try {
String userDN = "";
SearchControls constraints = new SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
// 查找用户DN
NamingEnumeration<SearchResult> en = ctx.search(BASEDN, Constants.ldapFilter.replace("#arg", uid), constraints);
while (en != null && en.hasMoreElements()) {
Object obj = en.nextElement();
if (obj instanceof SearchResult) {
SearchResult si = (SearchResult) obj;
userDN += si.getName();
userDN += "," + BASEDN;
System.out.println(userDN);
wirte("查找到用户" + uid + "的DN信息:" + userDN);
} else {
}
}
return userDN;
} catch (NamingException e) {
wirte("查找用户DN时错误!");
wirte("原因:" + e);
return null;
} catch (Exception e1) {
return null;
}
}
public boolean authenricate(String UID, String password) {
//是否成功
boolean valide = false;
try {
//连接
LDAP_connect();
String userDN = getUserDN(UID);
if (userDN != null && userDN != "") {
// 如果需要加密SHA-1
// password = SHA1.shaBase64(password);
ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, userDN);
ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, password);
ctx.reconnect(connCtls);
System.out.println(userDN + " 验证通过");
wirte("LDAP用户验证成功!");
valide = true;
} else {
wirte("未找到" + UID + "用户信息!");
valide = false;
}
} catch (NamingException e) {
wirte("用户信息认证失败!password:" + password);
valide = false;
} catch (Exception e) {
//创建连接失败
valide = false;
} finally {
// 关闭连接
closeLdapContext();
wirte("close ldap connection");
}
return valide;
}
private void closeLdapContext() {
if (ctx != null) {
try {
ctx.close();
} catch (NamingException e) {
wirte("关闭LDAP连接错误,错误原因:"+e);
}
}
}
@Override
public void run() {
// TODO Auto-generated method stub
while (true) {
try {
Thread.sleep(1000);
LDAPAuthentication ldap = new LDAPAuthentication();
if (ldap.authenricate("ldapuser", "ldappassword") == true) {
System.out.println("该用户认证成功");
wirte("该用户认证成功");
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
3.测试类
使用线程轮询的方式不停地调用认证方法
public class TestLDAP {
/**
* @param args
*/
public static void main(String[] args) {
LDAPAuthentication Authentication=new LDAPAuthentication();
Thread t1 =new Thread(Authentication);
t1.start();
}
}
4.效果
线程每轮询一次打印一次日志到文件,可以通过日志跟踪认证服务的正常状态。
5.扩展阅读
1) LDAP
http://baike.baidu.com/link?url=e59cBqJmOebBv1FnOUnDFDjAyIoLlmP2Gpg1npNF0b9FaoVO3YgAUppILHp7CPqQdDYC4w33DXxe_yIboMjb5_
2) LDAP概念和原理
http://blog.sina.com.cn/s/blog_6151984a0100ey3z.html
3)LDAP认证基本原理
http://www.edu.cn/sfrz_9956/20120608/t20120608_788018_1.shtml