我试图使用Spring LDAP(版本2.3.2)获取LDAP服务器上的所有条目。在我的代码中,我使用PagedResultsDirContextProcessor
对所有结果进行分页。这在支持PagedResultsControl
的服务器上运行良好。
但是,我现在需要连接到不支持PagedResultsControl
的LDAP服务器。如何在不使用PagedResultsControl
的情况下获取所有条目?
答案 0 :(得分:3)
您可以通过JNDI使用VirtualListView
。您必须检索并重新提供'contextID'到paginate,如下所示:
static final int LIST_SIZE = 20; // Adjust to suit
@Test
public void TestVLV() throws NamingException, IOException
{
Hashtable<String,Object> env = new Hashtable<>();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://localhost");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "cn=XXXXXXX");
env.put(Context.SECURITY_CREDENTIALS, "YYYYYYY");
try
{
/* Create initial context with no connection request controls */
LdapContext ctx = new InitialLdapContext(env, null);
/* Sort Control is required for VLV to work */
SortKey[] sortKeys =
{
// sort by cn
new SortKey("cn", true, "caseIgnoreOrderingMatch")
};
// Note: the constructors for SortControl that take String or String[]
// as the first argument produce 'no ordering rule' errors with OpenLDAP.
SortControl sctl = new SortControl(
// "cn",
// new String[]{"cn"},
sortKeys,
Control.CRITICAL);
/* VLV that returns the first 20 answers */
VirtualListViewControl vctl =
new VirtualListViewControl(1, 0, 0, LIST_SIZE-1, Control.CRITICAL);
/* Set context's request controls */
ctx.setRequestControls(new Control[]
{
sctl,
vctl
});
int count = 0;
SearchControls sc = new SearchControls(SearchControls.SUBTREE_SCOPE, 0, 0, null, false, false);
for (;;)
{
/* Perform search */
// System.out.println("namespace="+ctx.getNameInNamespace());
// System.out.println("count limit="+sc.getCountLimit());
// System.out.println("search scope="+sc.getSearchScope());
NamingEnumeration<SearchResult> ne =
ctx.search("ou=Users,dc=xxxx,dc=com", "(objectClass={0})", new String[]{"inetOrgPerson"}, sc);
/* Enumerate search results */
while (ne.hasMore())
{
count++;
SearchResult sr = ne.next();
// System.out.println(i+": "+sr.getName());
System.out.println(count+": "+sr.getNameInNamespace());
}
ne.close();
// Get the contextID.
Control[] controls = ctx.getResponseControls();
VirtualListViewResponseControl vlvrc = null;
byte[] contextID = null;
for (int j = 0; j < controls.length; j++)
{
if (controls[j] instanceof VirtualListViewResponseControl)
{
vlvrc = (VirtualListViewResponseControl)controls[j];
contextID = vlvrc.getContextID();
System.out.println("contextID=0x"+new BigInteger(1,contextID).toString(16));
if (contextID != null)
{
vctl = new VirtualListViewControl(vlvrc.getTargetOffset()+LIST_SIZE, 0, 0, LIST_SIZE-1, Control.CRITICAL);
vctl.setContextID(contextID);
ctx.setRequestControls(new Control[]
{
sctl,
vctl
});
}
break; // there should only be one VLV response control, and we're not interested in anything else.
}
}
if (vlvrc != null && contextID != null && count < vlvrc.getListSize())
{
System.out.println("Continuing");
}
else
{
System.out.println("Finished");
break;
}
}
ctx.close();
}
finally
{
}
}
当然,调整身份验证和搜索root并过滤以适合自己。
并测试它是否受支持(尽管上述代码中的'不受支持的关键控件'异常也会告诉您):
/**
* Is VLV Control supported?
*
* Query the rootDSE object to find out if VLV Control is supported.
* @return true if it is supported.
*/
static boolean isVLVControlSupported(LdapContext ctx)
throws NamingException
{
String[] returningAttributes =
{
"supportedControl"
};
// Fetch the supportedControl attribute of the rootDSE object.
Attributes attrs = ctx.getAttributes("", returningAttributes);
Attribute attr = attrs.get("supportedControl");
System.out.println("supportedControls="+attr);
if (attr != null)
{
// Fast way to check. add() would have been just as good. Does no damage to the DIT.
return attr.remove(VLV_CONTROL_OID);
}
return false;
}
VirtualListViewControl
和VirtualListViewResponseControl
是Sun / Oracle LDAP Booster Pack的一部分,您可以通过Maven获取它:
<dependency>
<groupId>com.sun</groupId>
<artifactId>ldapbp</artifactId>
<version>1.0</version>
<type>jar</type>
</dependency>
答案 1 :(得分:1)
超级沮丧。
我不会真的推荐它,但是您可以进行类似的操作,您可以通过cn / sn手动进行分页。
List<String> alphabetRange = getAlphabetRange();
for (int i = 0; i < alphabetRange.size() - 1; i++) {
String filter = "(&(sn>=" + alphabetRange.get(i) + ")" + "(sn<=" + alphabetRange.get(i + 1) + " ))";
NamingEnumeration<SearchResult> searchResult = context.search(base_dn, filter, controls);
while (searchResult.hasMore()) {
// searchResult.next().getAttributes() and do something with it
}
}
private List<String> getAlphabetRange() {
List<String> result = new ArrayList<>();
for (char alph = 'A'; alph <= 'Z'; alph++) {
if (alph == 'S') {
result.add("S");
result.add("Sd");
} else {
result.add(String.valueOf(alph));
}
}
result.add("Zz");
return result;
}
javax.naming.SizeLimitExceededException
。您可以添加更多“页面”,例如在[S-Sd][Sd-T]
答案 2 :(得分:-1)
您使用的是什么样的服务器?
如果服务器没有队列限制,则无法尝试设置无限制搜索:
SearchControls controls = new SearchControls();
controls.setTimeLimit(0);
controls.setCountLimit(0);