update the IPFilter to always allow traffic from a bound address

This change updates the IPFilter to always allow traffic from the bound addresses of the node
even if they have been explicitly disabled. This behavior can be disabled through a setting but
that could be dangerous if the blocking rule is added via a persistent setting stored in the cluster
state.

Closes elastic/elasticsearch#487

Original commit: elastic/x-pack-elasticsearch@4c1cf9455f
This commit is contained in:
jaymode 2015-09-16 12:44:13 -04:00
parent b219e9c496
commit 6a7462be3e
16 changed files with 241 additions and 85 deletions

View File

@ -12,12 +12,15 @@ import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.network.NetworkAddress; import org.elasticsearch.common.network.NetworkAddress;
import org.elasticsearch.common.transport.BoundTransportAddress; import org.elasticsearch.common.transport.BoundTransportAddress;
import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.transport.TransportAddress;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.*; import java.net.*;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -28,24 +31,34 @@ public class HttpESExporterUtils {
static final String VERSION_FIELD = "number"; static final String VERSION_FIELD = "number";
public static String[] extractHostsFromAddress(BoundTransportAddress boundAddress, ESLogger logger) { public static String[] extractHostsFromAddress(BoundTransportAddress boundAddress, ESLogger logger) {
if (boundAddress == null || boundAddress.boundAddress() == null) { if (boundAddress == null || boundAddress.boundAddresses() == null) {
logger.debug("local http server is not yet started. can't connect"); logger.debug("local http server is not yet started. can't connect");
return null; return null;
} }
if (boundAddress.boundAddress().uniqueAddressTypeId() != 1) { TransportAddress[] boundAddresses = boundAddress.boundAddresses();
logger.error("local node is not bound via the http transport. can't connect"); List<String> hosts = new ArrayList<>(boundAddresses.length);
return null; for (TransportAddress transportAddress : boundAddresses) {
if (transportAddress.uniqueAddressTypeId() == 1) {
InetSocketTransportAddress address = (InetSocketTransportAddress) transportAddress;
InetSocketAddress inetSocketAddress = address.address();
InetAddress inetAddress = inetSocketAddress.getAddress();
if (inetAddress == null) {
logger.error("failed to extract the ip address of from transport address [{}]", transportAddress);
continue;
}
hosts.add(NetworkAddress.formatAddress(inetSocketAddress));
} else {
logger.error("local node http transport is not bound via a InetSocketTransportAddress. address is [{}] with typeId [{}]", transportAddress, transportAddress.uniqueAddressTypeId());
}
} }
InetSocketTransportAddress address = (InetSocketTransportAddress) boundAddress.boundAddress();
InetSocketAddress inetSocketAddress = address.address(); if (hosts.isEmpty()) {
InetAddress inetAddress = inetSocketAddress.getAddress(); logger.error("could not extract any hosts from bound address. can't connect");
if (inetAddress == null) {
logger.error("failed to extract the ip address of current node.");
return null; return null;
} }
return new String[]{ NetworkAddress.formatAddress(inetSocketAddress) }; return hosts.toArray(new String[hosts.size()]);
} }
public static URL parseHostWithPath(String host, String path) throws URISyntaxException, MalformedURLException { public static URL parseHostWithPath(String host, String path) throws URISyntaxException, MalformedURLException {

View File

@ -15,8 +15,8 @@ import org.elasticsearch.common.component.LifecycleListener;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.inject.internal.Nullable; import org.elasticsearch.common.inject.internal.Nullable;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.common.transport.BoundTransportAddress;
import org.elasticsearch.common.util.ArrayUtils; import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.http.HttpServerTransport; import org.elasticsearch.http.HttpServerTransport;
import org.elasticsearch.node.settings.NodeSettingsService; import org.elasticsearch.node.settings.NodeSettingsService;
import org.elasticsearch.shield.audit.AuditTrail; import org.elasticsearch.shield.audit.AuditTrail;
@ -66,6 +66,7 @@ public class IPFilter extends AbstractLifecycleComponent<IPFilter> {
private NodeSettingsService nodeSettingsService; private NodeSettingsService nodeSettingsService;
private final AuditTrail auditTrail; private final AuditTrail auditTrail;
private final Transport transport; private final Transport transport;
private final boolean alwaysAllowBoundAddresses;
private Map<String, ShieldIpFilterRule[]> rules = Collections.EMPTY_MAP; private Map<String, ShieldIpFilterRule[]> rules = Collections.EMPTY_MAP;
private HttpServerTransport httpServerTransport = null; private HttpServerTransport httpServerTransport = null;
@ -75,6 +76,7 @@ public class IPFilter extends AbstractLifecycleComponent<IPFilter> {
this.nodeSettingsService = nodeSettingsService; this.nodeSettingsService = nodeSettingsService;
this.auditTrail = auditTrail; this.auditTrail = auditTrail;
this.transport = transport; this.transport = transport;
this.alwaysAllowBoundAddresses = settings.getAsBoolean("shield.filter.always_allow_bound_address", true);
} }
@Override @Override
@ -144,27 +146,30 @@ public class IPFilter extends AbstractLifecycleComponent<IPFilter> {
Map<String, ShieldIpFilterRule[]> profileRules = new HashMap<>(); Map<String, ShieldIpFilterRule[]> profileRules = new HashMap<>();
if (isHttpFilterEnabled && httpServerTransport != null && httpServerTransport.lifecycleState() == Lifecycle.State.STARTED) { if (isHttpFilterEnabled && httpServerTransport != null && httpServerTransport.lifecycleState() == Lifecycle.State.STARTED) {
InetAddress localAddress = ((InetSocketTransportAddress) this.httpServerTransport.boundAddress().boundAddress()).address().getAddress(); TransportAddress[] localAddresses = this.httpServerTransport.boundAddress().boundAddresses();
String[] httpAllowed = settings.getAsArray("shield.http.filter.allow", settings.getAsArray("transport.profiles.default.shield.filter.allow", settings.getAsArray("shield.transport.filter.allow"))); String[] httpAllowed = settings.getAsArray("shield.http.filter.allow", settings.getAsArray("transport.profiles.default.shield.filter.allow", settings.getAsArray("shield.transport.filter.allow")));
String[] httpDdenied = settings.getAsArray("shield.http.filter.deny", settings.getAsArray("transport.profiles.default.shield.filter.deny", settings.getAsArray("shield.transport.filter.deny"))); String[] httpDenied = settings.getAsArray("shield.http.filter.deny", settings.getAsArray("transport.profiles.default.shield.filter.deny", settings.getAsArray("shield.transport.filter.deny")));
profileRules.put(HTTP_PROFILE_NAME, ArrayUtils.concat(parseValue(httpAllowed, true, localAddress), parseValue(httpDdenied, false, localAddress), ShieldIpFilterRule.class)); profileRules.put(HTTP_PROFILE_NAME, createRules(httpAllowed, httpDenied, localAddresses));
} }
if (isIpFilterEnabled && this.transport.lifecycleState() == Lifecycle.State.STARTED) { if (isIpFilterEnabled && this.transport.lifecycleState() == Lifecycle.State.STARTED) {
InetAddress localAddress = ((InetSocketTransportAddress) this.transport.boundAddress().boundAddress()).address().getAddress(); TransportAddress[] localAddresses = this.transport.boundAddress().boundAddresses();
String[] allowed = settings.getAsArray("shield.transport.filter.allow"); String[] allowed = settings.getAsArray("shield.transport.filter.allow");
String[] denied = settings.getAsArray("shield.transport.filter.deny"); String[] denied = settings.getAsArray("shield.transport.filter.deny");
profileRules.put("default", ArrayUtils.concat(parseValue(allowed, true, localAddress), parseValue(denied, false, localAddress), ShieldIpFilterRule.class)); profileRules.put("default", createRules(allowed, denied, localAddresses));
Map<String, Settings> groupedSettings = settings.getGroups("transport.profiles."); Map<String, Settings> groupedSettings = settings.getGroups("transport.profiles.");
for (Map.Entry<String, Settings> entry : groupedSettings.entrySet()) { for (Map.Entry<String, Settings> entry : groupedSettings.entrySet()) {
String profile = entry.getKey(); String profile = entry.getKey();
BoundTransportAddress profileBoundTransportAddress = transport.profileBoundAddresses().get(profile);
if (profileBoundTransportAddress == null) {
// this could happen if a user updates the settings dynamically with a new profile
logger.warn("skipping ip filter rules for profile [{}] since the profile is not bound to any addresses", profile);
continue;
}
Settings profileSettings = entry.getValue().getByPrefix("shield.filter."); Settings profileSettings = entry.getValue().getByPrefix("shield.filter.");
profileRules.put(profile, ArrayUtils.concat( profileRules.put(profile, createRules(profileSettings.getAsArray("allow"), profileSettings.getAsArray("deny"), profileBoundTransportAddress.boundAddresses()));
parseValue(profileSettings.getAsArray("allow"), true, localAddress),
parseValue(profileSettings.getAsArray("deny"), false, localAddress),
ShieldIpFilterRule.class));
} }
} }
@ -172,32 +177,23 @@ public class IPFilter extends AbstractLifecycleComponent<IPFilter> {
return ImmutableMap.copyOf(profileRules); return ImmutableMap.copyOf(profileRules);
} }
private ShieldIpFilterRule[] parseValue(String[] values, boolean isAllowRule, InetAddress localAddress) { private ShieldIpFilterRule[] createRules(String[] allow, String[] deny, TransportAddress[] boundAddresses) {
List<ShieldIpFilterRule> rules = new ArrayList<>(); List<ShieldIpFilterRule> rules = new ArrayList<>();
for (int i = 0; i < values.length; i++) { // if we are always going to allow the bound addresses, then the rule for them should be the first rule in the list
if (alwaysAllowBoundAddresses) {
// never ever deny on localhost, do not even add this rule assert boundAddresses != null && boundAddresses.length > 0;
if (!isAllowRule && isLocalAddress(localAddress, values[i])) { rules.add(new ShieldIpFilterRule(true, boundAddresses));
logger.warn("Configuration setting not applied to reject connections on [{}]. local connections are always allowed!", values[i]);
continue;
}
rules.add(new ShieldIpFilterRule(isAllowRule, values[i]));
} }
return rules.toArray(new ShieldIpFilterRule[]{});
}
/** // add all rules to the same list. Allow takes precedence so they must come first!
* Checks if a user provided address is the same address that we are bound to. This is to prevent denying for (String value : allow) {
* connections from the machine we are running on rules.add(new ShieldIpFilterRule(true, value));
* }
* @param localAddress the InetAddress that this node is bound to. This should come from the transport for (String value : deny) {
* @param address the address that is being evaluated to be blocked rules.add(new ShieldIpFilterRule(false, value));
* @return true if the address is not the same as the localAddress }
*/
private boolean isLocalAddress(InetAddress localAddress, String address) { return rules.toArray(new ShieldIpFilterRule[rules.size()]);
// FIXME add the correct behavior, see https://github.com/elastic/x-plugins/issues/487
return false;
} }
private class ApplySettings implements NodeSettingsService.Listener { private class ApplySettings implements NodeSettingsService.Listener {

View File

@ -7,12 +7,16 @@ package org.elasticsearch.shield.transport.filter;
import com.google.common.net.InetAddresses; import com.google.common.net.InetAddresses;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.network.NetworkAddress;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.transport.TransportAddress;
import org.jboss.netty.handler.ipfilter.IpFilterRule; import org.jboss.netty.handler.ipfilter.IpFilterRule;
import org.jboss.netty.handler.ipfilter.IpSubnetFilterRule; import org.jboss.netty.handler.ipfilter.IpSubnetFilterRule;
import org.jboss.netty.handler.ipfilter.PatternRule; import org.jboss.netty.handler.ipfilter.PatternRule;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.Arrays;
/** /**
* decorator class to have a useful toString() method for an IpFilterRule * decorator class to have a useful toString() method for an IpFilterRule
@ -38,6 +42,7 @@ public class ShieldIpFilterRule implements IpFilterRule {
}; };
public static final ShieldIpFilterRule DENY_ALL = new ShieldIpFilterRule(true, "deny_all") { public static final ShieldIpFilterRule DENY_ALL = new ShieldIpFilterRule(true, "deny_all") {
@Override @Override
public boolean contains(InetAddress inetAddress) { public boolean contains(InetAddress inetAddress) {
return true; return true;
@ -62,6 +67,11 @@ public class ShieldIpFilterRule implements IpFilterRule {
this.ruleSpec = ruleSpec; this.ruleSpec = ruleSpec;
} }
ShieldIpFilterRule(boolean isAllowRule, TransportAddress... addresses) {
this.ruleSpec = getRuleSpec(addresses);
this.ipFilterRule = getRule(isAllowRule, ruleSpec);
}
@Override @Override
public boolean contains(InetAddress inetAddress) { public boolean contains(InetAddress inetAddress) {
return ipFilterRule.contains(inetAddress); return ipFilterRule.contains(inetAddress);
@ -90,12 +100,21 @@ public class ShieldIpFilterRule implements IpFilterRule {
return builder.toString(); return builder.toString();
} }
private static IpFilterRule getRule(boolean isAllowRule, String value) { static IpFilterRule getRule(boolean isAllowRule, String value) {
if ("_all".equals(value)) { String[] values = value.split(",");
int allRuleIndex = Arrays.binarySearch(values, 0, values.length, "_all");
if (allRuleIndex >= 0) {
// all rule was found. It should be the only rule!
if (values.length != 1) {
throw new IllegalArgumentException("rules that specify _all may not have other values!");
}
return isAllowRule ? ACCEPT_ALL : DENY_ALL; return isAllowRule ? ACCEPT_ALL : DENY_ALL;
} }
if (value.contains("/")) { if (value.contains("/")) {
if (values.length != 1) {
throw new IllegalArgumentException("multiple subnet filters cannot be specified in a single rule!");
}
try { try {
return new IpSubnetFilterRule(isAllowRule, value); return new IpSubnetFilterRule(isAllowRule, value);
} catch (UnknownHostException e) { } catch (UnknownHostException e) {
@ -103,9 +122,40 @@ public class ShieldIpFilterRule implements IpFilterRule {
} }
} }
boolean isInetAddress = InetAddresses.isInetAddress(value); boolean firstAdded = false;
String prefix = isInetAddress ? "i:" : "n:"; StringBuilder ruleSpec = new StringBuilder();
return new PatternRule(isAllowRule, prefix + value); for (String singleValue : values) {
if (firstAdded) {
ruleSpec.append(",");
} else {
firstAdded = true;
}
boolean isInetAddress = InetAddresses.isInetAddress(singleValue);
if (isInetAddress) {
ruleSpec.append("i:");
} else {
ruleSpec.append("n:");
}
ruleSpec.append(singleValue);
}
return new PatternRule(isAllowRule, ruleSpec.toString());
} }
static String getRuleSpec(TransportAddress... addresses) {
StringBuilder ruleSpec = new StringBuilder();
boolean firstAdded = false;
for (TransportAddress transportAddress : addresses) {
if (firstAdded) {
ruleSpec.append(",");
} else {
firstAdded = true;
}
assert transportAddress instanceof InetSocketTransportAddress;
ruleSpec.append(NetworkAddress.formatAddress(((InetSocketTransportAddress) transportAddress).address().getAddress()));
}
return ruleSpec.toString();
}
} }

View File

@ -16,10 +16,7 @@ import org.elasticsearch.cluster.ClusterService;
import org.elasticsearch.common.inject.util.Providers; import org.elasticsearch.common.inject.util.Providers;
import org.elasticsearch.common.network.NetworkAddress; import org.elasticsearch.common.network.NetworkAddress;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.BoundTransportAddress; import org.elasticsearch.common.transport.*;
import org.elasticsearch.common.transport.DummyTransportAddress;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.transport.LocalTransportAddress;
import org.elasticsearch.env.Environment; import org.elasticsearch.env.Environment;
import org.elasticsearch.index.IndexNotFoundException; import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.index.cache.IndexCacheModule; import org.elasticsearch.index.cache.IndexCacheModule;
@ -197,7 +194,7 @@ public class IndexAuditTrailTests extends ShieldIntegTestCase {
when(authService.authenticate(mock(RestRequest.class))).thenThrow(new UnsupportedOperationException("")); when(authService.authenticate(mock(RestRequest.class))).thenThrow(new UnsupportedOperationException(""));
when(authService.authenticate("_action", new LocalHostMockMessage(), user.user())).thenThrow(new UnsupportedOperationException("")); when(authService.authenticate("_action", new LocalHostMockMessage(), user.user())).thenThrow(new UnsupportedOperationException(""));
Transport transport = mock(Transport.class); Transport transport = mock(Transport.class);
when(transport.boundAddress()).thenReturn(new BoundTransportAddress(DummyTransportAddress.INSTANCE, DummyTransportAddress.INSTANCE)); when(transport.boundAddress()).thenReturn(new BoundTransportAddress(new TransportAddress[] { DummyTransportAddress.INSTANCE }, DummyTransportAddress.INSTANCE));
Environment env = new Environment(settings); Environment env = new Environment(settings);
threadPool = new ThreadPool("index audit trail tests"); threadPool = new ThreadPool("index audit trail tests");

View File

@ -11,6 +11,7 @@ import org.elasticsearch.common.inject.util.Providers;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.BoundTransportAddress; import org.elasticsearch.common.transport.BoundTransportAddress;
import org.elasticsearch.common.transport.DummyTransportAddress; import org.elasticsearch.common.transport.DummyTransportAddress;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.env.Environment; import org.elasticsearch.env.Environment;
import org.elasticsearch.shield.authc.AuthenticationService; import org.elasticsearch.shield.authc.AuthenticationService;
import org.elasticsearch.test.*; import org.elasticsearch.test.*;
@ -48,7 +49,7 @@ public class IndexAuditTrailUpdateMappingTests extends ShieldIntegTestCase {
AuthenticationService authService = mock(AuthenticationService.class); AuthenticationService authService = mock(AuthenticationService.class);
Settings settings = Settings.builder().put("shield.audit.index.rollover", rollover.name().toLowerCase(Locale.ENGLISH)).put("path.home", createTempDir()).build(); Settings settings = Settings.builder().put("shield.audit.index.rollover", rollover.name().toLowerCase(Locale.ENGLISH)).put("path.home", createTempDir()).build();
Transport transport = mock(Transport.class); Transport transport = mock(Transport.class);
when(transport.boundAddress()).thenReturn(new BoundTransportAddress(DummyTransportAddress.INSTANCE, DummyTransportAddress.INSTANCE)); when(transport.boundAddress()).thenReturn(new BoundTransportAddress(new TransportAddress[] { DummyTransportAddress.INSTANCE }, DummyTransportAddress.INSTANCE));
Environment env = new Environment(settings); Environment env = new Environment(settings);
IndexAuditTrail auditor = new IndexAuditTrail(settings, new IndexAuditUserHolder(), env, authService, transport, Providers.of(client()), threadPool, mock(ClusterService.class)); IndexAuditTrail auditor = new IndexAuditTrail(settings, new IndexAuditUserHolder(), env, authService, transport, Providers.of(client()), threadPool, mock(ClusterService.class));

View File

@ -109,7 +109,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
.put("shield.audit.logfile.prefix.emit_node_name", randomBoolean()) .put("shield.audit.logfile.prefix.emit_node_name", randomBoolean())
.build(); .build();
transport = mock(Transport.class); transport = mock(Transport.class);
when(transport.boundAddress()).thenReturn(new BoundTransportAddress(DummyTransportAddress.INSTANCE, DummyTransportAddress.INSTANCE)); when(transport.boundAddress()).thenReturn(new BoundTransportAddress(new TransportAddress[] { DummyTransportAddress.INSTANCE }, DummyTransportAddress.INSTANCE));
prefix = LoggingAuditTrail.resolvePrefix(settings, transport); prefix = LoggingAuditTrail.resolvePrefix(settings, transport);
} }

View File

@ -71,7 +71,7 @@ public class AnonymousUserTests extends ShieldIntegTestCase {
} }
private String getNodeUrl() { private String getNodeUrl() {
TransportAddress transportAddress = internalCluster().getInstance(HttpServerTransport.class).boundAddress().boundAddress(); TransportAddress transportAddress = randomFrom(internalCluster().getInstance(HttpServerTransport.class).boundAddress().boundAddresses());
assertThat(transportAddress, is(instanceOf(InetSocketTransportAddress.class))); assertThat(transportAddress, is(instanceOf(InetSocketTransportAddress.class)));
InetSocketTransportAddress inetSocketTransportAddress = (InetSocketTransportAddress) transportAddress; InetSocketTransportAddress inetSocketTransportAddress = (InetSocketTransportAddress) transportAddress;
return String.format(Locale.ROOT, "http://%s:%s/", "localhost", inetSocketTransportAddress.address().getPort()); return String.format(Locale.ROOT, "http://%s:%s/", "localhost", inetSocketTransportAddress.address().getPort());

View File

@ -71,7 +71,7 @@ public class PkiAuthenticationTests extends ShieldIntegTestCase {
public void testTransportClientCanAuthenticateViaPki() { public void testTransportClientCanAuthenticateViaPki() {
Settings settings = ShieldSettingsSource.getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.jks", "testnode"); Settings settings = ShieldSettingsSource.getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.jks", "testnode");
try (TransportClient client = createTransportClient(settings)) { try (TransportClient client = createTransportClient(settings)) {
client.addTransportAddress(internalCluster().getInstance(Transport.class).boundAddress().boundAddress()); client.addTransportAddress(randomFrom(internalCluster().getInstance(Transport.class).boundAddress().boundAddresses()));
IndexResponse response = client.prepareIndex("foo", "bar").setSource("pki", "auth").get(); IndexResponse response = client.prepareIndex("foo", "bar").setSource("pki", "auth").get();
assertThat(response.isCreated(), is(true)); assertThat(response.isCreated(), is(true));
} }
@ -84,7 +84,7 @@ public class PkiAuthenticationTests extends ShieldIntegTestCase {
@Test(expected = NoNodeAvailableException.class) @Test(expected = NoNodeAvailableException.class)
public void testTransportClientAuthenticationFailure() { public void testTransportClientAuthenticationFailure() {
try (TransportClient client = createTransportClient(Settings.EMPTY)) { try (TransportClient client = createTransportClient(Settings.EMPTY)) {
client.addTransportAddress(internalCluster().getInstance(Transport.class).boundAddress().boundAddress()); client.addTransportAddress(randomFrom(internalCluster().getInstance(Transport.class).boundAddress().boundAddresses()));
client.prepareIndex("foo", "bar").setSource("pki", "auth").get(); client.prepareIndex("foo", "bar").setSource("pki", "auth").get();
fail("transport client should not have been able to authenticate"); fail("transport client should not have been able to authenticate");
} }
@ -144,7 +144,7 @@ public class PkiAuthenticationTests extends ShieldIntegTestCase {
} }
private String getNodeUrl() { private String getNodeUrl() {
TransportAddress transportAddress = internalCluster().getInstance(HttpServerTransport.class).boundAddress().boundAddress(); TransportAddress transportAddress = randomFrom(internalCluster().getInstance(HttpServerTransport.class).boundAddress().boundAddresses());
assertThat(transportAddress, is(instanceOf(InetSocketTransportAddress.class))); assertThat(transportAddress, is(instanceOf(InetSocketTransportAddress.class)));
InetSocketTransportAddress inetSocketTransportAddress = (InetSocketTransportAddress) transportAddress; InetSocketTransportAddress inetSocketTransportAddress = (InetSocketTransportAddress) transportAddress;
return String.format(Locale.ROOT, "https://localhost:%s/", inetSocketTransportAddress.address().getPort()); return String.format(Locale.ROOT, "https://localhost:%s/", inetSocketTransportAddress.address().getPort());

View File

@ -97,7 +97,7 @@ public class PkiOptionalClientAuthTests extends ShieldIntegTestCase {
@Test @Test
public void testTransportClientWithoutClientCertificate() { public void testTransportClientWithoutClientCertificate() {
Transport transport = internalCluster().getDataNodeInstance(Transport.class); Transport transport = internalCluster().getDataNodeInstance(Transport.class);
int port = ((InetSocketTransportAddress)transport.profileBoundAddresses().get("want_client_auth").boundAddress()).address().getPort(); int port = ((InetSocketTransportAddress) randomFrom(transport.profileBoundAddresses().get("want_client_auth").boundAddresses())).address().getPort();
Settings settings = Settings.builder() Settings settings = Settings.builder()
.put(ShieldSettingsSource.getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/truststore-testnode-only.jks", "truststore-testnode-only")) .put(ShieldSettingsSource.getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/truststore-testnode-only.jks", "truststore-testnode-only"))

View File

@ -7,9 +7,11 @@ package org.elasticsearch.shield.transport.filter;
import com.google.common.net.InetAddresses; import com.google.common.net.InetAddresses;
import org.elasticsearch.common.component.Lifecycle; import org.elasticsearch.common.component.Lifecycle;
import org.elasticsearch.common.network.NetworkAddress;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.BoundTransportAddress; import org.elasticsearch.common.transport.BoundTransportAddress;
import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.http.HttpServerTransport; import org.elasticsearch.http.HttpServerTransport;
import org.elasticsearch.node.settings.NodeSettingsService; import org.elasticsearch.node.settings.NodeSettingsService;
import org.elasticsearch.shield.audit.AuditTrail; import org.elasticsearch.shield.audit.AuditTrail;
@ -21,7 +23,7 @@ import org.junit.Test;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import java.net.InetAddress; import java.net.InetAddress;
import java.util.Locale; import java.util.*;
import static org.elasticsearch.common.settings.Settings.settingsBuilder; import static org.elasticsearch.common.settings.Settings.settingsBuilder;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
@ -45,13 +47,17 @@ public class IPFilterTests extends ESTestCase {
httpTransport = mock(HttpServerTransport.class); httpTransport = mock(HttpServerTransport.class);
InetSocketTransportAddress httpAddress = new InetSocketTransportAddress(InetAddress.getLoopbackAddress(), 9200); InetSocketTransportAddress httpAddress = new InetSocketTransportAddress(InetAddress.getLoopbackAddress(), 9200);
when(httpTransport.boundAddress()).thenReturn(new BoundTransportAddress(httpAddress, httpAddress)); when(httpTransport.boundAddress()).thenReturn(new BoundTransportAddress(new TransportAddress[] { httpAddress }, httpAddress));
when(httpTransport.lifecycleState()).thenReturn(Lifecycle.State.STARTED); when(httpTransport.lifecycleState()).thenReturn(Lifecycle.State.STARTED);
transport = mock(Transport.class); transport = mock(Transport.class);
InetSocketTransportAddress address = new InetSocketTransportAddress(InetAddress.getLoopbackAddress(), 9300); InetSocketTransportAddress address = new InetSocketTransportAddress(InetAddress.getLoopbackAddress(), 9300);
when(transport.boundAddress()).thenReturn(new BoundTransportAddress(address, address)); when(transport.boundAddress()).thenReturn(new BoundTransportAddress(new TransportAddress[]{ address }, address));
when(transport.lifecycleState()).thenReturn(Lifecycle.State.STARTED); when(transport.lifecycleState()).thenReturn(Lifecycle.State.STARTED);
Map<String, BoundTransportAddress> profileBoundAddresses = Collections.singletonMap("client",
new BoundTransportAddress(new TransportAddress[]{ new InetSocketTransportAddress(InetAddress.getLoopbackAddress(), 9500) }, address));
when(transport.profileBoundAddresses()).thenReturn(profileBoundAddresses);
} }
@Test @Test
@ -171,15 +177,25 @@ public class IPFilterTests extends ESTestCase {
} }
@Test @Test
@AwaitsFix(bugUrl = "https://github.com/elastic/x-plugins/issues/487") public void testThatBoundAddressIsNeverRejected() throws Exception {
public void testThatLocalhostIsNeverRejected() throws Exception { List<String> addressStrings = new ArrayList<>();
Settings settings = settingsBuilder() for (TransportAddress address : transport.boundAddress().boundAddresses()) {
.put("shield.transport.filter.deny", "127.0.0.1") addressStrings.add(NetworkAddress.formatAddress(((InetSocketTransportAddress) address).address().getAddress()));
.build(); }
Settings settings;
if (randomBoolean()) {
settings = settingsBuilder().putArray("shield.transport.filter.deny", addressStrings.toArray(new String[addressStrings.size()])).build();
} else {
settings = settingsBuilder().put("shield.transport.filter.deny", "_all").build();
}
ipFilter = new IPFilter(settings, auditTrail, nodeSettingsService, transport).start(); ipFilter = new IPFilter(settings, auditTrail, nodeSettingsService, transport).start();
ipFilter.setHttpServerTransport(httpTransport); ipFilter.setHttpServerTransport(httpTransport);
assertAddressIsAllowedForProfile(IPFilter.HTTP_PROFILE_NAME, "127.0.0.1"); for (String addressString : addressStrings) {
assertAddressIsAllowedForProfile(IPFilter.HTTP_PROFILE_NAME, addressString);
assertAddressIsAllowedForProfile("default", addressString);
}
} }
private void assertAddressIsAllowedForProfile(String profile, String ... inetAddresses) { private void assertAddressIsAllowedForProfile(String profile, String ... inetAddresses) {

View File

@ -52,7 +52,7 @@ public class IpFilteringIntegrationTests extends ShieldIntegTestCase {
@Test @Test
public void testThatIpFilteringIsIntegratedIntoNettyPipelineViaHttp() throws Exception { public void testThatIpFilteringIsIntegratedIntoNettyPipelineViaHttp() throws Exception {
TransportAddress transportAddress = internalCluster().getDataNodeInstance(HttpServerTransport.class).boundAddress().boundAddress(); TransportAddress transportAddress = randomFrom(internalCluster().getDataNodeInstance(HttpServerTransport.class).boundAddress().boundAddresses());
assertThat(transportAddress, is(instanceOf(InetSocketTransportAddress.class))); assertThat(transportAddress, is(instanceOf(InetSocketTransportAddress.class)));
InetSocketTransportAddress inetSocketTransportAddress = (InetSocketTransportAddress) transportAddress; InetSocketTransportAddress inetSocketTransportAddress = (InetSocketTransportAddress) transportAddress;
@ -88,7 +88,7 @@ public class IpFilteringIntegrationTests extends ShieldIntegTestCase {
} }
private static int getProfilePort(String profile) { private static int getProfilePort(String profile) {
TransportAddress transportAddress = internalCluster().getInstance(Transport.class).profileBoundAddresses().get(profile).boundAddress(); TransportAddress transportAddress = randomFrom(internalCluster().getInstance(Transport.class).profileBoundAddresses().get(profile).boundAddresses());
assert transportAddress instanceof InetSocketTransportAddress; assert transportAddress instanceof InetSocketTransportAddress;
return ((InetSocketTransportAddress)transportAddress).address().getPort(); return ((InetSocketTransportAddress)transportAddress).address().getPort();
} }

View File

@ -10,6 +10,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.node.Node; import org.elasticsearch.node.Node;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope; import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.test.ShieldIntegTestCase; import org.elasticsearch.test.ShieldIntegTestCase;
import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import java.net.InetAddress; import java.net.InetAddress;
@ -24,14 +25,23 @@ import static org.hamcrest.Matchers.is;
@ClusterScope(scope = TEST, numDataNodes = 1) @ClusterScope(scope = TEST, numDataNodes = 1)
public class IpFilteringUpdateTests extends ShieldIntegTestCase { public class IpFilteringUpdateTests extends ShieldIntegTestCase {
private static int randomClientPort;
private final boolean httpEnabled = randomBoolean(); private final boolean httpEnabled = randomBoolean();
@BeforeClass
public static void getRandomPort() {
randomClientPort = randomIntBetween(49000, 65500);
}
@Override @Override
protected Settings nodeSettings(int nodeOrdinal) { protected Settings nodeSettings(int nodeOrdinal) {
String randomClientPortRange = randomClientPort + "-" + (randomClientPort+100);
return settingsBuilder() return settingsBuilder()
.put(super.nodeSettings(nodeOrdinal)) .put(super.nodeSettings(nodeOrdinal))
.put(Node.HTTP_ENABLED, httpEnabled) .put(Node.HTTP_ENABLED, httpEnabled)
.put("shield.transport.filter.deny", "127.0.0.200") .put("shield.transport.filter.deny", "127.0.0.200")
.put("transport.profiles.client.port", randomClientPortRange)
.build(); .build();
} }
@ -127,16 +137,16 @@ public class IpFilteringUpdateTests extends ShieldIntegTestCase {
@Test @Test
public void testThatDisablingIpFilterForProfilesWorksAsExpected() throws Exception { public void testThatDisablingIpFilterForProfilesWorksAsExpected() throws Exception {
Settings settings = settingsBuilder() Settings settings = settingsBuilder()
.put("transport.profiles.myprofile.shield.filter.deny", "127.0.0.8") .put("transport.profiles.client.shield.filter.deny", "127.0.0.8")
.build(); .build();
updateSettings(settings); updateSettings(settings);
assertConnectionRejected("myprofile", "127.0.0.8"); assertConnectionRejected("client", "127.0.0.8");
settings = settingsBuilder() settings = settingsBuilder()
.put("shield.transport.filter.enabled", false) .put("shield.transport.filter.enabled", false)
.build(); .build();
updateSettings(settings); updateSettings(settings);
assertConnectionAccepted("myprofile", "127.0.0.8"); assertConnectionAccepted("client", "127.0.0.8");
} }

View File

@ -0,0 +1,72 @@
/*
* 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.filter;
import org.elasticsearch.test.ESTestCase;
import org.jboss.netty.handler.ipfilter.IpFilterRule;
import org.jboss.netty.handler.ipfilter.IpSubnetFilterRule;
import org.jboss.netty.handler.ipfilter.PatternRule;
import org.junit.Test;
import static org.elasticsearch.shield.transport.filter.ShieldIpFilterRule.*;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.sameInstance;
/**
* Unit tests for the {@link ShieldIpFilterRule}
*/
public class ShieldIpFilterRuleTests extends ESTestCase {
@Test
public void testParseAllRules() {
IpFilterRule rule = getRule(true, "_all");
assertThat(rule, sameInstance(ACCEPT_ALL));
rule = getRule(false, "_all");
assertThat(rule, sameInstance(DENY_ALL));
}
@Test
public void testParseAllRuleWithOtherValues() {
String ruleValue = "_all," + randomFrom("name", "127.0.0.1", "127.0.0.0/24");
try {
getRule(randomBoolean(), ruleValue);
fail("an illegal argument exception should have been thrown!");
} catch (IllegalArgumentException e) {
// expected
}
}
@Test
public void testParseIpSubnetFilterRule() throws Exception {
final boolean allow = randomBoolean();
IpFilterRule rule = getRule(allow, "127.0.0.0/24");
assertThat(rule, instanceOf(IpSubnetFilterRule.class));
assertThat(rule.isAllowRule(), equalTo(allow));
IpSubnetFilterRule ipSubnetFilterRule = (IpSubnetFilterRule) rule;
assertThat(ipSubnetFilterRule.contains("127.0.0.1"), equalTo(true));
}
@Test
public void testParseIpSubnetFilterRuleWithOtherValues() throws Exception {
try {
getRule(randomBoolean(), "127.0.0.0/24," + randomFrom("name", "127.0.0.1", "192.0.0.0/24"));
fail("expected an exception to be thrown because only one subnet can be specified at a time");
} catch (IllegalArgumentException e) {
//expected
}
}
@Test
public void testParsePatternRules() {
final boolean allow = randomBoolean();
String ruleSpec = "127.0.0.1,::1,192.168.0.*,name*,specific_name";
IpFilterRule rule = getRule(allow, ruleSpec);
assertThat(rule, instanceOf(PatternRule.class));
assertThat(rule.isAllowRule(), equalTo(allow));
}
}

View File

@ -10,6 +10,7 @@ import org.elasticsearch.common.component.Lifecycle;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.BoundTransportAddress; import org.elasticsearch.common.transport.BoundTransportAddress;
import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.http.HttpServerTransport; import org.elasticsearch.http.HttpServerTransport;
import org.elasticsearch.node.settings.NodeSettingsService; import org.elasticsearch.node.settings.NodeSettingsService;
import org.elasticsearch.shield.audit.AuditTrail; import org.elasticsearch.shield.audit.AuditTrail;
@ -47,7 +48,7 @@ public class IPFilterNettyUpstreamHandlerTests extends ESTestCase {
Transport transport = mock(Transport.class); Transport transport = mock(Transport.class);
InetSocketTransportAddress address = new InetSocketTransportAddress(InetAddress.getLoopbackAddress(), 9300); InetSocketTransportAddress address = new InetSocketTransportAddress(InetAddress.getLoopbackAddress(), 9300);
when(transport.boundAddress()).thenReturn(new BoundTransportAddress(address, address)); when(transport.boundAddress()).thenReturn(new BoundTransportAddress(new TransportAddress[] { address }, address));
when(transport.lifecycleState()).thenReturn(Lifecycle.State.STARTED); when(transport.lifecycleState()).thenReturn(Lifecycle.State.STARTED);
NodeSettingsService nodeSettingsService = mock(NodeSettingsService.class); NodeSettingsService nodeSettingsService = mock(NodeSettingsService.class);
@ -56,7 +57,7 @@ public class IPFilterNettyUpstreamHandlerTests extends ESTestCase {
if (isHttpEnabled) { if (isHttpEnabled) {
HttpServerTransport httpTransport = mock(HttpServerTransport.class); HttpServerTransport httpTransport = mock(HttpServerTransport.class);
InetSocketTransportAddress httpAddress = new InetSocketTransportAddress(InetAddress.getLoopbackAddress(), 9200); InetSocketTransportAddress httpAddress = new InetSocketTransportAddress(InetAddress.getLoopbackAddress(), 9200);
when(httpTransport.boundAddress()).thenReturn(new BoundTransportAddress(httpAddress, httpAddress)); when(httpTransport.boundAddress()).thenReturn(new BoundTransportAddress(new TransportAddress[] { httpAddress }, httpAddress));
when(httpTransport.lifecycleState()).thenReturn(Lifecycle.State.STARTED); when(httpTransport.lifecycleState()).thenReturn(Lifecycle.State.STARTED);
ipFilter.setHttpServerTransport(httpTransport); ipFilter.setHttpServerTransport(httpTransport);
} }

View File

@ -65,7 +65,7 @@ public class SslIntegrationTests extends ShieldIntegTestCase {
.putArray("shield.ssl.ciphers", new String[]{"TLS_ECDH_anon_WITH_RC4_128_SHA", "SSL_RSA_WITH_3DES_EDE_CBC_SHA"}) .putArray("shield.ssl.ciphers", new String[]{"TLS_ECDH_anon_WITH_RC4_128_SHA", "SSL_RSA_WITH_3DES_EDE_CBC_SHA"})
.build()).build()) { .build()).build()) {
TransportAddress transportAddress = internalCluster().getInstance(Transport.class).boundAddress().boundAddress(); TransportAddress transportAddress = randomFrom(internalCluster().getInstance(Transport.class).boundAddress().boundAddresses());
transportClient.addTransportAddress(transportAddress); transportClient.addTransportAddress(transportAddress);
transportClient.admin().cluster().prepareHealth().get(); transportClient.admin().cluster().prepareHealth().get();
@ -82,7 +82,7 @@ public class SslIntegrationTests extends ShieldIntegTestCase {
.putArray("shield.ssl.supported_protocols", new String[]{"SSLv3"}) .putArray("shield.ssl.supported_protocols", new String[]{"SSLv3"})
.build()).build()) { .build()).build()) {
TransportAddress transportAddress = internalCluster().getInstance(Transport.class).boundAddress().boundAddress(); TransportAddress transportAddress = randomFrom(internalCluster().getInstance(Transport.class).boundAddress().boundAddresses());
transportClient.addTransportAddress(transportAddress); transportClient.addTransportAddress(transportAddress);
transportClient.admin().cluster().prepareHealth().get(); transportClient.admin().cluster().prepareHealth().get();
@ -121,7 +121,7 @@ public class SslIntegrationTests extends ShieldIntegTestCase {
} }
private String getNodeUrl() { private String getNodeUrl() {
TransportAddress transportAddress = internalCluster().getInstance(HttpServerTransport.class).boundAddress().boundAddress(); TransportAddress transportAddress = randomFrom(internalCluster().getInstance(HttpServerTransport.class).boundAddress().boundAddresses());
assertThat(transportAddress, is(instanceOf(InetSocketTransportAddress.class))); assertThat(transportAddress, is(instanceOf(InetSocketTransportAddress.class)));
InetSocketTransportAddress inetSocketTransportAddress = (InetSocketTransportAddress) transportAddress; InetSocketTransportAddress inetSocketTransportAddress = (InetSocketTransportAddress) transportAddress;
return String.format(Locale.ROOT, "https://%s:%s/", "localhost", inetSocketTransportAddress.address().getPort()); return String.format(Locale.ROOT, "https://%s:%s/", "localhost", inetSocketTransportAddress.address().getPort());

View File

@ -186,7 +186,7 @@ public class SslMultiPortTests extends ShieldIntegTestCase {
public void testThatProfileTransportClientCannotConnectToDefaultProfile() throws Exception { public void testThatProfileTransportClientCannotConnectToDefaultProfile() throws Exception {
Settings settings = ShieldSettingsSource.getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient-client-profile.jks", "testclient-client-profile"); Settings settings = ShieldSettingsSource.getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient-client-profile.jks", "testclient-client-profile");
try (TransportClient transportClient = createTransportClient(settings)) { try (TransportClient transportClient = createTransportClient(settings)) {
TransportAddress transportAddress = internalCluster().getInstance(Transport.class).boundAddress().boundAddress(); TransportAddress transportAddress = randomFrom(internalCluster().getInstance(Transport.class).boundAddress().boundAddresses());
transportClient.addTransportAddress(transportAddress); transportClient.addTransportAddress(transportAddress);
transportClient.admin().cluster().prepareHealth().get(); transportClient.admin().cluster().prepareHealth().get();
} }
@ -232,7 +232,7 @@ public class SslMultiPortTests extends ShieldIntegTestCase {
.put("cluster.name", internalCluster().getClusterName()) .put("cluster.name", internalCluster().getClusterName())
.build(); .build();
try (TransportClient transportClient = TransportClient.builder().settings(settings).build()) { try (TransportClient transportClient = TransportClient.builder().settings(settings).build()) {
transportClient.addTransportAddress(internalCluster().getInstance(Transport.class).boundAddress().boundAddress()); transportClient.addTransportAddress(randomFrom(internalCluster().getInstance(Transport.class).boundAddress().boundAddresses()));
assertGreenClusterState(transportClient); assertGreenClusterState(transportClient);
} }
} }
@ -326,7 +326,7 @@ public class SslMultiPortTests extends ShieldIntegTestCase {
.put("shield.ssl.truststore.password", "truststore-testnode-only") .put("shield.ssl.truststore.password", "truststore-testnode-only")
.build(); .build();
try (TransportClient transportClient = TransportClient.builder().settings(settings).build()) { try (TransportClient transportClient = TransportClient.builder().settings(settings).build()) {
transportClient.addTransportAddress(internalCluster().getInstance(Transport.class).boundAddress().boundAddress()); transportClient.addTransportAddress(randomFrom(internalCluster().getInstance(Transport.class).boundAddress().boundAddresses()));
assertGreenClusterState(transportClient); assertGreenClusterState(transportClient);
} }
} }
@ -364,7 +364,7 @@ public class SslMultiPortTests extends ShieldIntegTestCase {
.put("shield.transport.ssl", true) .put("shield.transport.ssl", true)
.build(); .build();
try (TransportClient transportClient = TransportClient.builder().settings(settings).build()) { try (TransportClient transportClient = TransportClient.builder().settings(settings).build()) {
transportClient.addTransportAddress(internalCluster().getInstance(Transport.class).boundAddress().boundAddress()); transportClient.addTransportAddress(randomFrom(internalCluster().getInstance(Transport.class).boundAddress().boundAddresses()));
assertGreenClusterState(transportClient); assertGreenClusterState(transportClient);
} }
} }
@ -424,7 +424,7 @@ public class SslMultiPortTests extends ShieldIntegTestCase {
} }
private static int getProfilePort(String profile) { private static int getProfilePort(String profile) {
TransportAddress transportAddress = internalCluster().getInstance(Transport.class).profileBoundAddresses().get(profile).boundAddress(); TransportAddress transportAddress = randomFrom(internalCluster().getInstance(Transport.class).profileBoundAddresses().get(profile).boundAddresses());
assert transportAddress instanceof InetSocketTransportAddress; assert transportAddress instanceof InetSocketTransportAddress;
return ((InetSocketTransportAddress)transportAddress).address().getPort(); return ((InetSocketTransportAddress)transportAddress).address().getPort();
} }