diff --git a/src/main/java/org/elasticsearch/cluster/metadata/RepositoriesMetaData.java b/src/main/java/org/elasticsearch/cluster/metadata/RepositoriesMetaData.java index 52e28ffd21e..f4d81028448 100644 --- a/src/main/java/org/elasticsearch/cluster/metadata/RepositoriesMetaData.java +++ b/src/main/java/org/elasticsearch/cluster/metadata/RepositoriesMetaData.java @@ -202,9 +202,7 @@ public class RepositoriesMetaData extends AbstractDiffable implements Me builder.startObject(repository.name(), XContentBuilder.FieldCaseConversion.NONE); builder.field("type", repository.type()); builder.startObject("settings"); - for (Map.Entry settingEntry : repository.settings().getAsMap().entrySet()) { - builder.field(settingEntry.getKey(), settingEntry.getValue()); - } + repository.settings().toXContent(builder, params); builder.endObject(); builder.endObject(); diff --git a/src/main/java/org/elasticsearch/rest/action/admin/cluster/repositories/get/RestGetRepositoriesAction.java b/src/main/java/org/elasticsearch/rest/action/admin/cluster/repositories/get/RestGetRepositoriesAction.java index 85b46925b5f..9f09081417a 100644 --- a/src/main/java/org/elasticsearch/rest/action/admin/cluster/repositories/get/RestGetRepositoriesAction.java +++ b/src/main/java/org/elasticsearch/rest/action/admin/cluster/repositories/get/RestGetRepositoriesAction.java @@ -27,6 +27,7 @@ import org.elasticsearch.cluster.metadata.RepositoryMetaData; import org.elasticsearch.common.Strings; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.settings.SettingsFilter; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.rest.*; import org.elasticsearch.rest.action.support.RestBuilderListener; @@ -40,11 +41,14 @@ import static org.elasticsearch.rest.RestStatus.OK; */ public class RestGetRepositoriesAction extends BaseRestHandler { + private final SettingsFilter settingsFilter; + @Inject - public RestGetRepositoriesAction(Settings settings, RestController controller, Client client) { + public RestGetRepositoriesAction(Settings settings, RestController controller, Client client, SettingsFilter settingsFilter) { super(settings, controller, client); controller.registerHandler(GET, "/_snapshot", this); controller.registerHandler(GET, "/_snapshot/{repository}", this); + this.settingsFilter = settingsFilter; } @Override @@ -53,6 +57,7 @@ public class RestGetRepositoriesAction extends BaseRestHandler { GetRepositoriesRequest getRepositoriesRequest = getRepositoryRequest(repositories); getRepositoriesRequest.masterNodeTimeout(request.paramAsTime("master_timeout", getRepositoriesRequest.masterNodeTimeout())); getRepositoriesRequest.local(request.paramAsBoolean("local", getRepositoriesRequest.local())); + settingsFilter.addFilterSettingParams(request); client.admin().cluster().getRepositories(getRepositoriesRequest, new RestBuilderListener(channel) { @Override public RestResponse buildResponse(GetRepositoriesResponse response, XContentBuilder builder) throws Exception { diff --git a/src/test/java/org/elasticsearch/snapshots/DedicatedClusterSnapshotRestoreTests.java b/src/test/java/org/elasticsearch/snapshots/DedicatedClusterSnapshotRestoreTests.java index f02041bf6f7..d36bd523154 100644 --- a/src/test/java/org/elasticsearch/snapshots/DedicatedClusterSnapshotRestoreTests.java +++ b/src/test/java/org/elasticsearch/snapshots/DedicatedClusterSnapshotRestoreTests.java @@ -56,9 +56,15 @@ import org.elasticsearch.discovery.zen.elect.ElectMasterService; import org.elasticsearch.index.store.IndexStore; import org.elasticsearch.indices.ttl.IndicesTTLService; import org.elasticsearch.repositories.RepositoryMissingException; +import org.elasticsearch.rest.RestChannel; +import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.rest.RestResponse; +import org.elasticsearch.rest.action.admin.cluster.repositories.get.RestGetRepositoriesAction; +import org.elasticsearch.rest.action.admin.cluster.state.RestClusterStateAction; import org.elasticsearch.snapshots.mockstore.MockRepositoryModule; import org.elasticsearch.snapshots.mockstore.MockRepositoryPlugin; import org.elasticsearch.test.InternalTestCluster; +import org.elasticsearch.test.rest.FakeRestRequest; import org.junit.Ignore; import org.junit.Test; @@ -70,6 +76,7 @@ import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; import static com.google.common.collect.Lists.newArrayList; import static org.elasticsearch.common.settings.Settings.settingsBuilder; @@ -622,6 +629,64 @@ public class DedicatedClusterSnapshotRestoreTests extends AbstractSnapshotTests } + @Test + public void testThatSensitiveRepositorySettingsAreNotExposed() throws Exception { + Settings nodeSettings = settingsBuilder().put("plugin.types", MockRepositoryPlugin.class.getName()).build(); + logger.info("--> start two nodes"); + internalCluster().startNodesAsync(2, nodeSettings).get(); + // Register mock repositories + client().admin().cluster().preparePutRepository("test-repo") + .setType("mock").setSettings(Settings.settingsBuilder() + .put("location", randomRepoPath()) + .put("secret.mock.username", "notsecretusername") + .put("secret.mock.password", "verysecretpassword") + ).get(); + + RestGetRepositoriesAction getRepoAction = internalCluster().getInstance(RestGetRepositoriesAction.class); + RestRequest getRepoRequest = new FakeRestRequest(); + getRepoRequest.params().put("repository", "test-repo"); + final CountDownLatch getRepoLatch = new CountDownLatch(1); + final AtomicReference getRepoError = new AtomicReference<>(); + getRepoAction.handleRequest(getRepoRequest, new RestChannel(getRepoRequest, true) { + @Override + public void sendResponse(RestResponse response) { + try { + assertThat(response.content().toUtf8(), containsString("notsecretusername")); + assertThat(response.content().toUtf8(), not(containsString("verysecretpassword"))); + } catch (AssertionError ex) { + getRepoError.set(ex); + } + getRepoLatch.countDown(); + } + }); + assertTrue(getRepoLatch.await(1, TimeUnit.SECONDS)); + if (getRepoError.get() != null) { + throw getRepoError.get(); + } + + RestClusterStateAction clusterStateAction = internalCluster().getInstance(RestClusterStateAction.class); + RestRequest clusterStateRequest = new FakeRestRequest(); + final CountDownLatch clusterStateLatch = new CountDownLatch(1); + final AtomicReference clusterStateError = new AtomicReference<>(); + clusterStateAction.handleRequest(clusterStateRequest, new RestChannel(clusterStateRequest, true) { + @Override + public void sendResponse(RestResponse response) { + try { + assertThat(response.content().toUtf8(), containsString("notsecretusername")); + assertThat(response.content().toUtf8(), not(containsString("verysecretpassword"))); + } catch (AssertionError ex) { + clusterStateError.set(ex); + } + clusterStateLatch.countDown(); + } + }); + assertTrue(clusterStateLatch.await(1, TimeUnit.SECONDS)); + if (clusterStateError.get() != null) { + throw clusterStateError.get(); + } + + } + @Test @Ignore public void chaosSnapshotTest() throws Exception { diff --git a/src/test/java/org/elasticsearch/snapshots/mockstore/MockRepositoryPlugin.java b/src/test/java/org/elasticsearch/snapshots/mockstore/MockRepositoryPlugin.java index b8aebe421c1..a09c8601f7f 100644 --- a/src/test/java/org/elasticsearch/snapshots/mockstore/MockRepositoryPlugin.java +++ b/src/test/java/org/elasticsearch/snapshots/mockstore/MockRepositoryPlugin.java @@ -19,9 +19,17 @@ package org.elasticsearch.snapshots.mockstore; +import org.elasticsearch.common.inject.AbstractModule; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.inject.Module; +import org.elasticsearch.common.settings.SettingsFilter; import org.elasticsearch.plugins.AbstractPlugin; import org.elasticsearch.repositories.RepositoriesModule; +import java.util.Collection; + +import static com.google.common.collect.Lists.newArrayList; + public class MockRepositoryPlugin extends AbstractPlugin { @Override @@ -37,4 +45,27 @@ public class MockRepositoryPlugin extends AbstractPlugin { public void onModule(RepositoriesModule repositoriesModule) { repositoriesModule.registerRepository("mock", MockRepositoryModule.class); } + + @Override + public Collection> modules() { + Collection> modules = newArrayList(); + modules.add(SettingsFilteringModule.class); + return modules; + } + + public static class SettingsFilteringModule extends AbstractModule { + + @Override + protected void configure() { + bind(SettingsFilteringService.class).asEagerSingleton(); + } + } + + public static class SettingsFilteringService { + @Inject + public SettingsFilteringService(SettingsFilter settingsFilter) { + settingsFilter.addFilter("secret.mock.password"); + } + } + }