我正在尝试使用
Spring LDAP(版本2.3.2)获取LDAP服务器上的所有条目.在我的代码中,我使用PagedResultsDirContextProcessor来对所有结果进行分页.这在支持PagedResultsControl的服务器上运行良好.
但是,我现在需要连接到不支持PagedResultsControl的LDAP服务器.如何在不使用PagedResultsControl的情况下获取所有条目?
解决方法
您可以通过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,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,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,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 { } }
当然,调整身份验证和搜索根目录并过滤以适合自己.
并测试它是否受支持(尽管上述代码中的“不受支持的关键控件”异常也会告诉您):
/** * 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>