mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Yannick Lecaillez
19.40.2015 a3f92d339613d2703be9dba3d06e1e229fc69482
opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryContainer.java
@@ -865,7 +865,11 @@
            if (!isBelowFilterThreshold(entryIDSet))
            {
              final EntryIDSet scopeSet = getIDSetFromScope(txn, aBaseDN, searchScope);
              final int lookThroughLimit = searchOperation.getClientConnection().getLookthroughLimit();
              final int idSetLimit =
                  lookThroughLimit == 0 ? SCOPE_IDSET_LIMIT : Math.min(SCOPE_IDSET_LIMIT, lookThroughLimit);
              final EntryIDSet scopeSet = getIDSetFromScope(txn, aBaseDN, searchScope, idSetLimit);
              entryIDSet.retainAll(scopeSet);
              if (debugBuffer != null)
              {
@@ -969,8 +973,8 @@
          return null;
        }
        private EntryIDSet getIDSetFromScope(final ReadableTransaction txn, DN aBaseDN, SearchScope searchScope)
            throws DirectoryException
        private EntryIDSet getIDSetFromScope(final ReadableTransaction txn, DN aBaseDN, SearchScope searchScope,
            int idSetLimit) throws DirectoryException
        {
          final EntryIDSet scopeSet;
          try
@@ -986,14 +990,14 @@
            case SINGLE_LEVEL:
              try (final SequentialCursor<?, EntryID> scopeCursor = dn2id.openChildrenCursor(txn, aBaseDN))
              {
                scopeSet = newIDSetFromCursor(scopeCursor, false);
                scopeSet = newIDSetFromCursor(scopeCursor, false, idSetLimit);
              }
              break;
            case SUBORDINATES:
            case WHOLE_SUBTREE:
              try (final SequentialCursor<?, EntryID> scopeCursor = dn2id.openSubordinatesCursor(txn, aBaseDN))
              {
                scopeSet = newIDSetFromCursor(scopeCursor, searchScope.equals(SearchScope.WHOLE_SUBTREE));
                scopeSet = newIDSetFromCursor(scopeCursor, searchScope.equals(SearchScope.WHOLE_SUBTREE), idSetLimit);
              }
              break;
            default:
@@ -1016,23 +1020,32 @@
    }
  }
  private static EntryIDSet newIDSetFromCursor(SequentialCursor<?, EntryID> cursor, boolean includeCurrent)
  private static EntryIDSet newIDSetFromCursor(SequentialCursor<?, EntryID> cursor, boolean includeCurrent,
      int idSetLimit)
  {
    long ids[] = new long[SCOPE_IDSET_LIMIT];
    long entryIDs[] = new long[idSetLimit];
    int offset = 0;
    if (includeCurrent) {
      ids[offset++] = cursor.getValue().longValue();
    }
    for(; offset < ids.length && cursor.next() ; offset++) {
      ids[offset] = cursor.getValue().longValue();
    if (includeCurrent)
    {
      entryIDs[offset++] = cursor.getValue().longValue();
    }
    ids = Arrays.copyOf(ids, offset);
    Arrays.sort(ids);
    while(offset < idSetLimit && cursor.next())
    {
      entryIDs[offset++] = cursor.getValue().longValue();
    }
    return offset == SCOPE_IDSET_LIMIT
        ? EntryIDSet.newUndefinedSet()
        : EntryIDSet.newDefinedSet(ids);
    if (offset == idSetLimit && cursor.next())
    {
      return EntryIDSet.newUndefinedSet();
    }
    else if (offset != idSetLimit)
    {
      entryIDs = Arrays.copyOf(entryIDs, offset);
    }
    Arrays.sort(entryIDs);
    return EntryIDSet.newDefinedSet(entryIDs);
  }
  private <E1 extends Exception, E2 extends Exception>
opendj-sdk/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/ClientConnectionStub.java
New file
@@ -0,0 +1,198 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
 * or http://forgerock.org/license/CDDLv1.0.html.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at legal-notices/CDDLv1_0.txt.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2015 ForgeRock AS
 */
package org.opends.server.backends.pluggable;
import java.net.InetAddress;
import java.util.Collection;
import org.forgerock.i18n.LocalizableMessage;
import org.opends.server.api.ClientConnection;
import org.opends.server.api.ConnectionHandler;
import org.opends.server.core.SearchOperation;
import org.opends.server.types.CancelRequest;
import org.opends.server.types.CancelResult;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.DisconnectReason;
import org.opends.server.types.IntermediateResponse;
import org.opends.server.types.Operation;
import org.opends.server.types.SearchResultEntry;
import org.opends.server.types.SearchResultReference;
class ClientConnectionStub extends ClientConnection
{
  @Override
  public long getConnectionID()
  {
    return 0;
  }
  @Override
  public ConnectionHandler<?> getConnectionHandler()
  {
    return null;
  }
  @Override
  public String getProtocol()
  {
    return null;
  }
  @Override
  public String getClientAddress()
  {
    return null;
  }
  @Override
  public int getClientPort()
  {
    return 0;
  }
  @Override
  public String getServerAddress()
  {
    return null;
  }
  @Override
  public int getServerPort()
  {
    return 0;
  }
  @Override
  public InetAddress getRemoteAddress()
  {
    return null;
  }
  @Override
  public InetAddress getLocalAddress()
  {
    return null;
  }
  @Override
  public boolean isConnectionValid()
  {
    return false;
  }
  @Override
  public boolean isSecure()
  {
    return false;
  }
  @Override
  public long getNumberOfOperations()
  {
    return 0;
  }
  @Override
  public void sendResponse(Operation operation)
  {
  }
  @Override
  public void sendSearchEntry(SearchOperation searchOperation, SearchResultEntry searchEntry) throws DirectoryException
  {
  }
  @Override
  public boolean sendSearchReference(SearchOperation searchOperation, SearchResultReference searchReference)
      throws DirectoryException
  {
    return false;
  }
  @Override
  protected boolean sendIntermediateResponseMessage(IntermediateResponse intermediateResponse)
  {
    return false;
  }
  @Override
  public void disconnect(DisconnectReason disconnectReason, boolean sendNotification, LocalizableMessage message)
  {
  }
  @Override
  public Collection<Operation> getOperationsInProgress()
  {
    return null;
  }
  @Override
  public Operation getOperationInProgress(int messageID)
  {
    return null;
  }
  @Override
  public boolean removeOperationInProgress(int messageID)
  {
    return false;
  }
  @Override
  public CancelResult cancelOperation(int messageID, CancelRequest cancelRequest)
  {
    return null;
  }
  @Override
  public void cancelAllOperations(CancelRequest cancelRequest)
  {
  }
  @Override
  public void cancelAllOperationsExcept(CancelRequest cancelRequest, int messageID)
  {
  }
  @Override
  public String getMonitorSummary()
  {
    return null;
  }
  @Override
  public void toString(StringBuilder buffer)
  {
  }
  @Override
  public int getSSF()
  {
    return 0;
  }
}
opendj-sdk/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/PluggableBackendImplTestCase.java
@@ -25,6 +25,7 @@
 */
package org.opends.server.backends.pluggable;
import static org.assertj.core.api.Assertions.assertThat;
import static org.forgerock.opendj.ldap.ModificationType.ADD;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -37,14 +38,18 @@
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Random;
import org.assertj.core.api.Assertions;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.ConditionResult;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.SearchScope;
import org.opends.server.DirectoryServerTestCase;
import org.opends.server.TestCaseUtils;
@@ -54,7 +59,10 @@
import org.opends.server.admin.std.server.BackendVLVIndexCfg;
import org.opends.server.admin.std.server.PluggableBackendCfg;
import org.opends.server.api.Backend.BackendOperation;
import org.opends.server.api.ClientConnection;
import org.opends.server.api.ConnectionHandler;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.SearchOperation;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.protocols.internal.SearchRequest;
@@ -62,14 +70,20 @@
import org.opends.server.types.AttributeType;
import org.opends.server.types.BackupConfig;
import org.opends.server.types.BackupDirectory;
import org.opends.server.types.CancelRequest;
import org.opends.server.types.CancelResult;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.DisconnectReason;
import org.opends.server.types.Entry;
import org.opends.server.types.IntermediateResponse;
import org.opends.server.types.LDIFExportConfig;
import org.opends.server.types.LDIFImportConfig;
import org.opends.server.types.Modification;
import org.opends.server.types.Operation;
import org.opends.server.types.RestoreConfig;
import org.opends.server.types.SearchResultEntry;
import org.opends.server.types.SearchResultReference;
import org.opends.server.workflowelement.localbackend.LocalBackendSearchOperation;
import org.testng.Reporter;
import org.testng.annotations.AfterClass;
@@ -716,6 +730,30 @@
    subTreeSearch(true);
  }
  @Test(dependsOnMethods = "testAdd")
  public void testSearchIsConsideredUnindexedBasedOnLookThroughLimit() throws DirectoryException {
    final int nbEntries = topEntries.size() + entries.size() + workEntries.size();
    final SearchRequest request = newSearchRequest(testBaseDN, SearchScope.WHOLE_SUBTREE, "objectclass=*");
    final ClientConnection connection = new ClientConnectionStub();
    connection.setLookthroughLimit(0);
    InternalSearchOperation searchOperation = new InternalSearchOperation(connection, 1, 1, request, null);
    searchOperation.run();
    assertThat(searchOperation.getEntriesSent()).isEqualTo(nbEntries);
    connection.setLookthroughLimit(nbEntries);
    searchOperation = new InternalSearchOperation(connection, 1, 1, request, null);
    searchOperation.run();
    assertThat(searchOperation.getEntriesSent()).isEqualTo(nbEntries);
    connection.setLookthroughLimit(nbEntries - 1);
    searchOperation = new InternalSearchOperation(connection, 1, 1, request, null);
    searchOperation.run();
    assertThat(searchOperation.getResultCode()).isEqualTo(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
    assertThat(searchOperation.getErrorMessage().toString()).contains("not have sufficient privileges", "unindexed search");
    assertThat(searchOperation.getEntriesSent()).isEqualTo(0);
  }
  private void subTreeSearch(boolean useInternalConnection) throws Exception
  {
    SearchRequest request = newSearchRequest(testBaseDN, SearchScope.WHOLE_SUBTREE, "objectclass=*");