From 33db777770ba0a2e612d60d26a4e44f280263201 Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Wed, 06 Mar 2013 11:57:52 +0000
Subject: [PATCH] Partial fix for OPENDJ-699: Implement DN reference mapping
---
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReferenceAttributeMapper.java | 127 +++++++++++++++++++++++++++++++++++++++--
1 files changed, 119 insertions(+), 8 deletions(-)
diff --git a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReferenceAttributeMapper.java b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReferenceAttributeMapper.java
index 7b52566..132e76e 100644
--- a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReferenceAttributeMapper.java
+++ b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReferenceAttributeMapper.java
@@ -15,20 +15,23 @@
*/
package org.forgerock.opendj.rest2ldap;
-import static org.forgerock.opendj.ldap.Filter.alwaysFalse;
+import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult;
import static org.forgerock.opendj.rest2ldap.Utils.accumulate;
import static org.forgerock.opendj.rest2ldap.Utils.adapt;
+import static org.forgerock.opendj.rest2ldap.Utils.ensureNotNull;
import static org.forgerock.opendj.rest2ldap.Utils.transform;
import static org.forgerock.opendj.rest2ldap.WritabilityPolicy.READ_WRITE;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
+import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.forgerock.json.fluent.JsonPointer;
import org.forgerock.json.fluent.JsonValue;
+import org.forgerock.json.resource.ResourceException;
import org.forgerock.json.resource.ResultHandler;
import org.forgerock.opendj.ldap.Attribute;
import org.forgerock.opendj.ldap.AttributeDescription;
@@ -37,23 +40,38 @@
import org.forgerock.opendj.ldap.ErrorResultException;
import org.forgerock.opendj.ldap.Filter;
import org.forgerock.opendj.ldap.Function;
+import org.forgerock.opendj.ldap.ResultCode;
+import org.forgerock.opendj.ldap.SearchResultHandler;
+import org.forgerock.opendj.ldap.SearchScope;
+import org.forgerock.opendj.ldap.requests.Requests;
+import org.forgerock.opendj.ldap.requests.SearchRequest;
+import org.forgerock.opendj.ldap.responses.Result;
import org.forgerock.opendj.ldap.responses.SearchResultEntry;
+import org.forgerock.opendj.ldap.responses.SearchResultReference;
/**
* An attribute mapper which provides a mapping from a JSON value to a single DN
* valued LDAP attribute.
*/
public final class ReferenceAttributeMapper extends AttributeMapper {
+ /**
+ * The maximum number of candidate references to allow in search filters.
+ */
+ private static final int SEARCH_MAX_CANDIDATES = 1000;
+ private final DN baseDN;
+ private Filter filter = null;
private boolean isRequired = false;
private boolean isSingleValued = false;
private final AttributeDescription ldapAttributeName;
private final AttributeMapper mapper;
+ private SearchScope scope = SearchScope.WHOLE_SUBTREE;
private WritabilityPolicy writabilityPolicy = READ_WRITE;
- ReferenceAttributeMapper(final AttributeDescription ldapAttributeName,
+ ReferenceAttributeMapper(final AttributeDescription ldapAttributeName, final DN baseDN,
final AttributeMapper mapper) {
this.ldapAttributeName = ldapAttributeName;
+ this.baseDN = baseDN;
this.mapper = mapper;
}
@@ -80,6 +98,47 @@
}
/**
+ * Sets the filter which should be used when searching for referenced LDAP
+ * entries. The default is {@code (objectClass=*)}.
+ *
+ * @param filter
+ * The filter which should be used when searching for referenced
+ * LDAP entries.
+ * @return This attribute mapper.
+ */
+ public ReferenceAttributeMapper searchFilter(final Filter filter) {
+ this.filter = ensureNotNull(filter);
+ return this;
+ }
+
+ /**
+ * Sets the filter which should be used when searching for referenced LDAP
+ * entries. The default is {@code (objectClass=*)}.
+ *
+ * @param filter
+ * The filter which should be used when searching for referenced
+ * LDAP entries.
+ * @return This attribute mapper.
+ */
+ public ReferenceAttributeMapper searchFilter(final String filter) {
+ return searchFilter(Filter.valueOf(filter));
+ }
+
+ /**
+ * Sets the search scope which should be used when searching for referenced
+ * LDAP entries. The default is {@link SearchScope#WHOLE_SUBTREE}.
+ *
+ * @param scope
+ * The search scope which should be used when searching for
+ * referenced LDAP entries.
+ * @return This attribute mapper.
+ */
+ public ReferenceAttributeMapper searchScope(final SearchScope scope) {
+ this.scope = ensureNotNull(scope);
+ return this;
+ }
+
+ /**
* Indicates whether or not the LDAP attribute supports updates. The default
* is {@link WritabilityPolicy#READ_WRITE}.
*
@@ -101,10 +160,62 @@
@Override
void getLDAPFilter(final Context c, final FilterType type, final JsonPointer jsonAttribute,
final String operator, final Object valueAssertion, final ResultHandler<Filter> h) {
- // TODO: only presence and equality matching will be supported. Equality matching will
- // only work for the primary key (whatever that is) by performing a reverse look up to
- // convert the primary key to a DN.
- h.handleResult(alwaysFalse());
+ // First construct a filter which can be used to find referenced resources.
+ final ResultHandler<Filter> filterHandler = new ResultHandler<Filter>() {
+ @Override
+ public void handleError(final ResourceException error) {
+ h.handleError(error); // Propagate.
+ }
+
+ @Override
+ public void handleResult(final Filter result) {
+ // Now construct a search to find candidate DNs.
+ final Filter searchFilter = filter != null ? Filter.and(filter, result) : result;
+ final SearchRequest request =
+ Requests.newSearchRequest(baseDN, scope, searchFilter, "1.1");
+
+ // Create a result handler which will collect the returned entries and construct a search filter.
+ final SearchResultHandler searchHandler = new SearchResultHandler() {
+ final List<Filter> subFilters = new LinkedList<Filter>();
+
+ @Override
+ public boolean handleEntry(final SearchResultEntry entry) {
+ if (subFilters.size() < SEARCH_MAX_CANDIDATES) {
+ subFilters.add(Filter.equality(ldapAttributeName.toString(), entry
+ .getName()));
+ return true;
+ } else {
+ // No point in continuing - maximum candidates reached.
+ return false;
+ }
+ }
+
+ @Override
+ public void handleErrorResult(final ErrorResultException error) {
+ h.handleError(adapt(error)); // Propagate.
+ }
+
+ @Override
+ public boolean handleReference(final SearchResultReference reference) {
+ // Ignore references.
+ return true;
+ }
+
+ @Override
+ public void handleResult(final Result result) {
+ if (subFilters.size() >= SEARCH_MAX_CANDIDATES) {
+ handleErrorResult(newErrorResult(ResultCode.ADMIN_LIMIT_EXCEEDED));
+ } else if (subFilters.size() == 1) {
+ h.handleResult(subFilters.get(0));
+ } else {
+ h.handleResult(Filter.or(subFilters));
+ }
+ }
+ };
+ c.getConnection().searchAsync(request, null, searchHandler);
+ }
+ };
+ mapper.getLDAPFilter(c, type, jsonAttribute, operator, valueAssertion, filterHandler);
}
@Override
@@ -116,7 +227,7 @@
try {
final DN dn = attribute.parse().usingSchema(c.getConfig().schema()).asDN();
readEntry(c, dn, h);
- } catch (Exception ex) {
+ } catch (final Exception ex) {
// The LDAP attribute could not be decoded.
h.handleError(adapt(ex));
}
@@ -146,7 +257,7 @@
for (final DN dn : dns) {
readEntry(c, dn, handler);
}
- } catch (Exception ex) {
+ } catch (final Exception ex) {
// The LDAP attribute could not be decoded.
h.handleError(adapt(ex));
}
--
Gitblit v1.10.0