393385: Make hostname verification configurable in SslContextFactory and enable it by default (See http://www.ietf.org/rfc/rfc2818.txt section 3.1)
This commit is contained in:
parent
46e13b305b
commit
9ebea3938d
|
@ -61,6 +61,7 @@ public abstract class AbstractHttpClientServerTest
|
|||
{
|
||||
if (sslContextFactory != null)
|
||||
{
|
||||
sslContextFactory.setEndpointIdentificationAlgorithm("");
|
||||
sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
|
||||
sslContextFactory.setKeyStorePassword("storepwd");
|
||||
sslContextFactory.setTrustStorePath("src/test/resources/truststore.jks");
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2013 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.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.server.NetworkConnector;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.server.handler.DefaultHandler;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static junit.framework.Assert.fail;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
/**
|
||||
* This test class runs tests to make sure that hostname verification (http://www.ietf.org/rfc/rfc2818.txt section 3
|
||||
* .1) is configurable in SslContextFactory and works as expected.
|
||||
*/
|
||||
public class HostnameVerificationTest
|
||||
{
|
||||
private SslContextFactory sslContextFactory = new SslContextFactory();
|
||||
private Server server;
|
||||
private HttpClient client;
|
||||
private NetworkConnector connector;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
if (sslContextFactory != null)
|
||||
{
|
||||
// keystore contains a hostname which doesn't match localhost
|
||||
sslContextFactory.setKeyStorePath("src/test/resources/keystore");
|
||||
sslContextFactory.setKeyStorePassword("abcdef");
|
||||
}
|
||||
|
||||
if (server == null)
|
||||
server = new Server();
|
||||
connector = new ServerConnector(server, sslContextFactory);
|
||||
server.addConnector(connector);
|
||||
server.setHandler(new DefaultHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
response.getWriter().write("foobar");
|
||||
}
|
||||
});
|
||||
server.start();
|
||||
|
||||
QueuedThreadPool executor = new QueuedThreadPool();
|
||||
executor.setName(executor.getName() + "-client");
|
||||
client = new HttpClient(sslContextFactory);
|
||||
client.setExecutor(executor);
|
||||
client.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* This test is supposed to verify that hostname verification works as described in:
|
||||
* http://www.ietf.org/rfc/rfc2818.txt section 3.1. It uses a certificate with a common name different to localhost
|
||||
* and sends a request to localhost. This should fail with a SSLHandshakeException.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void simpleGetWithHostnameVerificationEnabledTest() throws Exception
|
||||
{
|
||||
String uri = "https://localhost:" + connector.getLocalPort() + "/";
|
||||
try
|
||||
{
|
||||
client.GET(uri);
|
||||
fail("sending request to client should have failed with an Exception!");
|
||||
}
|
||||
catch (ExecutionException e)
|
||||
{
|
||||
assertThat("We got a SSLHandshakeException as localhost doesn't match the hostname of the certificate",
|
||||
e.getCause().getCause(), instanceOf(SSLHandshakeException.class));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This test has hostname verification disabled and connecting, ssl handshake and sending the request should just
|
||||
* work fine.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void simpleGetWithHostnameVerificationDisabledTest() throws Exception
|
||||
{
|
||||
sslContextFactory.setEndpointIdentificationAlgorithm("");
|
||||
String uri = "https://localhost:" + connector.getLocalPort() + "/";
|
||||
try
|
||||
{
|
||||
client.GET(uri);
|
||||
}
|
||||
catch (ExecutionException e)
|
||||
{
|
||||
fail("SSLHandshake should work just fine as hostname verification is disabled! " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,12 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.io;
|
||||
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
@ -31,7 +25,6 @@ import java.net.Socket;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLEngineResult;
|
||||
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
|
||||
|
@ -47,6 +40,12 @@ import org.junit.BeforeClass;
|
|||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
|
||||
public class SelectChannelEndPointSslTest extends SelectChannelEndPointTest
|
||||
{
|
||||
|
@ -60,6 +59,7 @@ public class SelectChannelEndPointSslTest extends SelectChannelEndPointTest
|
|||
__sslCtxFactory.setKeyStorePath(keystore.getAbsolutePath());
|
||||
__sslCtxFactory.setKeyStorePassword("storepwd");
|
||||
__sslCtxFactory.setKeyManagerPassword("keypwd");
|
||||
__sslCtxFactory.setEndpointIdentificationAlgorithm("");
|
||||
__sslCtxFactory.start();
|
||||
}
|
||||
|
||||
|
|
|
@ -148,7 +148,9 @@ public class AbstractTestOSGi
|
|||
|
||||
protected SslContextFactory getSslContextFactory()
|
||||
{
|
||||
return new SslContextFactory(true);
|
||||
SslContextFactory sslContextFactory = new SslContextFactory(true);
|
||||
sslContextFactory.setEndpointIdentificationAlgorithm("");
|
||||
return sslContextFactory;
|
||||
}
|
||||
|
||||
protected void testHttpServiceGreetings(BundleContext bundleContext, String protocol, int port) throws Exception
|
||||
|
|
|
@ -52,6 +52,7 @@ public class SSLExternalServerTest extends AbstractHTTPSPDYTest
|
|||
SslContextFactory sslContextFactory = new SslContextFactory();
|
||||
// Force TLSv1
|
||||
sslContextFactory.setIncludeProtocols("TLSv1");
|
||||
sslContextFactory.setEndpointIdentificationAlgorithm("");
|
||||
return new SPDYClient.Factory(threadPool, null, sslContextFactory, 30000);
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ public class SSLSynReplyTest extends SynReplyTest
|
|||
protected SPDYServerConnector newSPDYServerConnector(Server server, ServerSessionFrameListener listener)
|
||||
{
|
||||
SslContextFactory sslContextFactory = newSslContextFactory();
|
||||
sslContextFactory.setEndpointIdentificationAlgorithm("");
|
||||
return new SPDYServerConnector(server, sslContextFactory, listener);
|
||||
}
|
||||
|
||||
|
@ -41,6 +42,7 @@ public class SSLSynReplyTest extends SynReplyTest
|
|||
protected SPDYClient.Factory newSPDYClientFactory(Executor threadPool)
|
||||
{
|
||||
SslContextFactory sslContextFactory = newSslContextFactory();
|
||||
sslContextFactory.setEndpointIdentificationAlgorithm("");
|
||||
return new SPDYClient.Factory(threadPool, null, sslContextFactory);
|
||||
}
|
||||
|
||||
|
|
|
@ -41,12 +41,12 @@ import java.util.Collections;
|
|||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.net.ssl.CertPathTrustManagerParameters;
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLParameters;
|
||||
import javax.net.ssl.SSLServerSocket;
|
||||
import javax.net.ssl.SSLServerSocketFactory;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
|
@ -111,6 +111,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
|
||||
/** Excluded protocols. */
|
||||
private final Set<String> _excludeProtocols = new LinkedHashSet<>();
|
||||
|
||||
/** Included protocols. */
|
||||
private Set<String> _includeProtocols = null;
|
||||
|
||||
|
@ -196,6 +197,9 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
/** SSL context */
|
||||
private SSLContext _context;
|
||||
|
||||
/** EndpointIdentificationAlgorithm - when set to "HTTPS" hostname verification will be enabled */
|
||||
private String _endpointIdentificationAlgorithm = "HTTPS";
|
||||
|
||||
private boolean _trustAll;
|
||||
|
||||
/**
|
||||
|
@ -204,7 +208,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public SslContextFactory()
|
||||
{
|
||||
_trustAll=true;
|
||||
this(true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -815,6 +819,16 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
_context = sslContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* When set to "HTTPS" hostname verification will be enabled
|
||||
*
|
||||
* @param endpointIdentificationAlgorithm Set the endpointIdentificationAlgorithm
|
||||
*/
|
||||
public void setEndpointIdentificationAlgorithm(String endpointIdentificationAlgorithm)
|
||||
{
|
||||
this._endpointIdentificationAlgorithm = endpointIdentificationAlgorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method to provide alternate way to load a keystore.
|
||||
*
|
||||
|
@ -1292,6 +1306,10 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
|
||||
public void customize(SSLEngine sslEngine)
|
||||
{
|
||||
SSLParameters sslParams = sslEngine.getSSLParameters();
|
||||
sslParams.setEndpointIdentificationAlgorithm(_endpointIdentificationAlgorithm);
|
||||
sslEngine.setSSLParameters(sslParams);
|
||||
|
||||
if (getWantClientAuth())
|
||||
sslEngine.setWantClientAuth(getWantClientAuth());
|
||||
if (getNeedClientAuth())
|
||||
|
|
Loading…
Reference in New Issue