为什么我的Clojure实现LDAP分页结果功能不起作用?

时间:2012-03-07 04:38:04

标签: clojure clojure-java-interop

TLDR;这不是一个措辞严谨的问题,所以你可能不应该为此烦恼。我将在不久的将来删除它,除非人们认为它有一些救赎功能,而不是如何不在Stack Overflow上提问的好例子。

我正在为我的一个项目使用UnboundID LDAP SDK。我目前停留在实现分页结果搜索(在RFC2696中描述),我有一个有效的Java实现。我已经测试了Java代码,并且知道它对我的测试LDAP目录正常工作。 Java实现的主要部分是以下do..while循环:

do
{
  /*
   * Set the simple paged results control (if the cookie is null
   * this indicates the first time through the loop).
   */
  final SimplePagedResultsControl simplePagedResultsRequestControl =
      new SimplePagedResultsControl(pageSize,cookie);
  searchRequest.setControls(simplePagedResultsRequestControl);

  /*
   * Issue the search request:
   */
  SearchResult searchResult;
  searchResult = ldapConnection.search(searchRequest);
  final String msg =
      String
          .format(
              "searchRequest transmitted, pageSize: %d, entries returned: %d",
              Integer.valueOf(pageSize),
              Integer.valueOf(searchResult.getEntryCount()));
  final LogRecord record = new LogRecord(Level.INFO,msg);
  ldapCommandLineTool.out(new MinimalLogFormatter().format(record));
  total += searchResult.getEntryCount();
  /*
   * Get the cookie from the paged results control.
   */
  cookie = null;
  final SimplePagedResultsControl c =
      SimplePagedResultsControl.get(searchResult);
  if(c != null)
  {
    cookie = c.getCookie();
  }
}
while(cookie != null && cookie.getValueLength() > 0);

向搜索请求添加请求“控制”,向服务器指示它应该发回匹配条目的子集。假设初始请求有效,LDAP服务器返回pageSize条目和包含特殊“cookie”的响应控件。为了获得结果的下一个“页面”,客户端重新发送请求,请求控件中包含cookie,服务器包含一个带有后续响应的新cookie。此循环一直持续到没有更多条目返回,在这种情况下,没有cookie返回给客户端并且搜索请求已完成。

我试图将上面的代码移植到Clojure,但到目前为止我一直无法使用它。这是代码:

(defn fetch-all
  [& attrs]
  (with-connection
    (let [attrs (into-array (if attrs (map name attrs) ["*"]))
          scope SearchScope/SUB
          request (SearchRequest. searchbase scope account-filter attrs)]
      (loop [results [] cookie nil]
        (let [control [(SimplePagedResultsControl. page-size cookie)]]
          (doto request
            (.setSizeLimit 12345)
            (.setTimeLimitSeconds 60)
            (.setControls control))
          (let [result (.search *conn* request)
                results (concat result results)
                cookie (.. SimplePagedResultsControl (get result) getCookie)]
            (println "entries returned:" (.getEntryCount result))
            (when-not (> 0 (.getValueLength cookie))
              results
              (recur
               results cookie))))))))

Java代码检索了1720条带有18个请求的条目,但是在五个请求之后,我的“大小限制已被删除”LDAPSearchException失败。

我的问题是,为什么这两个实现的行为不同?我知道我正在向每个新请求发送收到的cookie,因为如果两次使用相同的cookie,则抛出异常。我也认为我知道我正在获得后续的结果页面,因为每页返回的条目集是不同的。

我很难过,并没有想到拖出Ettercap来分析流量。当然,我的代码中存在一些非常明显的错误,导致了不同的行为。

2 个答案:

答案 0 :(得分:1)

(let [control [(SimplePagedResultsControl. page-size cookie)]]

将控制绑定到单个结果控制对象的向量。 然后将该向量传递给

(.setControls control)

似乎只需要一个结果控制对象,而不是一个像你的java代码那样的向量。

答案 1 :(得分:1)

好的,两个错误,以及RFC中的问题:

  • (bug)结果与结果的串联应该是(concat(.getSearchEntries result)结果),
  • (bug)循环底部的'when-not'测试应该是'if'或'if-not'。
  • (gotcha)在RFC的第6节“安全注意事项”下,建议“服务器实现可以强制执行重写的sizelimit”,也就是说作为非特权用户,我仍然会达到极限,分页结果与否。实现之间的行为差​​异仅仅是因为我以匿名方式运行具有管理权限和Clojure代码的Java代码(doh!)。