Ip filtering: Check correct path for default file
Also added logging, so that on start up a message is logged, if all connections are rejected or the config file is not found. Closes elastic/elasticsearch#48 Original commit: elastic/x-pack-elasticsearch@51f16d75ba
This commit is contained in:
parent
c17c140cd2
commit
25d2480e78
|
@ -5,13 +5,13 @@
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.shield.n2n;
|
package org.elasticsearch.shield.n2n;
|
||||||
|
|
||||||
import org.elasticsearch.ElasticsearchException;
|
|
||||||
import org.elasticsearch.ElasticsearchParseException;
|
import org.elasticsearch.ElasticsearchParseException;
|
||||||
import org.elasticsearch.common.Nullable;
|
import org.elasticsearch.common.Nullable;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.component.AbstractComponent;
|
import org.elasticsearch.common.component.AbstractComponent;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
import org.elasticsearch.common.jackson.dataformat.yaml.snakeyaml.error.YAMLException;
|
import org.elasticsearch.common.jackson.dataformat.yaml.snakeyaml.error.YAMLException;
|
||||||
|
import org.elasticsearch.common.logging.ESLogger;
|
||||||
import org.elasticsearch.common.net.InetAddresses;
|
import org.elasticsearch.common.net.InetAddresses;
|
||||||
import org.elasticsearch.common.netty.handler.ipfilter.IpFilterRule;
|
import org.elasticsearch.common.netty.handler.ipfilter.IpFilterRule;
|
||||||
import org.elasticsearch.common.netty.handler.ipfilter.IpSubnetFilterRule;
|
import org.elasticsearch.common.netty.handler.ipfilter.IpSubnetFilterRule;
|
||||||
|
@ -20,6 +20,7 @@ import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.common.xcontent.yaml.YamlXContent;
|
import org.elasticsearch.common.xcontent.yaml.YamlXContent;
|
||||||
import org.elasticsearch.env.Environment;
|
import org.elasticsearch.env.Environment;
|
||||||
|
import org.elasticsearch.shield.plugin.SecurityPlugin;
|
||||||
import org.elasticsearch.watcher.FileChangesListener;
|
import org.elasticsearch.watcher.FileChangesListener;
|
||||||
import org.elasticsearch.watcher.FileWatcher;
|
import org.elasticsearch.watcher.FileWatcher;
|
||||||
import org.elasticsearch.watcher.ResourceWatcherService;
|
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||||
|
@ -51,7 +52,7 @@ public class IPFilteringN2NAuthenticator extends AbstractComponent implements N2
|
||||||
public IPFilteringN2NAuthenticator(Settings settings, Environment env, ResourceWatcherService watcherService) {
|
public IPFilteringN2NAuthenticator(Settings settings, Environment env, ResourceWatcherService watcherService) {
|
||||||
super(settings);
|
super(settings);
|
||||||
file = resolveFile(componentSettings, env);
|
file = resolveFile(componentSettings, env);
|
||||||
rules = parseFile(file);
|
rules = parseFile(file, logger);
|
||||||
watcher = new FileWatcher(file.getParent().toFile());
|
watcher = new FileWatcher(file.getParent().toFile());
|
||||||
watcher.addListener(new FileListener());
|
watcher.addListener(new FileListener());
|
||||||
watcherService.add(watcher);
|
watcherService.add(watcher);
|
||||||
|
@ -60,13 +61,15 @@ public class IPFilteringN2NAuthenticator extends AbstractComponent implements N2
|
||||||
private Path resolveFile(Settings settings, Environment env) {
|
private Path resolveFile(Settings settings, Environment env) {
|
||||||
String location = settings.get("file");
|
String location = settings.get("file");
|
||||||
if (location == null) {
|
if (location == null) {
|
||||||
return env.configFile().toPath().resolve(DEFAULT_FILE);
|
File shieldDirectory = new File(env.configFile(), SecurityPlugin.NAME);
|
||||||
|
return shieldDirectory.toPath().resolve(DEFAULT_FILE);
|
||||||
}
|
}
|
||||||
return Paths.get(location);
|
return Paths.get(location);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IpFilterRule[] parseFile(Path path) {
|
public static IpFilterRule[] parseFile(Path path, ESLogger logger) {
|
||||||
if (!Files.exists(path)) {
|
if (!Files.exists(path)) {
|
||||||
|
logger.info("No IP filtering rules loaded, as file {} does not exist. Rejecting all incoming connections!", path);
|
||||||
return NO_RULES;
|
return NO_RULES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,8 +112,11 @@ public class IPFilteringN2NAuthenticator extends AbstractComponent implements N2
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rules.size() == 0) {
|
if (rules.size() == 0) {
|
||||||
|
logger.info("No IP filtering rules loaded. Rejecting all incoming connections!");
|
||||||
return NO_RULES;
|
return NO_RULES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.debug("Loaded {} ip filtering rules", rules.size());
|
||||||
return rules.toArray(new IpFilterRule[rules.size()]);
|
return rules.toArray(new IpFilterRule[rules.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,9 +136,13 @@ public class IPFilteringN2NAuthenticator extends AbstractComponent implements N2
|
||||||
public boolean authenticate(@Nullable Principal peerPrincipal, InetAddress peerAddress, int peerPort) {
|
public boolean authenticate(@Nullable Principal peerPrincipal, InetAddress peerAddress, int peerPort) {
|
||||||
for (int i = 0; i < rules.length; i++) {
|
for (int i = 0; i < rules.length; i++) {
|
||||||
if (rules[i].contains(peerAddress)) {
|
if (rules[i].contains(peerAddress)) {
|
||||||
return rules[i].isAllowRule();
|
boolean isAllowed = rules[i].isAllowRule();
|
||||||
|
logger.trace("Authentication rule matched for host [{}]: {}", peerAddress, isAllowed);
|
||||||
|
return isAllowed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.trace("Rejecting host {}", peerAddress);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,7 +150,7 @@ public class IPFilteringN2NAuthenticator extends AbstractComponent implements N2
|
||||||
@Override
|
@Override
|
||||||
public void onFileCreated(File file) {
|
public void onFileCreated(File file) {
|
||||||
if (file.equals(IPFilteringN2NAuthenticator.this.file.toFile())) {
|
if (file.equals(IPFilteringN2NAuthenticator.this.file.toFile())) {
|
||||||
rules = parseFile(file.toPath());
|
rules = parseFile(file.toPath(), logger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,9 +164,7 @@ public class IPFilteringN2NAuthenticator extends AbstractComponent implements N2
|
||||||
@Override
|
@Override
|
||||||
public void onFileChanged(File file) {
|
public void onFileChanged(File file) {
|
||||||
if (file.equals(IPFilteringN2NAuthenticator.this.file.toFile())) {
|
if (file.equals(IPFilteringN2NAuthenticator.this.file.toFile())) {
|
||||||
if (file.equals(IPFilteringN2NAuthenticator.this.file.toFile())) {
|
rules = parseFile(file.toPath(), logger);
|
||||||
rules = parseFile(file.toPath());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,8 @@ public class IPFilteringN2NAuthenticatorTests extends ElasticsearchTestCase {
|
||||||
@Rule
|
@Rule
|
||||||
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||||
|
|
||||||
|
private final Settings resourceWatcherServiceSettings = settingsBuilder().put("watcher.interval.medium", TimeValue.timeValueMillis(200)).build();
|
||||||
|
|
||||||
private ResourceWatcherService resourceWatcherService;
|
private ResourceWatcherService resourceWatcherService;
|
||||||
private File configFile;
|
private File configFile;
|
||||||
private Settings settings;
|
private Settings settings;
|
||||||
|
@ -137,12 +139,11 @@ public class IPFilteringN2NAuthenticatorTests extends ElasticsearchTestCase {
|
||||||
@Test(expected = ElasticsearchParseException.class)
|
@Test(expected = ElasticsearchParseException.class)
|
||||||
public void testThatInvalidFileThrowsCorrectException() throws Exception {
|
public void testThatInvalidFileThrowsCorrectException() throws Exception {
|
||||||
writeConfigFile("deny: all allow: all \n\n");
|
writeConfigFile("deny: all allow: all \n\n");
|
||||||
IPFilteringN2NAuthenticator.parseFile(configFile.toPath());
|
IPFilteringN2NAuthenticator.parseFile(configFile.toPath(), logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeConfigFile(String data) throws IOException {
|
private void writeConfigFile(String data) throws IOException {
|
||||||
Files.write(data.getBytes(Charsets.UTF_8), configFile);
|
Files.write(data.getBytes(Charsets.UTF_8), configFile);
|
||||||
Settings resourceWatcherServiceSettings = settingsBuilder().put("watcher.interval.medium", TimeValue.timeValueMillis(200)).build();
|
|
||||||
resourceWatcherService = new ResourceWatcherService(resourceWatcherServiceSettings, new ThreadPool("resourceWatcher")).start();
|
resourceWatcherService = new ResourceWatcherService(resourceWatcherServiceSettings, new ThreadPool("resourceWatcher")).start();
|
||||||
settings = settingsBuilder().put("shield.n2n.file", configFile.getPath()).build();
|
settings = settingsBuilder().put("shield.n2n.file", configFile.getPath()).build();
|
||||||
ipFilteringN2NAuthenticator = new IPFilteringN2NAuthenticator(settings, new Environment(), resourceWatcherService);
|
ipFilteringN2NAuthenticator = new IPFilteringN2NAuthenticator(settings, new Environment(), resourceWatcherService);
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
package org.elasticsearch.shield.n2n;
|
package org.elasticsearch.shield.n2n;
|
||||||
|
|
||||||
import com.google.common.base.Charsets;
|
import com.google.common.base.Charsets;
|
||||||
import com.google.common.net.InetAddresses;
|
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.transport.InetSocketTransportAddress;
|
import org.elasticsearch.common.transport.InetSocketTransportAddress;
|
||||||
import org.elasticsearch.common.transport.TransportAddress;
|
import org.elasticsearch.common.transport.TransportAddress;
|
||||||
|
@ -18,11 +18,9 @@ import org.junit.Test;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.net.URL;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
|
import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
|
||||||
import static org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
|
import static org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
|
||||||
|
@ -38,12 +36,16 @@ public class IpFilteringIntegrationTests extends ShieldIntegrationTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Settings nodeSettings(int nodeOrdinal) {
|
protected Settings nodeSettings(int nodeOrdinal) {
|
||||||
|
ImmutableSettings.Builder builder = settingsBuilder().put(super.nodeSettings(nodeOrdinal));
|
||||||
|
// either deny all or do not have a configuration file, as this denies by default
|
||||||
|
if (getRandom().nextBoolean()) {
|
||||||
File folder = newFolder();
|
File folder = newFolder();
|
||||||
|
builder.put("shield.n2n.file", writeFile(folder, "ip_filter.yml", CONFIG_IPFILTER_DENY_ALL));
|
||||||
|
} else {
|
||||||
|
builder.remove("shield.n2n.file");
|
||||||
|
}
|
||||||
|
|
||||||
return settingsBuilder()
|
return builder.build();
|
||||||
.put(super.nodeSettings(nodeOrdinal))
|
|
||||||
.put("shield.n2n.file", writeFile(folder, "ip_filter.yml", CONFIG_IPFILTER_DENY_ALL))
|
|
||||||
.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = SocketException.class)
|
@Test(expected = SocketException.class)
|
||||||
|
@ -51,21 +53,22 @@ public class IpFilteringIntegrationTests extends ShieldIntegrationTest {
|
||||||
TransportAddress transportAddress = internalCluster().getDataNodeInstance(HttpServerTransport.class).boundAddress().boundAddress();
|
TransportAddress transportAddress = internalCluster().getDataNodeInstance(HttpServerTransport.class).boundAddress().boundAddress();
|
||||||
assertThat(transportAddress, is(instanceOf(InetSocketTransportAddress.class)));
|
assertThat(transportAddress, is(instanceOf(InetSocketTransportAddress.class)));
|
||||||
InetSocketTransportAddress inetSocketTransportAddress = (InetSocketTransportAddress) transportAddress;
|
InetSocketTransportAddress inetSocketTransportAddress = (InetSocketTransportAddress) transportAddress;
|
||||||
String url = String.format(Locale.ROOT, "http://%s:%s/", InetAddresses.toUriString(inetSocketTransportAddress.address().getAddress()), inetSocketTransportAddress.address().getPort());
|
|
||||||
|
|
||||||
logger.info("Opening connection to {}", url);
|
trySocketConnection(inetSocketTransportAddress.address());
|
||||||
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
|
|
||||||
connection.connect();
|
|
||||||
logger.info("HTTP connection response code [{}]", connection.getResponseCode());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = SocketException.class)
|
@Test(expected = SocketException.class)
|
||||||
public void testThatIpFilteringIsIntegratedIntoNettyPipelineViaTransportClient() throws Exception {
|
public void testThatIpFilteringIsIntegratedIntoNettyPipelineViaTransportClient() throws Exception {
|
||||||
InetSocketTransportAddress transportAddress = (InetSocketTransportAddress) internalCluster().getDataNodeInstance(Transport.class).boundAddress().boundAddress();
|
TransportAddress transportAddress = (InetSocketTransportAddress) internalCluster().getDataNodeInstance(Transport.class).boundAddress().boundAddress();
|
||||||
|
assertThat(transportAddress, is(instanceOf(InetSocketTransportAddress.class)));
|
||||||
|
InetSocketTransportAddress inetSocketTransportAddress = (InetSocketTransportAddress) transportAddress;
|
||||||
|
trySocketConnection(inetSocketTransportAddress.address());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void trySocketConnection(InetSocketAddress address) throws Exception {
|
||||||
try (Socket socket = new Socket()) {
|
try (Socket socket = new Socket()) {
|
||||||
logger.info("Connecting to {}", transportAddress.address());
|
logger.info("Connecting to {}", address);
|
||||||
socket.connect(transportAddress.address(), 500);
|
socket.connect(address, 500);
|
||||||
|
|
||||||
assertThat(socket.isConnected(), is(true));
|
assertThat(socket.isConnected(), is(true));
|
||||||
try (OutputStream os = socket.getOutputStream()) {
|
try (OutputStream os = socket.getOutputStream()) {
|
||||||
|
|
Loading…
Reference in New Issue