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()); + } +}