SSL: Re-enabling configuration option to disable client auth

In order to not require client side SSL certs for transport clients
another option was added in the profile configuration to enable
or disable client side certs. The same option has also been added
for HTTP.

Original commit: elastic/x-pack-elasticsearch@9658598bdc
This commit is contained in:
Alexander Reelsen 2014-12-02 13:39:03 +01:00
parent 1c54bf0d2e
commit 8bcbc690ce
4 changed files with 129 additions and 16 deletions

View File

@ -74,24 +74,14 @@ public class SSLService extends AbstractComponent {
return sslContext.getSocketFactory();
}
/**
* This engine is configured with a trust manager and a keystore that should have only one private key.
* Four possible usages for elasticsearch exist:
* Node-to-Node outbound:
* - sslEngine.setUseClientMode(true)
* Node-to-Node inbound:
* - sslEngine.setUseClientMode(false)
* - sslEngine.setNeedClientAuth(true)
* Client-to-Node:
* - sslEngine.setUseClientMode(true)
* Http Client-to-Node (inbound):
* - sslEngine.setUserClientMode(false)
* - sslEngine.setNeedClientAuth(false)
*/
public SSLEngine createSSLEngine() {
return createSSLEngine(this.sslContext);
}
public SSLContext getSslContext() {
return sslContext;
}
public SSLEngine createSSLEngineWithTruststore(Settings settings) {
String trustStore = settings.get("truststore.path", System.getProperty("javax.net.ssl.trustStore"));
String trustStorePassword = settings.get("truststore.password", System.getProperty("javax.net.ssl.trustStorePassword"));

View File

@ -54,7 +54,7 @@ public class NettySecuredHttpServerTransport extends NettyHttpServerTransport {
if (sslService != null) {
SSLEngine engine = sslService.createSSLEngine();
engine.setUseClientMode(false);
engine.setNeedClientAuth(false);
engine.setNeedClientAuth(settings.getAsBoolean("shield.http.ssl.client.auth", false));
pipeline.addFirst("ssl", new SslHandler(engine));
}

View File

@ -69,7 +69,7 @@ public class NettySecuredTransport extends NettyTransport {
serverEngine = sslService.createSSLEngine();
}
serverEngine.setUseClientMode(false);
serverEngine.setNeedClientAuth(true);
serverEngine.setNeedClientAuth(profileSettings.getAsBoolean("shield.ssl.client.auth", settings.getAsBoolean("shield.transport.ssl.client.auth", true)));
pipeline.addFirst("ssl", new SslHandler(serverEngine));
pipeline.replace("dispatcher", "dispatcher", new SecuredMessageChannelHandler(nettyTransport, logger));

View File

@ -0,0 +1,123 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.shield.transport.ssl;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.http.HttpServerTransport;
import org.elasticsearch.node.internal.InternalNode;
import org.elasticsearch.shield.ssl.SSLService;
import org.elasticsearch.shield.ssl.SSLServiceProvider;
import org.elasticsearch.test.ShieldIntegrationTest;
import org.elasticsearch.test.ShieldSettingsSource;
import org.elasticsearch.test.rest.client.http.HttpRequestBuilder;
import org.elasticsearch.test.rest.client.http.HttpResponse;
import org.elasticsearch.transport.Transport;
import org.junit.Test;
import javax.net.ssl.SSLHandshakeException;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
import static org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope;
import static org.hamcrest.Matchers.containsString;
@ClusterScope(scope = Scope.SUITE)
public class SslClientAuthTests extends ShieldIntegrationTest {
@Override
protected Settings nodeSettings(int nodeOrdinal) {
return settingsBuilder()
.put(super.nodeSettings(nodeOrdinal))
// invert the require auth settings
.put("shield.transport.ssl", true)
.put("shield.http.ssl", true)
.put("shield.http.ssl.client.auth", true)
.put("transport.profiles.default.shield.ssl.client.auth", false)
.put(InternalNode.HTTP_ENABLED, true)
.build();
}
@Override
protected boolean sslTransportEnabled() {
return true;
}
@Test(expected = SSLHandshakeException.class)
public void testThatHttpFailsWithoutSslClientAuth() throws IOException {
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
SSLContexts.createDefault(),
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
CloseableHttpClient client = HttpClients.custom().setSSLSocketFactory(socketFactory).build();
new HttpRequestBuilder(client)
.httpTransport(internalCluster().getInstance(HttpServerTransport.class))
.method("GET").path("/")
.protocol("https")
.execute();
}
@Test
public void testThatHttpWorksWithSslClientAuth() throws IOException {
Settings settings = settingsBuilder().put(ShieldSettingsSource.getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.jks", "testclient")).build();
SSLService sslService = new SSLServiceProvider(settings).get();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
sslService.getSslContext(),
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
CloseableHttpClient client = HttpClients.custom().setSSLSocketFactory(socketFactory).build();
HttpResponse response = new HttpRequestBuilder(client)
.httpTransport(internalCluster().getInstance(HttpServerTransport.class))
.method("GET").path("/")
.protocol("https")
.addHeader("Authorization", basicAuthHeaderValue(transportClientUsername(), transportClientPassword()))
.execute();
assertThat(response.getBody(), containsString("You Know, for Search"));
}
@Test
public void testThatTransportWorksWithoutSslClientAuth() throws Exception {
// specify an arbitrary keystore, that does not include the certs needed to connect to the transport protocol
File store;
try {
store = new File(ShieldSettingsSource.class.getResource("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient-client-profile.jks").toURI());
} catch (URISyntaxException e) {
throw new ElasticsearchException("exception while reading the store", e);
}
if (!store.exists()) {
throw new ElasticsearchException("store path doesn't exist");
}
Settings settings = settingsBuilder()
.put("shield.transport.ssl", true)
.put("shield.ssl.keystore.path", store.getPath())
.put("shield.ssl.keystore.password", "testclient-client-profile")
.put("cluster.name", internalCluster().getClusterName())
.put("shield.user", transportClientUsername() + ":" + new String(transportClientPassword().internalChars()))
.build();
try (TransportClient client = new TransportClient(settings)) {
Transport transport = internalCluster().getDataNodeInstance(Transport.class);
TransportAddress transportAddress = transport.boundAddress().publishAddress();
client.addTransportAddress(transportAddress);
assertGreenClusterState(client);
}
}
}