org.apache.hadoop.gateway.AuditLoggingTest.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.gateway.AuditLoggingTest.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.hadoop.gateway;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.IsNull.notNullValue;
import static org.hamcrest.core.IsNull.nullValue;
import static org.junit.Assert.fail;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.hadoop.gateway.audit.api.Action;
import org.apache.hadoop.gateway.audit.api.ActionOutcome;
import org.apache.hadoop.gateway.audit.api.AuditContext;
import org.apache.hadoop.gateway.audit.api.AuditServiceFactory;
import org.apache.hadoop.gateway.audit.api.CorrelationContext;
import org.apache.hadoop.gateway.audit.api.ResourceType;
import org.apache.hadoop.gateway.audit.log4j.audit.AuditConstants;
import org.apache.hadoop.gateway.audit.log4j.audit.Log4jAuditService;
import org.apache.hadoop.gateway.audit.log4j.correlation.Log4jCorrelationService;
import org.apache.hadoop.gateway.config.GatewayConfig;
import org.apache.hadoop.gateway.dispatch.DefaultDispatch;
import org.apache.hadoop.gateway.i18n.resources.ResourcesFactory;
import org.apache.hadoop.test.log.CollectAppender;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.log4j.spi.LoggingEvent;
import org.easymock.EasyMock;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class AuditLoggingTest {
    private static final String METHOD = "GET";
    private static final String PATH = "path";
    private static final String CONTEXT_PATH = "contextPath/";
    private static final String ADDRESS = "address";
    private static final String HOST = "host";

    private static final GatewayResources RES = ResourcesFactory.get(GatewayResources.class);

    @Before
    public void loggingSetup() {
        AuditServiceFactory.getAuditService().createContext();
        CollectAppender.queue.clear();
    }

    @After
    public void reset() {
        AuditServiceFactory.getAuditService().detachContext();
    }

    @Test
    /**
     * Empty filter chain. Two events with same correlation ID are expected:
     * 
     * action=access request_type=uri outcome=unavailable
     * action=access request_type=uri outcome=success message=Response status: 404
     */
    public void testNoFiltersAudit() throws ServletException, IOException {
        FilterConfig config = EasyMock.createNiceMock(FilterConfig.class);
        EasyMock.replay(config);

        HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
        ServletContext context = EasyMock.createNiceMock(ServletContext.class);
        GatewayConfig gatewayConfig = EasyMock.createNiceMock(GatewayConfig.class);
        EasyMock.expect(request.getMethod()).andReturn(METHOD).anyTimes();
        EasyMock.expect(request.getPathInfo()).andReturn(PATH).anyTimes();
        EasyMock.expect(request.getContextPath()).andReturn(CONTEXT_PATH).anyTimes();
        EasyMock.expect(request.getRemoteAddr()).andReturn(ADDRESS).anyTimes();
        EasyMock.expect(request.getRemoteHost()).andReturn(HOST).anyTimes();
        EasyMock.expect(request.getServletContext()).andReturn(context).anyTimes();
        EasyMock.expect(context.getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE)).andReturn(gatewayConfig)
                .anyTimes();
        EasyMock.expect(gatewayConfig.getHeaderNameForRemoteAddress()).andReturn("Custom-Forwarded-For").anyTimes();
        EasyMock.replay(request);
        EasyMock.replay(context);
        EasyMock.replay(gatewayConfig);

        HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
        EasyMock.replay(response);

        FilterChain chain = EasyMock.createNiceMock(FilterChain.class);
        EasyMock.replay(chain);

        GatewayFilter gateway = new GatewayFilter();
        gateway.init(config);
        gateway.doFilter(request, response, chain);
        gateway.destroy();

        assertThat(CollectAppender.queue.size(), is(1));
        Iterator<LoggingEvent> iterator = CollectAppender.queue.iterator();
        LoggingEvent accessEvent = iterator.next();
        verifyAuditEvent(accessEvent, CONTEXT_PATH + PATH, ResourceType.URI, Action.ACCESS,
                ActionOutcome.UNAVAILABLE, null, "Request method: GET");
    }

    @Test
    /**
     * One NoOp filter in chain. Single audit event with same with specified request URI is expected:
     * 
     * action=access request_type=uri outcome=unavailable
     */
    public void testNoopFilter() throws ServletException, IOException, URISyntaxException {

        FilterConfig config = EasyMock.createNiceMock(FilterConfig.class);
        EasyMock.replay(config);

        HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
        ServletContext context = EasyMock.createNiceMock(ServletContext.class);
        GatewayConfig gatewayConfig = EasyMock.createNiceMock(GatewayConfig.class);
        EasyMock.expect(request.getMethod()).andReturn(METHOD).anyTimes();
        EasyMock.expect(request.getPathInfo()).andReturn(PATH).anyTimes();
        EasyMock.expect(request.getContextPath()).andReturn(CONTEXT_PATH).anyTimes();
        EasyMock.expect(request.getRemoteAddr()).andReturn(ADDRESS).anyTimes();
        EasyMock.expect(request.getRemoteHost()).andReturn(HOST).anyTimes();
        EasyMock.expect(request.getServletContext()).andReturn(context).anyTimes();
        EasyMock.expect(context.getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE)).andReturn(gatewayConfig)
                .anyTimes();
        EasyMock.expect(gatewayConfig.getHeaderNameForRemoteAddress()).andReturn("Custom-Forwarded-For").anyTimes();
        EasyMock.replay(request);
        EasyMock.replay(context);
        EasyMock.replay(gatewayConfig);

        HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
        EasyMock.replay(response);

        FilterChain chain = EasyMock.createNiceMock(FilterChain.class);
        EasyMock.replay(chain);

        Filter filter = EasyMock.createNiceMock(Filter.class);
        EasyMock.replay(filter);

        GatewayFilter gateway = new GatewayFilter();
        gateway.addFilter("path", "filter", filter, null, null);
        gateway.init(config);
        gateway.doFilter(request, response, chain);
        gateway.destroy();

        assertThat(CollectAppender.queue.size(), is(1));
        Iterator<LoggingEvent> iterator = CollectAppender.queue.iterator();
        LoggingEvent accessEvent = iterator.next();
        verifyAuditEvent(accessEvent, CONTEXT_PATH + PATH, ResourceType.URI, Action.ACCESS,
                ActionOutcome.UNAVAILABLE, null, "Request method: GET");

    }

    @Test
    /**
     * Dispatching outbound request. Remote host is unreachable. Two log events is expected:
     * 
     * action=dispatch request_type=uri outcome=FAILED
     * action=dispatch request_type=uri outcome=unavailable
     */
    public void testHttpClientOutboundException() throws IOException, URISyntaxException {
        String uri = "http://outbound-host:port/path";

        HttpServletRequest inboundRequest = EasyMock.createNiceMock(HttpServletRequest.class);
        EasyMock.expect(inboundRequest.getHeaderNames()).andReturn(Collections.enumeration(new ArrayList<String>()))
                .anyTimes();
        EasyMock.replay(inboundRequest);

        HttpServletResponse outboundResponse = EasyMock.createNiceMock(HttpServletResponse.class);
        EasyMock.replay(outboundResponse);

        DefaultDispatch dispatch = new DefaultDispatch();
        dispatch.setHttpClient(new DefaultHttpClient());
        try {
            dispatch.doGet(new URI(uri), inboundRequest, outboundResponse);
            fail("Expected exception while accessing to unreachable host");
        } catch (IOException e) {
            Iterator<LoggingEvent> iterator = CollectAppender.queue.iterator();

            LoggingEvent unavailableEvent = iterator.next();
            verifyValue((String) unavailableEvent.getMDC(AuditConstants.MDC_RESOURCE_NAME_KEY), uri);
            verifyValue((String) unavailableEvent.getMDC(AuditConstants.MDC_RESOURCE_TYPE_KEY), ResourceType.URI);
            verifyValue((String) unavailableEvent.getMDC(AuditConstants.MDC_ACTION_KEY), Action.DISPATCH);
            verifyValue((String) unavailableEvent.getMDC(AuditConstants.MDC_OUTCOME_KEY),
                    ActionOutcome.UNAVAILABLE);

            LoggingEvent failureEvent = iterator.next();
            verifyValue((String) failureEvent.getMDC(AuditConstants.MDC_RESOURCE_NAME_KEY), uri);
            verifyValue((String) failureEvent.getMDC(AuditConstants.MDC_RESOURCE_TYPE_KEY), ResourceType.URI);
            verifyValue((String) failureEvent.getMDC(AuditConstants.MDC_ACTION_KEY), Action.DISPATCH);
            verifyValue((String) failureEvent.getMDC(AuditConstants.MDC_OUTCOME_KEY), ActionOutcome.FAILURE);

        }
    }

    private void verifyAuditEvent(LoggingEvent event, String resourceName, String resourceType, String action,
            String outcome, String targetService, String message) {
        event.getMDCCopy();
        CorrelationContext cc = (CorrelationContext) event
                .getMDC(Log4jCorrelationService.MDC_CORRELATION_CONTEXT_KEY);
        assertThat(cc, notNullValue());
        assertThat(cc.getRequestId(), is(notNullValue()));
        AuditContext ac = (AuditContext) event.getMDC(Log4jAuditService.MDC_AUDIT_CONTEXT_KEY);
        assertThat(ac, notNullValue());
        assertThat(ac.getRemoteIp(), is(ADDRESS));
        assertThat(ac.getRemoteHostname(), is(HOST));
        assertThat((String) event.getMDC(AuditConstants.MDC_SERVICE_KEY), is(AuditConstants.KNOX_SERVICE_NAME));
        assertThat((String) event.getMDC(AuditConstants.MDC_COMPONENT_KEY), is(AuditConstants.KNOX_COMPONENT_NAME));
        assertThat((String) event.getLoggerName(), is(AuditConstants.DEFAULT_AUDITOR_NAME));
        verifyValue((String) event.getMDC(AuditConstants.MDC_RESOURCE_NAME_KEY), resourceName);
        verifyValue((String) event.getMDC(AuditConstants.MDC_RESOURCE_TYPE_KEY), resourceType);
        verifyValue((String) event.getMDC(AuditConstants.MDC_ACTION_KEY), action);
        verifyValue((String) event.getMDC(AuditConstants.MDC_OUTCOME_KEY), outcome);
        verifyValue(ac.getTargetServiceName(), targetService);
        verifyValue(event.getRenderedMessage(), message);
    }

    private void verifyValue(String actual, String expected) {
        if (expected == null) {
            assertThat(actual, nullValue());
        } else {
            assertThat(actual, is(expected));
        }
    }

    private String getRequestId(LoggingEvent event) {
        CorrelationContext cc = (CorrelationContext) event
                .getMDC(Log4jCorrelationService.MDC_CORRELATION_CONTEXT_KEY);
        return cc == null ? null : cc.getRequestId();
    }

}