Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/**
* Copyright (c) Codice Foundation
*
* <p>This is free software: you can redistribute it and/or modify it under the terms of the GNU
* Lesser General Public License as published by the Free Software Foundation, either version 3 of
* the License, or any later version.
*
* <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. A copy of the GNU Lesser General Public
* License is distributed along with this program and can be found at
* <http://www.gnu.org/licenses/lgpl.html>.
*/
package org.codice.ddf.pax.web.jetty;

import static org.hamcrest.CoreMatchers.instanceOf;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;

import ch.qos.logback.access.jetty.RequestLogImpl;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.junit.After;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

public class AccessRequestLogTest {

private static final String ENABLED_PROP = "org.codice.ddf.http.access.log.enabled";

@Mock private Request mockRequest;

@Mock private Response mockResponse;

@After
public void tearDown() {
System.clearProperty(ENABLED_PROP);
}

@Test
public void inheritsFromRequestLogImpl() {
AccessRequestLog log = new AccessRequestLog();
assertThat(log, instanceOf(RequestLogImpl.class));
}

@Test
public void doesNotDelegateToSuperWhenDisabled() {
System.setProperty(ENABLED_PROP, "false");
MockitoAnnotations.openMocks(this);

AccessRequestLog log = spy(new AccessRequestLog());
log.log(mockRequest, mockResponse);

// Disabled: short-circuits before super.log is invoked, so no jetty Request methods get hit.
verify(mockRequest, never()).getMethod();
}

@Test
public void invokesSuperWhenEnabled() {
System.setProperty(ENABLED_PROP, "true");
MockitoAnnotations.openMocks(this);

AccessRequestLog log = new AccessRequestLog();
// No appenders configured, so super.log() iterates an empty list and returns;
// the call should not throw.
log.log(mockRequest, mockResponse);
}

@Test
public void defaultsToDisabledWhenSystemPropertyAbsent() {
System.clearProperty(ENABLED_PROP);
MockitoAnnotations.openMocks(this);

AccessRequestLog log = new AccessRequestLog();
log.log(mockRequest, mockResponse);

verify(mockRequest, never()).getMethod();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/**
* Copyright (c) Codice Foundation
*
* <p>This is free software: you can redistribute it and/or modify it under the terms of the GNU
* Lesser General Public License as published by the Free Software Foundation, either version 3 of
* the License, or any later version.
*
* <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. A copy of the GNU Lesser General Public
* License is distributed along with this program and can be found at
* <http://www.gnu.org/licenses/lgpl.html>.
*/
package org.codice.ddf.pax.web.jetty;

import static org.codice.ddf.pax.web.jetty.ResponseFilter.CACHE_CONTROL;
import static org.codice.ddf.pax.web.jetty.ResponseFilter.DEFAULT_CACHE_CONTROL_VALUE;
import static org.codice.ddf.pax.web.jetty.ResponseFilter.DEFAULT_CONTENT_SECURITY_POLICY;
import static org.codice.ddf.pax.web.jetty.ResponseFilter.DEFAULT_XSS_PROTECTION_VALUE;
import static org.codice.ddf.pax.web.jetty.ResponseFilter.DEFAULT_X_FRAME_OPTIONS_VALUE;
import static org.codice.ddf.pax.web.jetty.ResponseFilter.STRICT_TRANSPORT_SECURITY;
import static org.codice.ddf.pax.web.jetty.ResponseFilter.STRICT_TRANSPORT_SECURITY_VALUE;
import static org.codice.ddf.pax.web.jetty.ResponseFilter.X_CONTENT_SECURITY_POLICY;
import static org.codice.ddf.pax.web.jetty.ResponseFilter.X_FRAME_OPTIONS;
import static org.codice.ddf.pax.web.jetty.ResponseFilter.X_XSS_PROTECTION;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.util.Arrays;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class ResponseFilterTest {

@Mock private HttpServletRequest mockRequest;

@Mock private HttpServletResponse mockResponse;

@Mock private ProxyHttpFilterChain mockFilterChain;

private ResponseFilter filter;

@Before
public void setUp() {
filter = new ResponseFilter();
}

@Test
public void defaultSecurityHeadersAreSet() throws Exception {
when(mockRequest.getRequestURI()).thenReturn("/services/foo");

filter.doFilter(mockRequest, mockResponse, mockFilterChain);

verify(mockResponse).setHeader(X_XSS_PROTECTION, DEFAULT_XSS_PROTECTION_VALUE);
verify(mockResponse).setHeader(X_FRAME_OPTIONS, DEFAULT_X_FRAME_OPTIONS_VALUE);
verify(mockResponse).setHeader(X_CONTENT_SECURITY_POLICY, DEFAULT_CONTENT_SECURITY_POLICY);
verify(mockResponse).setHeader(STRICT_TRANSPORT_SECURITY, STRICT_TRANSPORT_SECURITY_VALUE);
verify(mockResponse).setHeader(CACHE_CONTROL, DEFAULT_CACHE_CONTROL_VALUE);
verify(mockFilterChain).doFilter(mockRequest, mockResponse);
}

@Test
public void cachingDisabledForIndexPaths() throws Exception {
when(mockRequest.getRequestURI()).thenReturn("/admin/");

filter.doFilter(mockRequest, mockResponse, mockFilterChain);

// Cache-Control gets set twice: once with the default, then overridden to no-cache.
verify(mockResponse).setHeader(CACHE_CONTROL, DEFAULT_CACHE_CONTROL_VALUE);
verify(mockResponse).setHeader(CACHE_CONTROL, "no-cache, no-store, must-revalidate");
verify(mockResponse).setHeader("Pragma", "no-cache");
verify(mockResponse).setHeader("Expires", "0");
}

@Test
public void cachingDisabledForHtmlPaths() throws Exception {
when(mockRequest.getRequestURI()).thenReturn("/index.html");

filter.doFilter(mockRequest, mockResponse, mockFilterChain);

verify(mockResponse).setHeader(CACHE_CONTROL, "no-cache, no-store, must-revalidate");
verify(mockResponse).setHeader("Pragma", "no-cache");
verify(mockResponse).setHeader("Expires", "0");
}

@Test
public void cachingNotDisabledForResourcePaths() throws Exception {
when(mockRequest.getRequestURI()).thenReturn("/static/app.js");

filter.doFilter(mockRequest, mockResponse, mockFilterChain);

verify(mockResponse, never()).setHeader("Pragma", "no-cache");
verify(mockResponse, never()).setHeader("Expires", "0");
// Default Cache-Control is still set, but the no-cache override is not.
verify(mockResponse, times(1)).setHeader(CACHE_CONTROL, DEFAULT_CACHE_CONTROL_VALUE);
}

@Test
public void customHeadersOverrideDefaults() throws Exception {
filter.setHeaders(Arrays.asList("X-Custom=value", "X-Other=42"));
when(mockRequest.getRequestURI()).thenReturn("/services/foo");

filter.doFilter(mockRequest, mockResponse, mockFilterChain);

verify(mockResponse).setHeader("X-Custom", "value");
verify(mockResponse).setHeader("X-Other", "42");
verify(mockResponse, never()).setHeader(X_XSS_PROTECTION, DEFAULT_XSS_PROTECTION_VALUE);
}

@Test
public void malformedHeadersAreSkipped() throws Exception {
filter.setHeaders(Arrays.asList("X-Good=value", "no-equals-sign"));
when(mockRequest.getRequestURI()).thenReturn("/services/foo");

filter.doFilter(mockRequest, mockResponse, mockFilterChain);

verify(mockResponse).setHeader("X-Good", "value");
verify(mockResponse, never()).setHeader("no-equals-sign", "");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* Copyright (c) Codice Foundation
*
* <p>This is free software: you can redistribute it and/or modify it under the terms of the GNU
* Lesser General Public License as published by the Free Software Foundation, either version 3 of
* the License, or any later version.
*
* <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. A copy of the GNU Lesser General Public
* License is distributed along with this program and can be found at
* <http://www.gnu.org/licenses/lgpl.html>.
*/
package org.codice.ddf.pax.web.jetty;

import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat;

import org.eclipse.jetty.security.Authenticator;
import org.eclipse.jetty.security.LoginService;
import org.junit.Before;
import org.junit.Test;

public class SecurityAuthServiceTest {

private SecurityAuthService service;

@Before
public void setUp() {
service = new SecurityAuthService();
}

@Test
public void returnsJettyAuthenticatorForMatchingMethodAndInterface() {
Authenticator result =
service.getAuthenticatorService(JettyAuthenticator.DDF_AUTH_METHOD, Authenticator.class);
assertThat(result, instanceOf(JettyAuthenticator.class));
}

@Test
public void returnsNullForNonMatchingMethod() {
Authenticator result = service.getAuthenticatorService("BASIC", Authenticator.class);
assertThat(result, nullValue());
}

@Test
public void returnsNullForNonAuthenticatorInterface() {
Object result =
service.getAuthenticatorService(JettyAuthenticator.DDF_AUTH_METHOD, LoginService.class);
assertThat(result, nullValue());
}
}
Loading