445542 - Add SecuredRedirectHandler for embedded jetty use to redirect to secure port/scheme
+ Adding SecuredRedirectHandler as option for those jetty embedded folks to have a simple http -> https solution (can even be setup and bound to specific connectors via the named virtualhosts concepts)
This commit is contained in:
parent
93520df3f9
commit
d0fa66ddf0
|
@ -0,0 +1,66 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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 java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.server.HttpChannel;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
|
||||
/**
|
||||
* Secured Redirect Handler
|
||||
* <p>
|
||||
* Using information present in the {@link HttpConfiguration}, will attempt to redirect to the {@link HttpConfiguration#getSecureScheme()} and
|
||||
* {@link HttpConfiguration#getSecurePort()} for any request that {@link HttpServletRequest#isSecure()} == false.
|
||||
*/
|
||||
public class SecuredRedirectHandler extends AbstractHandler
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
HttpConfiguration httpConfig = HttpChannel.getCurrentHttpChannel().getHttpConfiguration();
|
||||
|
||||
if (baseRequest.isSecure())
|
||||
{
|
||||
return; // all done
|
||||
}
|
||||
|
||||
if (httpConfig.getSecurePort() > 0)
|
||||
{
|
||||
String scheme = httpConfig.getSecureScheme();
|
||||
int port = httpConfig.getSecurePort();
|
||||
|
||||
String url = URIUtil.newURI(scheme,baseRequest.getServerName(),port,baseRequest.getRequestURI(),baseRequest.getQueryString());
|
||||
response.setContentLength(0);
|
||||
response.sendRedirect(url);
|
||||
}
|
||||
else
|
||||
{
|
||||
response.sendError(HttpStatus.FORBIDDEN_403,"Not Secure");
|
||||
}
|
||||
baseRequest.setHandled(true);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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 javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLSession;
|
||||
|
||||
public class AllowAllVerifier implements HostnameVerifier
|
||||
{
|
||||
@Override
|
||||
public boolean verify(String hostname, SSLSession session)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,288 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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 = 12080;
|
||||
int securePort = 12443;
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.server.ssl;
|
|||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -40,6 +41,7 @@ import org.eclipse.jetty.server.Server;
|
|||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.server.SslConnectionFactory;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.junit.AfterClass;
|
||||
|
@ -58,12 +60,13 @@ public class SslUploadTest
|
|||
@BeforeClass
|
||||
public static void startServer() throws Exception
|
||||
{
|
||||
String keystorePath = System.getProperty("basedir",".") + "/src/test/resources/keystore";
|
||||
File keystore = MavenTestingUtils.getTestResourceFile("keystore");
|
||||
|
||||
SslContextFactory sslContextFactory = new SslContextFactory();
|
||||
sslContextFactory.setKeyStorePath(keystorePath);
|
||||
sslContextFactory.setKeyStorePath(keystore.getAbsolutePath());
|
||||
sslContextFactory.setKeyStorePassword("storepwd");
|
||||
sslContextFactory.setKeyManagerPassword("keypwd");
|
||||
sslContextFactory.setTrustStorePath(keystorePath);
|
||||
sslContextFactory.setTrustStorePath(keystore.getAbsolutePath());
|
||||
sslContextFactory.setTrustStorePassword("storepwd");
|
||||
|
||||
server = new Server();
|
||||
|
|
Loading…
Reference in New Issue