467281 Remove Java 1.7 support from Jetty 9.3
This commit is contained in:
parent
054d6b9176
commit
c5e4abd792
|
@ -42,7 +42,6 @@ import org.eclipse.jetty.server.handler.DefaultHandler;
|
||||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||||
import org.eclipse.jetty.server.handler.RequestLogHandler;
|
import org.eclipse.jetty.server.handler.RequestLogHandler;
|
||||||
import org.eclipse.jetty.server.handler.StatisticsHandler;
|
import org.eclipse.jetty.server.handler.StatisticsHandler;
|
||||||
import org.eclipse.jetty.util.ssl.ExtendedSslContextFactory;
|
|
||||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||||
import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
|
import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
|
||||||
|
@ -129,7 +128,7 @@ public class LikeJettyXml
|
||||||
|
|
||||||
// === jetty-https.xml ===
|
// === jetty-https.xml ===
|
||||||
// SSL Context Factory
|
// SSL Context Factory
|
||||||
SslContextFactory sslContextFactory = new ExtendedSslContextFactory();
|
SslContextFactory sslContextFactory = new SslContextFactory();
|
||||||
sslContextFactory.setKeyStorePath(jetty_home + "/../../../jetty-server/src/test/config/etc/keystore");
|
sslContextFactory.setKeyStorePath(jetty_home + "/../../../jetty-server/src/test/config/etc/keystore");
|
||||||
sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
|
sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
|
||||||
sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
|
sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
|
|
||||||
<!-- ============================================================= -->
|
<!-- ============================================================= -->
|
||||||
<!-- SSL ContextFactory configuration -->
|
<!-- SSL ContextFactory configuration -->
|
||||||
<!-- For java 8 and beyond the keystore is created in -->
|
|
||||||
<!-- jetty-ssl-extended-context.xml -->
|
|
||||||
<!-- ============================================================= -->
|
<!-- ============================================================= -->
|
||||||
<Configure id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory">
|
<Configure id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory">
|
||||||
<Set name="KeyStorePath"><Property name="jetty.base" default="." />/<Property name="jetty.sslContext.keyStorePath" deprecated="jetty.keystore" default="etc/keystore"/></Set>
|
<Set name="KeyStorePath"><Property name="jetty.base" default="." />/<Property name="jetty.sslContext.keyStorePath" deprecated="jetty.keystore" default="etc/keystore"/></Set>
|
||||||
|
@ -26,4 +24,5 @@
|
||||||
<Item>SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA</Item>
|
<Item>SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA</Item>
|
||||||
</Array>
|
</Array>
|
||||||
</Set>
|
</Set>
|
||||||
|
<Set name="useCipherSuitesOrder"><Property name="jetty.sslContext.useCipherSuitesOrder" default="true"/></Set>
|
||||||
</Configure>
|
</Configure>
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
<?xml version="1.0"?>
|
|
||||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
|
||||||
|
|
||||||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
|
||||||
<!-- ============================================================= -->
|
|
||||||
<!-- Create an extended SSL Context Factory for use in java 8 -->
|
|
||||||
<!-- and later. -->
|
|
||||||
<!-- Configuration is completed in jetty-ssl-context.xml -->
|
|
||||||
<!-- ============================================================= -->
|
|
||||||
<New id="sslContextFactory" class="org.eclipse.jetty.util.ssl.ExtendedSslContextFactory">
|
|
||||||
<Set name="useCipherSuitesOrder"><Property name="jetty.sslContext.useCipherSuitesOrder" default="true"/></Set>
|
|
||||||
</New>
|
|
||||||
</Configure>
|
|
|
@ -1,12 +0,0 @@
|
||||||
#
|
|
||||||
# SSL java 7 Keystore module
|
|
||||||
#
|
|
||||||
[name]
|
|
||||||
ssl-context
|
|
||||||
|
|
||||||
[depend]
|
|
||||||
server
|
|
||||||
|
|
||||||
[xml]
|
|
||||||
etc/jetty-ssl-context.xml
|
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
#
|
|
||||||
# SSL java 8 Keystore module
|
|
||||||
#
|
|
||||||
[name]
|
|
||||||
ssl-context
|
|
||||||
|
|
||||||
[depend]
|
|
||||||
server
|
|
||||||
|
|
||||||
[xml]
|
|
||||||
etc/jetty-ssl-extended-context.xml
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
ssl
|
ssl
|
||||||
|
|
||||||
[depend]
|
[depend]
|
||||||
ssl-impl/ssl-java${java.version.minor}
|
server
|
||||||
|
|
||||||
[xml]
|
[xml]
|
||||||
etc/jetty-ssl.xml
|
etc/jetty-ssl.xml
|
||||||
|
|
|
@ -50,7 +50,6 @@ import org.eclipse.jetty.server.SslConnectionFactory;
|
||||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||||
import org.eclipse.jetty.util.ConcurrentArrayQueue;
|
import org.eclipse.jetty.util.ConcurrentArrayQueue;
|
||||||
import org.eclipse.jetty.util.IO;
|
import org.eclipse.jetty.util.IO;
|
||||||
import org.eclipse.jetty.util.ssl.ExtendedSslContextFactory;
|
|
||||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
@ -84,7 +83,7 @@ public class SslConnectionFactoryTest
|
||||||
https_config.addCustomizer(new SecureRequestCustomizer());
|
https_config.addCustomizer(new SecureRequestCustomizer());
|
||||||
|
|
||||||
|
|
||||||
SslContextFactory sslContextFactory = new ExtendedSslContextFactory();
|
SslContextFactory sslContextFactory = new SslContextFactory();
|
||||||
sslContextFactory.setKeyStorePath(keystoreFile.getAbsolutePath());
|
sslContextFactory.setKeyStorePath(keystoreFile.getAbsolutePath());
|
||||||
sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
|
sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
|
||||||
sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
|
sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
|
||||||
|
@ -110,11 +109,8 @@ public class SslConnectionFactoryTest
|
||||||
|
|
||||||
_server.start();
|
_server.start();
|
||||||
_port=https.getLocalPort();
|
_port=https.getLocalPort();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void after() throws Exception
|
public void after() throws Exception
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,250 +0,0 @@
|
||||||
//
|
|
||||||
// ========================================================================
|
|
||||||
// Copyright (c) 1995-2015 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.util.ssl;
|
|
||||||
|
|
||||||
import java.security.KeyStore;
|
|
||||||
import java.security.cert.Certificate;
|
|
||||||
import java.security.cert.X509Certificate;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import javax.naming.ldap.LdapName;
|
|
||||||
import javax.naming.ldap.Rdn;
|
|
||||||
import javax.net.ssl.KeyManager;
|
|
||||||
import javax.net.ssl.SNIHostName;
|
|
||||||
import javax.net.ssl.SNIMatcher;
|
|
||||||
import javax.net.ssl.SNIServerName;
|
|
||||||
import javax.net.ssl.SSLEngine;
|
|
||||||
import javax.net.ssl.SSLParameters;
|
|
||||||
import javax.net.ssl.StandardConstants;
|
|
||||||
import javax.net.ssl.X509ExtendedKeyManager;
|
|
||||||
import javax.security.auth.x500.X500Principal;
|
|
||||||
|
|
||||||
import org.eclipse.jetty.util.log.Log;
|
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Extended SSL ContextFactory supports additional SslContext features
|
|
||||||
* that are only available in Java-8, specifically: <ul>
|
|
||||||
* <li>{@link #setUseCipherSuitesOrder(boolean)}</li>
|
|
||||||
* <li>SNI - Server Name Indicator</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* <p>If the KeyStore contains multiple X509 certificates, then the CN element
|
|
||||||
* of the distinguished name is used to select the certificate alias to use for
|
|
||||||
* a connection. Simple wildcard names (eg *.domain.com) are supported.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class ExtendedSslContextFactory extends SslContextFactory
|
|
||||||
{
|
|
||||||
static final Logger LOG = Log.getLogger(ExtendedSslContextFactory.class);
|
|
||||||
private final Map<String,String> _aliases = new HashMap<>();
|
|
||||||
private final Map<String,String> _wild = new HashMap<>();
|
|
||||||
private boolean _useCipherSuitesOrder=true;
|
|
||||||
|
|
||||||
public boolean isUseCipherSuitesOrder()
|
|
||||||
{
|
|
||||||
return _useCipherSuitesOrder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUseCipherSuitesOrder(boolean useCipherSuitesOrder)
|
|
||||||
{
|
|
||||||
_useCipherSuitesOrder = useCipherSuitesOrder;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create the SSLContext object and start the lifecycle
|
|
||||||
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void doStart() throws Exception
|
|
||||||
{
|
|
||||||
super.doStart();
|
|
||||||
|
|
||||||
_aliases.clear();
|
|
||||||
if (_factory._keyStore!=null)
|
|
||||||
{
|
|
||||||
loop: for (String alias : Collections.list(_factory._keyStore.aliases()))
|
|
||||||
{
|
|
||||||
Certificate certificate = _factory._keyStore.getCertificate(alias);
|
|
||||||
if ("X.509".equals(certificate.getType()))
|
|
||||||
{
|
|
||||||
X509Certificate x509 = (X509Certificate)certificate;
|
|
||||||
|
|
||||||
// Exclude certificates with special uses
|
|
||||||
if (x509.getKeyUsage()!=null)
|
|
||||||
{
|
|
||||||
boolean[] b=x509.getKeyUsage();
|
|
||||||
if (b[5]/* keyCertSign */)
|
|
||||||
continue loop;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look for alternative name extensions
|
|
||||||
boolean named=false;
|
|
||||||
Collection<List<?>> altNames = x509.getSubjectAlternativeNames();
|
|
||||||
if (altNames!=null)
|
|
||||||
{
|
|
||||||
for (List<?> list : altNames)
|
|
||||||
{
|
|
||||||
if (((Number)list.get(0)).intValue() == 2 )
|
|
||||||
{
|
|
||||||
String cn = list.get(1).toString();
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
LOG.debug("Certificate san alias={} cn={} in {}",alias,cn,_factory);
|
|
||||||
if (cn!=null)
|
|
||||||
{
|
|
||||||
named=true;
|
|
||||||
_aliases.put(cn,alias);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no names found, look up the cn from the subject
|
|
||||||
if (!named)
|
|
||||||
{
|
|
||||||
LdapName name=new LdapName(x509.getSubjectX500Principal().getName(X500Principal.RFC2253));
|
|
||||||
for (Rdn rdn : name.getRdns())
|
|
||||||
{
|
|
||||||
if (rdn.getType().equalsIgnoreCase("cn"))
|
|
||||||
{
|
|
||||||
String cn = rdn.getValue().toString();
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
LOG.debug("Certificate cn alias={} cn={} in {}",alias,cn,_factory);
|
|
||||||
if (cn!=null && cn.contains(".") && !cn.contains(" "))
|
|
||||||
_aliases.put(cn,alias);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// find wild aliases
|
|
||||||
_wild.clear();
|
|
||||||
for (String name : _aliases.keySet())
|
|
||||||
if (name.startsWith("*."))
|
|
||||||
_wild.put(name.substring(1),_aliases.get(name));
|
|
||||||
|
|
||||||
LOG.info("x509={} for {}",_aliases,this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doStop() throws Exception
|
|
||||||
{
|
|
||||||
super.doStop();
|
|
||||||
_aliases.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected KeyManager[] getKeyManagers(KeyStore keyStore) throws Exception
|
|
||||||
{
|
|
||||||
KeyManager[] managers = super.getKeyManagers(keyStore);
|
|
||||||
if (managers!=null)
|
|
||||||
{
|
|
||||||
for (int idx = 0; idx < managers.length; idx++)
|
|
||||||
{
|
|
||||||
if (managers[idx] instanceof X509ExtendedKeyManager)
|
|
||||||
managers[idx]=new SniX509ExtendedKeyManager((X509ExtendedKeyManager)managers[idx],getCertAlias());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG.debug("managers={} for {}",managers,this);
|
|
||||||
return managers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void customize(SSLEngine sslEngine)
|
|
||||||
{
|
|
||||||
super.customize(sslEngine);
|
|
||||||
SSLParameters sslParams = sslEngine.getSSLParameters();
|
|
||||||
|
|
||||||
sslParams.setUseCipherSuitesOrder(_useCipherSuitesOrder);
|
|
||||||
sslParams.setSNIMatchers(Collections.singletonList((SNIMatcher)new AliasSNIMatcher()));
|
|
||||||
sslEngine.setSSLParameters(sslParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
class AliasSNIMatcher extends SNIMatcher
|
|
||||||
{
|
|
||||||
private String _alias;
|
|
||||||
private SNIHostName _name;
|
|
||||||
|
|
||||||
protected AliasSNIMatcher()
|
|
||||||
{
|
|
||||||
super(StandardConstants.SNI_HOST_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean matches(SNIServerName serverName)
|
|
||||||
{
|
|
||||||
LOG.debug("matches={} for {}",serverName,this);
|
|
||||||
|
|
||||||
if (_aliases.size()==0 && _wild.size()==0)
|
|
||||||
{
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
LOG.debug("No SNI ready certificates for {} in {}",serverName,ExtendedSslContextFactory.this);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (serverName instanceof SNIHostName)
|
|
||||||
{
|
|
||||||
_name=(SNIHostName)serverName;
|
|
||||||
|
|
||||||
// If we don't have a SNI name, or didn't see any certificate aliases,
|
|
||||||
// just say true as it will either somehow work or fail elsewhere
|
|
||||||
if (_name==null || _aliases.size()==0)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Try an exact match
|
|
||||||
_alias = _aliases.get(_name.getAsciiName());
|
|
||||||
if (_alias!=null)
|
|
||||||
{
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
LOG.debug("matched {}->{}",_name.getAsciiName(),_alias);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try wild card matches
|
|
||||||
String domain = _name.getAsciiName();
|
|
||||||
domain=domain.substring(domain.indexOf('.'));
|
|
||||||
_alias = _wild.get(domain);
|
|
||||||
if (_alias!=null)
|
|
||||||
{
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
LOG.debug("wild match {}->{}",_name.getAsciiName(),_alias);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAlias()
|
|
||||||
{
|
|
||||||
return _alias;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getServerName()
|
|
||||||
{
|
|
||||||
return _name==null?null:_name.getAsciiName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -85,9 +85,9 @@ public class SniX509ExtendedKeyManager extends X509ExtendedKeyManager
|
||||||
{
|
{
|
||||||
for (SNIMatcher m : matchers)
|
for (SNIMatcher m : matchers)
|
||||||
{
|
{
|
||||||
if (m instanceof ExtendedSslContextFactory.AliasSNIMatcher)
|
if (m instanceof SslContextFactory.AliasSNIMatcher)
|
||||||
{
|
{
|
||||||
ExtendedSslContextFactory.AliasSNIMatcher matcher = (ExtendedSslContextFactory.AliasSNIMatcher)m;
|
SslContextFactory.AliasSNIMatcher matcher = (SslContextFactory.AliasSNIMatcher)m;
|
||||||
alias=matcher.getAlias();
|
alias=matcher.getAlias();
|
||||||
host=matcher.getServerName();
|
host=matcher.getServerName();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -36,16 +36,23 @@ import java.security.cert.X509Certificate;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import javax.naming.ldap.LdapName;
|
||||||
|
import javax.naming.ldap.Rdn;
|
||||||
import javax.net.ssl.CertPathTrustManagerParameters;
|
import javax.net.ssl.CertPathTrustManagerParameters;
|
||||||
import javax.net.ssl.KeyManager;
|
import javax.net.ssl.KeyManager;
|
||||||
import javax.net.ssl.KeyManagerFactory;
|
import javax.net.ssl.KeyManagerFactory;
|
||||||
|
import javax.net.ssl.SNIHostName;
|
||||||
|
import javax.net.ssl.SNIMatcher;
|
||||||
|
import javax.net.ssl.SNIServerName;
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
import javax.net.ssl.SSLEngine;
|
import javax.net.ssl.SSLEngine;
|
||||||
import javax.net.ssl.SSLParameters;
|
import javax.net.ssl.SSLParameters;
|
||||||
|
@ -55,10 +62,12 @@ import javax.net.ssl.SSLServerSocketFactory;
|
||||||
import javax.net.ssl.SSLSession;
|
import javax.net.ssl.SSLSession;
|
||||||
import javax.net.ssl.SSLSocket;
|
import javax.net.ssl.SSLSocket;
|
||||||
import javax.net.ssl.SSLSocketFactory;
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
|
import javax.net.ssl.StandardConstants;
|
||||||
import javax.net.ssl.TrustManager;
|
import javax.net.ssl.TrustManager;
|
||||||
import javax.net.ssl.TrustManagerFactory;
|
import javax.net.ssl.TrustManagerFactory;
|
||||||
import javax.net.ssl.X509ExtendedKeyManager;
|
import javax.net.ssl.X509ExtendedKeyManager;
|
||||||
import javax.net.ssl.X509TrustManager;
|
import javax.net.ssl.X509TrustManager;
|
||||||
|
import javax.security.auth.x500.X500Principal;
|
||||||
|
|
||||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||||
import org.eclipse.jetty.util.log.Log;
|
import org.eclipse.jetty.util.log.Log;
|
||||||
|
@ -120,6 +129,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
|
|
||||||
/** Included cipher suites. */
|
/** Included cipher suites. */
|
||||||
private final List<String> _includeCipherSuites = new CopyOnWriteArrayList<String>();
|
private final List<String> _includeCipherSuites = new CopyOnWriteArrayList<String>();
|
||||||
|
private boolean _useCipherSuitesOrder=true;
|
||||||
|
|
||||||
/** Keystore path. */
|
/** Keystore path. */
|
||||||
private Resource _keyStoreResource;
|
private Resource _keyStoreResource;
|
||||||
|
@ -130,6 +140,8 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
|
|
||||||
/** SSL certificate alias */
|
/** SSL certificate alias */
|
||||||
private String _certAlias;
|
private String _certAlias;
|
||||||
|
private final Map<String,String> _certAliases = new HashMap<>();
|
||||||
|
private final Map<String,String> _certWilds = new HashMap<>();
|
||||||
|
|
||||||
/** Truststore path */
|
/** Truststore path */
|
||||||
private Resource _trustStoreResource;
|
private Resource _trustStoreResource;
|
||||||
|
@ -321,6 +333,74 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
LOG.debug("Enabled Protocols {} of {}",Arrays.asList(engine.getEnabledProtocols()),Arrays.asList(engine.getSupportedProtocols()));
|
LOG.debug("Enabled Protocols {} of {}",Arrays.asList(engine.getEnabledProtocols()),Arrays.asList(engine.getSupportedProtocols()));
|
||||||
LOG.debug("Enabled Ciphers {} of {}",Arrays.asList(engine.getEnabledCipherSuites()),Arrays.asList(engine.getSupportedCipherSuites()));
|
LOG.debug("Enabled Ciphers {} of {}",Arrays.asList(engine.getEnabledCipherSuites()),Arrays.asList(engine.getSupportedCipherSuites()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Look for X.509 certificates to create alias map
|
||||||
|
_certAliases.clear();
|
||||||
|
if (_factory._keyStore!=null)
|
||||||
|
{
|
||||||
|
loop: for (String alias : Collections.list(_factory._keyStore.aliases()))
|
||||||
|
{
|
||||||
|
Certificate certificate = _factory._keyStore.getCertificate(alias);
|
||||||
|
if ("X.509".equals(certificate.getType()))
|
||||||
|
{
|
||||||
|
X509Certificate x509 = (X509Certificate)certificate;
|
||||||
|
|
||||||
|
// Exclude certificates with special uses
|
||||||
|
if (x509.getKeyUsage()!=null)
|
||||||
|
{
|
||||||
|
boolean[] b=x509.getKeyUsage();
|
||||||
|
if (b[5]/* keyCertSign */)
|
||||||
|
continue loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for alternative name extensions
|
||||||
|
boolean named=false;
|
||||||
|
Collection<List<?>> altNames = x509.getSubjectAlternativeNames();
|
||||||
|
if (altNames!=null)
|
||||||
|
{
|
||||||
|
for (List<?> list : altNames)
|
||||||
|
{
|
||||||
|
if (((Number)list.get(0)).intValue() == 2 )
|
||||||
|
{
|
||||||
|
String cn = list.get(1).toString();
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("Certificate san alias={} cn={} in {}",alias,cn,_factory);
|
||||||
|
if (cn!=null)
|
||||||
|
{
|
||||||
|
named=true;
|
||||||
|
_certAliases.put(cn,alias);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no names found, look up the cn from the subject
|
||||||
|
if (!named)
|
||||||
|
{
|
||||||
|
LdapName name=new LdapName(x509.getSubjectX500Principal().getName(X500Principal.RFC2253));
|
||||||
|
for (Rdn rdn : name.getRdns())
|
||||||
|
{
|
||||||
|
if (rdn.getType().equalsIgnoreCase("cn"))
|
||||||
|
{
|
||||||
|
String cn = rdn.getValue().toString();
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("Certificate cn alias={} cn={} in {}",alias,cn,_factory);
|
||||||
|
if (cn!=null && cn.contains(".") && !cn.contains(" "))
|
||||||
|
_certAliases.put(cn,alias);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// find wild aliases
|
||||||
|
_certWilds.clear();
|
||||||
|
for (String name : _certAliases.keySet())
|
||||||
|
if (name.startsWith("*."))
|
||||||
|
_certWilds.put(name.substring(1),_certAliases.get(name));
|
||||||
|
|
||||||
|
LOG.info("x509={} for {}",_certAliases,this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -328,6 +408,8 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
{
|
{
|
||||||
_factory = null;
|
_factory = null;
|
||||||
super.doStop();
|
super.doStop();
|
||||||
|
_certAliases.clear();
|
||||||
|
_certWilds.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -434,6 +516,16 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
_includeCipherSuites.addAll(Arrays.asList(cipherSuites));
|
_includeCipherSuites.addAll(Arrays.asList(cipherSuites));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isUseCipherSuitesOrder()
|
||||||
|
{
|
||||||
|
return _useCipherSuitesOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUseCipherSuitesOrder(boolean useCipherSuitesOrder)
|
||||||
|
{
|
||||||
|
_useCipherSuitesOrder = useCipherSuitesOrder;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The file or URL of the SSL Key store.
|
* @return The file or URL of the SSL Key store.
|
||||||
*/
|
*/
|
||||||
|
@ -937,17 +1029,29 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
keyManagerFactory.init(keyStore,_keyManagerPassword == null?(_keyStorePassword == null?null:_keyStorePassword.toString().toCharArray()):_keyManagerPassword.toString().toCharArray());
|
keyManagerFactory.init(keyStore,_keyManagerPassword == null?(_keyStorePassword == null?null:_keyStorePassword.toString().toCharArray()):_keyManagerPassword.toString().toCharArray());
|
||||||
managers = keyManagerFactory.getKeyManagers();
|
managers = keyManagerFactory.getKeyManagers();
|
||||||
|
|
||||||
|
if (managers!=null)
|
||||||
|
{
|
||||||
if (_certAlias != null)
|
if (_certAlias != null)
|
||||||
{
|
{
|
||||||
for (int idx = 0; idx < managers.length; idx++)
|
for (int idx = 0; idx < managers.length; idx++)
|
||||||
{
|
{
|
||||||
if (managers[idx] instanceof X509ExtendedKeyManager)
|
if (managers[idx] instanceof X509ExtendedKeyManager)
|
||||||
{
|
|
||||||
managers[idx] = new AliasedX509ExtendedKeyManager((X509ExtendedKeyManager)managers[idx],_certAlias);
|
managers[idx] = new AliasedX509ExtendedKeyManager((X509ExtendedKeyManager)managers[idx],_certAlias);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_certAliases.isEmpty() || !_certWilds.isEmpty())
|
||||||
|
{
|
||||||
|
for (int idx = 0; idx < managers.length; idx++)
|
||||||
|
{
|
||||||
|
if (managers[idx] instanceof X509ExtendedKeyManager)
|
||||||
|
managers[idx]=new SniX509ExtendedKeyManager((X509ExtendedKeyManager)managers[idx],getCertAlias());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG.debug("managers={} for {}",managers,this);
|
||||||
|
|
||||||
return managers;
|
return managers;
|
||||||
}
|
}
|
||||||
|
@ -1386,6 +1490,9 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
{
|
{
|
||||||
SSLParameters sslParams = sslEngine.getSSLParameters();
|
SSLParameters sslParams = sslEngine.getSSLParameters();
|
||||||
sslParams.setEndpointIdentificationAlgorithm(_endpointIdentificationAlgorithm);
|
sslParams.setEndpointIdentificationAlgorithm(_endpointIdentificationAlgorithm);
|
||||||
|
sslParams.setUseCipherSuitesOrder(_useCipherSuitesOrder);
|
||||||
|
if (!_certAliases.isEmpty() || !_certWilds.isEmpty())
|
||||||
|
sslParams.setSNIMatchers(Collections.singletonList((SNIMatcher)new AliasSNIMatcher()));
|
||||||
sslEngine.setSSLParameters(sslParams);
|
sslEngine.setSSLParameters(sslParams);
|
||||||
|
|
||||||
if (getWantClientAuth())
|
if (getWantClientAuth())
|
||||||
|
@ -1517,4 +1624,62 @@ public class SslContextFactory extends AbstractLifeCycle
|
||||||
return String.format("SslFactory@%x{%s}",System.identityHashCode(this),SslContextFactory.this);
|
return String.format("SslFactory@%x{%s}",System.identityHashCode(this),SslContextFactory.this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AliasSNIMatcher extends SNIMatcher
|
||||||
|
{
|
||||||
|
private String _alias;
|
||||||
|
private SNIHostName _name;
|
||||||
|
|
||||||
|
protected AliasSNIMatcher()
|
||||||
|
{
|
||||||
|
super(StandardConstants.SNI_HOST_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(SNIServerName serverName)
|
||||||
|
{
|
||||||
|
LOG.debug("matches={} for {}",serverName,this);
|
||||||
|
|
||||||
|
if (serverName instanceof SNIHostName)
|
||||||
|
{
|
||||||
|
_name=(SNIHostName)serverName;
|
||||||
|
|
||||||
|
// If we don't have a SNI name, or didn't see any certificate aliases,
|
||||||
|
// just say true as it will either somehow work or fail elsewhere
|
||||||
|
if (_name==null || _certAliases.size()==0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Try an exact match
|
||||||
|
_alias = _certAliases.get(_name.getAsciiName());
|
||||||
|
if (_alias!=null)
|
||||||
|
{
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("matched {}->{}",_name.getAsciiName(),_alias);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try wild card matches
|
||||||
|
String domain = _name.getAsciiName();
|
||||||
|
domain=domain.substring(domain.indexOf('.'));
|
||||||
|
_alias = _certWilds.get(domain);
|
||||||
|
if (_alias!=null)
|
||||||
|
{
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("wild match {}->{}",_name.getAsciiName(),_alias);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAlias()
|
||||||
|
{
|
||||||
|
return _alias;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getServerName()
|
||||||
|
{
|
||||||
|
return _name==null?null:_name.getAsciiName();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
12
pom.xml
12
pom.xml
|
@ -325,7 +325,7 @@
|
||||||
<instructions>
|
<instructions>
|
||||||
<Bundle-SymbolicName>${bundle-symbolic-name}</Bundle-SymbolicName>
|
<Bundle-SymbolicName>${bundle-symbolic-name}</Bundle-SymbolicName>
|
||||||
<Bundle-Description>Jetty module for ${project.name}</Bundle-Description>
|
<Bundle-Description>Jetty module for ${project.name}</Bundle-Description>
|
||||||
<Bundle-RequiredExecutionEnvironment>JavaSE-1.7</Bundle-RequiredExecutionEnvironment>
|
<Bundle-RequiredExecutionEnvironment>JavaSE-1.8</Bundle-RequiredExecutionEnvironment>
|
||||||
<Bundle-DocURL>${jetty.url}</Bundle-DocURL>
|
<Bundle-DocURL>${jetty.url}</Bundle-DocURL>
|
||||||
<Bundle-Vendor>Eclipse Jetty Project</Bundle-Vendor>
|
<Bundle-Vendor>Eclipse Jetty Project</Bundle-Vendor>
|
||||||
<Bundle-Classpath>.</Bundle-Classpath>
|
<Bundle-Classpath>.</Bundle-Classpath>
|
||||||
|
@ -373,8 +373,7 @@
|
||||||
<detectJavaApiLink>true</detectJavaApiLink>
|
<detectJavaApiLink>true</detectJavaApiLink>
|
||||||
<excludePackageNames>com.acme.*;org.slf4j.*;org.mortbay.*</excludePackageNames>
|
<excludePackageNames>com.acme.*;org.slf4j.*;org.mortbay.*</excludePackageNames>
|
||||||
<links>
|
<links>
|
||||||
<link>http://docs.oracle.com/javase/7/docs/api/</link>
|
<link>http://docs.oracle.com/javase/8/docs/api/</link>
|
||||||
<link>http://docs.oracle.com/javaee/7/api/</link>
|
|
||||||
<link>http://download.eclipse.org/jetty/stable-9/apidocs/</link>
|
<link>http://download.eclipse.org/jetty/stable-9/apidocs/</link>
|
||||||
<link>http://junit.sourceforge.net/javadoc/</link>
|
<link>http://junit.sourceforge.net/javadoc/</link>
|
||||||
</links>
|
</links>
|
||||||
|
@ -708,8 +707,8 @@
|
||||||
<plugin>
|
<plugin>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>1.7</source>
|
<source>1.8</source>
|
||||||
<target>1.7</target>
|
<target>1.8</target>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
|
@ -788,8 +787,7 @@
|
||||||
<configuration>
|
<configuration>
|
||||||
<excludePackageNames>com.acme</excludePackageNames>
|
<excludePackageNames>com.acme</excludePackageNames>
|
||||||
<links>
|
<links>
|
||||||
<link>http://docs.oracle.com/javase/7/docs/api/</link>
|
<link>http://docs.oracle.com/javase/8/docs/api/</link>
|
||||||
<link>http://docs.oracle.com/javaee/6/api</link>
|
|
||||||
<link>http://junit.sourceforge.net/javadoc/</link>
|
<link>http://junit.sourceforge.net/javadoc/</link>
|
||||||
</links>
|
</links>
|
||||||
<tags>
|
<tags>
|
||||||
|
|
Loading…
Reference in New Issue