diff --git a/demos/demo-proxy-webapp/pom.xml b/demos/demo-proxy-webapp/pom.xml index 6df059958b3..92cd1006fe4 100644 --- a/demos/demo-proxy-webapp/pom.xml +++ b/demos/demo-proxy-webapp/pom.xml @@ -52,13 +52,14 @@ org.eclipse.jetty - jetty-jmx + jetty-client ${project.version} - test + provided - org.eclipse.jetty.toolchain - jetty-test-helper + org.eclipse.jetty + jetty-jmx + ${project.version} test diff --git a/demos/demo-proxy-webapp/src/main/webapp/WEB-INF/web.xml b/demos/demo-proxy-webapp/src/main/webapp/WEB-INF/web.xml index 52ae8850626..b2c9c38df64 100644 --- a/demos/demo-proxy-webapp/src/main/webapp/WEB-INF/web.xml +++ b/demos/demo-proxy-webapp/src/main/webapp/WEB-INF/web.xml @@ -12,10 +12,12 @@ JavadocTransparentProxy org.eclipse.jetty.proxy.ProxyServlet$Transparent - proxyTohttp://www.eclipse.org/jetty/javadoc/ + proxyTo + https://www.eclipse.org/jetty/javadoc/ - hostHeadereclipse.org + hostHeader + www.eclipse.org 1 true diff --git a/demos/demo-proxy-webapp/src/test/java/org/eclipse/jetty/TestTransparentProxyServer.java b/demos/demo-proxy-webapp/src/test/java/org/eclipse/jetty/TestTransparentProxyServer.java deleted file mode 100644 index 96a88bb834b..00000000000 --- a/demos/demo-proxy-webapp/src/test/java/org/eclipse/jetty/TestTransparentProxyServer.java +++ /dev/null @@ -1,122 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others. -// -// This program and the accompanying materials are made available under -// the terms of the Eclipse Public License 2.0 which is available at -// https://www.eclipse.org/legal/epl-2.0 -// -// This Source Code may also be made available under the following -// Secondary Licenses when the conditions for such availability set -// forth in the Eclipse Public License, v. 2.0 are satisfied: -// the Apache License v2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0 -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// ======================================================================== -// - -package org.eclipse.jetty; - -import java.lang.management.ManagementFactory; - -import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory; -import org.eclipse.jetty.http2.HTTP2Cipher; -import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory; -import org.eclipse.jetty.jmx.MBeanContainer; -import org.eclipse.jetty.server.ForwardedRequestCustomizer; -import org.eclipse.jetty.server.HttpConfiguration; -import org.eclipse.jetty.server.HttpConnectionFactory; -import org.eclipse.jetty.server.SecureRequestCustomizer; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.server.SslConnectionFactory; -import org.eclipse.jetty.server.handler.ContextHandlerCollection; -import org.eclipse.jetty.server.handler.DefaultHandler; -import org.eclipse.jetty.server.handler.HandlerList; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.eclipse.jetty.util.thread.QueuedThreadPool; -import org.eclipse.jetty.webapp.WebAppContext; -import org.junit.jupiter.api.Disabled; - -@Disabled("Not a test case") -public class TestTransparentProxyServer -{ - public static void main(String[] args) throws Exception - { - String jettyRoot = "../../.."; - - // Setup Threadpool - QueuedThreadPool threadPool = new QueuedThreadPool(); - threadPool.setMaxThreads(100); - - // Setup server - Server server = new Server(threadPool); - server.manage(threadPool); - - // Setup JMX - MBeanContainer mbContainer = new MBeanContainer(ManagementFactory.getPlatformMBeanServer()); - server.addBean(mbContainer); - - // Common HTTP configuration - HttpConfiguration httpConfig = new HttpConfiguration(); - httpConfig.setSecurePort(8443); - httpConfig.addCustomizer(new ForwardedRequestCustomizer()); - httpConfig.setSendDateHeader(true); - httpConfig.setSendServerVersion(true); - - // Http Connector - HttpConnectionFactory http = new HttpConnectionFactory(httpConfig); - ServerConnector httpConnector = new ServerConnector(server, http); - httpConnector.setPort(8080); - httpConnector.setIdleTimeout(30000); - server.addConnector(httpConnector); - - // SSL configurations - SslContextFactory.Server sslContextFactory = new SslContextFactory.Server(); - sslContextFactory.setKeyStorePath(jettyRoot + "/jetty-server/src/main/config/modules/test-keystore/test-keystore.p12"); - sslContextFactory.setKeyStorePassword("storepwd"); - sslContextFactory.setExcludeCipherSuites( - "SSL_RSA_WITH_DES_CBC_SHA", - "SSL_DHE_RSA_WITH_DES_CBC_SHA", - "SSL_DHE_DSS_WITH_DES_CBC_SHA", - "SSL_RSA_EXPORT_WITH_RC4_40_MD5", - "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", - "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", - "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"); - sslContextFactory.setCipherComparator(new HTTP2Cipher.CipherComparator()); - - // HTTPS Configuration - HttpConfiguration httpsConfig = new HttpConfiguration(httpConfig); - httpsConfig.addCustomizer(new SecureRequestCustomizer()); - - // HTTP2 factory - HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(httpsConfig); - ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory(); - alpn.setDefaultProtocol(h2.getProtocol()); - - // SSL Factory - SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory, alpn.getProtocol()); - - // HTTP2 Connector - ServerConnector http2Connector = - new ServerConnector(server, ssl, alpn, h2, new HttpConnectionFactory(httpsConfig)); - http2Connector.setPort(8443); - http2Connector.setIdleTimeout(15000); - server.addConnector(http2Connector); - - // Handlers - ContextHandlerCollection contexts = new ContextHandlerCollection(); - server.setHandler(new HandlerList(contexts, new DefaultHandler())); - - // Setup proxy webapp - WebAppContext webapp = new WebAppContext(); - webapp.setResourceBase("src/main/webapp"); - contexts.addHandler(webapp); - - // start server - server.setStopAtShutdown(true); - server.start(); - server.join(); - } -} diff --git a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AbstractProxyServlet.java b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AbstractProxyServlet.java index ff10e1f27ec..61c8007849c 100644 --- a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AbstractProxyServlet.java +++ b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AbstractProxyServlet.java @@ -54,6 +54,7 @@ import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.io.ClientConnector; import org.eclipse.jetty.util.HttpCookieStore; import org.eclipse.jetty.util.StringUtil; +import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -370,7 +371,9 @@ public abstract class AbstractProxyServlet extends HttpServlet protected ClientConnector newClientConnector() { - return new ClientConnector(); + ClientConnector clientConnector = new ClientConnector(); + clientConnector.setSslContextFactory(new SslContextFactory.Client()); + return clientConnector; } protected HttpClient getHttpClient() diff --git a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletTest.java b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletTest.java index eb6af2ea4ad..7dab8df1ec2 100644 --- a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletTest.java +++ b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletTest.java @@ -78,17 +78,21 @@ import org.eclipse.jetty.client.util.InputStreamResponseListener; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeaderValue; import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.SslConnectionFactory; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.StringUtil; +import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; @@ -129,6 +133,7 @@ public class ProxyServletTest private AbstractProxyServlet proxyServlet; private Server server; private ServerConnector serverConnector; + private ServerConnector tlsServerConnector; private void startServer(HttpServlet servlet) throws Exception { @@ -138,6 +143,16 @@ public class ProxyServletTest serverConnector = new ServerConnector(server); server.addConnector(serverConnector); + SslContextFactory.Server sslContextFactory = new SslContextFactory.Server(); + String keyStorePath = MavenTestingUtils.getTestResourceFile("server_keystore.p12").getAbsolutePath(); + sslContextFactory.setKeyStorePath(keyStorePath); + sslContextFactory.setKeyStorePassword("storepwd"); + tlsServerConnector = new ServerConnector(server, new SslConnectionFactory( + sslContextFactory, + HttpVersion.HTTP_1_1.asString()), + new HttpConnectionFactory()); + server.addConnector(tlsServerConnector); + ServletContextHandler appCtx = new ServletContextHandler(server, "/", true, false); ServletHolder appServletHolder = new ServletHolder(servlet); appCtx.addServlet(appServletHolder, "/*"); @@ -738,27 +753,80 @@ public class ProxyServletTest public static Stream transparentImpls() { return Stream.of( - ProxyServlet.Transparent.class, - AsyncProxyServlet.Transparent.class, - AsyncMiddleManServlet.Transparent.class + new ProxyServlet.Transparent() + { + @Override + protected HttpClient newHttpClient() + { + return newTrustAllClient(super.newHttpClient()); + } + + @Override + public String toString() + { + return ProxyServlet.Transparent.class.getName(); + } + }, + new AsyncProxyServlet.Transparent() + { + @Override + protected HttpClient newHttpClient() + { + return newTrustAllClient(super.newHttpClient()); + } + + @Override + public String toString() + { + return AsyncProxyServlet.Transparent.class.getName(); + } + }, + new AsyncMiddleManServlet.Transparent() + { + @Override + protected HttpClient newHttpClient() + { + return newTrustAllClient(super.newHttpClient()); + } + + @Override + public String toString() + { + return AsyncMiddleManServlet.Transparent.class.getName(); + } + } ).map(Arguments::of); } - @ParameterizedTest - @MethodSource("transparentImpls") - public void testTransparentProxy(Class proxyServletClass) throws Exception + private static HttpClient newTrustAllClient(HttpClient client) { - testTransparentProxyWithPrefix(proxyServletClass, "/proxy"); + SslContextFactory.Client sslContextFactory = client.getSslContextFactory(); + sslContextFactory.setTrustAll(true); + return client; } @ParameterizedTest @MethodSource("transparentImpls") - public void testTransparentProxyWithRootContext(Class proxyServletClass) throws Exception + public void testTransparentProxy(AbstractProxyServlet proxyServletClass) throws Exception { - testTransparentProxyWithPrefix(proxyServletClass, "/"); + testTransparentProxyWithPrefix(proxyServletClass, "http", "/proxy"); } - private void testTransparentProxyWithPrefix(Class proxyServletClass, String prefix) throws Exception + @ParameterizedTest + @MethodSource("transparentImpls") + public void testTransparentProxyTls(AbstractProxyServlet proxyServletClass) throws Exception + { + testTransparentProxyWithPrefix(proxyServletClass, "https", "/proxy"); + } + + @ParameterizedTest + @MethodSource("transparentImpls") + public void testTransparentProxyWithRootContext(AbstractProxyServlet proxyServletClass) throws Exception + { + testTransparentProxyWithPrefix(proxyServletClass, "http", "/"); + } + + private void testTransparentProxyWithPrefix(AbstractProxyServlet proxyServletClass, String scheme, String prefix) throws Exception { final String target = "/test"; startServer(new HttpServlet() @@ -771,7 +839,10 @@ public class ProxyServletTest resp.setStatus(target.equals(req.getRequestURI()) ? 200 : 404); } }); - String proxyTo = "http://localhost:" + serverConnector.getLocalPort(); + int serverPort = serverConnector.getLocalPort(); + if (HttpScheme.HTTPS.is(scheme)) + serverPort = tlsServerConnector.getLocalPort(); + String proxyTo = scheme + "://localhost:" + serverPort; Map params = new HashMap<>(); params.put("proxyTo", proxyTo); params.put("prefix", prefix); @@ -789,33 +860,33 @@ public class ProxyServletTest @ParameterizedTest @MethodSource("transparentImpls") - public void testTransparentProxyWithQuery(Class proxyServletClass) throws Exception + public void testTransparentProxyWithQuery(AbstractProxyServlet proxyServletClass) throws Exception { testTransparentProxyWithQuery(proxyServletClass, "/foo", "/proxy", "/test"); } @ParameterizedTest @MethodSource("transparentImpls") - public void testTransparentProxyEmptyContextWithQuery(Class proxyServletClass) throws Exception + public void testTransparentProxyEmptyContextWithQuery(AbstractProxyServlet proxyServletClass) throws Exception { testTransparentProxyWithQuery(proxyServletClass, "", "/proxy", "/test"); } @ParameterizedTest @MethodSource("transparentImpls") - public void testTransparentProxyEmptyTargetWithQuery(Class proxyServletClass) throws Exception + public void testTransparentProxyEmptyTargetWithQuery(AbstractProxyServlet proxyServletClass) throws Exception { testTransparentProxyWithQuery(proxyServletClass, "/bar", "/proxy", ""); } @ParameterizedTest @MethodSource("transparentImpls") - public void testTransparentProxyEmptyContextEmptyTargetWithQuery(Class proxyServletClass) throws Exception + public void testTransparentProxyEmptyContextEmptyTargetWithQuery(AbstractProxyServlet proxyServletClass) throws Exception { testTransparentProxyWithQuery(proxyServletClass, "", "/proxy", ""); } - private void testTransparentProxyWithQuery(Class proxyServletClass, String proxyToContext, String prefix, String target) throws Exception + private void testTransparentProxyWithQuery(AbstractProxyServlet proxyServletClass, String proxyToContext, String prefix, String target) throws Exception { final String query = "a=1&b=2"; startServer(new HttpServlet() @@ -859,7 +930,7 @@ public class ProxyServletTest @ParameterizedTest @MethodSource("transparentImpls") - public void testTransparentProxyWithQueryWithSpaces(Class proxyServletClass) throws Exception + public void testTransparentProxyWithQueryWithSpaces(AbstractProxyServlet proxyServletClass) throws Exception { final String target = "/test"; final String query = "a=1&b=2&c=1234%205678&d=hello+world"; @@ -901,7 +972,7 @@ public class ProxyServletTest @ParameterizedTest @MethodSource("transparentImpls") - public void testTransparentProxyWithoutPrefix(Class proxyServletClass) throws Exception + public void testTransparentProxyWithoutPrefix(AbstractProxyServlet proxyServletClass) throws Exception { final String target = "/test"; startServer(new HttpServlet() diff --git a/pom.xml b/pom.xml index 73fed73bf38..bf002f08094 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ 1.25.2 benchmarks 2.0.0 - 5.6.2 + 5.7.0 3.6.0 1.3.1 3.1.3.Final @@ -58,7 +58,7 @@ false - 5.4 + 5.5 2.1.1.RELEASE diff --git a/tests/test-sessions/pom.xml b/tests/test-sessions/pom.xml index 25a0746b134..a32b3ebb952 100644 --- a/tests/test-sessions/pom.xml +++ b/tests/test-sessions/pom.xml @@ -10,7 +10,22 @@ Jetty Tests :: Sessions :: Parent http://www.eclipse.org/jetty pom - + + + + org.junit.jupiter + junit-jupiter + ${junit.version} + test + + + org.junit.jupiter + junit-jupiter-api + ${junit.version} + test + + + test-sessions-common test-file-sessions diff --git a/tests/test-sessions/test-sessions-common/pom.xml b/tests/test-sessions/test-sessions-common/pom.xml index 9f1dd27c356..dd50420e699 100644 --- a/tests/test-sessions/test-sessions-common/pom.xml +++ b/tests/test-sessions/test-sessions-common/pom.xml @@ -48,5 +48,10 @@ junit-jupiter compile + + org.junit.jupiter + junit-jupiter-api + compile + diff --git a/tests/test-webapps/test-proxy-webapp/src/test/java/org/eclipse/jetty/ProxyWebAppTest.java b/tests/test-webapps/test-proxy-webapp/src/test/java/org/eclipse/jetty/ProxyWebAppTest.java new file mode 100644 index 00000000000..0e4206e53d6 --- /dev/null +++ b/tests/test-webapps/test-proxy-webapp/src/test/java/org/eclipse/jetty/ProxyWebAppTest.java @@ -0,0 +1,96 @@ +// +// ======================================================================== +// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; + +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; +import org.eclipse.jetty.util.component.LifeCycle; +import org.eclipse.jetty.webapp.WebAppContext; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; + +/** + * Test the configuration found in WEB-INF/web.xml for purposes of the demo-base + */ +public class ProxyWebAppTest +{ + private Server server; + private HttpClient client; + + @BeforeEach + public void setup() throws Exception + { + server = new Server(); + + ServerConnector connector = new ServerConnector(server); + connector.setPort(0); + server.addConnector(connector); + + WebAppContext webapp = new WebAppContext(); + // This is a pieced together WebApp. + // We don't have a valid WEB-INF/lib to rely on at this point. + // So, open up server classes here, for purposes of this testcase. + webapp.getServerClasspathPattern().add("-org.eclipse.jetty.proxy."); + webapp.setWar(MavenTestingUtils.getProjectDirPath("src/main/webapp").toString()); + webapp.setExtraClasspath(MavenTestingUtils.getTargetPath().resolve("classes").toString()); + server.setHandler(webapp); + + server.start(); + + client = new HttpClient(); + client.start(); + } + + @AfterEach + public void teardown() + { + LifeCycle.stop(client); + LifeCycle.stop(server); + } + + @Test + @Tag("external") + public void testProxyRequest() throws InterruptedException, ExecutionException, TimeoutException + { + ContentResponse response = client.newRequest(server.getURI().resolve("/proxy/current/")) + .followRedirects(false) + .send(); + + // Expecting a 200 OK (not a 302 redirect or other error) + // If we got an error here, that means our configuration in web.xml is bad / out of date. + // Such as the redirect from the eclipse website, we want all of the requests to go through + // this proxy configuration, not redirected to the actual website. + assertThat("response status", response.getStatus(), is(HttpStatus.OK_200)); + // Expecting a Javadoc / APIDoc response - look for something unique for APIdoc. + assertThat("response", response.getContentAsString(), containsString("All Classes")); + } +} diff --git a/tests/test-webapps/test-proxy-webapp/src/test/resources/jetty-logging.properties b/tests/test-webapps/test-proxy-webapp/src/test/resources/jetty-logging.properties new file mode 100644 index 00000000000..bf725104bbd --- /dev/null +++ b/tests/test-webapps/test-proxy-webapp/src/test/resources/jetty-logging.properties @@ -0,0 +1,5 @@ +org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog +#org.eclipse.jetty.LEVEL=WARN +#org.eclipse.jetty.client.LEVEL=DEBUG +#org.eclipse.jetty.http.LEVEL=DEBUG +#org.eclipse.jetty.proxy.LEVEL=DEBUG