Merge pull request #4823 from Pedro Costa

* gh-4823:
  Polish contribution
  Make TLS protocols and cipher suites configurable via the environemnt
pull/5052/merge
Andy Wilkinson 9 years ago
commit 59e119eb9a

@ -41,6 +41,11 @@ public class Ssl {
*/
private String[] ciphers;
/**
* Enabled SSL protocols.
*/
private String[] enabledProtocols;
/**
* Alias that identifies the key in the key store.
*/
@ -168,6 +173,14 @@ public class Ssl {
this.keyStoreProvider = keyStoreProvider;
}
public String[] getEnabledProtocols() {
return this.enabledProtocols;
}
public void setEnabledProtocols(String[] enabledProtocols) {
this.enabledProtocols = enabledProtocols;
}
public String getTrustStore() {
return this.trustStore;
}

@ -215,6 +215,9 @@ public class JettyEmbeddedServletContainerFactory
if (ssl.getCiphers() != null) {
factory.setIncludeCipherSuites(ssl.getCiphers());
}
if (ssl.getEnabledProtocols() != null) {
factory.setIncludeProtocols(ssl.getEnabledProtocols());
}
configureSslTrustStore(factory, ssl);
}

@ -321,8 +321,11 @@ public class TomcatEmbeddedServletContainerFactory
protocol.setKeyPass(ssl.getKeyPassword());
protocol.setKeyAlias(ssl.getKeyAlias());
configureSslKeyStore(protocol, ssl);
String ciphers = StringUtils.arrayToCommaDelimitedString(ssl.getCiphers());
protocol.setCiphers(ciphers);
protocol.setCiphers(StringUtils.arrayToCommaDelimitedString(ssl.getCiphers()));
if (ssl.getEnabledProtocols() != null) {
protocol.setProperty("sslEnabledProtocols",
StringUtils.arrayToCommaDelimitedString(ssl.getEnabledProtocols()));
}
configureSslTrustStore(protocol, ssl);
}

@ -62,6 +62,7 @@ import io.undertow.servlet.handlers.DefaultServlet;
import io.undertow.servlet.util.ImmediateInstanceFactory;
import org.xnio.OptionMap;
import org.xnio.Options;
import org.xnio.Sequence;
import org.xnio.SslClientAuthMode;
import org.xnio.Xnio;
import org.xnio.XnioWorker;
@ -259,6 +260,14 @@ public class UndertowEmbeddedServletContainerFactory
builder.addHttpsListener(port, getListenAddress(), sslContext);
builder.setSocketOption(Options.SSL_CLIENT_AUTH_MODE,
getSslClientAuthMode(ssl));
if (ssl.getEnabledProtocols() != null) {
builder.setSocketOption(Options.SSL_ENABLED_PROTOCOLS,
Sequence.of(ssl.getEnabledProtocols()));
}
if (ssl.getCiphers() != null) {
builder.setSocketOption(Options.SSL_ENABLED_CIPHER_SUITES,
Sequence.of(ssl.getCiphers()));
}
}
catch (NoSuchAlgorithmException ex) {
throw new IllegalStateException(ex);

@ -404,7 +404,7 @@ public abstract class AbstractEmbeddedServletContainerFactoryTests {
AbstractEmbeddedServletContainerFactory factory = getFactory();
addTestTxtFile(factory);
factory.setSsl(getSsl(ClientAuth.NEED, null, "classpath:test.p12",
"classpath:test.p12"));
"classpath:test.p12", null, null));
this.container = factory.getEmbeddedServletContainer();
this.container.start();
KeyStore keyStore = KeyStore.getInstance("pkcs12");
@ -428,7 +428,7 @@ public abstract class AbstractEmbeddedServletContainerFactoryTests {
AbstractEmbeddedServletContainerFactory factory = getFactory();
addTestTxtFile(factory);
factory.setSsl(getSsl(ClientAuth.NEED, "password", "classpath:test.jks",
"classpath:test.jks"));
"classpath:test.jks", null, null));
this.container = factory.getEmbeddedServletContainer();
this.container.start();
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
@ -526,11 +526,11 @@ public abstract class AbstractEmbeddedServletContainerFactoryTests {
}
private Ssl getSsl(ClientAuth clientAuth, String keyPassword, String keyStore) {
return getSsl(clientAuth, keyPassword, keyStore, null);
return getSsl(clientAuth, keyPassword, keyStore, null, null, null);
}
private Ssl getSsl(ClientAuth clientAuth, String keyPassword, String keyStore,
String trustStore) {
String trustStore, String[] supportedProtocols, String[] ciphers) {
Ssl ssl = new Ssl();
ssl.setClientAuth(clientAuth);
if (keyPassword != null) {
@ -546,9 +546,37 @@ public abstract class AbstractEmbeddedServletContainerFactoryTests {
ssl.setTrustStorePassword("secret");
ssl.setTrustStoreType(getStoreType(trustStore));
}
if (ciphers != null) {
ssl.setCiphers(ciphers);
}
if (supportedProtocols != null) {
ssl.setEnabledProtocols(supportedProtocols);
}
return ssl;
}
protected void testRestrictedSSLProtocolsAndCipherSuites(String[] protocols,
String[] ciphers) throws Exception {
AbstractEmbeddedServletContainerFactory factory = getFactory();
factory.setSsl(getSsl(null, "password", "src/test/resources/test.jks", null,
protocols, ciphers));
this.container = factory.getEmbeddedServletContainer(
new ServletRegistrationBean(new ExampleServlet(true, false), "/hello"));
this.container.start();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
new SSLContextBuilder()
.loadTrustMaterial(null, new TrustSelfSignedStrategy()).build());
HttpClient httpClient = HttpClients.custom().setSSLSocketFactory(socketFactory)
.build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(
httpClient);
assertThat(getResponse(getLocalUrl("https", "/hello"), requestFactory))
.contains("scheme=https");
}
private String getStoreType(String keyStore) {
return (keyStore.endsWith(".p12") ? "pkcs12" : null);
}

@ -152,6 +152,56 @@ public class JettyEmbeddedServletContainerFactoryTests
});
}
@Test
public void sslEnabledMultiProtocolsConfiguration() throws Exception {
Ssl ssl = new Ssl();
ssl.setKeyStore("src/test/resources/test.jks");
ssl.setKeyStorePassword("secret");
ssl.setKeyPassword("password");
ssl.setCiphers(new String[] { "ALPHA", "BRAVO", "CHARLIE" });
ssl.setEnabledProtocols(new String[] { "TLSv1.1", "TLSv1.2" });
JettyEmbeddedServletContainerFactory factory = getFactory();
factory.setSsl(ssl);
this.container = factory.getEmbeddedServletContainer();
this.container.start();
JettyEmbeddedServletContainer jettyContainer = (JettyEmbeddedServletContainer) this.container;
ServerConnector connector = (ServerConnector) jettyContainer.getServer()
.getConnectors()[0];
SslConnectionFactory connectionFactory = connector
.getConnectionFactory(SslConnectionFactory.class);
assertThat(connectionFactory.getSslContextFactory().getIncludeProtocols())
.isEqualTo(new String[] { "TLSv1.1", "TLSv1.2" });
}
@Test
public void sslEnabledProtocolsConfiguration() throws Exception {
Ssl ssl = new Ssl();
ssl.setKeyStore("src/test/resources/test.jks");
ssl.setKeyStorePassword("secret");
ssl.setKeyPassword("password");
ssl.setCiphers(new String[] { "ALPHA", "BRAVO", "CHARLIE" });
ssl.setEnabledProtocols(new String[] { "TLSv1.1" });
JettyEmbeddedServletContainerFactory factory = getFactory();
factory.setSsl(ssl);
this.container = factory.getEmbeddedServletContainer();
this.container.start();
JettyEmbeddedServletContainer jettyContainer = (JettyEmbeddedServletContainer) this.container;
ServerConnector connector = (ServerConnector) jettyContainer.getServer()
.getConnectors()[0];
SslConnectionFactory connectionFactory = connector
.getConnectionFactory(SslConnectionFactory.class);
assertThat(connectionFactory.getSslContextFactory().getIncludeProtocols())
.isEqualTo(new String[] { "TLSv1.1" });
}
private void assertTimeout(JettyEmbeddedServletContainerFactory factory,
int expected) {
this.container = factory.getEmbeddedServletContainer();

@ -17,6 +17,7 @@
package org.springframework.boot.context.embedded.tomcat;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.HashMap;
@ -41,11 +42,13 @@ import org.mockito.InOrder;
import org.springframework.boot.context.embedded.AbstractEmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.AbstractEmbeddedServletContainerFactoryTests;
import org.springframework.boot.context.embedded.EmbeddedServletContainerException;
import org.springframework.boot.context.embedded.Ssl;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.util.SocketUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyObject;
@ -260,6 +263,78 @@ public class TomcatEmbeddedServletContainerFactoryTests
assertThat(jsseProtocol.getCiphers()).isEqualTo("ALPHA,BRAVO,CHARLIE");
}
@Test
public void sslEnabledMultipleProtocolsConfiguration() throws Exception {
Ssl ssl = new Ssl();
ssl.setKeyStore("test.jks");
ssl.setKeyStorePassword("secret");
ssl.setEnabledProtocols(new String[] { "TLSv1.1", "TLSv1.2" });
ssl.setCiphers(new String[] { "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "BRAVO" });
TomcatEmbeddedServletContainerFactory factory = getFactory();
factory.setSsl(ssl);
this.container = factory
.getEmbeddedServletContainer(sessionServletRegistration());
Tomcat tomcat = ((TomcatEmbeddedServletContainer) this.container).getTomcat();
Connector connector = tomcat.getConnector();
AbstractHttp11JsseProtocol<?> jsseProtocol = (AbstractHttp11JsseProtocol<?>) connector
.getProtocolHandler();
assertThat(jsseProtocol.getSslProtocol()).isEqualTo("TLS");
assertThat(jsseProtocol.getProperty("sslEnabledProtocols"))
.isEqualTo("TLSv1.1,TLSv1.2");
}
@Test
public void sslEnabledProtocolsConfiguration() throws Exception {
Ssl ssl = new Ssl();
ssl.setKeyStore("test.jks");
ssl.setKeyStorePassword("secret");
ssl.setEnabledProtocols(new String[] { "TLSv1.2" });
ssl.setCiphers(new String[] { "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "BRAVO" });
TomcatEmbeddedServletContainerFactory factory = getFactory();
factory.setSsl(ssl);
this.container = factory
.getEmbeddedServletContainer(sessionServletRegistration());
Tomcat tomcat = ((TomcatEmbeddedServletContainer) this.container).getTomcat();
Connector connector = tomcat.getConnector();
AbstractHttp11JsseProtocol<?> jsseProtocol = (AbstractHttp11JsseProtocol<?>) connector
.getProtocolHandler();
assertThat(jsseProtocol.getSslProtocol()).isEqualTo("TLS");
assertThat(jsseProtocol.getProperty("sslEnabledProtocols")).isEqualTo("TLSv1.2");
}
@Test
public void primaryConnectorPortClashThrowsIllegalStateException()
throws InterruptedException, IOException {
final int port = SocketUtils.findAvailableTcpPort(40000);
doWithBlockedPort(port, new Runnable() {
@Override
public void run() {
TomcatEmbeddedServletContainerFactory factory = getFactory();
factory.setPort(port);
try {
TomcatEmbeddedServletContainerFactoryTests.this.container = factory
.getEmbeddedServletContainer();
TomcatEmbeddedServletContainerFactoryTests.this.container.start();
fail();
}
catch (EmbeddedServletContainerException ex) {
// Ignore
}
}
});
}
@Override
protected void addConnector(int port,
AbstractEmbeddedServletContainerFactory factory) {

@ -26,6 +26,8 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import javax.net.ssl.SSLHandshakeException;
import io.undertow.Undertow.Builder;
import io.undertow.servlet.api.DeploymentInfo;
import io.undertow.servlet.api.DeploymentManager;
@ -201,6 +203,36 @@ public class UndertowEmbeddedServletContainerFactoryTests
});
}
@Test(expected = SSLHandshakeException.class)
public void sslRestrictedProtocolsEmptyCipherFailure() throws Exception {
testRestrictedSSLProtocolsAndCipherSuites(new String[] { "TLSv1.2" },
new String[] { "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" });
}
@Test(expected = SSLHandshakeException.class)
public void sslRestrictedProtocolsECDHETLS1Failure() throws Exception {
testRestrictedSSLProtocolsAndCipherSuites(new String[] { "TLSv1" },
new String[] { "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256" });
}
@Test
public void sslRestrictedProtocolsECDHESuccess() throws Exception {
testRestrictedSSLProtocolsAndCipherSuites(new String[] { "TLSv1.2" },
new String[] { "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256" });
}
@Test
public void sslRestrictedProtocolsRSATLS12Success() throws Exception {
testRestrictedSSLProtocolsAndCipherSuites(new String[] { "TLSv1.2" },
new String[] { "TLS_RSA_WITH_AES_128_CBC_SHA256" });
}
@Test(expected = SSLHandshakeException.class)
public void sslRestrictedProtocolsRSATLS11Failure() throws Exception {
testRestrictedSSLProtocolsAndCipherSuites(new String[] { "TLSv1.1" },
new String[] { "TLS_RSA_WITH_AES_128_CBC_SHA256" });
}
@Override
protected Object getJspServlet() {
return null; // Undertow does not support JSPs

Loading…
Cancel
Save