最近做一项目,涉及集成AD域系统的一些信息,现在总结下自己使用ldap协议,java实现AD信息的检索方式,希望对读者有点帮助。
目的机的连接,LDAPUrl连接地址,如:ldap://10.xxx.1.xxx:389,user具有检索信息权限的用户名,password相应的密码。返回相关的上下文信息LdapContext对象实例。
public LdapContext connectLDAP(String LDAPUrl, String user, String password)
throws Exception {
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, LDAPUrl);
env.put(Context.SECURITY_PRINCIPAL, user);
env.put(Context.SECURITY_CREDENTIALS, password);
// env.put(Context.BATCHSIZE, "2000");
LdapContext ctx = new InitialLdapContext(env, null);
// Control[] contys=ctx.getRequestControls();
// 链接ldap
System.out.println("connection is ok");
return ctx;
}
得到LdapContext相关实例后,可以检索某个信息点objectClass的数据,objectClass数据如:user-用户,organizationalUnit-组织单位等,userbase为DC(域控制器)名称,如:DC=xxx1,DC=xxx2,DC=xxx3
public List ldapDatalist(LdapContext context, String base,
String objectClass) throws Exception {
List resultlist = new ArrayList();
if (context != null) {
try {
SearchControls cons = new SearchControls(
SearchControls.SUBTREE_SCOPE, 0, 0, null, false, false);//设置检索控制
NamingEnumeration en = context.search(base, "(objectClass="
+ objectClass + ")", cons); // 查询相关信息,
while (en != null && en.hasMoreElements()) {
SearchResult result = (SearchResult) en.next();
NamingEnumeration attrs = result.getAttributes().getAll();
int count = 0;
Map ou = new HashMap();
while (attrs.hasMore()) {
Attribute attr = (Attribute) attrs.next();
// if (count == 0) {
// System.out.print(attr.getID() + ":"
// + attr.get().toString() + "|");
// }
if ("objectSid".equals(attr.getID())
|| "objectGUID".equals(attr.getID())) {
ou.put(attr.getID(), getGUID(attr.get().toString()
.getBytes()));
} else if ("whenCreated".equals(attr.getID())
|| "whenChanged".equals(attr.getID())
|| "dSCorePropagationData".equals(attr.getID())) {
String value = attr.get().toString();
ou.put(attr.getID(), value.subSequence(0, value
.indexOf(".")));
} else {
ou.put(attr.getID(), attr.get().toString());
}
count++;
}
resultlist.add(ou);
}
} catch (Exception ee) {
ee.printStackTrace();
return null;
}
}
System.out.println("总共:" + resultlist.size() + "条信息.");
return resultlist;
}
正常检索可以得到属性-值的Map信息列表。但当某中类型的数据量很大的时候,你会发现每次检索数据只能获取到100条数据记录。其中值得注意的是,LDAP获取数据的默认上限为1000。很多时候,数据会超出1000,将会丢失多余的数据。为此,如果不改配置,则需要分批进行读取,这就需要根据entryid排序来进行。在LDAP Java JDK的文档中寻找关于Filter的描述。以下是从原文中查找到关于如何设置该限制的相关描述。
Setting Size and Time Limits
By default, when you search the directory from a client built with the Netscape Directory SDK for Java, the maximum number of entries to return is set to 1000, and there is no maximum time limit for waiting on an operation to complete.
To change these default values, you can do one of the following:
l Use the setOption method of the LDAPConnection object to set the LDAPv2.SIZELIMIT and LDAPv2.TIMELIMIT preferences.
l Use the setMaxResults method and the setTimeLimit method of the LDAPSearchConstraints object to change this for a particular set of search constraints.
Setting the size limit or time limit may cause an LDAPException to be thrown if the size limit or time limit is exceeded:
If the size limit is exceeded, the server returns an LDAPException.SIZE_LIMIT_EXCEEDED result code.
If the time limit is exceeded, the server returns an LDAPException.TIME_LIMIT_EXCEEDED result code.
Note that the smallest unit supported by the Netscape Directory Server is seconds, not milliseconds. Since the Netscape Directory SDK for Java allows you to specify the time limit in milliseconds, the value that you specify will be rounded to the nearest second by the Directory Server.
当你用Netscape目录Java开发包建立客户端程序搜索目录时,每个入口的最大返回数值默认被设置为1000并且操作完成时间没有限制。
要是不改变这些默认值,数据检索时我们可以使用下列的方法进行分页读取:
public List ldapDatalistPage(LdapContext context, String base,
String objectClass) {
List resultlist = new ArrayList();
int pageSize = 1000; // 1000 entries per page
byte[] cookie = null;
int total;
try {
context.setRequestControls(new Control[] { new PagedResultsControl(
pageSize, Control.CRITICAL) });//分页读取控制
do {//循环检索数据
// Perform the search
SearchControls cons = new SearchControls(
SearchControls.SUBTREE_SCOPE, 0, 0, null, false, false);
NamingEnumeration results = context.search(base,
"(objectClass=" + objectClass + ")", cons); // 查询所有信息
// Iterate over a batch of search results
while (results != null && results.hasMoreElements()) {
SearchResult result = (SearchResult) results.next();
NamingEnumeration attrs = result.getAttributes().getAll();
int count = 0;
Map ou = new HashMap();
while (attrs.hasMore()) {
Attribute attr = (Attribute) attrs.next();
if ("objectSid".equals(attr.getID())
|| "objectGUID".equals(attr.getID())) {
ou.put(attr.getID(), getGUID(attr.get().toString()
.getBytes()));
} else if ("whenCreated".equals(attr.getID())
|| "whenChanged".equals(attr.getID())
|| "dSCorePropagationData".equals(attr.getID())) {
String value = attr.get().toString();
ou.put(attr.getID(), value.subSequence(0, value
.indexOf(".")));
} else {
ou.put(attr.getID(), attr.get().toString());
}
count++;
}
resultlist.add(ou);
}
// Examine the paged results control response
Control[] controls = context.getResponseControls();
if (controls != null) {
for (int i = 0; i < controls.length; i++) {
if (controls[i] instanceof PagedResultsResponseControl) {
PagedResultsResponseControl prrc = (PagedResultsResponseControl) controls[i];
total = prrc.getResultSize();
cookie = prrc.getCookie();
} else {
// Handle other response controls (if any)
}
}
}
// Re-activate paged results
context.setRequestControls(new Control[] { new PagedResultsControl(
pageSize, cookie, Control.CRITICAL) });
} while (cookie != null);
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("总共:" + resultlist.size() + "条信息.");
return resultlist;
}