allow for the Environment to be optional in the ClientSSLService

This change makes the environment optional for the ClientSSLService, which is used for
Transport Clients and also used for LDAP client connections. Since we use the ClientSSLService
for LDAP connections, we still need the environment when running as a node under the
security manager to resolve paths from the configuration directory.

Closes elastic/elasticsearch#573

Original commit: elastic/x-pack-elasticsearch@862fafffe3
This commit is contained in:
jaymode 2015-09-03 10:13:53 -04:00
parent e17b3894d3
commit 94dbf3f2a7
12 changed files with 84 additions and 51 deletions

View File

@ -24,6 +24,7 @@ import java.io.InputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.Arrays;
@ -46,8 +47,8 @@ public abstract class AbstractSSLService extends AbstractComponent {
static final int DEFAULT_SESSION_CACHE_SIZE = 1000;
static final String DEFAULT_PROTOCOL = "TLSv1.2";
protected final Environment env;
protected final LoadingCache<SSLSettings, SSLContext> sslContexts = CacheBuilder.newBuilder().build(new SSLContextCacheLoader());
protected Environment env;
public AbstractSSLService(Settings settings, Environment environment) {
super(settings);
@ -174,6 +175,10 @@ public abstract class AbstractSSLService extends AbstractComponent {
return requestedCiphersList.toArray(new String[requestedCiphersList.size()]);
}
protected Path resolvePath(String location) {
return env.configFile().resolve(location);
}
private class SSLContextCacheLoader extends CacheLoader<SSLSettings, SSLContext> {
@Override
@ -238,7 +243,7 @@ public abstract class AbstractSSLService extends AbstractComponent {
}
private KeyStore readKeystore(String path, String password) throws Exception {
try (InputStream in = Files.newInputStream(env.binFile().getParent().resolve(path))) {
try (InputStream in = Files.newInputStream(resolvePath(path))) {
// Load TrustStore
KeyStore ks = KeyStore.getInstance("jks");
assert password != null;

View File

@ -5,15 +5,26 @@
*/
package org.elasticsearch.shield.ssl;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.io.PathUtils;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import java.nio.file.Path;
@SuppressForbidden(reason = "we don't have the environment to resolve files from when running in a transport client")
public class ClientSSLService extends AbstractSSLService {
@Inject
public ClientSSLService(Settings settings, Environment environment) {
super(settings, environment);
public ClientSSLService(Settings settings) {
super(settings, null);
}
@Inject(optional = true)
public void setEnvironment(Environment environment) {
this.env = environment;
}
@Override
@ -34,4 +45,12 @@ public class ClientSSLService extends AbstractSSLService {
return sslSettings;
}
@Override
protected Path resolvePath(String location) {
if (env == null) {
return PathUtils.get(Strings.cleanPath(location));
}
return super.resolvePath(location);
}
}

View File

@ -43,7 +43,8 @@ public class ActiveDirectoryGroupsResolverTests extends ESTestCase {
ClientSSLService clientSSLService = new ClientSSLService(Settings.builder()
.put("shield.ssl.keystore.path", keystore)
.put("shield.ssl.keystore.password", "changeit")
.build(), env);
.build());
clientSSLService.setEnvironment(env);
LDAPURL ldapurl = new LDAPURL(ActiveDirectorySessionFactoryTests.AD_LDAP_URL);
LDAPConnectionOptions options = new LDAPConnectionOptions();

View File

@ -51,7 +51,8 @@ public class ActiveDirectorySessionFactoryTests extends ESTestCase {
clientSSLService = new ClientSSLService(Settings.builder()
.put("shield.ssl.keystore.path", keystore)
.put("shield.ssl.keystore.password", "changeit")
.build(), env);
.build());
clientSSLService.setEnvironment(env);
globalSettings = Settings.builder().put("path.home", createTempDir()).build();
}

View File

@ -63,7 +63,8 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
clientSSLService = new ClientSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", keystore)
.put("shield.ssl.keystore.password", "changeit")
.build(), env);
.build());
clientSSLService.setEnvironment(env);
globalSettings = settingsBuilder().put("path.home", createTempDir()).build();
}

View File

@ -48,7 +48,8 @@ public class OpenLdapTests extends ESTestCase {
clientSSLService = new ClientSSLService(Settings.builder()
.put("shield.ssl.keystore.path", keystore)
.put("shield.ssl.keystore.password", "changeit")
.build(), env);
.build());
clientSSLService.setEnvironment(env);
globalSettings = Settings.builder().put("path.home", createTempDir()).build();
}

View File

@ -43,7 +43,8 @@ public class SearchGroupsResolverTests extends ESTestCase {
ClientSSLService clientSSLService = new ClientSSLService(Settings.builder()
.put("shield.ssl.keystore.path", keystore)
.put("shield.ssl.keystore.password", "changeit")
.build(), env);
.build());
clientSSLService.setEnvironment(env);
LDAPURL ldapurl = new LDAPURL(OpenLdapTests.OPEN_LDAP_URL);
LDAPConnectionOptions options = new LDAPConnectionOptions();

View File

@ -41,7 +41,8 @@ public class UserAttributeGroupsResolverTests extends ESTestCase {
ClientSSLService clientSSLService = new ClientSSLService(Settings.builder()
.put("shield.ssl.keystore.path", keystore)
.put("shield.ssl.keystore.password", "changeit")
.build(), env);
.build());
clientSSLService.setEnvironment(env);
LDAPURL ldapurl = new LDAPURL(ActiveDirectorySessionFactoryTests.AD_LDAP_URL);
LDAPConnectionOptions options = new LDAPConnectionOptions();

View File

@ -34,7 +34,7 @@ public class ClientSSLServiceTests extends ESTestCase {
@Before
public void setup() throws Exception {
testclientStore = getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.jks");
env = new Environment(settingsBuilder().put("path.home", createTempDir()).build());
env = randomBoolean() ? new Environment(settingsBuilder().put("path.home", createTempDir()).build()) : null;
}
@Test
@ -46,7 +46,7 @@ public class ClientSSLServiceTests extends ESTestCase {
.put("shield.ssl.keystore.password", "testclient")
.put("shield.ssl.truststore.path", testclientStore)
.put("shield.ssl.truststore.password", "testclient")
.build(), env).createSSLEngine();
.build()).createSSLEngine();
fail("expected an exception");
} catch (ElasticsearchException e) {
assertThat(e.getMessage(), containsString("failed to initialize the SSLContext"));
@ -57,10 +57,10 @@ public class ClientSSLServiceTests extends ESTestCase {
public void testThatCustomTruststoreCanBeSpecified() throws Exception {
Path testnodeStore = getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.jks");
ClientSSLService sslService = new ClientSSLService(settingsBuilder()
ClientSSLService sslService = createClientSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testclientStore)
.put("shield.ssl.keystore.password", "testclient")
.build(), env);
.build());
Settings.Builder settingsBuilder = settingsBuilder()
.put("truststore.path", testnodeStore)
@ -75,10 +75,10 @@ public class ClientSSLServiceTests extends ESTestCase {
@Test
public void testThatSslContextCachingWorks() throws Exception {
ClientSSLService sslService = new ClientSSLService(settingsBuilder()
ClientSSLService sslService = createClientSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testclientStore)
.put("shield.ssl.keystore.password", "testclient")
.build(), env);
.build());
SSLContext sslContext = sslService.sslContext();
SSLContext cachedSslContext = sslService.sslContext();
@ -89,21 +89,21 @@ public class ClientSSLServiceTests extends ESTestCase {
@Test
public void testThatKeyStoreAndKeyCanHaveDifferentPasswords() throws Exception {
Path differentPasswordsStore = getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode-different-passwords.jks");
new ClientSSLService(settingsBuilder()
createClientSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", differentPasswordsStore)
.put("shield.ssl.keystore.password", "testnode")
.put("shield.ssl.keystore.key_password", "testnode1")
.build(), env).createSSLEngine();
.build()).createSSLEngine();
}
@Test
public void testIncorrectKeyPasswordThrowsException() throws Exception {
Path differentPasswordsStore = getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode-different-passwords.jks");
try {
new ClientSSLService(settingsBuilder()
createClientSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", differentPasswordsStore)
.put("shield.ssl.keystore.password", "testnode")
.build(), env).createSSLEngine();
.build()).createSSLEngine();
fail("expected an exception");
} catch (ElasticsearchException e) {
assertThat(e.getMessage(), containsString("failed to initialize a KeyManagerFactory"));
@ -112,20 +112,20 @@ public class ClientSSLServiceTests extends ESTestCase {
@Test
public void testThatSSLv3IsNotEnabled() throws Exception {
ClientSSLService sslService = new ClientSSLService(settingsBuilder()
ClientSSLService sslService = createClientSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testclientStore)
.put("shield.ssl.keystore.password", "testclient")
.build(), env);
.build());
SSLEngine engine = sslService.createSSLEngine();
assertThat(Arrays.asList(engine.getEnabledProtocols()), not(hasItem("SSLv3")));
}
@Test
public void testThatSSLSessionCacheHasDefaultLimits() throws Exception {
ClientSSLService sslService = new ClientSSLService(settingsBuilder()
ClientSSLService sslService = createClientSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testclientStore)
.put("shield.ssl.keystore.password", "testclient")
.build(), env);
.build());
SSLSessionContext context = sslService.sslContext().getServerSessionContext();
assertThat(context.getSessionCacheSize(), equalTo(1000));
assertThat(context.getSessionTimeout(), equalTo((int) TimeValue.timeValueHours(24).seconds()));
@ -133,12 +133,12 @@ public class ClientSSLServiceTests extends ESTestCase {
@Test
public void testThatSettingSSLSessionCacheLimitsWorks() throws Exception {
ClientSSLService sslService = new ClientSSLService(settingsBuilder()
ClientSSLService sslService = createClientSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testclientStore)
.put("shield.ssl.keystore.password", "testclient")
.put("shield.ssl.session.cache_size", "300")
.put("shield.ssl.session.cache_timeout", "600s")
.build(), env);
.build());
SSLSessionContext context = sslService.sslContext().getServerSessionContext();
assertThat(context.getSessionCacheSize(), equalTo(300));
assertThat(context.getSessionTimeout(), equalTo(600));
@ -146,27 +146,27 @@ public class ClientSSLServiceTests extends ESTestCase {
@Test
public void testThatCreateClientSSLEngineWithoutAnySettingsWorks() throws Exception {
ClientSSLService sslService = new ClientSSLService(Settings.EMPTY, env);
ClientSSLService sslService = createClientSSLService(Settings.EMPTY);
SSLEngine sslEngine = sslService.createSSLEngine();
assertThat(sslEngine, notNullValue());
}
@Test
public void testThatCreateSSLEngineWithOnlyTruststoreWorks() throws Exception {
ClientSSLService sslService = new ClientSSLService(settingsBuilder()
ClientSSLService sslService = createClientSSLService(settingsBuilder()
.put("shield.ssl.truststore.path", testclientStore)
.put("shield.ssl.truststore.password", "testclient")
.build(), env);
.build());
SSLEngine sslEngine = sslService.createSSLEngine();
assertThat(sslEngine, notNullValue());
}
@Test
public void testThatCreateSSLEngineWithOnlyKeystoreWorks() throws Exception {
ClientSSLService sslService = new ClientSSLService(settingsBuilder()
ClientSSLService sslService = createClientSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testclientStore)
.put("shield.ssl.keystore.password", "testclient")
.build(), env);
.build());
SSLEngine sslEngine = sslService.createSSLEngine();
assertThat(sslEngine, notNullValue());
}
@ -174,7 +174,7 @@ public class ClientSSLServiceTests extends ESTestCase {
@Test
@Network
public void testThatSSLContextWithoutSettingsWorks() throws Exception {
ClientSSLService sslService = new ClientSSLService(Settings.EMPTY, env);
ClientSSLService sslService = createClientSSLService(Settings.EMPTY);
SSLContext sslContext = sslService.sslContext();
try (CloseableHttpClient client = HttpClients.custom().setSslcontext(sslContext).build()) {
// Execute a GET on a site known to have a valid certificate signed by a trusted public CA
@ -187,10 +187,10 @@ public class ClientSSLServiceTests extends ESTestCase {
@Test
@Network
public void testThatSSLContextWithKeystoreDoesNotTrustAllPublicCAs() throws Exception {
ClientSSLService sslService = new ClientSSLService(settingsBuilder()
ClientSSLService sslService = createClientSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testclientStore)
.put("shield.ssl.keystore.password", "testclient")
.build(), env);
.build());
SSLContext sslContext = sslService.sslContext();
try (CloseableHttpClient client = HttpClients.custom().setSslcontext(sslContext).build()) {
// Execute a GET on a site known to have a valid certificate signed by a trusted public CA
@ -205,17 +205,17 @@ public class ClientSSLServiceTests extends ESTestCase {
@Test(expected = IllegalArgumentException.class)
public void testThatTruststorePasswordIsRequired() throws Exception {
ClientSSLService sslService = new ClientSSLService(settingsBuilder()
ClientSSLService sslService = createClientSSLService(settingsBuilder()
.put("shield.ssl.truststore.path", testclientStore)
.build(), env);
.build());
sslService.sslContext();
}
@Test(expected = IllegalArgumentException.class)
public void testThatKeystorePasswordIsRequired() throws Exception {
ClientSSLService sslService = new ClientSSLService(settingsBuilder()
ClientSSLService sslService = createClientSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testclientStore)
.build(), env);
.build());
sslService.sslContext();
}
@ -224,9 +224,9 @@ public class ClientSSLServiceTests extends ESTestCase {
List<String> ciphers = new ArrayList<>(Arrays.asList(AbstractSSLService.DEFAULT_CIPHERS));
ciphers.add("foo");
ciphers.add("bar");
ClientSSLService sslService = new ClientSSLService(settingsBuilder()
ClientSSLService sslService = createClientSSLService(settingsBuilder()
.putArray("shield.ssl.ciphers", ciphers.toArray(new String[ciphers.size()]))
.build(), env);
.build());
SSLEngine engine = sslService.createSSLEngine();
assertThat(engine, is(notNullValue()));
String[] enabledCiphers = engine.getEnabledCipherSuites();
@ -235,18 +235,18 @@ public class ClientSSLServiceTests extends ESTestCase {
@Test(expected = IllegalArgumentException.class)
public void invalidCiphersOnlyThrowsException() throws Exception {
ClientSSLService sslService = new ClientSSLService(settingsBuilder()
ClientSSLService sslService = createClientSSLService(settingsBuilder()
.putArray("shield.ssl.ciphers", new String[] { "foo", "bar" })
.build(), env);
.build());
sslService.createSSLEngine();
}
@Test
public void testThatSSLSocketFactoryHasProperCiphersAndProtocols() throws Exception {
ClientSSLService sslService = new ClientSSLService(settingsBuilder()
ClientSSLService sslService = createClientSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testclientStore)
.put("shield.ssl.keystore.password", "testclient")
.build(), env);
.build());
SSLSocketFactory factory = sslService.sslSocketFactory();
assertThat(factory.getDefaultCipherSuites(), is(sslService.ciphers()));
@ -255,4 +255,10 @@ public class ClientSSLServiceTests extends ESTestCase {
assertThat(socket.getEnabledProtocols(), is(sslService.supportedProtocols()));
}
}
ClientSSLService createClientSSLService(Settings settings) {
ClientSSLService clientSSLService = new ClientSSLService(settings);
clientSSLService.setEnvironment(env);
return clientSSLService;
}
}

View File

@ -49,7 +49,8 @@ public class ShieldNettyTransportTests extends ESTestCase {
Environment env = new Environment(settingsBuilder().put("path.home", createTempDir()).build());
settingsFilter = new ShieldSettingsFilter(settings, new SettingsFilter(settings));
serverSSLService = new ServerSSLService(settings, settingsFilter, env);
clientSSLService = new ClientSSLService(settings, env);
clientSSLService = new ClientSSLService(settings);
clientSSLService.setEnvironment(env);
}
@Test

View File

@ -13,7 +13,6 @@ 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.env.Environment;
import org.elasticsearch.http.HttpServerTransport;
import org.elasticsearch.node.Node;
import org.elasticsearch.shield.ShieldPlugin;
@ -73,8 +72,7 @@ public class SslClientAuthTests extends ShieldIntegTestCase {
@Test
public void testThatHttpWorksWithSslClientAuth() throws IOException {
Settings settings = settingsBuilder().put(ShieldSettingsSource.getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.jks", "testclient")).build();
Environment env = new Environment(settingsBuilder().put("path.home", createTempDir()).build());
ClientSSLService sslService = new ClientSSLService(settings, env);
ClientSSLService sslService = new ClientSSLService(settings);
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
sslService.sslContext(),

View File

@ -21,7 +21,6 @@ import org.elasticsearch.common.io.Streams;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.env.Environment;
import org.elasticsearch.http.HttpServerTransport;
import org.elasticsearch.node.Node;
import org.elasticsearch.shield.ssl.ClientSSLService;
@ -95,8 +94,7 @@ public class SslIntegrationTests extends ShieldIntegTestCase {
@Test
public void testThatConnectionToHTTPWorks() throws Exception {
Settings settings = ShieldSettingsSource.getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.jks", "testclient");
Environment env = new Environment(settingsBuilder().put("path.home", createTempDir()).build());
ClientSSLService service = new ClientSSLService(settings, env);
ClientSSLService service = new ClientSSLService(settings);
CredentialsProvider provider = new BasicCredentialsProvider();
provider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(nodeClientUsername(), new String(nodeClientPassword().internalChars())));