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

Matthew Swift
01.09.2014 44b1ade8f82e2cc1a0e8f776b44c29235aa7d088
Fix various bugs in access log filtering:

* OPENDJ-1429: Access log filtering criterion request-target-dn-not-equal-to does not work
* OPENDJ-1432: Access log filtering criterion on etime property does not work
* OPENDJ-1433: Access log filtering criterion on result code property does not work
* OPENDJ-1434: Access log filtering criteria user-dn-not-equal-to does not work
* OPENDJ-1435: Access log filtering criteria user-is-not-member-of does not work.

Also added unit tests. Use a single commit because a) the fixes are very small and closely related, and b) some of the bugs have a common cause.
2 files modified
409 ■■■■■ changed files
opends/src/server/org/opends/server/loggers/AbstractTextAccessLogPublisher.java 46 ●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/loggers/AbstractTextAccessLogPublisherTest.java 363 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/loggers/AbstractTextAccessLogPublisher.java
@@ -21,7 +21,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2011-2013 ForgeRock AS
 *      Copyright 2011-2014 ForgeRock AS
 */
package org.opends.server.loggers;
@@ -473,24 +473,30 @@
    private boolean filterDN(final DN dn, PatternDN[] notEqualTo,
        PatternDN[] equalTo)
    {
      for (final PatternDN pattern : notEqualTo)
      if (notEqualTo.length > 0)
      {
        if (pattern.matchesDN(dn))
        for (final PatternDN pattern : notEqualTo)
        {
          return false;
          if (pattern.matchesDN(dn))
          {
            return false;
          }
        }
      }
      for (final PatternDN pattern : equalTo)
      if (equalTo.length > 0)
      {
        if (pattern.matchesDN(dn))
        for (final PatternDN pattern : equalTo)
        {
          return true;
          if (pattern.matchesDN(dn))
          {
            return true;
          }
        }
        return false;
      }
      // The DN did not match.
      return false;
      return true;
    }
@@ -500,26 +506,22 @@
      // Check response code.
      final Integer resultCode = operation.getResultCode().getIntValue();
      if (!cfg.getResponseResultCodeNotEqualTo().isEmpty())
      if (!cfg.getResponseResultCodeNotEqualTo().isEmpty()
          && cfg.getResponseResultCodeNotEqualTo().contains(resultCode))
      {
        if (cfg.getResponseResultCodeNotEqualTo().contains(resultCode))
        {
          return false;
        }
        return false;
      }
      if (!cfg.getResponseResultCodeEqualTo().isEmpty())
      if (!cfg.getResponseResultCodeEqualTo().isEmpty()
          && !cfg.getResponseResultCodeEqualTo().contains(resultCode))
      {
        if (!cfg.getResponseResultCodeNotEqualTo().contains(resultCode))
        {
          return false;
        }
        return false;
      }
      // Check etime.
      final long etime = operation.getProcessingTime();
      final Integer etimeGT = cfg.getResponseEtimeLessThan();
      final Integer etimeGT = cfg.getResponseEtimeGreaterThan();
      if (etimeGT != null)
      {
        if (etime <= ((long) etimeGT))
@@ -691,10 +693,10 @@
            }
          }
        }
        return false;
      }
      // The user entry did not match.
      return false;
      return true;
    }
  }
opends/tests/unit-tests-testng/src/server/org/opends/server/loggers/AbstractTextAccessLogPublisherTest.java
@@ -21,25 +21,109 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2013 ForgeRock AS
 *      Copyright 2013-2014 ForgeRock AS
 */
package org.opends.server.loggers;
import static org.mockito.Mockito.*;
import static org.testng.Assert.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.Arrays;
import java.util.SortedSet;
import java.util.TreeSet;
import org.opends.server.DirectoryServerTestCase;
import org.opends.server.TestCaseUtils;
import org.opends.server.admin.std.meta.AccessLogFilteringCriteriaCfgDefn.LogRecordType;
import org.opends.server.admin.std.server.AccessLogFilteringCriteriaCfg;
import org.opends.server.api.ClientConnection;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.SearchOperation;
import org.opends.server.loggers.AbstractTextAccessLogPublisher.CriteriaFilter;
import org.opends.server.loggers.AbstractTextAccessLogPublisher.RootFilter;
import org.opends.server.types.AddressMask;
import org.opends.server.types.AuthenticationInfo;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.Operation;
import org.opends.server.types.OperationType;
import org.opends.server.types.ResultCode;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
@SuppressWarnings("javadoc")
public class AbstractTextAccessLogPublisherTest extends DirectoryServerTestCase
{
  @AfterClass
  public void afterClass() throws Exception
  {
    // Make sure group is removed from group manager.
    TestCaseUtils.deleteEntry(dn("cn=group 1,ou=Groups,o=test"));
    TestCaseUtils.clearDataBackends();
  }
  @BeforeClass
  public void beforeClass() throws Exception
  {
    TestCaseUtils.startServer();
    TestCaseUtils.clearDataBackends();
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.addEntries(
        // @formatter:off
        "dn: ou=People,o=test",
        "objectClass: top",
        "objectClass: organizationalUnit",
        "ou: People",
        "",
        "dn: ou=Groups,o=test",
        "objectClass: top",
        "objectClass: organizationalUnit",
        "ou: Groups",
        "",
        "dn: cn=group 1,ou=Groups,o=test",
        "objectClass: top",
        "objectClass: groupOfNames",
        "cn: group 1",
        "member: uid=user.1,ou=People,o=test",
        "",
        "dn: uid=user.1,ou=People,o=test",
        "objectClass: top",
        "objectClass: person",
        "objectClass: organizationalPerson",
        "objectClass: inetOrgPerson",
        "uid: user.1",
        "givenName: User",
        "sn: 1",
        "cn: User 1",
        "userPassword: password",
        "",
        "dn: uid=user.2,ou=People,o=test",
        "objectClass: top",
        "objectClass: person",
        "objectClass: organizationalPerson",
        "objectClass: inetOrgPerson",
        "uid: user.2",
        "givenName: User",
        "sn: 2",
        "cn: User 2",
        "userPassword: password");
        // @formatter:on
  }
  @DataProvider(name = "isLoggableData")
  public Object[][] getIsLoggableData()
  private Object[][] getIsLoggableData()
  {
    // When suppress is set to true and the corresponding operation is set to
    // true too, then the operation is not loggable.
@@ -49,6 +133,7 @@
    // There is just one exception: when the operation is a synchronization
    // operation and we do not suppress synchronization operation, then we
    // return true regardless of whether this is an internal operation
    // @formatter:off
    return new Object[][] {
      { true, true, true, true, false },
      { true, true, true, false, false },
@@ -66,21 +151,279 @@
      { false, false, true, false, true },
      { false, false, false, true, true },
      { false, false, false, false, true }, };
    // @formatter:on
  }
  @Test(dataProvider = "isLoggableData")
  public void rootFilterIsLoggable(boolean suppressSynchronization,
      boolean isSynchronizationOp, boolean suppressInternal,
      boolean isInternalOp, boolean expectedTestResult)
  public void rootFilterIsLoggable(final boolean suppressSynchronization,
      final boolean isSynchronizationOp, final boolean suppressInternal,
      final boolean isInternalOp, final boolean expectedTestResult)
  {
    final Operation operation = mock(Operation.class);
    when(operation.isSynchronizationOperation())
        .thenReturn(isSynchronizationOp);
    when(operation.isInnerOperation()).thenReturn(isInternalOp);
    final RootFilter filter =
        new RootFilter(suppressInternal, suppressSynchronization, null, null);
    assertEquals(filter.isLoggable(operation), expectedTestResult);
    final RootFilter filter = new RootFilter(suppressInternal,
        suppressSynchronization, null, null);
    assertThat(filter.isLoggable(operation)).isEqualTo(expectedTestResult);
  }
  @Test
  public void testCriteriaFilterDefault() throws Exception
  {
    final AccessLogFilteringCriteriaCfg cfg = mockCriteriaFilterCfg();
    final CriteriaFilter filter = new CriteriaFilter(cfg);
    final Operation operation = mockAnonymousSearchOperation();
    assertThat(filter.isRequestLoggable(operation)).isTrue();
  }
  @Test
  public void testCriteriaFilterRequestTargetDNEqualTo() throws Exception
  {
    final AccessLogFilteringCriteriaCfg cfg = mockCriteriaFilterCfg();
    when(cfg.getRequestTargetDNEqualTo()).thenReturn(setOf("dc=com"));
    final CriteriaFilter filter = new CriteriaFilter(cfg);
    final SearchOperation operation = mockAnonymousSearchOperation();
    when(operation.getBaseDN()).thenReturn(dn("dc=com"), dn("dc=org"));
    assertThat(filter.isRequestLoggable(operation)).isTrue();
    assertThat(filter.isRequestLoggable(operation)).isFalse();
  }
  @Test
  public void testCriteriaFilterRequestTargetDNNotEqualTo() throws Exception
  {
    final AccessLogFilteringCriteriaCfg cfg = mockCriteriaFilterCfg();
    when(cfg.getRequestTargetDNNotEqualTo()).thenReturn(setOf("dc=com"));
    final CriteriaFilter filter = new CriteriaFilter(cfg);
    final SearchOperation operation = mockAnonymousSearchOperation();
    when(operation.getBaseDN()).thenReturn(dn("dc=com"), dn("dc=org"));
    assertThat(filter.isRequestLoggable(operation)).isFalse();
    assertThat(filter.isRequestLoggable(operation)).isTrue();
  }
  @Test
  public void testCriteriaFilterResponseEtimeGreaterThan() throws Exception
  {
    final AccessLogFilteringCriteriaCfg cfg = mockCriteriaFilterCfg();
    when(cfg.getResponseEtimeGreaterThan()).thenReturn(100);
    final CriteriaFilter filter = new CriteriaFilter(cfg);
    final SearchOperation operation = mockAnonymousSearchOperation();
    when(operation.getProcessingTime()).thenReturn(50L, 150L);
    assertThat(filter.isResponseLoggable(operation)).isFalse();
    assertThat(filter.isResponseLoggable(operation)).isTrue();
  }
  @Test
  public void testCriteriaFilterResponseEtimeLessThan() throws Exception
  {
    final AccessLogFilteringCriteriaCfg cfg = mockCriteriaFilterCfg();
    when(cfg.getResponseEtimeLessThan()).thenReturn(100);
    final CriteriaFilter filter = new CriteriaFilter(cfg);
    final SearchOperation operation = mockAnonymousSearchOperation();
    when(operation.getProcessingTime()).thenReturn(50L, 150L);
    assertThat(filter.isResponseLoggable(operation)).isTrue();
    assertThat(filter.isResponseLoggable(operation)).isFalse();
  }
  @Test
  public void testCriteriaFilterResponseResultCodeEqualTo() throws Exception
  {
    final AccessLogFilteringCriteriaCfg cfg = mockCriteriaFilterCfg();
    when(cfg.getResponseResultCodeEqualTo()).thenReturn(setOf(32));
    final CriteriaFilter filter = new CriteriaFilter(cfg);
    final SearchOperation operation = mockAnonymousSearchOperation();
    when(operation.getResultCode()).thenReturn(ResultCode.NO_SUCH_OBJECT,
        ResultCode.SUCCESS);
    assertThat(filter.isResponseLoggable(operation)).isTrue();
    assertThat(filter.isResponseLoggable(operation)).isFalse();
  }
  @Test
  public void testCriteriaFilterResponseResultCodeNotEqualTo() throws Exception
  {
    final AccessLogFilteringCriteriaCfg cfg = mockCriteriaFilterCfg();
    when(cfg.getResponseResultCodeNotEqualTo()).thenReturn(setOf(32));
    final CriteriaFilter filter = new CriteriaFilter(cfg);
    final SearchOperation operation = mockAnonymousSearchOperation();
    when(operation.getResultCode()).thenReturn(ResultCode.NO_SUCH_OBJECT,
        ResultCode.SUCCESS);
    assertThat(filter.isResponseLoggable(operation)).isFalse();
    assertThat(filter.isResponseLoggable(operation)).isTrue();
  }
  @Test
  public void testCriteriaFilterUserDNEqualTo() throws Exception
  {
    final AccessLogFilteringCriteriaCfg cfg = mockCriteriaFilterCfg();
    when(cfg.getUserDNEqualTo())
        .thenReturn(setOf(dnOfUserInGroup().toString()));
    final CriteriaFilter filter = new CriteriaFilter(cfg);
    final SearchOperation operation1 = mockAuthenticatedSearchOperation(dnOfUserInGroup());
    assertThat(filter.isRequestLoggable(operation1)).isTrue();
    final SearchOperation operation2 = mockAuthenticatedSearchOperation(dnOfUserNotInGroup());
    assertThat(filter.isRequestLoggable(operation2)).isFalse();
  }
  @Test
  public void testCriteriaFilterUserDNNotEqualTo() throws Exception
  {
    final AccessLogFilteringCriteriaCfg cfg = mockCriteriaFilterCfg();
    when(cfg.getUserDNNotEqualTo()).thenReturn(
        setOf(dnOfUserInGroup().toString()));
    final CriteriaFilter filter = new CriteriaFilter(cfg);
    final SearchOperation operation1 = mockAuthenticatedSearchOperation(dnOfUserInGroup());
    assertThat(filter.isRequestLoggable(operation1)).isFalse();
    final SearchOperation operation2 = mockAuthenticatedSearchOperation(dnOfUserNotInGroup());
    assertThat(filter.isRequestLoggable(operation2)).isTrue();
  }
  @Test
  public void testCriteriaFilterUserIsMemberOf() throws Exception
  {
    final AccessLogFilteringCriteriaCfg cfg = mockCriteriaFilterCfg();
    when(cfg.getUserIsMemberOf()).thenReturn(setOf(dnOfGroup()));
    final CriteriaFilter filter = new CriteriaFilter(cfg);
    final SearchOperation operation1 = mockAuthenticatedSearchOperation(dnOfUserInGroup());
    assertThat(filter.isRequestLoggable(operation1)).isTrue();
    final SearchOperation operation2 = mockAuthenticatedSearchOperation(dnOfUserNotInGroup());
    assertThat(filter.isRequestLoggable(operation2)).isFalse();
  }
  @Test
  public void testCriteriaFilterUserIsNotMemberOf() throws Exception
  {
    final AccessLogFilteringCriteriaCfg cfg = mockCriteriaFilterCfg();
    when(cfg.getUserIsNotMemberOf()).thenReturn(setOf(dnOfGroup()));
    final CriteriaFilter filter = new CriteriaFilter(cfg);
    final SearchOperation operation1 = mockAuthenticatedSearchOperation(dnOfUserInGroup());
    assertThat(filter.isRequestLoggable(operation1)).isFalse();
    final SearchOperation operation2 = mockAuthenticatedSearchOperation(dnOfUserNotInGroup());
    assertThat(filter.isRequestLoggable(operation2)).isTrue();
  }
  private DN dn(final String dn)
  {
    try
    {
      return DN.decode(dn);
    }
    catch (final DirectoryException e)
    {
      throw new RuntimeException(e);
    }
  }
  private DN dnOfGroup()
  {
    return dn("cn=group 1,ou=Groups,o=test");
  }
  private DN dnOfUserInGroup()
  {
    return dn("uid=user.1,ou=People,o=test");
  }
  private DN dnOfUserNotInGroup()
  {
    return dn("uid=user.2,ou=People,o=test");
  }
  private SearchOperation mockAnonymousSearchOperation() throws Exception
  {
    return mockSearchOperation(new AuthenticationInfo());
  }
  private SearchOperation mockAuthenticatedSearchOperation(final DN user)
      throws Exception
  {
    return mockSearchOperation(new AuthenticationInfo(
        DirectoryServer.getEntry(user), false));
  }
  private AccessLogFilteringCriteriaCfg mockCriteriaFilterCfg()
  {
    final AccessLogFilteringCriteriaCfg cfg = mock(AccessLogFilteringCriteriaCfg.class);
    when(cfg.getConnectionClientAddressEqualTo()).thenReturn(
        new TreeSet<AddressMask>());
    when(cfg.getConnectionClientAddressNotEqualTo()).thenReturn(
        new TreeSet<AddressMask>());
    when(cfg.getConnectionPortEqualTo()).thenReturn(new TreeSet<Integer>());
    when(cfg.getConnectionProtocolEqualTo()).thenReturn(new TreeSet<String>());
    when(cfg.getLogRecordType()).thenReturn(new TreeSet<LogRecordType>());
    when(cfg.getRequestTargetDNEqualTo()).thenReturn(new TreeSet<String>());
    when(cfg.getRequestTargetDNNotEqualTo()).thenReturn(new TreeSet<String>());
    when(cfg.getResponseEtimeGreaterThan()).thenReturn(null);
    when(cfg.getResponseEtimeLessThan()).thenReturn(null);
    when(cfg.getResponseResultCodeEqualTo()).thenReturn(new TreeSet<Integer>());
    when(cfg.getResponseResultCodeNotEqualTo()).thenReturn(
        new TreeSet<Integer>());
    when(cfg.isSearchResponseIsIndexed()).thenReturn(null);
    when(cfg.getSearchResponseNentriesGreaterThan()).thenReturn(null);
    when(cfg.getSearchResponseNentriesLessThan()).thenReturn(null);
    when(cfg.getUserDNEqualTo()).thenReturn(new TreeSet<String>());
    when(cfg.getUserDNNotEqualTo()).thenReturn(new TreeSet<String>());
    when(cfg.getUserIsMemberOf()).thenReturn(new TreeSet<DN>());
    when(cfg.getUserIsNotMemberOf()).thenReturn(new TreeSet<DN>());
    return cfg;
  }
  private SearchOperation mockSearchOperation(final AuthenticationInfo authInfo)
      throws Exception
  {
    final SearchOperation operation = mock(SearchOperation.class);
    final ClientConnection connection = mock(ClientConnection.class);
    when(operation.getOperationType()).thenReturn(OperationType.SEARCH);
    when(operation.getClientConnection()).thenReturn(connection);
    when(operation.getResultCode()).thenReturn(ResultCode.SUCCESS);
    when(connection.getAuthenticationInfo()).thenReturn(authInfo);
    return operation;
  }
  private <T> SortedSet<T> setOf(final T... values)
  {
    return new TreeSet<T>(Arrays.asList(values));
  }
}