问题描述
我正在尝试使用 Spring LDAP(版本 2.3.2)获取 LDAP 服务器上的所有条目.在我的代码中,我使用 PagedResultsDirContextProcessor 对所有结果进行分页.这在支持 PagedResultsControl 的服务器上运行良好.
I'm trying to get all entries on an LDAP server using Spring LDAP (version 2.3.2). Within my code, I make use of PagedResultsDirContextProcessor to paginate through all the result. This works fine on the servers which support PagedResultsControl.
但是,我现在需要连接到不支持 PagedResultsControl 的 LDAP 服务器.如何在不使用 PagedResultsControl 的情况下获取所有条目?
However, I now need to connect to an LDAP server which does not support PagedResultsControl. How can I get all entries without using PagedResultsControl?
推荐答案
您可以通过 JNDI 使用 VirtualListView.您必须检索并重新提供contextID"才能进行分页,如下所示:
You can use VirtualListView via JNDI. You have to retrieve and re-supply the 'contextID' to paginate, as follows:
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 { } }
当然,调整身份验证和搜索根目录和过滤器以适合自己.
Adjust the authentication and search root and filter to suit yourself, of course.
并测试它是否受支持(尽管上述代码中的不支持的关键控制"异常也会告诉您):
And to test whether it is supported (although an 'unsupported critical control' exception from the above code will tell you just as well):
/** * 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 获得:
The VirtualListViewControl and VirtualListViewResponseControl are part of the Sun/Oracle LDAP Booster Pack, which you can obtain via Maven as:
<dependency> <groupId>com.sun</groupId> <artifactId>ldapbp</artifactId> <version>1.0</version> <type>jar</type> </dependency>