/* * 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 2013-2015 ForgeRock AS */ package org.opends.server.loggers; import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; import static org.opends.server.util.CollectionUtils.*; import java.util.TreeSet; import org.forgerock.opendj.ldap.AddressMask; import org.forgerock.opendj.ldap.ResultCode; 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.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.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") private Object[][] getIsLoggableData() { // When suppress is set to true and the corresponding operation is set to // true too, then the operation is not loggable. // You can read the array like this: read two by two from line start, if // both are true in a pair, then the expected result is false (not // loggable). // 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 }, { true, true, false, true, false }, { true, true, false, false, false }, { true, false, true, true, false }, { true, false, true, false, true }, { true, false, false, true, true }, { true, false, false, false, true }, { false, true, true, true, true }, { false, true, true, false, true }, { false, true, false, true, true }, { false, true, false, false, true }, { false, false, true, true, false }, { false, false, true, false, true }, { false, false, false, true, true }, { false, false, false, false, true }, }; // @formatter:on } @Test(dataProvider = "isLoggableData") 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); 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(newTreeSet("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(newTreeSet("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(newTreeSet(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(newTreeSet(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(newTreeSet(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( newTreeSet(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(newTreeSet(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(newTreeSet(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.valueOf(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; } }