use of com.unboundid.ldap.sdk.controls.RFC3672SubentriesRequestControl in project ldapsdk by pingidentity.
the class InMemoryRequestHandler method processSearchRequest.
/**
* Attempts to process the provided search request. The attempt will fail
* if any of the following conditions is true:
* <UL>
* <LI>There is a problem with any of the request controls.</LI>
* <LI>The modify DN request contains a malformed target DN, new RDN, or
* new superior DN.</LI>
* <LI>The new DN of the entry would conflict with the DN of an existing
* entry.</LI>
* <LI>The new DN of the entry would exist outside the set of defined
* base DNs.</LI>
* <LI>The new DN of the entry is not a defined base DN and does not exist
* immediately below an existing entry.</LI>
* </UL>
*
* @param messageID The message ID of the LDAP message containing the
* search request.
* @param request The search request that was included in the LDAP
* message that was received.
* @param controls The set of controls included in the LDAP message.
* It may be empty if there were no controls, but will
* not be {@code null}.
* @param entryList A list to which to add search result entries
* intended for return to the client. It must not be
* {@code null}.
* @param referenceList A list to which to add search result references
* intended for return to the client. It must not be
* {@code null}.
*
* @return The {@link LDAPMessage} containing the response to send to the
* client. The protocol op in the {@code LDAPMessage} must be an
* {@code SearchResultDoneProtocolOp}.
*/
@NotNull()
LDAPMessage processSearchRequest(final int messageID, @NotNull final SearchRequestProtocolOp request, @NotNull final List<Control> controls, @NotNull final List<SearchResultEntry> entryList, @NotNull final List<SearchResultReference> referenceList) {
synchronized (entryMap) {
// Sleep before processing, if appropriate.
final long processingStartTime = System.currentTimeMillis();
sleepBeforeProcessing();
// Look at the filter and see if it contains any unsupported elements.
try {
ensureFilterSupported(request.getFilter());
} catch (final LDAPException le) {
Debug.debugException(le);
return new LDAPMessage(messageID, new SearchResultDoneProtocolOp(le.getResultCode().intValue(), null, le.getMessage(), null));
}
// Look at the time limit for the search request and see if sleeping
// would have caused us to exceed that time limit. It's extremely
// unlikely that any search in the in-memory directory server would take
// a second or more to complete, and that's the minimum time limit that
// can be requested, so there's no need to check the time limit in most
// cases. However, someone may want to force a "time limit exceeded"
// response by configuring a delay that is greater than the requested time
// limit, so we should check now to see if that's been exceeded.
final long timeLimitMillis = 1000L * request.getTimeLimit();
if (timeLimitMillis > 0L) {
final long timeLimitExpirationTime = processingStartTime + timeLimitMillis;
if (System.currentTimeMillis() >= timeLimitExpirationTime) {
return new LDAPMessage(messageID, new SearchResultDoneProtocolOp(ResultCode.TIME_LIMIT_EXCEEDED_INT_VALUE, null, ERR_MEM_HANDLER_TIME_LIMIT_EXCEEDED.get(), null));
}
}
// Process the provided request controls.
final Map<String, Control> controlMap;
try {
controlMap = RequestControlPreProcessor.processControls(LDAPMessage.PROTOCOL_OP_TYPE_SEARCH_REQUEST, controls);
} catch (final LDAPException le) {
Debug.debugException(le);
return new LDAPMessage(messageID, new SearchResultDoneProtocolOp(le.getResultCode().intValue(), null, le.getMessage(), null));
}
final ArrayList<Control> responseControls = new ArrayList<>(1);
// If this operation type is not allowed, then reject it.
final boolean isInternalOp = controlMap.containsKey(OID_INTERNAL_OPERATION_REQUEST_CONTROL);
if ((!isInternalOp) && (!config.getAllowedOperationTypes().contains(OperationType.SEARCH))) {
return new LDAPMessage(messageID, new SearchResultDoneProtocolOp(ResultCode.UNWILLING_TO_PERFORM_INT_VALUE, null, ERR_MEM_HANDLER_SEARCH_NOT_ALLOWED.get(), null));
}
// client is authenticated.
if ((authenticatedDN.isNullDN() && config.getAuthenticationRequiredOperationTypes().contains(OperationType.SEARCH))) {
return new LDAPMessage(messageID, new SearchResultDoneProtocolOp(ResultCode.INSUFFICIENT_ACCESS_RIGHTS_INT_VALUE, null, ERR_MEM_HANDLER_SEARCH_REQUIRES_AUTH.get(), null));
}
// Get the parsed base DN.
final DN baseDN;
final Schema schema = schemaRef.get();
try {
baseDN = new DN(request.getBaseDN(), schema);
} catch (final LDAPException le) {
Debug.debugException(le);
return new LDAPMessage(messageID, new SearchResultDoneProtocolOp(ResultCode.INVALID_DN_SYNTAX_INT_VALUE, null, ERR_MEM_HANDLER_SEARCH_MALFORMED_BASE.get(request.getBaseDN(), le.getMessage()), null));
}
// See if the search base or one of its superiors is a smart referral.
final boolean hasManageDsaIT = controlMap.containsKey(ManageDsaITRequestControl.MANAGE_DSA_IT_REQUEST_OID);
if (!hasManageDsaIT) {
final Entry referralEntry = findNearestReferral(baseDN);
if (referralEntry != null) {
return new LDAPMessage(messageID, new SearchResultDoneProtocolOp(ResultCode.REFERRAL_INT_VALUE, referralEntry.getDN(), INFO_MEM_HANDLER_REFERRAL_ENCOUNTERED.get(), getReferralURLs(baseDN, referralEntry)));
}
}
// Make sure that the base entry exists. It may be the root DSE or
// subschema subentry.
final Entry baseEntry;
boolean includeChangeLog = true;
if (baseDN.isNullDN()) {
baseEntry = generateRootDSE();
includeChangeLog = false;
} else if (baseDN.equals(subschemaSubentryDN)) {
baseEntry = subschemaSubentryRef.get();
} else {
baseEntry = entryMap.get(baseDN);
}
if (baseEntry == null) {
return new LDAPMessage(messageID, new SearchResultDoneProtocolOp(ResultCode.NO_SUCH_OBJECT_INT_VALUE, getMatchedDNString(baseDN), ERR_MEM_HANDLER_SEARCH_BASE_DOES_NOT_EXIST.get(request.getBaseDN()), null));
}
// controls.
try {
handleAssertionRequestControl(controlMap, baseEntry);
handleProxiedAuthControl(controlMap);
} catch (final LDAPException le) {
Debug.debugException(le);
return new LDAPMessage(messageID, new SearchResultDoneProtocolOp(le.getResultCode().intValue(), null, le.getMessage(), null));
}
// Determine whether to include subentries in search results.
final boolean includeSubEntries;
final boolean includeNonSubEntries;
final SearchScope scope = request.getScope();
if (scope == SearchScope.BASE) {
includeSubEntries = true;
includeNonSubEntries = true;
} else if (controlMap.containsKey(DraftLDUPSubentriesRequestControl.SUBENTRIES_REQUEST_OID)) {
includeSubEntries = true;
includeNonSubEntries = false;
} else if (controlMap.containsKey(RFC3672SubentriesRequestControl.SUBENTRIES_REQUEST_OID)) {
includeSubEntries = true;
final RFC3672SubentriesRequestControl c = (RFC3672SubentriesRequestControl) controlMap.get(RFC3672SubentriesRequestControl.SUBENTRIES_REQUEST_OID);
includeNonSubEntries = (!c.returnOnlySubEntries());
} else if (baseEntry.hasObjectClass("ldapSubEntry") || baseEntry.hasObjectClass("inheritableLDAPSubEntry")) {
includeSubEntries = true;
includeNonSubEntries = true;
} else if (filterIncludesLDAPSubEntry(request.getFilter())) {
includeSubEntries = true;
includeNonSubEntries = true;
} else {
includeSubEntries = false;
includeNonSubEntries = true;
}
// Create a temporary list to hold all of the entries to be returned.
// These entries will not have been pared down based on the requested
// attributes.
final List<Entry> fullEntryList = new ArrayList<>(entryMap.size());
findEntriesAndRefs: {
// Check the scope. If it is a base-level search, then we only need to
// examine the base entry. Otherwise, we'll have to scan the entire
// entry map.
final Filter filter = request.getFilter();
if (scope == SearchScope.BASE) {
try {
if (filter.matchesEntry(baseEntry, schema)) {
processSearchEntry(baseEntry, includeSubEntries, includeNonSubEntries, includeChangeLog, hasManageDsaIT, fullEntryList, referenceList);
}
} catch (final Exception e) {
Debug.debugException(e);
}
break findEntriesAndRefs;
}
// set.
if ((scope == SearchScope.ONE) && baseDN.isNullDN()) {
for (final DN dn : baseDNs) {
final Entry e = entryMap.get(dn);
if (e != null) {
try {
if (filter.matchesEntry(e, schema)) {
processSearchEntry(e, includeSubEntries, includeNonSubEntries, includeChangeLog, hasManageDsaIT, fullEntryList, referenceList);
}
} catch (final Exception ex) {
Debug.debugException(ex);
}
}
}
break findEntriesAndRefs;
}
// Try to use indexes to process the request. If we can't use any
// indexes to get a candidate list, then just iterate over all the
// entries. It's not necessary to consider the root DSE for non-base
// scopes.
final Set<DN> candidateDNs = indexSearch(filter);
if (candidateDNs == null) {
for (final Map.Entry<DN, ReadOnlyEntry> me : entryMap.entrySet()) {
final DN dn = me.getKey();
final Entry entry = me.getValue();
try {
if (dn.matchesBaseAndScope(baseDN, scope)) {
if (filter.matchesEntry(entry, schema) || (((!hasManageDsaIT) && entry.hasObjectClass("referral") && entry.hasAttribute("ref")))) {
processSearchEntry(entry, includeSubEntries, includeNonSubEntries, includeChangeLog, hasManageDsaIT, fullEntryList, referenceList);
}
}
} catch (final Exception e) {
Debug.debugException(e);
}
}
} else {
for (final DN dn : candidateDNs) {
try {
if (!dn.matchesBaseAndScope(baseDN, scope)) {
continue;
}
final Entry entry = entryMap.get(dn);
if (filter.matchesEntry(entry, schema) || (((!hasManageDsaIT) && entry.hasObjectClass("referral") && entry.hasAttribute("ref")))) {
processSearchEntry(entry, includeSubEntries, includeNonSubEntries, includeChangeLog, hasManageDsaIT, fullEntryList, referenceList);
}
} catch (final Exception e) {
Debug.debugException(e);
}
}
}
}
// If the request included the server-side sort request control, then sort
// the matching entries appropriately.
final ServerSideSortRequestControl sortRequestControl = (ServerSideSortRequestControl) controlMap.get(ServerSideSortRequestControl.SERVER_SIDE_SORT_REQUEST_OID);
if (sortRequestControl != null) {
final EntrySorter entrySorter = new EntrySorter(false, schema, sortRequestControl.getSortKeys());
final SortedSet<Entry> sortedEntrySet = entrySorter.sort(fullEntryList);
fullEntryList.clear();
fullEntryList.addAll(sortedEntrySet);
responseControls.add(new ServerSideSortResponseControl(ResultCode.SUCCESS, null));
}
// If the request included the simple paged results control, then handle
// it.
final SimplePagedResultsControl pagedResultsControl = (SimplePagedResultsControl) controlMap.get(SimplePagedResultsControl.PAGED_RESULTS_OID);
if (pagedResultsControl != null) {
final int totalSize = fullEntryList.size();
final int pageSize = pagedResultsControl.getSize();
final ASN1OctetString cookie = pagedResultsControl.getCookie();
final int offset;
if ((cookie == null) || (cookie.getValueLength() == 0)) {
// This is the first request in the series, so start at the beginning
// of the list.
offset = 0;
} else {
// offset within the result list at which to start the next batch.
try {
final ASN1Integer offsetInteger = ASN1Integer.decodeAsInteger(cookie.getValue());
offset = offsetInteger.intValue();
} catch (final Exception e) {
Debug.debugException(e);
return new LDAPMessage(messageID, new SearchResultDoneProtocolOp(ResultCode.PROTOCOL_ERROR_INT_VALUE, null, ERR_MEM_HANDLER_MALFORMED_PAGED_RESULTS_COOKIE.get(), null), responseControls);
}
}
// Create an iterator that will be used to remove entries from the
// result set that are outside of the requested page of results.
int pos = 0;
final Iterator<Entry> iterator = fullEntryList.iterator();
// offset.
while (iterator.hasNext() && (pos < offset)) {
iterator.next();
iterator.remove();
pos++;
}
// Next, skip over the entries that should be returned.
int keptEntries = 0;
while (iterator.hasNext() && (keptEntries < pageSize)) {
iterator.next();
pos++;
keptEntries++;
}
// to include in the response. Otherwise, use an empty cookie.
if (iterator.hasNext()) {
responseControls.add(new SimplePagedResultsControl(totalSize, new ASN1OctetString(new ASN1Integer(pos).encode()), false));
while (iterator.hasNext()) {
iterator.next();
iterator.remove();
}
} else {
responseControls.add(new SimplePagedResultsControl(totalSize, new ASN1OctetString(), false));
}
}
// If the request includes the virtual list view request control, then
// handle it.
final VirtualListViewRequestControl vlvRequest = (VirtualListViewRequestControl) controlMap.get(VirtualListViewRequestControl.VIRTUAL_LIST_VIEW_REQUEST_OID);
if (vlvRequest != null) {
final int totalEntries = fullEntryList.size();
final ASN1OctetString assertionValue = vlvRequest.getAssertionValue();
// Figure out the position of the target entry in the list.
int offset = vlvRequest.getTargetOffset();
if (assertionValue == null) {
// The offset is one-based, so we need to adjust it for the list's
// zero-based offset. Also, make sure to put it within the bounds of
// the list.
offset--;
offset = Math.max(0, offset);
offset = Math.min(fullEntryList.size(), offset);
} else {
final SortKey primarySortKey = sortRequestControl.getSortKeys()[0];
final Entry testEntry = new Entry("cn=test", schema, new Attribute(primarySortKey.getAttributeName(), assertionValue));
final EntrySorter entrySorter = new EntrySorter(false, schema, primarySortKey);
offset = fullEntryList.size();
for (int i = 0; i < fullEntryList.size(); i++) {
if (entrySorter.compare(fullEntryList.get(i), testEntry) >= 0) {
offset = i;
break;
}
}
}
// Get the start and end positions based on the before and after counts.
final int beforeCount = Math.max(0, vlvRequest.getBeforeCount());
final int afterCount = Math.max(0, vlvRequest.getAfterCount());
final int start = Math.max(0, (offset - beforeCount));
final int end = Math.min(fullEntryList.size(), (offset + afterCount + 1));
// Create an iterator to use to alter the list so that it only contains
// the appropriate set of entries.
int pos = 0;
final Iterator<Entry> iterator = fullEntryList.iterator();
while (iterator.hasNext()) {
iterator.next();
if ((pos < start) || (pos >= end)) {
iterator.remove();
}
pos++;
}
// Create the appropriate response control.
responseControls.add(new VirtualListViewResponseControl((offset + 1), totalEntries, ResultCode.SUCCESS, null));
}
// Process the set of requested attributes so that we can pare down the
// entries.
final SearchEntryParer parer = new SearchEntryParer(request.getAttributes(), schema);
final int sizeLimit;
if (request.getSizeLimit() > 0) {
sizeLimit = Math.min(request.getSizeLimit(), maxSizeLimit);
} else {
sizeLimit = maxSizeLimit;
}
int entryCount = 0;
for (final Entry e : fullEntryList) {
entryCount++;
if (entryCount > sizeLimit) {
return new LDAPMessage(messageID, new SearchResultDoneProtocolOp(ResultCode.SIZE_LIMIT_EXCEEDED_INT_VALUE, null, ERR_MEM_HANDLER_SEARCH_SIZE_LIMIT_EXCEEDED.get(), null), responseControls);
}
final Entry trimmedEntry = parer.pareEntry(e);
if (request.typesOnly()) {
final Entry typesOnlyEntry = new Entry(trimmedEntry.getDN(), schema);
for (final Attribute a : trimmedEntry.getAttributes()) {
typesOnlyEntry.addAttribute(new Attribute(a.getName()));
}
entryList.add(new SearchResultEntry(typesOnlyEntry));
} else {
entryList.add(new SearchResultEntry(trimmedEntry));
}
}
return new LDAPMessage(messageID, new SearchResultDoneProtocolOp(ResultCode.SUCCESS_INT_VALUE, null, null, null), responseControls);
}
}
use of com.unboundid.ldap.sdk.controls.RFC3672SubentriesRequestControl in project ldapsdk by pingidentity.
the class LDAPSearch method getSearchControls.
/**
* Retrieves a list of the controls that should be used when processing search
* operations.
*
* @return A list of the controls that should be used when processing search
* operations.
*
* @throws LDAPException If a problem is encountered while generating the
* controls for a search request.
*/
@NotNull()
private List<Control> getSearchControls() {
final ArrayList<Control> controls = new ArrayList<>(10);
if (searchControl.isPresent()) {
controls.addAll(searchControl.getValues());
}
if (joinRequestControl != null) {
controls.add(joinRequestControl);
}
if (matchedValuesRequestControl != null) {
controls.add(matchedValuesRequestControl);
}
if (matchingEntryCountRequestControl != null) {
controls.add(matchingEntryCountRequestControl);
}
if (overrideSearchLimitsRequestControl != null) {
controls.add(overrideSearchLimitsRequestControl);
}
if (persistentSearchRequestControl != null) {
controls.add(persistentSearchRequestControl);
}
if (sortRequestControl != null) {
controls.add(sortRequestControl);
}
if (vlvRequestControl != null) {
controls.add(vlvRequestControl);
}
controls.addAll(routeToBackendSetRequestControls);
if (accountUsable.isPresent()) {
controls.add(new AccountUsableRequestControl(true));
}
if (getBackendSetID.isPresent()) {
controls.add(new GetBackendSetIDRequestControl(false));
}
if (getServerID.isPresent()) {
controls.add(new GetServerIDRequestControl(false));
}
if (includeReplicationConflictEntries.isPresent()) {
controls.add(new ReturnConflictEntriesRequestControl(true));
}
if (includeSoftDeletedEntries.isPresent()) {
final String valueStr = StaticUtils.toLowerCase(includeSoftDeletedEntries.getValue());
if (valueStr.equals("with-non-deleted-entries")) {
controls.add(new SoftDeletedEntryAccessRequestControl(true, true, false));
} else if (valueStr.equals("without-non-deleted-entries")) {
controls.add(new SoftDeletedEntryAccessRequestControl(true, false, false));
} else {
controls.add(new SoftDeletedEntryAccessRequestControl(true, false, true));
}
}
if (draftLDUPSubentries.isPresent()) {
controls.add(new DraftLDUPSubentriesRequestControl(true));
}
if (rfc3672Subentries.isPresent()) {
controls.add(new RFC3672SubentriesRequestControl(rfc3672Subentries.getValue()));
}
if (manageDsaIT.isPresent()) {
controls.add(new ManageDsaITRequestControl(true));
}
if (realAttributesOnly.isPresent()) {
controls.add(new RealAttributesOnlyRequestControl(true));
}
if (routeToServer.isPresent()) {
controls.add(new RouteToServerRequestControl(false, routeToServer.getValue(), false, false, false));
}
if (virtualAttributesOnly.isPresent()) {
controls.add(new VirtualAttributesOnlyRequestControl(true));
}
if (excludeBranch.isPresent()) {
final ArrayList<String> dns = new ArrayList<>(excludeBranch.getValues().size());
for (final DN dn : excludeBranch.getValues()) {
dns.add(dn.toString());
}
controls.add(new ExcludeBranchRequestControl(true, dns));
}
if (assertionFilter.isPresent()) {
controls.add(new AssertionRequestControl(assertionFilter.getValue(), true));
}
if (getEffectiveRightsAuthzID.isPresent()) {
final String[] attributes;
if (getEffectiveRightsAttribute.isPresent()) {
attributes = new String[getEffectiveRightsAttribute.getValues().size()];
for (int i = 0; i < attributes.length; i++) {
attributes[i] = getEffectiveRightsAttribute.getValues().get(i);
}
} else {
attributes = StaticUtils.NO_STRINGS;
}
controls.add(new GetEffectiveRightsRequestControl(true, getEffectiveRightsAuthzID.getValue(), attributes));
}
if (operationPurpose.isPresent()) {
controls.add(new OperationPurposeRequestControl(true, "ldapsearch", Version.NUMERIC_VERSION_STRING, "LDAPSearch.getSearchControls", operationPurpose.getValue()));
}
if (proxyAs.isPresent()) {
controls.add(new ProxiedAuthorizationV2RequestControl(proxyAs.getValue()));
}
if (proxyV1As.isPresent()) {
controls.add(new ProxiedAuthorizationV1RequestControl(proxyV1As.getValue()));
}
if (suppressOperationalAttributeUpdates.isPresent()) {
final EnumSet<SuppressType> suppressTypes = EnumSet.noneOf(SuppressType.class);
for (final String s : suppressOperationalAttributeUpdates.getValues()) {
if (s.equalsIgnoreCase("last-access-time")) {
suppressTypes.add(SuppressType.LAST_ACCESS_TIME);
} else if (s.equalsIgnoreCase("last-login-time")) {
suppressTypes.add(SuppressType.LAST_LOGIN_TIME);
} else if (s.equalsIgnoreCase("last-login-ip")) {
suppressTypes.add(SuppressType.LAST_LOGIN_IP);
}
}
controls.add(new SuppressOperationalAttributeUpdateRequestControl(suppressTypes));
}
if (rejectUnindexedSearch.isPresent()) {
controls.add(new RejectUnindexedSearchRequestControl());
}
if (permitUnindexedSearch.isPresent()) {
controls.add(new PermitUnindexedSearchRequestControl());
}
return controls;
}
use of com.unboundid.ldap.sdk.controls.RFC3672SubentriesRequestControl in project ldapsdk by pingidentity.
the class RequestControlPreProcessorTestCase method testRFC3672LDUPSubentriesControl.
/**
* Provides test coverage for the subentries control as described in RFC 3672.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test()
public void testRFC3672LDUPSubentriesControl() throws Exception {
final String oid = RFC3672SubentriesRequestControl.SUBENTRIES_REQUEST_OID;
final Control vc = new RFC3672SubentriesRequestControl(true, true);
final Control vn = new RFC3672SubentriesRequestControl(false, false);
final Control ic = new Control(oid, true, new ASN1OctetString("foo"));
final Control in = new Control(oid, false, new ASN1OctetString("foo"));
final Class<?> c = RFC3672SubentriesRequestControl.class;
// Test with acceptable operation types.
for (final byte opType : Arrays.asList(LDAPMessage.PROTOCOL_OP_TYPE_SEARCH_REQUEST)) {
// A valid critical control.
ensureControlHandled(opType, Arrays.asList(vc), oid, c);
// A valid non-critical control.
ensureControlHandled(opType, Arrays.asList(vn), oid, c);
// Multiple instances of the control.
ensureException(opType, Arrays.asList(vc, vn));
// Malformed critical control.
ensureException(opType, Arrays.asList(ic));
// Malformed non-critical control.
ensureException(opType, Arrays.asList(in));
}
// Test with unacceptable operation types.
for (final byte opType : Arrays.asList(LDAPMessage.PROTOCOL_OP_TYPE_ABANDON_REQUEST, LDAPMessage.PROTOCOL_OP_TYPE_ADD_REQUEST, LDAPMessage.PROTOCOL_OP_TYPE_BIND_REQUEST, LDAPMessage.PROTOCOL_OP_TYPE_COMPARE_REQUEST, LDAPMessage.PROTOCOL_OP_TYPE_DELETE_REQUEST, LDAPMessage.PROTOCOL_OP_TYPE_EXTENDED_REQUEST, LDAPMessage.PROTOCOL_OP_TYPE_MODIFY_REQUEST, LDAPMessage.PROTOCOL_OP_TYPE_MODIFY_DN_REQUEST, LDAPMessage.PROTOCOL_OP_TYPE_UNBIND_REQUEST)) {
// A valid critical control.
ensureException(opType, Arrays.asList(vc));
// A valid non-critical control.
ensureControlIgnored(opType, Arrays.asList(vn), oid);
// Malformed critical control.
ensureException(opType, Arrays.asList(ic));
// Malformed non-critical control.
ensureControlIgnored(opType, Arrays.asList(in), oid);
}
}
use of com.unboundid.ldap.sdk.controls.RFC3672SubentriesRequestControl in project ldapsdk by pingidentity.
the class InMemoryDirectoryControlsTestCase method testRFC3672SubentriesControl.
/**
* Provides test coverage for the subentries request control as described in
* RFC 3672.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test()
public void testRFC3672SubentriesControl() throws Exception {
final InMemoryDirectoryServer ds = getTestDS(true, true);
final LDAPConnection conn = ds.getConnection();
RFC3672SubentriesRequestControl returnOnlySubentriesControl = new RFC3672SubentriesRequestControl(true);
RFC3672SubentriesRequestControl returnRegularAndSubentriesControl = new RFC3672SubentriesRequestControl(false);
conn.add("dn: cn=subentry test,dc=example,dc=com", "objectClass: top", "objectClass: ldapSubEntry", "cn: subentry test");
// Ensure that the subentry is returned for a base-level search even if the
// control is not present.
SearchRequest searchRequest = new SearchRequest("cn=subentry test,dc=example,dc=com", SearchScope.BASE, "(objectClass=*)");
SearchResult searchResult = conn.search(searchRequest);
assertEquals(searchResult.getResultCode(), ResultCode.SUCCESS);
assertEquals(searchResult.getEntryCount(), 1);
assertNotNull(searchResult.getSearchEntry("cn=subentry test,dc=example,dc=com"));
// Ensure that the entry is also returned for a base-level search if the
// control is provided, regardless of whether regular entries are to be
// returned.
searchRequest.setControls(returnOnlySubentriesControl);
searchResult = conn.search(searchRequest);
assertEquals(searchResult.getResultCode(), ResultCode.SUCCESS);
assertEquals(searchResult.getEntryCount(), 1);
assertNotNull(searchResult.getSearchEntry("cn=subentry test,dc=example,dc=com"));
searchRequest.setControls(returnRegularAndSubentriesControl);
searchResult = conn.search(searchRequest);
assertEquals(searchResult.getResultCode(), ResultCode.SUCCESS);
assertEquals(searchResult.getEntryCount(), 1);
assertNotNull(searchResult.getSearchEntry("cn=subentry test,dc=example,dc=com"));
// Ensure that the subentry is not returned for a non-base search without
// the control.
searchRequest = new SearchRequest("dc=example,dc=com", SearchScope.SUB, "(objectClass=*)");
searchResult = conn.search(searchRequest);
assertEquals(searchResult.getResultCode(), ResultCode.SUCCESS);
assertEquals(searchResult.getEntryCount(), 3);
assertNotNull(searchResult.getSearchEntry("dc=example,dc=com"));
assertNotNull(searchResult.getSearchEntry("ou=People,dc=example,dc=com"));
assertNotNull(searchResult.getSearchEntry("uid=test.user,ou=People,dc=example,dc=com"));
assertNull(searchResult.getSearchEntry("cn=subentry test,dc=example,dc=com"));
// Ensure that only the subentry is returned for the same non-base search if
// the subentries control is provided with returnOnlySubnetries flag set to
// true.
searchRequest.setControls(returnOnlySubentriesControl);
searchResult = conn.search(searchRequest);
assertEquals(searchResult.getResultCode(), ResultCode.SUCCESS);
assertEquals(searchResult.getEntryCount(), 1);
assertNotNull(searchResult.getSearchEntry("cn=subentry test,dc=example,dc=com"));
// Ensure that all entries, including subentry are returned for a subtree
// search from the naming context with a filter of
// "(|(objectClass=*)(objectClass=ldapSubEntry))".
searchRequest.setControls(returnRegularAndSubentriesControl);
searchResult = conn.search(searchRequest);
assertEquals(searchResult.getResultCode(), ResultCode.SUCCESS);
assertEquals(searchResult.getEntryCount(), 4);
assertNotNull(searchResult.getSearchEntry("dc=example,dc=com"));
assertNotNull(searchResult.getSearchEntry("ou=People,dc=example,dc=com"));
assertNotNull(searchResult.getSearchEntry("uid=test.user,ou=People,dc=example,dc=com"));
assertNotNull(searchResult.getSearchEntry("cn=subentry test,dc=example,dc=com"));
conn.close();
}
Aggregations