mirror of https://github.com/apache/lucene.git
SOLR-5776: refactor SSLConfig so that SSLTestConfig can provide SSLContexts using a NullSecureRandom to prevent SSL tests from blocking on entropy starved machines
(cherry picked from commit f45bd03ca2cc301dcec4e68c49d961c306d8f434) Conflicts: solr/test-framework/src/java/org/apache/solr/util/SSLTestConfig.java
This commit is contained in:
parent
8349546eaa
commit
98b0da47ad
|
@ -77,38 +77,63 @@ public class SSLConfig {
|
|||
|
||||
/**
|
||||
* Returns an SslContextFactory that should be used by a jetty server based on the specified
|
||||
* configuration, or null if no SSL should be used.
|
||||
* SSLConfig param which may be null.
|
||||
*
|
||||
* The specified sslConfig will be completely ignored if the "tests.jettySsl" system property is
|
||||
* true - in which case standard "javax.net.ssl.*" system properties will be used instead, along
|
||||
* with "tests.jettySsl.clientAuth"
|
||||
* if the SSLConfig param is non-null, then this method will return the results of
|
||||
* {@link #createContextFactory()}.
|
||||
*
|
||||
* @see #isSSLMode
|
||||
* If the SSLConfig param is null, then this method will return null unless the
|
||||
* <code>tests.jettySsl</code> system property is true, in which case standard "javax.net.ssl.*"
|
||||
* system properties will be used instead, along with "tests.jettySsl.clientAuth".
|
||||
*
|
||||
* @see #createContextFactory()
|
||||
*/
|
||||
public static SslContextFactory createContextFactory(SSLConfig sslConfig) {
|
||||
|
||||
if (sslConfig == null) {
|
||||
if (Boolean.getBoolean("tests.jettySsl")) {
|
||||
return configureSslFromSysProps();
|
||||
}
|
||||
if (sslConfig != null) {
|
||||
return sslConfig.createContextFactory();
|
||||
}
|
||||
// else...
|
||||
if (Boolean.getBoolean("tests.jettySsl")) {
|
||||
return configureSslFromSysProps();
|
||||
}
|
||||
// else...
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an SslContextFactory that should be used by a jetty server based on this SSLConfig instance,
|
||||
* or null if SSL should not be used.
|
||||
*
|
||||
* The default implementation generates a simple factory according to the keystore, truststore,
|
||||
* and clientAuth properties of this object.
|
||||
*
|
||||
* @see #getKeyStore
|
||||
* @see #getKeyStorePassword
|
||||
* @see #isClientAuthMode
|
||||
* @see #getTrustStore
|
||||
* @see #getTrustStorePassword
|
||||
*/
|
||||
public SslContextFactory createContextFactory() {
|
||||
|
||||
if (! isSSLMode()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!sslConfig.isSSLMode())
|
||||
return null;
|
||||
|
||||
SslContextFactory factory = new SslContextFactory(false);
|
||||
if (sslConfig.getKeyStore() != null)
|
||||
factory.setKeyStorePath(sslConfig.getKeyStore());
|
||||
if (sslConfig.getKeyStorePassword() != null)
|
||||
factory.setKeyStorePassword(sslConfig.getKeyStorePassword());
|
||||
factory.setNeedClientAuth(sslConfig.isClientAuthMode());
|
||||
// else...
|
||||
|
||||
if (sslConfig.isClientAuthMode()) {
|
||||
if (sslConfig.getTrustStore() != null)
|
||||
factory.setTrustStorePath(sslConfig.getTrustStore());
|
||||
if (sslConfig.getTrustStorePassword() != null)
|
||||
factory.setTrustStorePassword(sslConfig.getTrustStorePassword());
|
||||
SslContextFactory factory = new SslContextFactory(false);
|
||||
if (getKeyStore() != null)
|
||||
factory.setKeyStorePath(getKeyStore());
|
||||
if (getKeyStorePassword() != null)
|
||||
factory.setKeyStorePassword(getKeyStorePassword());
|
||||
|
||||
factory.setNeedClientAuth(isClientAuthMode());
|
||||
|
||||
if (isClientAuthMode()) {
|
||||
if (getTrustStore() != null)
|
||||
factory.setTrustStorePath(getTrustStore());
|
||||
if (getTrustStorePassword() != null)
|
||||
factory.setTrustStorePassword(getTrustStorePassword());
|
||||
}
|
||||
return factory;
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@ import java.security.KeyManagementException;
|
|||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.SecureRandomSpi;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
@ -41,6 +43,7 @@ import org.apache.solr.client.solrj.impl.HttpClientConfigurer;
|
|||
import org.apache.solr.common.params.SolrParams;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.security.CertificateUtils;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
|
||||
public class SSLTestConfig extends SSLConfig {
|
||||
public static File TEST_KEYSTORE = ExternalPaths.SERVER_HOME == null ? null
|
||||
|
@ -79,7 +82,10 @@ public class SSLTestConfig extends SSLConfig {
|
|||
|
||||
/**
|
||||
* Builds a new SSLContext for HTTP <b>clients</b> to use when communicating with servers which have
|
||||
* been configured based on the settings of this object. Also explicitly allows the use of self-signed
|
||||
* been configured based on the settings of this object.
|
||||
*
|
||||
* NOTE: Uses a completely insecure {@link SecureRandom} instance to prevent tests from blocking
|
||||
* due to lack of entropy, also explicitly allows the use of self-signed
|
||||
* certificates (since that's what is almost always used during testing).
|
||||
*/
|
||||
public SSLContext buildClientSSLContext() throws KeyManagementException,
|
||||
|
@ -88,7 +94,8 @@ public class SSLTestConfig extends SSLConfig {
|
|||
assert isSSLMode();
|
||||
|
||||
SSLContextBuilder builder = SSLContexts.custom();
|
||||
|
||||
builder.setSecureRandom(NullSecureRandom.INSTANCE);
|
||||
|
||||
// NOTE: KeyStore & TrustStore are swapped because they are from configured from server perspective...
|
||||
// we are a client - our keystore contains the keys the server trusts, and vice versa
|
||||
builder.loadTrustMaterial(buildKeyStore(getKeyStore(), getKeyStorePassword()), new TrustSelfSignedStrategy()).build();
|
||||
|
@ -101,6 +108,54 @@ public class SSLTestConfig extends SSLConfig {
|
|||
return builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a new SSLContext for jetty servers which have been configured based on the settings of
|
||||
* this object.
|
||||
*
|
||||
* NOTE: Uses a completely insecure {@link SecureRandom} instance to prevent tests from blocking
|
||||
* due to lack of entropy, also explicitly allows the use of self-signed
|
||||
* certificates (since that's what is almost always used during testing).
|
||||
* almost always used during testing).
|
||||
*/
|
||||
public SSLContext buildServerSSLContext() throws KeyManagementException,
|
||||
UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException {
|
||||
|
||||
assert isSSLMode();
|
||||
|
||||
SSLContextBuilder builder = SSLContexts.custom();
|
||||
builder.setSecureRandom(NullSecureRandom.INSTANCE);
|
||||
|
||||
builder.loadKeyMaterial(buildKeyStore(getKeyStore(), getKeyStorePassword()), getKeyStorePassword().toCharArray());
|
||||
|
||||
if (isClientAuthMode()) {
|
||||
builder.loadTrustMaterial(buildKeyStore(getTrustStore(), getTrustStorePassword()), new TrustSelfSignedStrategy()).build();
|
||||
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an SslContextFactory using {@link buildServerSSLContext} if SSL should be used, else returns null.
|
||||
*/
|
||||
@Override
|
||||
public SslContextFactory createContextFactory() {
|
||||
if (!isSSLMode()) {
|
||||
return null;
|
||||
}
|
||||
// else...
|
||||
|
||||
|
||||
SslContextFactory factory = new SslContextFactory(false);
|
||||
try {
|
||||
factory.setSslContext(buildServerSSLContext());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("ssl context init failure: " + e.getMessage(), e);
|
||||
}
|
||||
factory.setNeedClientAuth(isClientAuthMode());
|
||||
return factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a KeyStore using the specified filename and password
|
||||
*/
|
||||
|
@ -202,5 +257,42 @@ public class SSLTestConfig extends SSLConfig {
|
|||
System.clearProperty("javax.net.ssl.trustStore");
|
||||
System.clearProperty("javax.net.ssl.trustStorePassword");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A mocked up instance of SecureRandom that always does the minimal amount of work to generate
|
||||
* "random" numbers. This is to prevent blocking issues that arise in platform default
|
||||
* SecureRandom instances due to too many instances / not enough random entropy.
|
||||
* Tests do not need secure SSL.
|
||||
*/
|
||||
private static class NullSecureRandom extends SecureRandom {
|
||||
public static final SecureRandom INSTANCE = new NullSecureRandom();
|
||||
|
||||
/** SPI Used to init all instances */
|
||||
private static final SecureRandomSpi NULL_SPI = new SecureRandomSpi() {
|
||||
/** NOOP: returns new uninitialized byte[] */
|
||||
public byte[] engineGenerateSeed(int numBytes) {
|
||||
return new byte[numBytes];
|
||||
}
|
||||
/** NOOP */
|
||||
public void engineNextBytes(byte[] bytes) { /* NOOP */ }
|
||||
/** NOOP */
|
||||
public void engineSetSeed(byte[] seed) { /* NOOP */ }
|
||||
};
|
||||
|
||||
private NullSecureRandom() {
|
||||
super(NULL_SPI, null) ;
|
||||
}
|
||||
|
||||
/** NOOP: returns new uninitialized byte[] */
|
||||
public byte[] generateSeed(int numBytes) {
|
||||
return new byte[numBytes];
|
||||
}
|
||||
/** NOOP */
|
||||
synchronized public void nextBytes(byte[] bytes) { /* NOOP */ }
|
||||
/** NOOP */
|
||||
synchronized public void setSeed(byte[] seed) { /* NOOP */ }
|
||||
/** NOOP */
|
||||
synchronized public void setSeed(long seed) { /* NOOP */ }
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue