Introduced settings filtering

Enables filtering out sensitive settings from the nodes info API rest endpoint. Also provide a mechanism to filter out additional settings via a new `shield.hide_settings` setting.

Original commit: elastic/x-pack-elasticsearch@9bab5049e7
This commit is contained in:
uboness 2015-03-14 13:42:09 -07:00
parent 5ba1bdb816
commit 3015ebccdb
20 changed files with 367 additions and 63 deletions

View File

@ -12,9 +12,9 @@ import org.elasticsearch.shield.action.ShieldActionModule;
import org.elasticsearch.shield.audit.AuditTrailModule;
import org.elasticsearch.shield.authc.AuthenticationModule;
import org.elasticsearch.shield.authz.AuthorizationModule;
import org.elasticsearch.shield.signature.SignatureModule;
import org.elasticsearch.shield.rest.ShieldRestModule;
import org.elasticsearch.shield.license.LicenseModule;
import org.elasticsearch.shield.rest.ShieldRestModule;
import org.elasticsearch.shield.signature.SignatureModule;
import org.elasticsearch.shield.ssl.SSLModule;
import org.elasticsearch.shield.support.AbstractShieldModule;
import org.elasticsearch.shield.transport.ShieldTransportModule;
@ -54,5 +54,8 @@ public class ShieldModule extends AbstractShieldModule.Spawn {
@Override
protected void configure(boolean clientMode) {
if (!clientMode) {
bind(ShieldSettingsFilter.class).asEagerSingleton();
}
}
}

View File

@ -0,0 +1,54 @@
/*
* 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;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsFilter;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
/**
*
*/
public class ShieldSettingsFilter extends AbstractComponent implements SettingsFilter.Filter {
static final String HIDE_SETTINGS_SETTING = "shield.hide_settings";
private final Set<String> removePatterns;
@Inject
public ShieldSettingsFilter(Settings settings, SettingsFilter settingsFilter) {
super(settings);
settingsFilter.addFilter(this);
this.removePatterns = new CopyOnWriteArraySet<>();
removePatterns.add(HIDE_SETTINGS_SETTING);
Collections.addAll(removePatterns, settings.getAsArray(HIDE_SETTINGS_SETTING));
}
public void filterOut(String... patterns) {
Collections.addAll(removePatterns, patterns);
}
@Override
public void filter(ImmutableSettings.Builder settings) {
for (Iterator<Map.Entry<String, String>> iter = settings.internalMap().entrySet().iterator(); iter.hasNext();) {
Map.Entry<String, String> setting = iter.next();
for (String regexp : removePatterns) {
if (Regex.simpleMatch(regexp, setting.getKey())) {
iter.remove();
}
}
}
}
}

View File

@ -7,6 +7,7 @@ package org.elasticsearch.shield.authc;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.shield.ShieldSettingsFilter;
import org.elasticsearch.shield.User;
import org.elasticsearch.transport.TransportMessage;
@ -115,6 +116,9 @@ public abstract class Realm<T extends AuthenticationToken> implements Comparable
return internal;
}
public void filterOutSensitiveSettings(String realmName, ShieldSettingsFilter filter) {
}
/**
* Creates a new realm based on the given settigns.
*

View File

@ -14,6 +14,7 @@ import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.shield.ShieldSettingsException;
import org.elasticsearch.shield.ShieldSettingsFilter;
import org.elasticsearch.shield.authc.esusers.ESUsersRealm;
import java.util.*;
@ -26,14 +27,16 @@ public class Realms extends AbstractLifecycleComponent<Realms> implements Iterab
private final Environment env;
private final Map<String, Realm.Factory> factories;
private final ShieldSettingsFilter settingsFilter;
private List<Realm> realms = Collections.emptyList();
@Inject
public Realms(Settings settings, Environment env, Map<String, Realm.Factory> factories) {
public Realms(Settings settings, Environment env, Map<String, Realm.Factory> factories, ShieldSettingsFilter settingsFilter) {
super(settings);
this.env = env;
this.factories = factories;
this.settingsFilter = settingsFilter;
}
@Override
@ -79,6 +82,7 @@ public class Realms extends AbstractLifecycleComponent<Realms> implements Iterab
if (factory == null) {
throw new ShieldSettingsException("unknown realm type [" + type + "] set for realm [" + name + "]");
}
factory.filterOutSensitiveSettings(name, settingsFilter);
RealmConfig config = new RealmConfig(name, realmSettings, settings, env);
if (!config.enabled()) {
if (logger.isDebugEnabled()) {

View File

@ -11,16 +11,17 @@ import org.elasticsearch.common.primitives.Ints;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.shield.ShieldSettingsException;
import org.elasticsearch.shield.authc.RealmConfig;
import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.shield.authc.ldap.support.LdapSearchScope;
import org.elasticsearch.shield.authc.ldap.support.LdapSession;
import org.elasticsearch.shield.authc.ldap.support.LdapSession.GroupsResolver;
import org.elasticsearch.shield.authc.ldap.support.SessionFactory;
import org.elasticsearch.shield.authc.ldap.support.LdapSearchScope;
import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.shield.ssl.ClientSSLService;
import javax.net.SocketFactory;
import static org.elasticsearch.shield.authc.ldap.support.LdapUtils.*;
import static org.elasticsearch.shield.authc.ldap.support.LdapUtils.createFilter;
import static org.elasticsearch.shield.authc.ldap.support.LdapUtils.search;
/**
* This Class creates LdapSessions authenticating via the custom Active Directory protocol. (that being

View File

@ -9,6 +9,7 @@ import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.shield.ShieldSettingsException;
import org.elasticsearch.shield.ShieldSettingsFilter;
import org.elasticsearch.shield.authc.RealmConfig;
import org.elasticsearch.shield.authc.ldap.support.AbstractLdapRealm;
import org.elasticsearch.shield.authc.ldap.support.LdapRoleMapper;
@ -39,6 +40,11 @@ public class LdapRealm extends AbstractLdapRealm {
this.clientSSLService = clientSSLService;
}
@Override
public void filterOutSensitiveSettings(String realmName, ShieldSettingsFilter filter) {
LdapUserSearchSessionFactory.filterOutSensitiveSettings(realmName, filter);
}
@Override
public LdapRealm create(RealmConfig config) {
SessionFactory sessionFactory = sessionFactory(config, clientSSLService);

View File

@ -9,10 +9,10 @@ import com.unboundid.ldap.sdk.*;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.shield.ShieldSettingsException;
import org.elasticsearch.shield.authc.RealmConfig;
import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.shield.authc.ldap.support.LdapSession;
import org.elasticsearch.shield.authc.ldap.support.LdapSession.GroupsResolver;
import org.elasticsearch.shield.authc.ldap.support.SessionFactory;
import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.shield.ssl.ClientSSLService;
import javax.net.SocketFactory;

View File

@ -7,11 +7,11 @@ package org.elasticsearch.shield.authc.ldap;
import com.unboundid.ldap.sdk.*;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.primitives.Ints;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.shield.ShieldSettingsException;
import org.elasticsearch.shield.ShieldSettingsFilter;
import org.elasticsearch.shield.authc.RealmConfig;
import org.elasticsearch.shield.authc.ldap.support.LdapSearchScope;
import org.elasticsearch.shield.authc.ldap.support.LdapSession;
@ -21,7 +21,6 @@ import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.shield.ssl.ClientSSLService;
import javax.net.SocketFactory;
import java.util.Locale;
import static com.unboundid.ldap.sdk.Filter.createEqualityFilter;
@ -54,6 +53,14 @@ public class LdapUserSearchSessionFactory extends SessionFactory {
serverSet = serverSet(settings, sslService);
connectionPool = connectionPool(config.settings(), serverSet, timeout);
groupResolver = groupResolver(settings);
}
static void filterOutSensitiveSettings(String realmName, ShieldSettingsFilter filter) {
filter.filterOut("shield.authc.realms." + realmName + ".bind_dn");
filter.filterOut("shield.authc.realms." + realmName + ".bind_password");
filter.filterOut("shield.authc.realms." + realmName + ".hostname_verification");
}
static LDAPConnectionPool connectionPool(Settings settings, ServerSet serverSet, TimeValue timeout) {

View File

@ -8,7 +8,6 @@ package org.elasticsearch.shield.authc.ldap.support;
import com.unboundid.ldap.sdk.LDAPConnectionOptions;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.LDAPURL;
import com.unboundid.ldap.sdk.ServerSet;
import com.unboundid.util.ssl.HostNameSSLSocketVerifier;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.logging.ESLogger;
@ -18,7 +17,6 @@ import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.shield.ShieldSettingsException;
import org.elasticsearch.shield.authc.RealmConfig;
import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.shield.ssl.ClientSSLService;
import java.util.regex.Pattern;

View File

@ -33,8 +33,12 @@ import java.util.List;
*/
public abstract class AbstractSSLService extends AbstractComponent {
public static final String CIPHERS_SETTING = "ciphers";
public static final String SUPPORTED_PROTOCOLS_SETTING = "supported_protocols";
public static final String[] DEFAULT_SUPPORTED_PROTOCOLS = new String[] { "TLSv1", "TLSv1.1", "TLSv1.2" };
static final String[] DEFAULT_CIPHERS = new String[] { "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA" };
static final String[] DEFAULT_SUPPORTED_PROTOCOLS = new String[] { "TLSv1", "TLSv1.1", "TLSv1.2" };
static final TimeValue DEFAULT_SESSION_CACHE_TIMEOUT = TimeValue.timeValueHours(24);
static final int DEFAULT_SESSION_CACHE_SIZE = 1000;
static final String DEFAULT_PROTOCOL = "TLS";
@ -53,11 +57,11 @@ public abstract class AbstractSSLService extends AbstractComponent {
}
public String[] supportedProtocols() {
return componentSettings.getAsArray("supported_protocols", DEFAULT_SUPPORTED_PROTOCOLS);
return componentSettings.getAsArray(SUPPORTED_PROTOCOLS_SETTING, DEFAULT_SUPPORTED_PROTOCOLS);
}
public String[] ciphers() {
return componentSettings.getAsArray("ciphers", DEFAULT_CIPHERS);
return componentSettings.getAsArray(CIPHERS_SETTING, DEFAULT_CIPHERS);
}
public SSLEngine createSSLEngine() {
@ -69,8 +73,8 @@ public abstract class AbstractSSLService extends AbstractComponent {
}
public SSLEngine createSSLEngine(Settings settings, String host, int port) {
String[] ciphers = settings.getAsArray("ciphers", ciphers());
String[] supportedProtocols = settings.getAsArray("supported_protocols", supportedProtocols());
String[] ciphers = settings.getAsArray(CIPHERS_SETTING, ciphers());
String[] supportedProtocols = settings.getAsArray(SUPPORTED_PROTOCOLS_SETTING, supportedProtocols());
return createSSLEngine(sslContext(settings), ciphers, supportedProtocols, host, port);
}
@ -92,6 +96,26 @@ public abstract class AbstractSSLService extends AbstractComponent {
}
}
/**
* @return The list of sensitive settings. (these settings shouldnot be exposed via rest API for example)
*/
public static String[] sensitiveSettings() {
return new String[] {
CIPHERS_SETTING,
SUPPORTED_PROTOCOLS_SETTING,
"protocol",
"session.cache_size",
"session.cache_timeout",
"keystore.path",
"keystore.password",
"keystore.algorithm",
"keystore.key_password",
"truststore.path",
"truststore.password",
"truststore.algorithm"
};
}
protected abstract SSLSettings sslSettings(Settings customSettings);
SSLEngine createSSLEngine(SSLContext sslContext, String[] ciphers, String[] supportedProtocols, String host, int port) {
@ -219,7 +243,7 @@ public abstract class AbstractSSLService extends AbstractComponent {
}
static class SSLSettings {
public static class SSLSettings {
private static final ESLogger logger = Loggers.getLogger(SSLSettings.class);

View File

@ -8,12 +8,17 @@ package org.elasticsearch.shield.ssl;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.shield.ShieldSettingsException;
import org.elasticsearch.shield.ShieldSettingsFilter;
public class ServerSSLService extends AbstractSSLService {
@Inject
public ServerSSLService(Settings settings) {
public ServerSSLService(Settings settings, ShieldSettingsFilter settingsFilter) {
super(settings);
// we need to filter out all this sensitive information from all rest
// responses
settingsFilter.filterOut("shield.ssl.*");
}
@Override

View File

@ -14,6 +14,7 @@ import org.elasticsearch.common.network.NetworkService;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.BigArrays;
import org.elasticsearch.shield.ShieldSettingsFilter;
import org.elasticsearch.shield.ssl.ClientSSLService;
import org.elasticsearch.shield.ssl.ServerSSLService;
import org.elasticsearch.shield.transport.filter.IPFilter;
@ -34,17 +35,20 @@ public class ShieldNettyTransport extends NettyTransport {
private final ServerSSLService serverSslService;
private final ClientSSLService clientSSLService;
private final ShieldSettingsFilter settingsFilter;
private final @Nullable IPFilter authenticator;
private final boolean ssl;
@Inject
public ShieldNettyTransport(Settings settings, ThreadPool threadPool, NetworkService networkService, BigArrays bigArrays, Version version,
@Nullable IPFilter authenticator, @Nullable ServerSSLService serverSSLService, ClientSSLService clientSSLService) {
@Nullable IPFilter authenticator, @Nullable ServerSSLService serverSSLService, ClientSSLService clientSSLService,
ShieldSettingsFilter settingsFilter) {
super(settings, threadPool, networkService, bigArrays, version);
this.authenticator = authenticator;
this.ssl = settings.getAsBoolean("shield.transport.ssl", false);
this.serverSslService = serverSSLService;
this.clientSSLService = clientSSLService;
this.settingsFilter = settingsFilter;
}
@Override
@ -64,6 +68,7 @@ public class ShieldNettyTransport extends NettyTransport {
public SslServerChannelPipelineFactory(NettyTransport nettyTransport, String name, Settings settings, Settings profileSettings) {
super(nettyTransport, name, settings);
this.profileSettings = profileSettings;
settingsFilter.filterOut("transport.profiles." + name + ".shield.*");
}
@Override

View File

@ -16,7 +16,6 @@ import org.elasticsearch.test.ShieldIntegrationTest;
import org.elasticsearch.test.rest.client.http.HttpRequestBuilder;
import org.elasticsearch.test.rest.client.http.HttpResponse;
import org.junit.After;
import org.junit.Before;
import java.io.IOException;
import java.util.Locale;
@ -29,18 +28,11 @@ import static org.hamcrest.Matchers.*;
*/
public abstract class AbstractPrivilegeTests extends ShieldIntegrationTest {
private CloseableHttpClient httpClient;
@Before
public void createHttpClient() {
httpClient = HttpClients.createDefault();
}
private CloseableHttpClient httpClient = HttpClients.createDefault();
@After
public void closeHttpClient() throws IOException {
if (httpClient != null) {
httpClient.close();
}
public void cleanup() throws IOException {
httpClient.close();
}
protected void assertAccessIsAllowed(String user, String method, String uri, String body, Map<String, String> params) throws IOException {

View File

@ -0,0 +1,178 @@
/*
* 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.integration;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.http.HttpServerTransport;
import org.elasticsearch.node.internal.InternalNode;
import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.shield.authc.support.UsernamePasswordToken;
import org.elasticsearch.shield.ssl.AbstractSSLService;
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.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope.SUITE;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.Matchers.is;
@ClusterScope(scope = SUITE)
public class SettingsFilterTests extends ShieldIntegrationTest {
private CloseableHttpClient httpClient = HttpClients.createDefault();
private InetSocketTransportAddress address;
private String clientPortSetting;
@Before
public void init() {
HttpServerTransport httpServerTransport = internalCluster().getDataNodeInstance(HttpServerTransport.class);
address = (InetSocketTransportAddress) httpServerTransport.boundAddress().boundAddress();
}
@After
public void cleanup() throws IOException {
httpClient.close();
}
@Override
protected Settings nodeSettings(int nodeOrdinal) {
int clientProfilePort = randomIntBetween(49000, 65400);
return ImmutableSettings.builder().put(super.nodeSettings(nodeOrdinal))
.put(InternalNode.HTTP_ENABLED, true)
// ldap realm filtering
.put("shield.authc.realms.esusers.type", "esusers")
.put("shield.authc.realms.ldap1.type", "ldap")
.put("shield.authc.realms.ldap1.enabled", "false")
.put("shield.authc.realms.ldap1.url", "ldap://host.domain")
.put("shield.authc.realms.ldap1.hostname_verification", randomAsciiOfLength(5))
.put("shield.authc.realms.ldap1.bind_dn", randomAsciiOfLength(5))
.put("shield.authc.realms.ldap1.bind_password", randomAsciiOfLength(5))
.put("shield.ssl.keystore.path", "/path/to/keystore")
.put("shield.ssl.ciphers", "_ciphers")
.put("shield.ssl.supported_protocols", randomFrom(AbstractSSLService.DEFAULT_SUPPORTED_PROTOCOLS))
.put("shield.ssl.keystore.password", randomAsciiOfLength(5))
.put("shield.ssl.keystore.algorithm", "_algorithm")
.put("shield.ssl.keystore.key_password", randomAsciiOfLength(5))
.put("shield.ssl.truststore.password", randomAsciiOfLength(5))
.put("shield.ssl.truststore.algorithm", "_algorithm")
// client profile
.put("transport.profiles.client.port", clientProfilePort + "-" + (clientProfilePort + 100))
.put("transport.profiles.client.shield.keystore.path", "/path/to/keystore")
.put("transport.profiles.client.shield.ciphers", "_ciphers")
.put("transport.profiles.client.shield.supported_protocols", randomFrom(AbstractSSLService.DEFAULT_SUPPORTED_PROTOCOLS))
.put("transport.profiles.client.shield.keystore.password", randomAsciiOfLength(5))
.put("transport.profiles.client.shield.keystore.algorithm", "_algorithm")
.put("transport.profiles.client.shield.keystore.key_password", randomAsciiOfLength(5))
.put("transport.profiles.client.shield.truststore.password", randomAsciiOfLength(5))
.put("transport.profiles.client.shield.truststore.algorithm", "_algorithm")
// custom settings
.put("foo.bar", "_secret")
.put("foo.baz", "_secret")
.put("bar.baz", "_secret")
.put("baz.foo", "_not_a_secret") // should not be filtered
.put("shield.hide_settings", "foo.*,bar.baz")
.build();
}
@Override
protected boolean sslTransportEnabled() {
return false;
}
@Test
public void testFiltering() throws Exception {
HttpResponse response = executeRequest("GET", "/_nodes", null, Collections.<String, String>emptyMap());
List<Settings> list = extractSettings(response.getBody());
for (Settings settings : list) {
assertThat(settings.get("shield.authc.realms.ldap1.hostname_verification"), nullValue());
assertThat(settings.get("shield.authc.realms.ldap1.bind_password"), nullValue());
assertThat(settings.get("shield.authc.realms.ldap1.bind_dn"), nullValue());
assertThat(settings.get("shield.authc.realms.ldap1.url"), is("ldap://host.domain"));
assertThat(settings.get("shield.ssl.keystore.path"), nullValue());
assertThat(settings.get("shield.ssl.ciphers"), nullValue());
assertThat(settings.get("shield.ssl.supported_protocols"), nullValue());
assertThat(settings.get("shield.ssl.keystore.password"), nullValue());
assertThat(settings.get("shield.ssl.keystore.algorithm"), nullValue());
assertThat(settings.get("shield.ssl.keystore.key_password"), nullValue());
assertThat(settings.get("shield.ssl.truststore.password"), nullValue());
assertThat(settings.get("shield.ssl.truststore.algorithm"), nullValue());
// the client profile settings is also filtered out
assertThat(settings.get("transport.profiles.client.port"), notNullValue());
assertThat(settings.get("transport.profiles.client.shield.keystore.path"), nullValue());
assertThat(settings.get("transport.profiles.client.shield.ciphers"), nullValue());
assertThat(settings.get("transport.profiles.client.shield.supported_protocols"), nullValue());
assertThat(settings.get("transport.profiles.client.shield.keystore.password"), nullValue());
assertThat(settings.get("transport.profiles.client.shield.keystore.algorithm"), nullValue());
assertThat(settings.get("transport.profiles.client.shield.keystore.key_password"), nullValue());
assertThat(settings.get("transport.profiles.client.shield.truststore.password"), nullValue());
assertThat(settings.get("transport.profiles.client.shield.truststore.algorithm"), nullValue());
assertThat(settings.get("shield.hide_settings"), nullValue());
assertThat(settings.get("foo.bar"), nullValue());
assertThat(settings.get("foo.baz"), nullValue());
assertThat(settings.get("bar.baz"), nullValue());
assertThat(settings.get("baz.foo"), is("_not_a_secret"));
}
}
static List<Settings> extractSettings(String data) throws Exception {
List<Settings> settingsList = new ArrayList<>();
XContentParser parser = JsonXContent.jsonXContent.createParser(data.getBytes(UTF8));
XContentParser.Token token = null;
while ((token = parser.nextToken()) != null) {
if (token == XContentParser.Token.FIELD_NAME && parser.currentName().equals("settings")) {
parser.nextToken();
XContentBuilder builder = XContentBuilder.builder(parser.contentType().xContent());
settingsList.add(ImmutableSettings.builder().loadFromSource(builder.copyCurrentStructure(parser).bytes().toUtf8()).build());
}
}
return settingsList;
}
protected HttpResponse executeRequest(String method, String uri, String body, Map<String, String> params) throws IOException {
HttpServerTransport httpServerTransport = internalCluster().getDataNodeInstance(HttpServerTransport.class);
address = (InetSocketTransportAddress) httpServerTransport.boundAddress().boundAddress();
HttpRequestBuilder requestBuilder = new HttpRequestBuilder(httpClient)
.host(address.address().getHostName())
.port(address.address().getPort())
.method(method)
.path(uri);
for (Map.Entry<String, String> entry : params.entrySet()) {
requestBuilder.addParam(entry.getKey(), entry.getValue());
}
if (body != null) {
requestBuilder.body(body);
}
requestBuilder.addHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, UsernamePasswordToken.basicAuthHeaderValue(ShieldSettingsSource.DEFAULT_USER_NAME, new SecuredString(ShieldSettingsSource.DEFAULT_PASSWORD.toCharArray())));
return requestBuilder.execute();
}
}

View File

@ -14,6 +14,7 @@ import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.shield.ShieldSettingsFilter;
import org.elasticsearch.shield.User;
import org.elasticsearch.shield.audit.AuditTrail;
import org.elasticsearch.shield.authc.support.SecuredString;
@ -61,7 +62,7 @@ public class InternalAuthenticationServiceTests extends ElasticsearchTestCase {
when(firstRealm.type()).thenReturn("first");
secondRealm = mock(Realm.class);
when(secondRealm.type()).thenReturn("second");
realms = new Realms(ImmutableSettings.EMPTY, new Environment(ImmutableSettings.EMPTY), Collections.<String, Realm.Factory>emptyMap()) {
realms = new Realms(ImmutableSettings.EMPTY, new Environment(ImmutableSettings.EMPTY), Collections.<String, Realm.Factory>emptyMap(), mock(ShieldSettingsFilter.class)) {
@Override
protected List<Realm> initRealms() {
return ImmutableList.of(firstRealm, secondRealm);

View File

@ -10,6 +10,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.shield.ShieldSettingsException;
import org.elasticsearch.shield.ShieldSettingsFilter;
import org.elasticsearch.shield.User;
import org.elasticsearch.shield.authc.esusers.ESUsersRealm;
import org.elasticsearch.test.ElasticsearchTestCase;
@ -20,6 +21,7 @@ import org.junit.Test;
import java.util.*;
import static org.hamcrest.Matchers.*;
import static org.mockito.Mockito.mock;
/**
*
@ -27,6 +29,7 @@ import static org.hamcrest.Matchers.*;
public class RealmsTests extends ElasticsearchTestCase {
private Map<String, Realm.Factory> factories;
private ShieldSettingsFilter settingsFilter;
@Before
public void init() throws Exception {
@ -36,6 +39,7 @@ public class RealmsTests extends ElasticsearchTestCase {
DummyRealm.Factory factory = new DummyRealm.Factory("type_" + i, rarely());
factories.put("type_" + i, factory);
}
settingsFilter = mock(ShieldSettingsFilter.class);
}
@Test
@ -54,7 +58,7 @@ public class RealmsTests extends ElasticsearchTestCase {
}
Settings settings = builder.build();
Environment env = new Environment(settings);
Realms realms = new Realms(settings, env, factories);
Realms realms = new Realms(settings, env, factories, settingsFilter);
realms.start();
int i = 0;
for (Realm realm : realms) {
@ -75,12 +79,12 @@ public class RealmsTests extends ElasticsearchTestCase {
.put("shield.authc.realms.realm_2.order", 1)
.build();
Environment env = new Environment(settings);
new Realms(settings, env, factories).start();
new Realms(settings, env, factories, settingsFilter).start();
}
@Test
public void testWithEmptySettings() throws Exception {
Realms realms = new Realms(ImmutableSettings.EMPTY, new Environment(ImmutableSettings.EMPTY), factories);
Realms realms = new Realms(ImmutableSettings.EMPTY, new Environment(ImmutableSettings.EMPTY), factories, settingsFilter);
realms.start();
Iterator<Realm> iter = realms.iterator();
assertThat(iter.hasNext(), is(true));
@ -112,7 +116,7 @@ public class RealmsTests extends ElasticsearchTestCase {
}
Settings settings = builder.build();
Environment env = new Environment(settings);
Realms realms = new Realms(settings, env, factories);
Realms realms = new Realms(settings, env, factories, mock(ShieldSettingsFilter.class));
realms.start();
Iterator<Realm> iterator = realms.iterator();

View File

@ -23,7 +23,8 @@ import org.junit.Test;
import java.nio.file.Path;
import java.nio.file.Paths;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.hasItem;
@Network
public class OpenLdapTests extends ElasticsearchTestCase {

View File

@ -6,8 +6,10 @@
package org.elasticsearch.shield.ssl;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.shield.ShieldSettingsException;
import org.elasticsearch.shield.ShieldSettingsFilter;
import org.elasticsearch.test.ElasticsearchTestCase;
import org.junit.Before;
import org.junit.Test;
@ -23,35 +25,40 @@ import java.util.List;
import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
import static org.hamcrest.Matchers.*;
import static org.mockito.Mockito.mock;
public class ServerSSLServiceTests extends ElasticsearchTestCase {
Path testnodeStore;
ShieldSettingsFilter settingsFilter;
@Before
public void setup() throws Exception {
testnodeStore = Paths.get(getClass().getResource("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.jks").toURI());
settingsFilter = mock(ShieldSettingsFilter.class);
}
@Test(expected = ElasticsearchSSLException.class)
public void testThatInvalidProtocolThrowsException() throws Exception {
new ServerSSLService(settingsBuilder()
.put("shield.ssl.protocol", "non-existing")
.put("shield.ssl.keystore.path", testnodeStore)
.put("shield.ssl.keystore.password", "testnode")
.put("shield.ssl.truststore.path", testnodeStore)
.put("shield.ssl.truststore.password", "testnode")
.build()).createSSLEngine();
Settings settings = settingsBuilder()
.put("shield.ssl.protocol", "non-existing")
.put("shield.ssl.keystore.path", testnodeStore)
.put("shield.ssl.keystore.password", "testnode")
.put("shield.ssl.truststore.path", testnodeStore)
.put("shield.ssl.truststore.password", "testnode")
.build();
new ServerSSLService(settings, settingsFilter).createSSLEngine();
}
@Test
public void testThatCustomTruststoreCanBeSpecified() throws Exception {
Path testClientStore = Paths.get(getClass().getResource("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.jks").toURI());
ServerSSLService sslService = new ServerSSLService(settingsBuilder()
Settings settings = settingsBuilder()
.put("shield.ssl.keystore.path", testnodeStore)
.put("shield.ssl.keystore.password", "testnode")
.build());
.build();
ServerSSLService sslService = new ServerSSLService(settings, settingsFilter);
ImmutableSettings.Builder settingsBuilder = settingsBuilder()
.put("truststore.path", testClientStore)
@ -69,7 +76,7 @@ public class ServerSSLServiceTests extends ElasticsearchTestCase {
ServerSSLService sslService = new ServerSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testnodeStore)
.put("shield.ssl.keystore.password", "testnode")
.build());
.build(), settingsFilter);
SSLContext sslContext = sslService.sslContext();
SSLContext cachedSslContext = sslService.sslContext();
@ -84,7 +91,7 @@ public class ServerSSLServiceTests extends ElasticsearchTestCase {
.put("shield.ssl.keystore.path", differentPasswordsStore)
.put("shield.ssl.keystore.password", "testnode")
.put("shield.ssl.keystore.key_password", "testnode1")
.build()).createSSLEngine();
.build(), settingsFilter).createSSLEngine();
}
@Test(expected = ElasticsearchSSLException.class)
@ -93,7 +100,7 @@ public class ServerSSLServiceTests extends ElasticsearchTestCase {
new ServerSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", differentPasswordsStore)
.put("shield.ssl.keystore.password", "testnode")
.build()).createSSLEngine();
.build(), settingsFilter).createSSLEngine();
}
@Test
@ -101,7 +108,7 @@ public class ServerSSLServiceTests extends ElasticsearchTestCase {
ServerSSLService sslService = new ServerSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testnodeStore)
.put("shield.ssl.keystore.password", "testnode")
.build());
.build(), settingsFilter);
SSLEngine engine = sslService.createSSLEngine();
assertThat(Arrays.asList(engine.getEnabledProtocols()), not(hasItem("SSLv3")));
}
@ -111,7 +118,7 @@ public class ServerSSLServiceTests extends ElasticsearchTestCase {
ServerSSLService sslService = new ServerSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testnodeStore)
.put("shield.ssl.keystore.password", "testnode")
.build());
.build(), settingsFilter);
SSLSessionContext context = sslService.sslContext().getServerSessionContext();
assertThat(context.getSessionCacheSize(), equalTo(1000));
assertThat(context.getSessionTimeout(), equalTo((int) TimeValue.timeValueHours(24).seconds()));
@ -124,7 +131,7 @@ public class ServerSSLServiceTests extends ElasticsearchTestCase {
.put("shield.ssl.keystore.password", "testnode")
.put("shield.ssl.session.cache_size", "300")
.put("shield.ssl.session.cache_timeout", "600s")
.build());
.build(), settingsFilter);
SSLSessionContext context = sslService.sslContext().getServerSessionContext();
assertThat(context.getSessionCacheSize(), equalTo(300));
assertThat(context.getSessionTimeout(), equalTo(600));
@ -132,7 +139,7 @@ public class ServerSSLServiceTests extends ElasticsearchTestCase {
@Test(expected = ShieldSettingsException.class)
public void testThatCreateSSLEngineWithoutAnySettingsDoesNotWork() throws Exception {
ServerSSLService sslService = new ServerSSLService(ImmutableSettings.EMPTY);
ServerSSLService sslService = new ServerSSLService(ImmutableSettings.EMPTY, settingsFilter);
sslService.createSSLEngine();
}
@ -141,7 +148,7 @@ public class ServerSSLServiceTests extends ElasticsearchTestCase {
ServerSSLService sslService = new ServerSSLService(settingsBuilder()
.put("shield.ssl.truststore.path", testnodeStore)
.put("shield.ssl.truststore.password", "testnode")
.build());
.build(), settingsFilter);
SSLEngine sslEngine = sslService.createSSLEngine();
assertThat(sslEngine, notNullValue());
}
@ -152,7 +159,7 @@ public class ServerSSLServiceTests extends ElasticsearchTestCase {
.put("shield.ssl.keystore.path", testnodeStore)
.put("shield.ssl.keystore.password", "testnode")
.put("shield.ssl.truststore.path", testnodeStore)
.build());
.build(), settingsFilter);
sslService.sslContext();
}
@ -160,7 +167,7 @@ public class ServerSSLServiceTests extends ElasticsearchTestCase {
public void testThatKeystorePasswordIsRequired() throws Exception {
ServerSSLService sslService = new ServerSSLService(settingsBuilder()
.put("shield.ssl.keystore.path", testnodeStore)
.build());
.build(), settingsFilter);
sslService.sslContext();
}
@ -173,7 +180,7 @@ public class ServerSSLServiceTests extends ElasticsearchTestCase {
.put("shield.ssl.keystore.path", testnodeStore)
.put("shield.ssl.keystore.password", "testnode")
.putArray("shield.ssl.ciphers", ciphers.toArray(new String[ciphers.size()]))
.build());
.build(), settingsFilter);
SSLEngine engine = sslService.createSSLEngine();
assertThat(engine, is(notNullValue()));
String[] enabledCiphers = engine.getEnabledCipherSuites();
@ -186,7 +193,7 @@ public class ServerSSLServiceTests extends ElasticsearchTestCase {
.put("shield.ssl.keystore.path", testnodeStore)
.put("shield.ssl.keystore.password", "testnode")
.putArray("shield.ssl.ciphers", new String[] { "foo", "bar" })
.build());
.build(), settingsFilter);
sslService.createSSLEngine();
}
}

View File

@ -15,7 +15,10 @@ import org.elasticsearch.common.netty.channel.*;
import org.elasticsearch.common.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.elasticsearch.common.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.elasticsearch.common.netty.handler.ssl.SslHandler;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsFilter;
import org.elasticsearch.shield.ShieldException;
import org.elasticsearch.shield.ShieldSettingsFilter;
import org.elasticsearch.shield.ssl.ServerSSLService;
import org.elasticsearch.test.ElasticsearchTestCase;
import org.junit.After;
@ -62,10 +65,13 @@ public class HandshakeWaitingHandlerTests extends ElasticsearchTestCase {
randomPort = randomIntBetween(49000, 65500);
iterations = randomIntBetween(10, 100);
ServerSSLService sslService = new ServerSSLService(settingsBuilder()
Settings settings = settingsBuilder()
.put("shield.ssl.keystore.path", Paths.get(HandshakeWaitingHandlerTests.class.getResource("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.jks").toURI()))
.put("shield.ssl.keystore.password", "testnode")
.build());
.build();
ShieldSettingsFilter settingsFilter = new ShieldSettingsFilter(settings, new SettingsFilter(settings));
ServerSSLService sslService = new ServerSSLService(settings, settingsFilter);
sslContext = sslService.sslContext();

View File

@ -12,7 +12,9 @@ import org.elasticsearch.common.netty.handler.ssl.SslHandler;
import org.elasticsearch.common.network.NetworkService;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsFilter;
import org.elasticsearch.common.util.BigArrays;
import org.elasticsearch.shield.ShieldSettingsFilter;
import org.elasticsearch.shield.ssl.ClientSSLService;
import org.elasticsearch.shield.ssl.ServerSSLService;
import org.elasticsearch.test.ElasticsearchTestCase;
@ -33,6 +35,7 @@ public class ShieldNettyTransportTests extends ElasticsearchTestCase {
private ServerSSLService serverSSLService;
private ClientSSLService clientSSLService;
private ShieldSettingsFilter settingsFilter;
@Before
public void createSSLService() throws Exception {
@ -41,14 +44,15 @@ public class ShieldNettyTransportTests extends ElasticsearchTestCase {
.put("shield.ssl.keystore.path", testnodeStore)
.put("shield.ssl.keystore.password", "testnode")
.build();
serverSSLService = new ServerSSLService(settings);
settingsFilter = new ShieldSettingsFilter(settings, new SettingsFilter(settings));
serverSSLService = new ServerSSLService(settings, settingsFilter);
clientSSLService = new ClientSSLService(settings);
}
@Test
public void testThatSSLCanBeDisabledByProfile() throws Exception {
Settings settings = ImmutableSettings.builder().put("shield.transport.ssl", true).build();
ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class), mock(NetworkService.class), mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService);
ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class), mock(NetworkService.class), mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService, settingsFilter);
setOpenChannelsHandlerToMock(transport);
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", ImmutableSettings.builder().put("shield.ssl", false).build());
assertThat(factory.getPipeline().get(SslHandler.class), nullValue());
@ -57,7 +61,7 @@ public class ShieldNettyTransportTests extends ElasticsearchTestCase {
@Test
public void testThatSSLCanBeEnabledByProfile() throws Exception {
Settings settings = ImmutableSettings.builder().put("shield.transport.ssl", false).build();
ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class), mock(NetworkService.class), mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService);
ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class), mock(NetworkService.class), mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService, settingsFilter);
setOpenChannelsHandlerToMock(transport);
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", ImmutableSettings.builder().put("shield.ssl", true).build());
assertThat(factory.getPipeline().get(SslHandler.class), notNullValue());
@ -66,7 +70,7 @@ public class ShieldNettyTransportTests extends ElasticsearchTestCase {
@Test
public void testThatProfileTakesDefaultSSLSetting() throws Exception {
Settings settings = ImmutableSettings.builder().put("shield.transport.ssl", true).build();
ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class), mock(NetworkService.class), mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService);
ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class), mock(NetworkService.class), mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService, settingsFilter);
setOpenChannelsHandlerToMock(transport);
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", ImmutableSettings.EMPTY);
assertThat(factory.getPipeline().get(SslHandler.class), notNullValue());