blob: 47377514e19b19493920f30e29af3d174162c6c0 [file] [log] [blame]
//
// ========================================================================
// Copyright (c) 1995-2017 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);
}
}
}