diff --git a/platform/platform-paxweb-jettyconfig/src/test/java/org/codice/ddf/pax/web/jetty/AccessRequestLogTest.java b/platform/platform-paxweb-jettyconfig/src/test/java/org/codice/ddf/pax/web/jetty/AccessRequestLogTest.java
new file mode 100644
index 000000000000..de53bb008f88
--- /dev/null
+++ b/platform/platform-paxweb-jettyconfig/src/test/java/org/codice/ddf/pax/web/jetty/AccessRequestLogTest.java
@@ -0,0 +1,82 @@
+/**
+ * Copyright (c) Codice Foundation
+ *
+ *
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.
+ *
+ *
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
+ * .
+ */
+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();
+ }
+}
diff --git a/platform/platform-paxweb-jettyconfig/src/test/java/org/codice/ddf/pax/web/jetty/ResponseFilterTest.java b/platform/platform-paxweb-jettyconfig/src/test/java/org/codice/ddf/pax/web/jetty/ResponseFilterTest.java
new file mode 100644
index 000000000000..95c83f30770a
--- /dev/null
+++ b/platform/platform-paxweb-jettyconfig/src/test/java/org/codice/ddf/pax/web/jetty/ResponseFilterTest.java
@@ -0,0 +1,128 @@
+/**
+ * Copyright (c) Codice Foundation
+ *
+ * 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.
+ *
+ *
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
+ * .
+ */
+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", "");
+ }
+}
diff --git a/platform/platform-paxweb-jettyconfig/src/test/java/org/codice/ddf/pax/web/jetty/SecurityAuthServiceTest.java b/platform/platform-paxweb-jettyconfig/src/test/java/org/codice/ddf/pax/web/jetty/SecurityAuthServiceTest.java
new file mode 100644
index 000000000000..3a20677bb045
--- /dev/null
+++ b/platform/platform-paxweb-jettyconfig/src/test/java/org/codice/ddf/pax/web/jetty/SecurityAuthServiceTest.java
@@ -0,0 +1,53 @@
+/**
+ * Copyright (c) Codice Foundation
+ *
+ * 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.
+ *
+ *
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
+ * .
+ */
+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());
+ }
+}