| // |
| // ======================================================================== |
| // Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. |
| // ------------------------------------------------------------------------ |
| // 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.server.handler; |
| |
| import static org.hamcrest.Matchers.*; |
| import static org.junit.Assert.*; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.io.PrintWriter; |
| import java.io.StringWriter; |
| import java.net.HttpURLConnection; |
| import java.net.URI; |
| import java.net.URL; |
| |
| import javax.net.ssl.HostnameVerifier; |
| import javax.net.ssl.HttpsURLConnection; |
| import javax.net.ssl.SSLSocketFactory; |
| import javax.servlet.ServletException; |
| import javax.servlet.http.HttpServletRequest; |
| import javax.servlet.http.HttpServletResponse; |
| |
| import org.eclipse.jetty.server.Connector; |
| import org.eclipse.jetty.server.Handler; |
| import org.eclipse.jetty.server.HttpConfiguration; |
| import org.eclipse.jetty.server.HttpConnectionFactory; |
| import org.eclipse.jetty.server.Request; |
| 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.toolchain.test.IO; |
| import org.eclipse.jetty.toolchain.test.MavenTestingUtils; |
| import org.eclipse.jetty.util.ssl.SslContextFactory; |
| import org.junit.AfterClass; |
| import org.junit.BeforeClass; |
| import org.junit.Test; |
| |
| public class SecuredRedirectHandlerTest |
| { |
| private static Server server; |
| private static HostnameVerifier origVerifier; |
| private static SSLSocketFactory origSsf; |
| private static URI serverHttpUri; |
| private static URI serverHttpsUri; |
| |
| @BeforeClass |
| public static void startServer() throws Exception |
| { |
| // Setup SSL |
| File keystore = MavenTestingUtils.getTestResourceFile("keystore"); |
| SslContextFactory sslContextFactory = new SslContextFactory(); |
| sslContextFactory.setKeyStorePath(keystore.getAbsolutePath()); |
| sslContextFactory.setKeyStorePassword("storepwd"); |
| sslContextFactory.setKeyManagerPassword("keypwd"); |
| sslContextFactory.setTrustStorePath(keystore.getAbsolutePath()); |
| sslContextFactory.setTrustStorePassword("storepwd"); |
| |
| server = new Server(); |
| |
| int port = 32080; |
| int securePort = 32443; |
| |
| // Setup HTTP Configuration |
| HttpConfiguration httpConf = new HttpConfiguration(); |
| httpConf.setSecurePort(securePort); |
| httpConf.setSecureScheme("https"); |
| |
| ServerConnector httpConnector = new ServerConnector(server,new HttpConnectionFactory(httpConf)); |
| httpConnector.setName("unsecured"); |
| httpConnector.setPort(port); |
| |
| // Setup HTTPS Configuration |
| HttpConfiguration httpsConf = new HttpConfiguration(httpConf); |
| httpsConf.addCustomizer(new SecureRequestCustomizer()); |
| |
| ServerConnector httpsConnector = new ServerConnector(server,new SslConnectionFactory(sslContextFactory,"http/1.1"),new HttpConnectionFactory(httpsConf)); |
| httpsConnector.setName("secured"); |
| httpsConnector.setPort(securePort); |
| |
| // Add connectors |
| server.setConnectors(new Connector[] { httpConnector, httpsConnector }); |
| |
| // Wire up contexts |
| String secureHosts[] = new String[] { "@secured" }; |
| |
| ContextHandler test1Context = new ContextHandler(); |
| test1Context.setContextPath("/test1"); |
| test1Context.setHandler(new HelloHandler("Hello1")); |
| test1Context.setVirtualHosts(secureHosts); |
| |
| ContextHandler test2Context = new ContextHandler(); |
| test2Context.setContextPath("/test2"); |
| test2Context.setHandler(new HelloHandler("Hello2")); |
| test2Context.setVirtualHosts(secureHosts); |
| |
| ContextHandler rootContext = new ContextHandler(); |
| rootContext.setContextPath("/"); |
| rootContext.setHandler(new RootHandler("/test1","/test2")); |
| rootContext.setVirtualHosts(secureHosts); |
| |
| // Wire up context for unsecure handling to only |
| // the named 'unsecured' connector |
| ContextHandler redirectHandler = new ContextHandler(); |
| redirectHandler.setContextPath("/"); |
| redirectHandler.setHandler(new SecuredRedirectHandler()); |
| redirectHandler.setVirtualHosts(new String[] { "@unsecured" }); |
| |
| // Establish all handlers that have a context |
| ContextHandlerCollection contextHandlers = new ContextHandlerCollection(); |
| contextHandlers.setHandlers(new Handler[] { redirectHandler, rootContext, test1Context, test2Context }); |
| |
| // Create server level handler tree |
| HandlerList handlers = new HandlerList(); |
| handlers.addHandler(contextHandlers); |
| handlers.addHandler(new DefaultHandler()); // round things out |
| |
| server.setHandler(handlers); |
| |
| server.start(); |
| |
| // calculate serverUri |
| String host = httpConnector.getHost(); |
| if (host == null) |
| { |
| host = "localhost"; |
| } |
| serverHttpUri = new URI(String.format("http://%s:%d/",host,httpConnector.getLocalPort())); |
| serverHttpsUri = new URI(String.format("https://%s:%d/",host,httpsConnector.getLocalPort())); |
| |
| origVerifier = HttpsURLConnection.getDefaultHostnameVerifier(); |
| origSsf = HttpsURLConnection.getDefaultSSLSocketFactory(); |
| |
| HttpsURLConnection.setDefaultHostnameVerifier(new AllowAllVerifier()); |
| HttpsURLConnection.setDefaultSSLSocketFactory(sslContextFactory.getSslContext().getSocketFactory()); |
| } |
| |
| @AfterClass |
| public static void stopServer() throws Exception |
| { |
| HttpsURLConnection.setDefaultSSLSocketFactory(origSsf); |
| HttpsURLConnection.setDefaultHostnameVerifier(origVerifier); |
| |
| server.stop(); |
| server.join(); |
| } |
| |
| @Test |
| public void testRedirectUnsecuredRoot() throws Exception |
| { |
| URL url = serverHttpUri.resolve("/").toURL(); |
| HttpURLConnection connection = (HttpURLConnection)url.openConnection(); |
| connection.setInstanceFollowRedirects(false); |
| connection.setAllowUserInteraction(false); |
| assertThat("response code",connection.getResponseCode(),is(302)); |
| assertThat("location header",connection.getHeaderField("Location"),is(serverHttpsUri.resolve("/").toASCIIString())); |
| connection.disconnect(); |
| } |
| |
| @Test |
| public void testRedirectSecuredRoot() throws Exception |
| { |
| URL url = serverHttpsUri.resolve("/").toURL(); |
| HttpURLConnection connection = (HttpURLConnection)url.openConnection(); |
| connection.setInstanceFollowRedirects(false); |
| connection.setAllowUserInteraction(false); |
| assertThat("response code",connection.getResponseCode(),is(200)); |
| String content = getContent(connection); |
| assertThat("response content",content,containsString("<a href=\"/test1\">")); |
| connection.disconnect(); |
| } |
| |
| @Test |
| public void testAccessUnsecuredHandler() throws Exception |
| { |
| URL url = serverHttpUri.resolve("/test1").toURL(); |
| HttpURLConnection connection = (HttpURLConnection)url.openConnection(); |
| connection.setInstanceFollowRedirects(false); |
| connection.setAllowUserInteraction(false); |
| assertThat("response code",connection.getResponseCode(),is(302)); |
| assertThat("location header",connection.getHeaderField("Location"),is(serverHttpsUri.resolve("/test1").toASCIIString())); |
| connection.disconnect(); |
| } |
| |
| @Test |
| public void testAccessUnsecured404() throws Exception |
| { |
| URL url = serverHttpUri.resolve("/nothing/here").toURL(); |
| HttpURLConnection connection = (HttpURLConnection)url.openConnection(); |
| connection.setInstanceFollowRedirects(false); |
| connection.setAllowUserInteraction(false); |
| assertThat("response code",connection.getResponseCode(),is(302)); |
| assertThat("location header",connection.getHeaderField("Location"),is(serverHttpsUri.resolve("/nothing/here").toASCIIString())); |
| connection.disconnect(); |
| } |
| |
| @Test |
| public void testAccessSecured404() throws Exception |
| { |
| URL url = serverHttpsUri.resolve("/nothing/here").toURL(); |
| HttpURLConnection connection = (HttpURLConnection)url.openConnection(); |
| connection.setInstanceFollowRedirects(false); |
| connection.setAllowUserInteraction(false); |
| assertThat("response code",connection.getResponseCode(),is(404)); |
| connection.disconnect(); |
| } |
| |
| private String getContent(HttpURLConnection connection) throws IOException |
| { |
| try (InputStream in = connection.getInputStream(); InputStreamReader reader = new InputStreamReader(in)) |
| { |
| StringWriter writer = new StringWriter(); |
| IO.copy(reader,writer); |
| return writer.toString(); |
| } |
| } |
| |
| public static class HelloHandler extends AbstractHandler |
| { |
| private final String msg; |
| |
| public HelloHandler(String msg) |
| { |
| this.msg = msg; |
| } |
| |
| @Override |
| public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException |
| { |
| response.setContentType("text/plain"); |
| response.getWriter().printf("%s%n",msg); |
| baseRequest.setHandled(true); |
| } |
| } |
| |
| public static class RootHandler extends AbstractHandler |
| { |
| private final String[] childContexts; |
| |
| public RootHandler(String... children) |
| { |
| this.childContexts = children; |
| } |
| |
| @Override |
| public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException |
| { |
| if (!"/".equals(target)) |
| { |
| response.sendError(404); |
| return; |
| } |
| |
| response.setContentType("text/html"); |
| PrintWriter out = response.getWriter(); |
| out.println("<html>"); |
| out.println("<head><title>Contexts</title></head>"); |
| out.println("<body>"); |
| out.println("<h4>Child Contexts</h4>"); |
| out.println("<ul>"); |
| for (String child : childContexts) |
| { |
| out.printf("<li><a href=\"%s\">%s</a></li>%n",child,child); |
| } |
| out.println("</ul>"); |
| out.println("</body></html>"); |
| baseRequest.setHandled(true); |
| } |
| } |
| } |