From e82c969959da090f2aeb3941a574100af43f07e1 Mon Sep 17 00:00:00 2001 From: jaymode Date: Wed, 13 Jan 2016 10:07:01 -0500 Subject: [PATCH] migrate from ContextAndHeaders to ThreadContext This change migrates all of the xpack code to use the new ThreadContext when dealing with headers and context data. For the most part this is a simple cutover, but there are some things that required special casing. The internal actions that executed by a user's requests need to forcefully drop the context and set the system user. The workaround for this will be improved in a followup. Additionally, the RequestContext still lives on due to the OptOutQueryCache, which requires some core changes to fix this issue. Original commit: elastic/x-pack-elasticsearch@87d2966d936f8ed91c844089c04e03ccd7e1eaae --- .../tests/ShieldCachePermissionTests.java | 8 +- .../shield/qa/ShieldTransportClientIT.java | 3 +- .../java/org/elasticsearch/shield/RestIT.java | 4 +- .../example/realm/CustomRealm.java | 21 +- .../example/realm/CustomRealmFactory.java | 6 +- .../example/realm/CustomRealmIT.java | 14 +- .../smoketest/SmokeTestPluginsSslIT.java | 4 +- .../smoketest/SmokeTestPluginsIT.java | 4 +- .../smoketest/WatcherWithShieldIT.java | 6 +- .../plugin/rest/RestDeleteLicenseAction.java | 2 +- .../plugin/rest/RestGetLicenseAction.java | 2 +- .../plugin/rest/RestPutLicenseAction.java | 2 +- .../shield/MarvelShieldIntegration.java | 12 +- .../marvel/shield/SecuredClient.java | 9 +- .../collector/AbstractCollectorTestCase.java | 8 +- .../marvel/test/MarvelIntegTestCase.java | 15 +- .../elasticsearch/shield/ShieldPlugin.java | 7 +- .../shield/action/ShieldActionFilter.java | 61 +++- .../action/admin/role/RestAddRoleAction.java | 2 +- .../admin/role/RestDeleteRoleAction.java | 2 +- .../action/admin/role/RestGetRolesAction.java | 2 +- .../action/admin/user/RestAddUserAction.java | 2 +- .../admin/user/RestDeleteUserAction.java | 2 +- .../action/admin/user/RestGetUsersAction.java | 2 +- .../authc/cache/ClearRealmCacheRequest.java | 2 +- .../authz/cache/ClearRolesCacheRequest.java | 2 +- .../interceptor/BulkRequestInterceptor.java | 9 +- ...cumentLevelSecurityRequestInterceptor.java | 8 +- .../RealtimeRequestInterceptor.java | 5 +- .../interceptor/SearchRequestInterceptor.java | 5 +- .../interceptor/UpdateRequestInterceptor.java | 5 +- .../shield/admin/ShieldTemplateService.java | 29 +- .../shield/audit/index/IndexAuditTrail.java | 53 ++-- .../audit/logfile/LoggingAuditTrail.java | 90 +++--- .../shield/authc/AuthenticationService.java | 7 +- .../authc/InternalAuthenticationService.java | 81 +++-- .../org/elasticsearch/shield/authc/Realm.java | 18 +- .../activedirectory/ActiveDirectoryRealm.java | 5 +- .../authc/esnative/ESNativeUsersStore.java | 43 ++- .../shield/authc/esusers/ESUsersRealm.java | 9 +- .../shield/authc/ldap/LdapRealm.java | 5 +- .../authc/ldap/support/AbstractLdapRealm.java | 5 +- .../shield/authc/pki/PkiRealm.java | 12 +- .../authc/support/UsernamePasswordRealm.java | 16 +- .../authc/support/UsernamePasswordToken.java | 11 +- .../authz/InternalAuthorizationService.java | 19 +- .../authz/accesscontrol/OptOutQueryCache.java | 2 +- .../authz/accesscontrol/RequestContext.java | 9 +- .../ShieldIndexSearcherWrapper.java | 24 +- .../authz/esnative/ESNativeRolesStore.java | 45 ++- .../shield/rest/RemoteHostHeader.java | 14 +- .../shield/rest/ShieldRestFilter.java | 15 +- .../rest/action/RestAuthenticateAction.java | 2 +- .../rest/action/RestShieldInfoAction.java | 2 +- .../cache/RestClearRealmCacheAction.java | 2 +- .../cache/RestClearRolesCacheAction.java | 2 +- .../transport/ClientTransportFilter.java | 2 +- .../transport/ServerTransportFilter.java | 15 +- .../ShieldServerTransportService.java | 55 +++- .../netty/ShieldNettyHttpServerTransport.java | 7 +- .../integration/BulkUpdateTests.java | 2 +- .../integration/ClearRealmsCacheTests.java | 4 +- .../DocumentAndFieldLevelSecurityTests.java | 22 +- .../DocumentLevelSecurityRandomTests.java | 5 +- .../DocumentLevelSecurityTests.java | 130 ++++---- .../FieldLevelSecurityRandomTests.java | 21 +- .../integration/FieldLevelSecurityTests.java | 258 ++++++++-------- ...onsWithAliasesWildcardsAndRegexsTests.java | 14 +- .../integration/LicensingTests.java | 4 +- .../MultipleIndicesPermissionsTests.java | 36 ++- .../PermissionPrecedenceTests.java | 13 +- .../SearchGetAndSuggestPermissionsTests.java | 30 +- .../integration/ShieldClearScrollTests.java | 20 +- .../ldap/AbstractAdLdapRealmTestCase.java | 13 +- .../action/ShieldActionFilterTests.java | 6 +- .../shield/admin/ESNativeTests.java | 21 +- .../audit/index/IndexAuditTrailTests.java | 2 +- .../RemoteIndexAuditTrailStartingTests.java | 4 +- .../audit/logfile/LoggingAuditTrailTests.java | 119 +++++--- .../InternalAuthenticationServiceTests.java | 266 +++++++++------- .../shield/authc/RealmsTests.java | 10 +- .../shield/authc/RunAsIntegTests.java | 30 +- .../authc/esusers/ESUsersRealmTests.java | 41 +-- .../shield/authc/pki/PkiRealmTests.java | 41 +-- .../support/UsernamePasswordTokenTests.java | 27 +- .../shield/authz/AnalyzeTests.java | 22 +- .../shield/authz/IndexAliasesTests.java | 288 ++++++++---------- .../InternalAuthorizationServiceTests.java | 15 +- ...dIndexSearcherWrapperIntegrationTests.java | 13 +- .../ShieldIndexSearcherWrapperUnitTests.java | 45 +-- .../shield/rest/ShieldRestFilterTests.java | 6 +- .../transport/ClientTransportFilterTests.java | 2 +- .../transport/ServerTransportFilterTests.java | 4 +- .../ShieldNettyHttpServerTransportTests.java | 9 +- .../test/ShieldIntegTestCase.java | 12 +- .../test/ShieldSettingsSource.java | 21 +- .../xpack/test/rest/XPackRestTestCase.java | 4 +- .../watcher/client/WatcherClient.java | 8 +- .../watcher/execution/ExecutionService.java | 3 +- .../execution/InternalWatchExecutor.java | 8 + .../watcher/execution/WatchExecutor.java | 3 + .../watcher/rest/WatcherRestHandler.java | 4 +- .../rest/action/RestAckWatchAction.java | 2 +- .../rest/action/RestActivateWatchAction.java | 8 +- .../rest/action/RestDeleteWatchAction.java | 2 +- .../rest/action/RestExecuteWatchAction.java | 2 +- .../rest/action/RestGetWatchAction.java | 2 +- .../action/RestHijackOperationAction.java | 10 +- .../rest/action/RestPutWatchAction.java | 2 +- .../rest/action/RestWatchServiceAction.java | 14 +- .../rest/action/RestWatcherInfoAction.java | 2 +- .../rest/action/RestWatcherStatsAction.java | 2 +- .../watcher/shield/ShieldIntegration.java | 21 +- .../watcher/support/WatcherUtils.java | 2 +- .../support/init/proxy/ClientProxy.java | 21 +- .../init/proxy/ScriptServiceProxy.java | 40 ++- .../watcher/shield/BasicShieldTests.java | 46 ++- .../AbstractWatcherIntegrationTestCase.java | 20 +- .../watcher/test/TimeWarpedWatcherPlugin.java | 6 + 119 files changed, 1443 insertions(+), 1200 deletions(-) diff --git a/elasticsearch/qa/messy-test-xpack-with-mustache/src/test/java/org/elasticsearch/messy/tests/ShieldCachePermissionTests.java b/elasticsearch/qa/messy-test-xpack-with-mustache/src/test/java/org/elasticsearch/messy/tests/ShieldCachePermissionTests.java index 89ea309c3b9..51acd912627 100644 --- a/elasticsearch/qa/messy-test-xpack-with-mustache/src/test/java/org/elasticsearch/messy/tests/ShieldCachePermissionTests.java +++ b/elasticsearch/qa/messy-test-xpack-with-mustache/src/test/java/org/elasticsearch/messy/tests/ShieldCachePermissionTests.java @@ -95,9 +95,9 @@ public class ShieldCachePermissionTests extends ShieldIntegTestCase { // Repeat with unauthorized user!!!! try { - response = client().prepareSearch("data").setTypes("a").setQuery(QueryBuilders.constantScoreQuery( + response = client().filterWithHeader(Collections.singletonMap("Authorization", basicAuthHeaderValue(READ_ONE_IDX_USER, new SecuredString("changeme".toCharArray())))) + .prepareSearch("data").setTypes("a").setQuery(QueryBuilders.constantScoreQuery( QueryBuilders.termsLookupQuery("token", new TermsLookup("tokens", "tokens", "1", "tokens")))) - .putHeader("Authorization", basicAuthHeaderValue(READ_ONE_IDX_USER, new SecuredString("changeme".toCharArray()))) .execute().actionGet(); fail("search phase exception should have been thrown! response was:\n" + response.toString()); } catch (SearchPhaseExecutionException e) { @@ -115,9 +115,9 @@ public class ShieldCachePermissionTests extends ShieldIntegTestCase { // Repeat with unauthorized user!!!! try { - response = client().prepareSearch("data").setTypes("a") + response = client().filterWithHeader(Collections.singletonMap("Authorization", basicAuthHeaderValue(READ_ONE_IDX_USER, new SecuredString("changeme".toCharArray())))) + .prepareSearch("data").setTypes("a") .setTemplate(new Template("testTemplate", ScriptService.ScriptType.INDEXED, MustacheScriptEngineService.NAME, null, Collections.singletonMap("name", "token"))) - .putHeader("Authorization", basicAuthHeaderValue(READ_ONE_IDX_USER, new SecuredString("changeme".toCharArray()))) .execute().actionGet(); fail("search phase exception should have been thrown! response was:\n" + response.toString()); } catch (SearchPhaseExecutionException e) { diff --git a/elasticsearch/qa/shield-client-tests/src/test/java/org/elasticsearch/shield/qa/ShieldTransportClientIT.java b/elasticsearch/qa/shield-client-tests/src/test/java/org/elasticsearch/shield/qa/ShieldTransportClientIT.java index 96c44da55df..65401e78c43 100644 --- a/elasticsearch/qa/shield-client-tests/src/test/java/org/elasticsearch/shield/qa/ShieldTransportClientIT.java +++ b/elasticsearch/qa/shield-client-tests/src/test/java/org/elasticsearch/shield/qa/ShieldTransportClientIT.java @@ -90,7 +90,8 @@ public class ShieldTransportClientIT extends ESIntegTestCase { // this checks that the transport client is really running in a limited state ClusterHealthResponse response; if (useTransportUser) { - response = client.admin().cluster().prepareHealth().putHeader("Authorization", basicAuthHeaderValue("test_user", new SecuredString("changeme".toCharArray()))).get(); + response = client.filterWithHeader(Collections.singletonMap("Authorization", basicAuthHeaderValue("test_user", new SecuredString("changeme".toCharArray())))) + .admin().cluster().prepareHealth().get(); } else { response = client.admin().cluster().prepareHealth().get(); } diff --git a/elasticsearch/qa/shield-core-rest-tests/src/test/java/org/elasticsearch/shield/RestIT.java b/elasticsearch/qa/shield-core-rest-tests/src/test/java/org/elasticsearch/shield/RestIT.java index 1be6b237b0d..e636d968ec2 100644 --- a/elasticsearch/qa/shield-core-rest-tests/src/test/java/org/elasticsearch/shield/RestIT.java +++ b/elasticsearch/qa/shield-core-rest-tests/src/test/java/org/elasticsearch/shield/RestIT.java @@ -7,8 +7,8 @@ package org.elasticsearch.shield; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; -import org.elasticsearch.client.support.Headers; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.test.rest.ESRestTestCase; import org.elasticsearch.test.rest.RestTestCandidate; @@ -36,7 +36,7 @@ public class RestIT extends ESRestTestCase { protected Settings restClientSettings() { String token = basicAuthHeaderValue(USER, new SecuredString(PASS.toCharArray())); return Settings.builder() - .put(Headers.PREFIX + ".Authorization", token) + .put(ThreadContext.PREFIX + ".Authorization", token) .build(); } } diff --git a/elasticsearch/qa/shield-example-realm/src/main/java/org/elasticsearch/example/realm/CustomRealm.java b/elasticsearch/qa/shield-example-realm/src/main/java/org/elasticsearch/example/realm/CustomRealm.java index a4e02ae55be..0bd6898c772 100644 --- a/elasticsearch/qa/shield-example-realm/src/main/java/org/elasticsearch/example/realm/CustomRealm.java +++ b/elasticsearch/qa/shield-example-realm/src/main/java/org/elasticsearch/example/realm/CustomRealm.java @@ -5,14 +5,13 @@ */ package org.elasticsearch.example.realm; -import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.shield.User; import org.elasticsearch.shield.authc.AuthenticationToken; import org.elasticsearch.shield.authc.Realm; import org.elasticsearch.shield.authc.RealmConfig; import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.shield.authc.support.UsernamePasswordToken; -import org.elasticsearch.transport.TransportMessage; public class CustomRealm extends Realm { @@ -35,22 +34,10 @@ public class CustomRealm extends Realm { } @Override - public UsernamePasswordToken token(RestRequest request) { - String user = request.header(USER_HEADER); + public UsernamePasswordToken token(ThreadContext threadContext) { + String user = threadContext.getHeader(USER_HEADER); if (user != null) { - String password = request.header(PW_HEADER); - if (password != null) { - return new UsernamePasswordToken(user, new SecuredString(password.toCharArray())); - } - } - return null; - } - - @Override - public UsernamePasswordToken token(TransportMessage message) { - String user = message.getHeader(USER_HEADER); - if (user != null) { - String password = message.getHeader(PW_HEADER); + String password = threadContext.getHeader(PW_HEADER); if (password != null) { return new UsernamePasswordToken(user, new SecuredString(password.toCharArray())); } diff --git a/elasticsearch/qa/shield-example-realm/src/main/java/org/elasticsearch/example/realm/CustomRealmFactory.java b/elasticsearch/qa/shield-example-realm/src/main/java/org/elasticsearch/example/realm/CustomRealmFactory.java index 9b652072ba3..2bab07e8267 100644 --- a/elasticsearch/qa/shield-example-realm/src/main/java/org/elasticsearch/example/realm/CustomRealmFactory.java +++ b/elasticsearch/qa/shield-example-realm/src/main/java/org/elasticsearch/example/realm/CustomRealmFactory.java @@ -5,13 +5,17 @@ */ package org.elasticsearch.example.realm; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.rest.RestController; import org.elasticsearch.shield.authc.Realm; import org.elasticsearch.shield.authc.RealmConfig; public class CustomRealmFactory extends Realm.Factory { - public CustomRealmFactory() { + @Inject + public CustomRealmFactory(RestController controller) { super(CustomRealm.TYPE, false); + controller.registerRelevantHeaders(CustomRealm.USER_HEADER, CustomRealm.PW_HEADER); } @Override diff --git a/elasticsearch/qa/shield-example-realm/src/test/java/org/elasticsearch/example/realm/CustomRealmIT.java b/elasticsearch/qa/shield-example-realm/src/test/java/org/elasticsearch/example/realm/CustomRealmIT.java index ad0110cf734..2bd0c252abe 100644 --- a/elasticsearch/qa/shield-example-realm/src/test/java/org/elasticsearch/example/realm/CustomRealmIT.java +++ b/elasticsearch/qa/shield-example-realm/src/test/java/org/elasticsearch/example/realm/CustomRealmIT.java @@ -8,11 +8,11 @@ package org.elasticsearch.example.realm; import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse; import org.elasticsearch.action.admin.cluster.node.info.NodeInfo; import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse; -import org.elasticsearch.client.support.Headers; import org.elasticsearch.client.transport.NoNodeAvailableException; import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.TransportAddress; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.plugins.Plugin; import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.rest.client.http.HttpResponse; @@ -30,8 +30,8 @@ public class CustomRealmIT extends ESIntegTestCase { @Override protected Settings externalClusterClientSettings() { return Settings.builder() - .put(Headers.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER) - .put(Headers.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW) + .put(ThreadContext.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER) + .put(ThreadContext.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW) .build(); } @@ -64,8 +64,8 @@ public class CustomRealmIT extends ESIntegTestCase { Settings settings = Settings.builder() .put("cluster.name", clusterName) - .put(Headers.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER) - .put(Headers.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW) + .put(ThreadContext.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER) + .put(ThreadContext.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW) .build(); try (TransportClient client = TransportClient.builder().settings(settings).addPlugin(XPackPlugin.class).build()) { client.addTransportAddress(publishAddress); @@ -83,8 +83,8 @@ public class CustomRealmIT extends ESIntegTestCase { Settings settings = Settings.builder() .put("cluster.name", clusterName) - .put(Headers.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER + randomAsciiOfLength(1)) - .put(Headers.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW) + .put(ThreadContext.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER + randomAsciiOfLength(1)) + .put(ThreadContext.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW) .build(); try (TransportClient client = TransportClient.builder().addPlugin(XPackPlugin.class).settings(settings).build()) { client.addTransportAddress(publishAddress); diff --git a/elasticsearch/qa/smoke-test-plugins-ssl/src/test/java/org/elasticsearch/smoketest/SmokeTestPluginsSslIT.java b/elasticsearch/qa/smoke-test-plugins-ssl/src/test/java/org/elasticsearch/smoketest/SmokeTestPluginsSslIT.java index 059d3b7391d..17878a9e51f 100644 --- a/elasticsearch/qa/smoke-test-plugins-ssl/src/test/java/org/elasticsearch/smoketest/SmokeTestPluginsSslIT.java +++ b/elasticsearch/qa/smoke-test-plugins-ssl/src/test/java/org/elasticsearch/smoketest/SmokeTestPluginsSslIT.java @@ -8,9 +8,9 @@ package org.elasticsearch.smoketest; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.elasticsearch.ElasticsearchException; -import org.elasticsearch.client.support.Headers; import org.elasticsearch.common.io.PathUtils; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.test.rest.ESRestTestCase; import org.elasticsearch.test.rest.RestTestCandidate; @@ -64,7 +64,7 @@ public class SmokeTestPluginsSslIT extends ESRestTestCase { protected Settings restClientSettings() { String token = basicAuthHeaderValue(USER, new SecuredString(PASS.toCharArray())); return Settings.builder() - .put(Headers.PREFIX + ".Authorization", token) + .put(ThreadContext.PREFIX + ".Authorization", token) .put(RestClient.PROTOCOL, "https") .put(RestClient.TRUSTSTORE_PATH, keyStore) .put(RestClient.TRUSTSTORE_PASSWORD, KEYSTORE_PASS) diff --git a/elasticsearch/qa/smoke-test-plugins/src/test/java/org/elasticsearch/smoketest/SmokeTestPluginsIT.java b/elasticsearch/qa/smoke-test-plugins/src/test/java/org/elasticsearch/smoketest/SmokeTestPluginsIT.java index cee8474ab58..1eb52f667c4 100644 --- a/elasticsearch/qa/smoke-test-plugins/src/test/java/org/elasticsearch/smoketest/SmokeTestPluginsIT.java +++ b/elasticsearch/qa/smoke-test-plugins/src/test/java/org/elasticsearch/smoketest/SmokeTestPluginsIT.java @@ -7,8 +7,8 @@ package org.elasticsearch.smoketest; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; -import org.elasticsearch.client.support.Headers; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.test.rest.ESRestTestCase; import org.elasticsearch.test.rest.RestTestCandidate; @@ -36,7 +36,7 @@ public class SmokeTestPluginsIT extends ESRestTestCase { protected Settings restClientSettings() { String token = basicAuthHeaderValue(USER, new SecuredString(PASS.toCharArray())); return Settings.builder() - .put(Headers.PREFIX + ".Authorization", token) + .put(ThreadContext.PREFIX + ".Authorization", token) .build(); } } diff --git a/elasticsearch/qa/smoke-test-watcher-with-shield/src/test/java/org/elasticsearch/smoketest/WatcherWithShieldIT.java b/elasticsearch/qa/smoke-test-watcher-with-shield/src/test/java/org/elasticsearch/smoketest/WatcherWithShieldIT.java index 26defbbac7c..16ea6d762fa 100644 --- a/elasticsearch/qa/smoke-test-watcher-with-shield/src/test/java/org/elasticsearch/smoketest/WatcherWithShieldIT.java +++ b/elasticsearch/qa/smoke-test-watcher-with-shield/src/test/java/org/elasticsearch/smoketest/WatcherWithShieldIT.java @@ -15,8 +15,8 @@ import org.apache.http.client.methods.HttpPut; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.BasicHttpClientConnectionManager; -import org.elasticsearch.client.support.Headers; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.shield.authc.support.UsernamePasswordToken; import org.elasticsearch.test.rest.ESRestTestCase; @@ -67,7 +67,7 @@ public class WatcherWithShieldIT extends ESRestTestCase { protected Settings restClientSettings() { String token = basicAuthHeaderValue("watcher_manager", new SecuredString("changeme".toCharArray())); return Settings.builder() - .put(Headers.PREFIX + ".Authorization", token) + .put(ThreadContext.PREFIX + ".Authorization", token) .build(); } @@ -75,7 +75,7 @@ public class WatcherWithShieldIT extends ESRestTestCase { protected Settings restAdminSettings() { String token = basicAuthHeaderValue(TEST_ADMIN_USERNAME, new SecuredString(TEST_ADMIN_PASSWORD.toCharArray())); return Settings.builder() - .put(Headers.PREFIX + ".Authorization", token) + .put(ThreadContext.PREFIX + ".Authorization", token) .build(); } } diff --git a/elasticsearch/x-pack/license-plugin/src/main/java/org/elasticsearch/license/plugin/rest/RestDeleteLicenseAction.java b/elasticsearch/x-pack/license-plugin/src/main/java/org/elasticsearch/license/plugin/rest/RestDeleteLicenseAction.java index 33570b95262..5f058098da3 100644 --- a/elasticsearch/x-pack/license-plugin/src/main/java/org/elasticsearch/license/plugin/rest/RestDeleteLicenseAction.java +++ b/elasticsearch/x-pack/license-plugin/src/main/java/org/elasticsearch/license/plugin/rest/RestDeleteLicenseAction.java @@ -23,7 +23,7 @@ public class RestDeleteLicenseAction extends BaseRestHandler { @Inject public RestDeleteLicenseAction(Settings settings, RestController controller, Client client) { - super(settings, controller, client); + super(settings, client); controller.registerHandler(DELETE, "/_license", this); } diff --git a/elasticsearch/x-pack/license-plugin/src/main/java/org/elasticsearch/license/plugin/rest/RestGetLicenseAction.java b/elasticsearch/x-pack/license-plugin/src/main/java/org/elasticsearch/license/plugin/rest/RestGetLicenseAction.java index 9f84017137f..50efc2962c9 100644 --- a/elasticsearch/x-pack/license-plugin/src/main/java/org/elasticsearch/license/plugin/rest/RestGetLicenseAction.java +++ b/elasticsearch/x-pack/license-plugin/src/main/java/org/elasticsearch/license/plugin/rest/RestGetLicenseAction.java @@ -32,7 +32,7 @@ public class RestGetLicenseAction extends BaseRestHandler { @Inject public RestGetLicenseAction(Settings settings, RestController controller, Client client) { - super(settings, controller, client); + super(settings, client); controller.registerHandler(GET, "/_license", this); } diff --git a/elasticsearch/x-pack/license-plugin/src/main/java/org/elasticsearch/license/plugin/rest/RestPutLicenseAction.java b/elasticsearch/x-pack/license-plugin/src/main/java/org/elasticsearch/license/plugin/rest/RestPutLicenseAction.java index 52e328e040a..71dd598ab47 100644 --- a/elasticsearch/x-pack/license-plugin/src/main/java/org/elasticsearch/license/plugin/rest/RestPutLicenseAction.java +++ b/elasticsearch/x-pack/license-plugin/src/main/java/org/elasticsearch/license/plugin/rest/RestPutLicenseAction.java @@ -29,7 +29,7 @@ public class RestPutLicenseAction extends BaseRestHandler { @Inject public RestPutLicenseAction(Settings settings, RestController controller, Client client) { - super(settings, controller, client); + super(settings, client); controller.registerHandler(PUT, "/_license", this); controller.registerHandler(POST, "/_license", this); } diff --git a/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/shield/MarvelShieldIntegration.java b/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/shield/MarvelShieldIntegration.java index 9873319ac75..1f54956dec1 100644 --- a/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/shield/MarvelShieldIntegration.java +++ b/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/shield/MarvelShieldIntegration.java @@ -6,13 +6,13 @@ package org.elasticsearch.marvel.shield; import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.client.Client; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Injector; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.shield.ShieldPlugin; import org.elasticsearch.shield.ShieldSettingsFilter; import org.elasticsearch.shield.authc.AuthenticationService; -import org.elasticsearch.transport.TransportMessage; import java.io.IOException; @@ -24,18 +24,24 @@ public class MarvelShieldIntegration { private final boolean enabled; private final AuthenticationService authcService; private final ShieldSettingsFilter settingsFilter; + private final Client client; @Inject public MarvelShieldIntegration(Settings settings, Injector injector) { enabled = enabled(settings); authcService = enabled ? injector.getInstance(AuthenticationService.class) : null; settingsFilter = enabled ? injector.getInstance(ShieldSettingsFilter.class) : null; + client = injector.getInstance(Client.class); } - public void bindInternalMarvelUser(TransportMessage message) { + public Client getClient() { + return client; + } + + public void bindInternalMarvelUser() { if (authcService != null) { try { - authcService.attachUserHeaderIfMissing(message, InternalMarvelUser.INSTANCE); + authcService.attachUserHeaderIfMissing(InternalMarvelUser.INSTANCE); } catch (IOException e) { throw new ElasticsearchException("failed to attach marvel user to request", e); } diff --git a/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/shield/SecuredClient.java b/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/shield/SecuredClient.java index 488fdbfbb02..a4be6e013c4 100644 --- a/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/shield/SecuredClient.java +++ b/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/shield/SecuredClient.java @@ -13,6 +13,7 @@ import org.elasticsearch.action.ActionResponse; import org.elasticsearch.client.Client; import org.elasticsearch.client.FilterClient; import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.util.concurrent.ThreadContext; /** * @@ -29,8 +30,10 @@ public class SecuredClient extends FilterClient { @Override protected , Response extends ActionResponse, RequestBuilder extends ActionRequestBuilder> void doExecute( - Action action, Request request, ActionListener listener) { - this.shieldIntegration.bindInternalMarvelUser(request); - super.doExecute(action, request, listener); + Action action, Request request, ActionListener listener) { + try (ThreadContext.StoredContext ctx = threadPool().getThreadContext().stashContext()) { + this.shieldIntegration.bindInternalMarvelUser(); + super.doExecute(action, request, listener); + } } } diff --git a/elasticsearch/x-pack/marvel/src/test/java/org/elasticsearch/marvel/agent/collector/AbstractCollectorTestCase.java b/elasticsearch/x-pack/marvel/src/test/java/org/elasticsearch/marvel/agent/collector/AbstractCollectorTestCase.java index b8447d72791..2df5645b9b6 100644 --- a/elasticsearch/x-pack/marvel/src/test/java/org/elasticsearch/marvel/agent/collector/AbstractCollectorTestCase.java +++ b/elasticsearch/x-pack/marvel/src/test/java/org/elasticsearch/marvel/agent/collector/AbstractCollectorTestCase.java @@ -66,12 +66,14 @@ public class AbstractCollectorTestCase extends MarvelIntegTestCase { public SecuredClient securedClient() { MarvelShieldIntegration integration = internalCluster().getInstance(MarvelShieldIntegration.class); - return new SecuredClient(client(), integration); + // we must get the client from the same node! + return new SecuredClient(integration.getClient(), integration); } public SecuredClient securedClient(String nodeId) { - MarvelShieldIntegration integration = internalCluster().getInstance(MarvelShieldIntegration.class); - return new SecuredClient(client(nodeId), integration); + MarvelShieldIntegration integration = internalCluster().getInstance(MarvelShieldIntegration.class, nodeId); + // we must get the client from the same node! + return new SecuredClient(integration.getClient(), integration); } protected void assertCanCollect(AbstractCollector collector) { diff --git a/elasticsearch/x-pack/marvel/src/test/java/org/elasticsearch/marvel/test/MarvelIntegTestCase.java b/elasticsearch/x-pack/marvel/src/test/java/org/elasticsearch/marvel/test/MarvelIntegTestCase.java index 306ca9a58b5..50be32d4bb6 100644 --- a/elasticsearch/x-pack/marvel/src/test/java/org/elasticsearch/marvel/test/MarvelIntegTestCase.java +++ b/elasticsearch/x-pack/marvel/src/test/java/org/elasticsearch/marvel/test/MarvelIntegTestCase.java @@ -6,6 +6,8 @@ package org.elasticsearch.marvel.test; import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.client.Client; +import org.elasticsearch.client.node.NodeClient; import org.elasticsearch.cluster.metadata.IndexTemplateMetaData; import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.Streams; @@ -44,7 +46,9 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.function.Function; +import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures; import static org.hamcrest.Matchers.allOf; @@ -116,6 +120,16 @@ public abstract class MarvelIntegTestCase extends ESIntegTestCase { return nodePlugins(); } + @Override + protected Function getClientWrapper() { + if (shieldEnabled == false) { + return Function.identity(); + } + Map headers = Collections.singletonMap("Authorization", + basicAuthHeaderValue(ShieldSettings.TEST_USERNAME, new SecuredString(ShieldSettings.TEST_PASSWORD.toCharArray()))); + return client -> (client instanceof NodeClient) ? client.filterWithHeader(headers) : client; + } + /** * Override and returns {@code false} to force running without shield */ @@ -386,7 +400,6 @@ public abstract class MarvelIntegTestCase extends ESIntegTestCase { builder.remove("index.queries.cache.type"); builder.put("shield.enabled", true) - .put("shield.user", "test:changeme") .put("shield.authc.realms.esusers.type", ESUsersRealm.TYPE) .put("shield.authc.realms.esusers.order", 0) .put("shield.authc.realms.esusers.files.users", writeFile(folder, "users", USERS)) diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/ShieldPlugin.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/ShieldPlugin.java index 9fb9fa9a694..2eff395ee6c 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/ShieldPlugin.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/ShieldPlugin.java @@ -7,12 +7,12 @@ package org.elasticsearch.shield; import org.elasticsearch.action.ActionModule; import org.elasticsearch.client.Client; -import org.elasticsearch.client.support.Headers; import org.elasticsearch.common.component.LifecycleComponent; import org.elasticsearch.common.inject.Module; import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.SettingsModule; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.env.Environment; import org.elasticsearch.index.IndexModule; import org.elasticsearch.plugins.Plugin; @@ -194,7 +194,8 @@ public class ShieldPlugin extends Plugin { if (flsDlsEnabled(settings)) { module.setSearcherWrapper((indexService) -> new ShieldIndexSearcherWrapper(indexService.getIndexSettings(), indexService.getQueryShardContext(), indexService.mapperService(), - indexService.cache().bitsetFilterCache(), shieldLicenseState)); + indexService.cache().bitsetFilterCache(), indexService.getIndexServices().getThreadPool().getThreadContext(), + shieldLicenseState)); } if (clientMode == false) { module.registerQueryCache(ShieldPlugin.OPT_OUT_QUERY_CACHE, OptOutQueryCache::new); @@ -263,7 +264,7 @@ public class ShieldPlugin extends Plugin { } private void addUserSettings(Settings.Builder settingsBuilder) { - String authHeaderSettingName = Headers.PREFIX + "." + UsernamePasswordToken.BASIC_AUTH_HEADER; + String authHeaderSettingName = ThreadContext.PREFIX + "." + UsernamePasswordToken.BASIC_AUTH_HEADER; if (settings.get(authHeaderSettingName) != null) { return; } diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/ShieldActionFilter.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/ShieldActionFilter.java index 138589e61ba..9a29e8c9fe0 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/ShieldActionFilter.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/ShieldActionFilter.java @@ -16,6 +16,7 @@ import org.elasticsearch.action.support.ActionFilterChain; import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.license.plugin.core.LicenseUtils; import org.elasticsearch.shield.ShieldPlugin; import org.elasticsearch.shield.User; @@ -26,7 +27,10 @@ import org.elasticsearch.shield.authz.AuthorizationService; import org.elasticsearch.shield.authz.privilege.HealthAndStatsPrivilege; import org.elasticsearch.shield.crypto.CryptoService; import org.elasticsearch.shield.license.ShieldLicenseState; +import org.elasticsearch.shield.support.AutomatonPredicate; +import org.elasticsearch.shield.support.Automatons; import org.elasticsearch.tasks.Task; +import org.elasticsearch.threadpool.ThreadPool; import java.io.IOException; import java.util.ArrayList; @@ -42,6 +46,8 @@ import static org.elasticsearch.shield.support.Exceptions.authorizationError; public class ShieldActionFilter extends AbstractComponent implements ActionFilter { private static final Predicate LICENSE_EXPIRATION_ACTION_MATCHER = HealthAndStatsPrivilege.INSTANCE.predicate(); + // FIXME clean up this hack + static final Predicate INTERNAL_PREDICATE = new AutomatonPredicate(Automatons.patterns("internal:*")); private final AuthenticationService authcService; private final AuthorizationService authzService; @@ -50,10 +56,12 @@ public class ShieldActionFilter extends AbstractComponent implements ActionFilte private final ShieldActionMapper actionMapper; private final Set requestInterceptors; private final ShieldLicenseState licenseState; + private final ThreadContext threadContext; @Inject public ShieldActionFilter(Settings settings, AuthenticationService authcService, AuthorizationService authzService, CryptoService cryptoService, - AuditTrail auditTrail, ShieldLicenseState licenseState, ShieldActionMapper actionMapper, Set requestInterceptors) { + AuditTrail auditTrail, ShieldLicenseState licenseState, ShieldActionMapper actionMapper, Set requestInterceptors, + ThreadPool threadPool) { super(settings); this.authcService = authcService; this.authzService = authzService; @@ -62,6 +70,7 @@ public class ShieldActionFilter extends AbstractComponent implements ActionFilte this.actionMapper = actionMapper; this.licenseState = licenseState; this.requestInterceptors = requestInterceptors; + this.threadContext = threadPool.getThreadContext(); } @Override @@ -78,8 +87,56 @@ public class ShieldActionFilter extends AbstractComponent implements ActionFilte throw LicenseUtils.newComplianceException(ShieldPlugin.NAME); } - try { + try (ThreadContext.StoredContext original = threadContext.newStoredContext()) { if (licenseState.securityEnabled()) { + // FIXME yet another hack. Needed to work around something like + /* + FailedNodeException[total failure in fetching]; nested: ElasticsearchSecurityException[action [internal:gateway/local/started_shards] is unauthorized for user [test_user]]; + at org.elasticsearch.gateway.AsyncShardFetch$1.onFailure(AsyncShardFetch.java:284) + at org.elasticsearch.action.support.TransportAction$1.onFailure(TransportAction.java:84) + at org.elasticsearch.shield.action.ShieldActionFilter.apply(ShieldActionFilter.java:121) + at org.elasticsearch.action.support.TransportAction$RequestFilterChain.proceed(TransportAction.java:133) + at org.elasticsearch.action.support.TransportAction.execute(TransportAction.java:107) + at org.elasticsearch.action.support.TransportAction.execute(TransportAction.java:74) + at org.elasticsearch.gateway.TransportNodesListGatewayStartedShards.list(TransportNodesListGatewayStartedShards.java:78) + at org.elasticsearch.gateway.AsyncShardFetch.asyncFetch(AsyncShardFetch.java:274) + at org.elasticsearch.gateway.AsyncShardFetch.fetchData(AsyncShardFetch.java:124) + at org.elasticsearch.gateway.GatewayAllocator$InternalPrimaryShardAllocator.fetchData(GatewayAllocator.java:156) + at org.elasticsearch.gateway.PrimaryShardAllocator.allocateUnassigned(PrimaryShardAllocator.java:83) + at org.elasticsearch.gateway.GatewayAllocator.allocateUnassigned(GatewayAllocator.java:120) + at org.elasticsearch.cluster.routing.allocation.allocator.ShardsAllocators.allocateUnassigned(ShardsAllocators.java:72) + at org.elasticsearch.cluster.routing.allocation.AllocationService.reroute(AllocationService.java:309) + at org.elasticsearch.cluster.routing.allocation.AllocationService.reroute(AllocationService.java:273) + at org.elasticsearch.cluster.routing.allocation.AllocationService.reroute(AllocationService.java:259) + at org.elasticsearch.cluster.routing.RoutingService$2.execute(RoutingService.java:158) + at org.elasticsearch.cluster.ClusterStateUpdateTask.execute(ClusterStateUpdateTask.java:45) + at org.elasticsearch.cluster.service.InternalClusterService.runTasksForExecutor(InternalClusterService.java:447) + at org.elasticsearch.cluster.service.InternalClusterService$UpdateTask.run(InternalClusterService.java:757) + at org.elasticsearch.common.util.concurrent.EsThreadPoolExecutor$FilterRunnable.run(EsThreadPoolExecutor.java:211) + at org.elasticsearch.common.util.concurrent.PrioritizedEsThreadPoolExecutor$TieBreakingPrioritizedRunnable.runAndClean(PrioritizedEsThreadPoolExecutor.java:237) + at org.elasticsearch.common.util.concurrent.PrioritizedEsThreadPoolExecutor$TieBreakingPrioritizedRunnable.run(PrioritizedEsThreadPoolExecutor.java:200) + at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) + at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) + at java.lang.Thread.run(Thread.java:745) + */ + if (INTERNAL_PREDICATE.test(action)) { + try (ThreadContext.StoredContext ctx = threadContext.stashContext()) { + String shieldAction = actionMapper.action(action, request); + User user = authcService.authenticate(shieldAction, request, User.SYSTEM); + authzService.authorize(user, shieldAction, request); + request = unsign(user, shieldAction, request); + + for (RequestInterceptor interceptor : requestInterceptors) { + if (interceptor.supports(request)) { + interceptor.intercept(request, user); + } + } + chain.proceed(task, action, request, new SigningListener(this, listener)); + return; + } + } + + /** here we fallback on the system user. Internal system requests are requests that are triggered by the system itself (e.g. pings, update mappings, share relocation, etc...) and were not originated diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/admin/role/RestAddRoleAction.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/admin/role/RestAddRoleAction.java index e9d7e84ebad..f47c69752d0 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/admin/role/RestAddRoleAction.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/admin/role/RestAddRoleAction.java @@ -27,7 +27,7 @@ public class RestAddRoleAction extends BaseRestHandler { @Inject public RestAddRoleAction(Settings settings, RestController controller, Client client) { - super(settings, controller, client); + super(settings, client); controller.registerHandler(RestRequest.Method.POST, "/_shield/role/{role}", this); controller.registerHandler(RestRequest.Method.PUT, "/_shield/role/{role}", this); } diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/admin/role/RestDeleteRoleAction.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/admin/role/RestDeleteRoleAction.java index 691698b9412..5903bde982a 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/admin/role/RestDeleteRoleAction.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/admin/role/RestDeleteRoleAction.java @@ -26,7 +26,7 @@ public class RestDeleteRoleAction extends BaseRestHandler { @Inject public RestDeleteRoleAction(Settings settings, RestController controller, Client client) { - super(settings, controller, client); + super(settings, client); controller.registerHandler(RestRequest.Method.DELETE, "/_shield/role/{role}", this); } diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/admin/role/RestGetRolesAction.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/admin/role/RestGetRolesAction.java index 94d2412e10e..2683a6c0dac 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/admin/role/RestGetRolesAction.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/admin/role/RestGetRolesAction.java @@ -28,7 +28,7 @@ public class RestGetRolesAction extends BaseRestHandler { @Inject public RestGetRolesAction(Settings settings, RestController controller, Client client) { - super(settings, controller, client); + super(settings, client); controller.registerHandler(RestRequest.Method.GET, "/_shield/role/", this); controller.registerHandler(RestRequest.Method.GET, "/_shield/role/{roles}", this); controller.registerHandler(RestRequest.Method.GET, "/_shield/roles/", this); diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/admin/user/RestAddUserAction.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/admin/user/RestAddUserAction.java index 916e0e3f3b4..ab8d39513ef 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/admin/user/RestAddUserAction.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/admin/user/RestAddUserAction.java @@ -30,7 +30,7 @@ public class RestAddUserAction extends BaseRestHandler { @Inject public RestAddUserAction(Settings settings, RestController controller, Client client) { - super(settings, controller, client); + super(settings, client); controller.registerHandler(RestRequest.Method.POST, "/_shield/user/{username}", this); controller.registerHandler(RestRequest.Method.PUT, "/_shield/user/{username}", this); } diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/admin/user/RestDeleteUserAction.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/admin/user/RestDeleteUserAction.java index 954933f41fd..a37f28cda16 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/admin/user/RestDeleteUserAction.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/admin/user/RestDeleteUserAction.java @@ -30,7 +30,7 @@ public class RestDeleteUserAction extends BaseRestHandler { @Inject public RestDeleteUserAction(Settings settings, RestController controller, Client client) { - super(settings, controller, client); + super(settings, client); controller.registerHandler(RestRequest.Method.DELETE, "/_shield/user/{username}", this); } diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/admin/user/RestGetUsersAction.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/admin/user/RestGetUsersAction.java index 7a9c481b5d6..2383a9eb6ae 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/admin/user/RestGetUsersAction.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/admin/user/RestGetUsersAction.java @@ -29,7 +29,7 @@ public class RestGetUsersAction extends BaseRestHandler { @Inject public RestGetUsersAction(Settings settings, RestController controller, Client client) { - super(settings, controller, client); + super(settings, client); controller.registerHandler(RestRequest.Method.GET, "/_shield/user/", this); controller.registerHandler(RestRequest.Method.GET, "/_shield/user/{user}", this); controller.registerHandler(RestRequest.Method.GET, "/_shield/users/", this); diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/authc/cache/ClearRealmCacheRequest.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/authc/cache/ClearRealmCacheRequest.java index b8d4f0a8561..edc05c062ec 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/authc/cache/ClearRealmCacheRequest.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/authc/cache/ClearRealmCacheRequest.java @@ -93,7 +93,7 @@ public class ClearRealmCacheRequest extends BaseNodesRequest { + private final ThreadContext threadContext; + @Inject - public BulkRequestInterceptor(Settings settings) { + public BulkRequestInterceptor(Settings settings, ThreadPool threadPool) { super(settings); + this.threadContext = threadPool.getThreadContext(); } public void intercept(BulkRequest request, User user) { - IndicesAccessControl indicesAccessControl = ((TransportRequest) request).getFromContext(InternalAuthorizationService.INDICES_PERMISSIONS_KEY); + IndicesAccessControl indicesAccessControl= threadContext.getTransient(InternalAuthorizationService.INDICES_PERMISSIONS_KEY); for (IndicesRequest indicesRequest : request.subRequests()) { for (String index : indicesRequest.indices()) { IndicesAccessControl.IndexAccessControl indexAccessControl = indicesAccessControl.getIndexPermissions(index); diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/interceptor/FieldAndDocumentLevelSecurityRequestInterceptor.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/interceptor/FieldAndDocumentLevelSecurityRequestInterceptor.java index 91613f40c07..6c8fba59d76 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/interceptor/FieldAndDocumentLevelSecurityRequestInterceptor.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/interceptor/FieldAndDocumentLevelSecurityRequestInterceptor.java @@ -10,6 +10,7 @@ import org.elasticsearch.action.IndicesRequest; import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.logging.support.LoggerMessageFormat; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.shield.User; import org.elasticsearch.shield.authz.InternalAuthorizationService; import org.elasticsearch.shield.authz.accesscontrol.IndicesAccessControl; @@ -24,8 +25,11 @@ import java.util.List; */ public abstract class FieldAndDocumentLevelSecurityRequestInterceptor extends AbstractComponent implements RequestInterceptor { - public FieldAndDocumentLevelSecurityRequestInterceptor(Settings settings) { + private final ThreadContext threadContext; + + public FieldAndDocumentLevelSecurityRequestInterceptor(Settings settings, ThreadContext threadContext) { super(settings); + this.threadContext = threadContext; } public void intercept(Request request, User user) { @@ -37,7 +41,7 @@ public abstract class FieldAndDocumentLevelSecurityRequestInterceptor e } else { throw new IllegalArgumentException(LoggerMessageFormat.format("Expected a request of type [{}] or [{}] but got [{}] instead", CompositeIndicesRequest.class, IndicesRequest.class, request.getClass())); } - IndicesAccessControl indicesAccessControl = ((TransportRequest) request).getFromContext(InternalAuthorizationService.INDICES_PERMISSIONS_KEY); + IndicesAccessControl indicesAccessControl = threadContext.getTransient(InternalAuthorizationService.INDICES_PERMISSIONS_KEY); for (IndicesRequest indicesRequest : indicesRequests) { for (String index : indicesRequest.indices()) { IndicesAccessControl.IndexAccessControl indexAccessControl = indicesAccessControl.getIndexPermissions(index); diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/interceptor/RealtimeRequestInterceptor.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/interceptor/RealtimeRequestInterceptor.java index ace29e1e805..df0ac5f1e44 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/interceptor/RealtimeRequestInterceptor.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/interceptor/RealtimeRequestInterceptor.java @@ -8,6 +8,7 @@ package org.elasticsearch.shield.action.interceptor; import org.elasticsearch.action.RealtimeRequest; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportRequest; /** @@ -17,8 +18,8 @@ import org.elasticsearch.transport.TransportRequest; public class RealtimeRequestInterceptor extends FieldAndDocumentLevelSecurityRequestInterceptor { @Inject - public RealtimeRequestInterceptor(Settings settings) { - super(settings); + public RealtimeRequestInterceptor(Settings settings, ThreadPool threadPool) { + super(settings, threadPool.getThreadContext()); } @Override diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/interceptor/SearchRequestInterceptor.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/interceptor/SearchRequestInterceptor.java index e0db0d1efe7..51afa39f1c0 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/interceptor/SearchRequestInterceptor.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/interceptor/SearchRequestInterceptor.java @@ -8,6 +8,7 @@ package org.elasticsearch.shield.action.interceptor; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportRequest; /** @@ -16,8 +17,8 @@ import org.elasticsearch.transport.TransportRequest; public class SearchRequestInterceptor extends FieldAndDocumentLevelSecurityRequestInterceptor { @Inject - public SearchRequestInterceptor(Settings settings) { - super(settings); + public SearchRequestInterceptor(Settings settings, ThreadPool threadPool) { + super(settings, threadPool.getThreadContext()); } @Override diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/interceptor/UpdateRequestInterceptor.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/interceptor/UpdateRequestInterceptor.java index 5043e29dd5b..9cee0ccffd2 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/interceptor/UpdateRequestInterceptor.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/action/interceptor/UpdateRequestInterceptor.java @@ -10,6 +10,7 @@ import org.elasticsearch.action.update.UpdateRequest; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.rest.RestStatus; +import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportRequest; /** @@ -22,8 +23,8 @@ import org.elasticsearch.transport.TransportRequest; public class UpdateRequestInterceptor extends FieldAndDocumentLevelSecurityRequestInterceptor { @Inject - public UpdateRequestInterceptor(Settings settings) { - super(settings); + public UpdateRequestInterceptor(Settings settings, ThreadPool threadPool) { + super(settings, threadPool.getThreadContext()); } @Override diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/admin/ShieldTemplateService.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/admin/ShieldTemplateService.java index 7c0c120824f..77376f8accb 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/admin/ShieldTemplateService.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/admin/ShieldTemplateService.java @@ -6,9 +6,15 @@ package org.elasticsearch.shield.admin; import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.action.Action; +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.ActionRequest; +import org.elasticsearch.action.ActionRequestBuilder; +import org.elasticsearch.action.ActionResponse; import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest; import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateResponse; import org.elasticsearch.client.Client; +import org.elasticsearch.client.FilterClient; import org.elasticsearch.cluster.ClusterChangedEvent; import org.elasticsearch.cluster.ClusterService; import org.elasticsearch.cluster.ClusterState; @@ -21,11 +27,13 @@ import org.elasticsearch.common.inject.Provider; import org.elasticsearch.common.io.Streams; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.AbstractRunnable; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.gateway.GatewayService; import org.elasticsearch.shield.authc.AuthenticationService; import org.elasticsearch.threadpool.ThreadPool; import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.io.InputStream; import java.util.concurrent.atomic.AtomicBoolean; @@ -58,8 +66,7 @@ public class ShieldTemplateService extends AbstractComponent implements ClusterS } private void createShieldTemplate() { - Client client = this.clientProvider.get(); - AuthenticationService authService = this.authProvider.get(); + final Client client = getClient(); try (InputStream is = getClass().getResourceAsStream("/" + SHIELD_TEMPLATE_NAME + ".json")) { ByteArrayOutputStream out = new ByteArrayOutputStream(); Streams.copy(is, out); @@ -67,7 +74,6 @@ public class ShieldTemplateService extends AbstractComponent implements ClusterS logger.info("--> putting the shield index template"); PutIndexTemplateRequest putTemplateRequest = client.admin().indices() .preparePutTemplate(SHIELD_TEMPLATE_NAME).setSource(template).request(); - authService.attachUserHeaderIfMissing(putTemplateRequest, adminUser.user()); PutIndexTemplateResponse templateResponse = client.admin().indices().putTemplate(putTemplateRequest).get(); if (templateResponse.isAcknowledged() == false) { throw new ElasticsearchException("adding template for shield admin index was not acknowledged"); @@ -81,6 +87,23 @@ public class ShieldTemplateService extends AbstractComponent implements ClusterS } + Client getClient() { + Client unwrapped = clientProvider.get(); + return new FilterClient(unwrapped) { + @Override + protected , Response extends ActionResponse, RequestBuilder extends ActionRequestBuilder> void doExecute(Action action, Request request, ActionListener listener) { + try (ThreadContext.StoredContext ctx = threadPool().getThreadContext().stashContext()) { + try { + authProvider.get().attachUserHeaderIfMissing(adminUser.user()); + } catch (IOException e) { + throw new ElasticsearchException("failed to set shield user", e); + } + super.doExecute(action, request, listener); + } + } + }; + } + @Override public void clusterChanged(ClusterChangedEvent event) { if (event.state().blocks().hasGlobalBlock(GatewayService.STATE_NOT_RECOVERED_BLOCK)) { diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/audit/index/IndexAuditTrail.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/audit/index/IndexAuditTrail.java index 6e05dc1e785..db39e85923e 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/audit/index/IndexAuditTrail.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/audit/index/IndexAuditTrail.java @@ -6,6 +6,11 @@ package org.elasticsearch.shield.audit.index; import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.action.Action; +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.ActionRequest; +import org.elasticsearch.action.ActionRequestBuilder; +import org.elasticsearch.action.ActionResponse; import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse; import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsRequest; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; @@ -17,6 +22,7 @@ import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkResponse; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.client.Client; +import org.elasticsearch.client.FilterClient; import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.cluster.ClusterChangedEvent; import org.elasticsearch.cluster.ClusterService; @@ -37,6 +43,7 @@ import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.util.concurrent.AbstractRunnable; import org.elasticsearch.common.util.concurrent.EsExecutors; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilderString; import org.elasticsearch.common.xcontent.XContentFactory; @@ -525,7 +532,7 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail, Cl Message msg = new Message().start(); common("transport", type, msg.builder); - originAttributes(message, msg.builder, transport); + originAttributes(message, msg.builder, transport, threadPool.getThreadContext()); if (action != null) { msg.builder.field(Field.ACTION, action); @@ -557,7 +564,7 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail, Cl Message msg = new Message().start(); common("transport", type, msg.builder); - originAttributes(message, msg.builder, transport); + originAttributes(message, msg.builder, transport, threadPool.getThreadContext()); if (action != null) { msg.builder.field(Field.ACTION, action); @@ -631,10 +638,10 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail, Cl return builder; } - private static XContentBuilder originAttributes(TransportMessage message, XContentBuilder builder, Transport transport) throws IOException { + private static XContentBuilder originAttributes(TransportMessage message, XContentBuilder builder, Transport transport, ThreadContext threadContext) throws IOException { // first checking if the message originated in a rest call - InetSocketAddress restAddress = RemoteHostHeader.restRemoteAddress(message); + InetSocketAddress restAddress = RemoteHostHeader.restRemoteAddress(threadContext); if (restAddress != null) { builder.field(Field.ORIGIN_TYPE, "rest"); builder.field(Field.ORIGIN_ADDRESS, NetworkAddress.formatAddress(restAddress.getAddress())); @@ -677,7 +684,20 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail, Cl private void initializeClient() { if (indexToRemoteCluster == false) { // in the absence of client settings for remote indexing, fall back to the client that was passed in. - this.client = clientProvider.get(); + Client unfiltered = clientProvider.get(); + this.client = new FilterClient(unfiltered) { + @Override + protected , Response extends ActionResponse, RequestBuilder extends ActionRequestBuilder> void doExecute(Action action, Request request, ActionListener listener) { + try (ThreadContext.StoredContext ctx = threadPool().getThreadContext().stashContext()) { + try { + authenticationService.attachUserHeaderIfMissing(auditUser.user()); + } catch (IOException e) { + throw new ElasticsearchException("failed to attach audit user to request", e); + } + super.doExecute(action, request, listener); + } + } + }; } else { Settings clientSettings = settings.getByPrefix("shield.audit.index.client."); String[] hosts = clientSettings.getAsArray("hosts"); @@ -763,7 +783,7 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail, Cl assert !Thread.currentThread().isInterrupted() : "current thread has been interrupted before putting index template!!!"; if (!indexToRemoteCluster) { - authenticationService.attachUserHeaderIfMissing(request, auditUser.user()); + authenticationService.attachUserHeaderIfMissing(auditUser.user()); } PutIndexTemplateResponse response = client.admin().indices().putTemplate(request).actionGet(); if (!response.isAcknowledged()) { @@ -780,18 +800,10 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail, Cl } String index = resolve(INDEX_NAME_PREFIX, dateTime, rollover); IndicesExistsRequest existsRequest = new IndicesExistsRequest(index); - // TODO need to clean this up so we don't forget to attach the header... - if (!indexToRemoteCluster) { - authenticationService.attachUserHeaderIfMissing(existsRequest, auditUser.user()); - } if (client.admin().indices().exists(existsRequest).get().isExists()) { logger.debug("index [{}] exists so we need to update mappings", index); PutMappingRequest putMappingRequest = new PutMappingRequest(index).type(DOC_TYPE).source(request.mappings().get(DOC_TYPE)); - if (!indexToRemoteCluster) { - authenticationService.attachUserHeaderIfMissing(putMappingRequest, auditUser.user()); - } - PutMappingResponse putMappingResponse = client.admin().indices().putMapping(putMappingRequest).get(); if (!putMappingResponse.isAcknowledged()) { throw new IllegalStateException("failed to put mappings for audit logging index [" + index + "]"); @@ -815,15 +827,7 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail, Cl bulkProcessor = BulkProcessor.builder(client, new BulkProcessor.Listener() { @Override - public void beforeBulk(long executionId, BulkRequest request) { - try { - if (!indexToRemoteCluster) { - authenticationService.attachUserHeaderIfMissing(request, auditUser.user()); - } - } catch (IOException e) { - throw new ElasticsearchException("failed to attach user header", e); - } - } + public void beforeBulk(long executionId, BulkRequest request) {} @Override public void afterBulk(long executionId, BulkRequest request, BulkResponse response) { @@ -895,9 +899,6 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail, Cl IndexRequest indexRequest = client.prepareIndex() .setIndex(resolve(INDEX_NAME_PREFIX, message.timestamp, rollover)) .setType(DOC_TYPE).setSource(message.builder).request(); - if (!indexToRemoteCluster) { - authenticationService.attachUserHeaderIfMissing(indexRequest, auditUser.user()); - } bulkProcessor.add(indexRequest); } catch (InterruptedException e) { logger.debug("index audit queue consumer interrupted", e); diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/audit/logfile/LoggingAuditTrail.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/audit/logfile/LoggingAuditTrail.java index c5a9839b85b..179e2fc0271 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/audit/logfile/LoggingAuditTrail.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/audit/logfile/LoggingAuditTrail.java @@ -15,6 +15,7 @@ import org.elasticsearch.common.network.NetworkAddress; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.common.transport.TransportAddress; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.shield.User; import org.elasticsearch.shield.admin.ShieldInternalUserHolder; @@ -24,6 +25,7 @@ import org.elasticsearch.shield.authz.privilege.Privilege; import org.elasticsearch.shield.authz.privilege.SystemPrivilege; import org.elasticsearch.shield.rest.RemoteHostHeader; import org.elasticsearch.shield.transport.filter.ShieldIpFilterRule; +import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.Transport; import org.elasticsearch.transport.TransportMessage; @@ -44,6 +46,7 @@ public class LoggingAuditTrail extends AbstractLifecycleComponent message) { if (logger.isDebugEnabled()) { - logger.debug("{}[transport] [run_as_granted]\t{}, principal=[{}], run_as_principal=[{}], action=[{}], request=[{}]", prefix, originAttributes(message, transport), user.principal(), user.runAs().principal(), action, message.getClass().getSimpleName()); + logger.debug("{}[transport] [run_as_granted]\t{}, principal=[{}], run_as_principal=[{}], action=[{}], request=[{}]", prefix, originAttributes(message, transport, threadContext), user.principal(), user.runAs().principal(), action, message.getClass().getSimpleName()); } else { - logger.info("{}[transport] [run_as_granted]\t{}, principal=[{}], run_as_principal=[{}], action=[{}]", prefix, originAttributes(message, transport), user.principal(), user.runAs().principal(), action); + logger.info("{}[transport] [run_as_granted]\t{}, principal=[{}], run_as_principal=[{}], action=[{}]", prefix, originAttributes(message, transport, threadContext), user.principal(), user.runAs().principal(), action); } } @Override public void runAsDenied(User user, String action, TransportMessage message) { if (logger.isDebugEnabled()) { - logger.debug("{}[transport] [run_as_denied]\t{}, principal=[{}], run_as_principal=[{}], action=[{}], request=[{}]", prefix, originAttributes(message, transport), user.principal(), user.runAs().principal(), action, message.getClass().getSimpleName()); + logger.debug("{}[transport] [run_as_denied]\t{}, principal=[{}], run_as_principal=[{}], action=[{}], request=[{}]", prefix, originAttributes(message, transport, threadContext), user.principal(), user.runAs().principal(), action, message.getClass().getSimpleName()); } else { - logger.info("{}[transport] [run_as_denied]\t{}, principal=[{}], run_as_principal=[{}], action=[{}]", prefix, originAttributes(message, transport), user.principal(), user.runAs().principal(), action); + logger.info("{}[transport] [run_as_denied]\t{}, principal=[{}], run_as_principal=[{}], action=[{}]", prefix, originAttributes(message, transport, threadContext), user.principal(), user.runAs().principal(), action); } } @@ -317,11 +321,11 @@ public class LoggingAuditTrail extends AbstractLifecycleComponent message) { - AuthenticationToken token = message.getFromContext(TOKEN_KEY); + AuthenticationToken token = threadContext.getTransient(TOKEN_KEY); if (token != null) { return token; } for (Realm realm : realms) { - token = realm.token(message); + token = realm.token(threadContext); if (token != null) { if (logger.isTraceEnabled()) { logger.trace("realm [{}] resolved authentication token [{}] from transport request with action [{}]", realm, token.principal(), action); } - message.putInContext(TOKEN_KEY, token); + threadContext.putTransient(TOKEN_KEY, token); return token; } } diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/Realm.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/Realm.java index d27f3686a20..fed1d1b5a94 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/Realm.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/Realm.java @@ -6,10 +6,9 @@ package org.elasticsearch.shield.authc; import org.elasticsearch.common.logging.ESLogger; -import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.shield.ShieldSettingsFilter; import org.elasticsearch.shield.User; -import org.elasticsearch.transport.TransportMessage; /** * An authentication mechanism to which the default authentication {@link org.elasticsearch.shield.authc.AuthenticationService service} @@ -60,22 +59,13 @@ public abstract class Realm implements Comparable public abstract boolean supports(AuthenticationToken token); /** - * Attempts to extract an authentication token from the given rest request. If an appropriate token + * Attempts to extract an authentication token from the given context. If an appropriate token * is found it's returned, otherwise {@code null} is returned. * - * @param request The rest request + * @param context The context that will provide information about the incoming request * @return The authentication token or {@code null} if not found */ - public abstract T token(RestRequest request); - - /** - * Attempts to extract an authentication token from the given transport message. If an appropriate token - * is found it's returned, otherwise {@code null} is returned. - * - * @param message The transport message - * @return The authentication token or {@code null} if not found - */ - public abstract T token(TransportMessage message); + public abstract T token(ThreadContext context); /** * Authenticates the given token. A successful authentication will return the User associated diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/activedirectory/ActiveDirectoryRealm.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/activedirectory/ActiveDirectoryRealm.java index f3fe939dc09..a18433d6663 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/activedirectory/ActiveDirectoryRealm.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/activedirectory/ActiveDirectoryRealm.java @@ -6,6 +6,7 @@ package org.elasticsearch.shield.authc.activedirectory; import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.rest.RestController; import org.elasticsearch.shield.ShieldSettingsFilter; import org.elasticsearch.shield.authc.RealmConfig; import org.elasticsearch.shield.authc.ldap.support.AbstractLdapRealm; @@ -33,8 +34,8 @@ public class ActiveDirectoryRealm extends AbstractLdapRealm { private final ClientSSLService clientSSLService; @Inject - public Factory(ResourceWatcherService watcherService, ClientSSLService clientSSLService) { - super(ActiveDirectoryRealm.TYPE); + public Factory(ResourceWatcherService watcherService, ClientSSLService clientSSLService, RestController restController) { + super(ActiveDirectoryRealm.TYPE, restController); this.watcherService = watcherService; this.clientSSLService = clientSSLService; } diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/esnative/ESNativeUsersStore.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/esnative/ESNativeUsersStore.java index e2f1a67e66a..782ed05c7c4 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/esnative/ESNativeUsersStore.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/esnative/ESNativeUsersStore.java @@ -11,9 +11,12 @@ import com.carrotsearch.hppc.ObjectLongMap; import com.carrotsearch.hppc.cursors.ObjectCursor; import com.carrotsearch.hppc.cursors.ObjectLongCursor; import org.elasticsearch.ElasticsearchException; -import org.elasticsearch.ElasticsearchSecurityException; import org.elasticsearch.ExceptionsHelper; +import org.elasticsearch.action.Action; import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.ActionRequest; +import org.elasticsearch.action.ActionRequestBuilder; +import org.elasticsearch.action.ActionResponse; import org.elasticsearch.action.LatchedActionListener; import org.elasticsearch.action.delete.DeleteRequest; import org.elasticsearch.action.delete.DeleteResponse; @@ -27,6 +30,7 @@ import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchScrollRequest; import org.elasticsearch.client.Client; +import org.elasticsearch.client.FilterClient; import org.elasticsearch.cluster.ClusterChangedEvent; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.ClusterStateListener; @@ -40,11 +44,11 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.util.concurrent.AbstractRunnable; import org.elasticsearch.common.util.concurrent.FutureUtils; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.gateway.GatewayService; import org.elasticsearch.index.IndexNotFoundException; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilders; -import org.elasticsearch.rest.RestStatus; import org.elasticsearch.search.SearchHit; import org.elasticsearch.shield.User; import org.elasticsearch.shield.action.admin.user.AddUserRequest; @@ -58,7 +62,6 @@ import org.elasticsearch.shield.authc.support.Hasher; import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.shield.client.ShieldClient; import org.elasticsearch.threadpool.ThreadPool; -import org.elasticsearch.transport.TransportMessage; import java.io.IOException; import java.util.ArrayList; @@ -116,16 +119,6 @@ public class ESNativeUsersStore extends AbstractComponent implements ClusterStat this.threadPool = threadPool; } - private final void attachUser(TransportMessage message) { - try { - authService.attachUserHeaderIfMissing(message, adminUser.user()); - } catch (IOException e) { - logger.error("failed to attach authorization to internal message!", e); - throw new ElasticsearchSecurityException("unable to attach administrative user to transport message", - RestStatus.SERVICE_UNAVAILABLE, e); - } - } - @Nullable private UserAndPassword transformUser(Map sourceMap) { if (sourceMap == null) { @@ -207,7 +200,6 @@ public class ESNativeUsersStore extends AbstractComponent implements ClusterStat .setSize(scrollSize) .setFetchSource(true) .request(); - attachUser(request); request.indicesOptions().ignoreUnavailable(); // This function is MADNESS! But it works, don't think about it too hard... @@ -224,11 +216,9 @@ public class ESNativeUsersStore extends AbstractComponent implements ClusterStat } SearchScrollRequest scrollRequest = client.prepareSearchScroll(resp.getScrollId()) .setScroll(scrollKeepAlive).request(); - attachUser(scrollRequest); client.searchScroll(scrollRequest, this); } else { ClearScrollRequest clearScrollRequest = client.prepareClearScroll().addScrollId(resp.getScrollId()).request(); - attachUser(clearScrollRequest); client.clearScroll(clearScrollRequest, new ActionListener() { @Override public void onResponse(ClearScrollResponse response) { @@ -291,7 +281,6 @@ public class ESNativeUsersStore extends AbstractComponent implements ClusterStat try { GetRequest request = client.prepareGet(ShieldTemplateService.SHIELD_ADMIN_INDEX_NAME, INDEX_USER_TYPE, user).request(); request.indicesOptions().ignoreUnavailable(); - attachUser(request); client.get(request, new ActionListener() { @Override public void onResponse(GetResponse getFields) { @@ -332,7 +321,6 @@ public class ESNativeUsersStore extends AbstractComponent implements ClusterStat "password", String.valueOf(addUserRequest.passwordHash()), "roles", addUserRequest.roles()) .request(); - attachUser(request); client.index(request, new ActionListener() { @Override @@ -367,7 +355,6 @@ public class ESNativeUsersStore extends AbstractComponent implements ClusterStat DeleteRequest request = client.prepareDelete(ShieldTemplateService.SHIELD_ADMIN_INDEX_NAME, INDEX_USER_TYPE, deleteUserRequest.user()).request(); request.indicesOptions().ignoreUnavailable(); - attachUser(request); client.delete(request, new ActionListener() { @Override public void onResponse(DeleteResponse deleteResponse) { @@ -420,8 +407,20 @@ public class ESNativeUsersStore extends AbstractComponent implements ClusterStat public void start() { try { if (state.compareAndSet(State.INITIALIZED, State.STARTING)) { - this.client = clientProvider.get(); this.authService = authProvider.get(); + this.client = new FilterClient(clientProvider.get()) { + @Override + protected , Response extends ActionResponse, RequestBuilder extends ActionRequestBuilder> void doExecute(Action action, Request request, ActionListener listener) { + try (ThreadContext.StoredContext ctx = threadPool().getThreadContext().stashContext()) { + try { + authService.attachUserHeaderIfMissing(adminUser.user()); + } catch (IOException e) { + throw new ElasticsearchException("failed to set shield user", e); + } + super.doExecute(action, request, listener); + } + } + }; this.scrollSize = settings.getAsInt("shield.authc.native.scroll.size", 1000); this.scrollKeepAlive = settings.getAsTime("shield.authc.native.scroll.keep_alive", TimeValue.timeValueSeconds(10L)); @@ -484,7 +483,6 @@ public class ESNativeUsersStore extends AbstractComponent implements ClusterStat ShieldClient shieldClient = new ShieldClient(client); ClearRealmCacheRequest request = shieldClient.prepareClearRealmCache() .usernames(username).request(); - attachUser(request); shieldClient.clearRealmCache(request, new ActionListener() { @Override public void onResponse(ClearRealmCacheResponse nodes) { @@ -628,7 +626,6 @@ public class ESNativeUsersStore extends AbstractComponent implements ClusterStat .setVersion(true) .setFetchSource(true) .request(); - attachUser(request); response = client.search(request).actionGet(); boolean keepScrolling = response.getHits().getHits().length > 0; @@ -639,7 +636,6 @@ public class ESNativeUsersStore extends AbstractComponent implements ClusterStat map.put(username, version); } SearchScrollRequest scrollRequest = client.prepareSearchScroll(response.getScrollId()).setScroll(scrollKeepAlive).request(); - attachUser(scrollRequest); response = client.searchScroll(scrollRequest).actionGet(); keepScrolling = response.getHits().getHits().length > 0; } @@ -648,7 +644,6 @@ public class ESNativeUsersStore extends AbstractComponent implements ClusterStat } finally { if (response != null) { ClearScrollRequest clearScrollRequest = client.prepareClearScroll().addScrollId(response.getScrollId()).request(); - attachUser(clearScrollRequest); client.clearScroll(clearScrollRequest).actionGet(); } } diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/esusers/ESUsersRealm.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/esusers/ESUsersRealm.java index 8c0c9a935bb..5035c796c6e 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/esusers/ESUsersRealm.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/esusers/ESUsersRealm.java @@ -8,11 +8,12 @@ package org.elasticsearch.shield.authc.esusers; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; +import org.elasticsearch.rest.RestController; import org.elasticsearch.shield.User; -import org.elasticsearch.shield.authc.Realm; import org.elasticsearch.shield.authc.RealmConfig; import org.elasticsearch.shield.authc.support.CachingUsernamePasswordRealm; import org.elasticsearch.shield.authc.support.RefreshListener; +import org.elasticsearch.shield.authc.support.UsernamePasswordRealm; import org.elasticsearch.shield.authc.support.UsernamePasswordToken; import org.elasticsearch.watcher.ResourceWatcherService; @@ -66,15 +67,15 @@ public class ESUsersRealm extends CachingUsernamePasswordRealm { } } - public static class Factory extends Realm.Factory { + public static class Factory extends UsernamePasswordRealm.Factory { private final Settings settings; private final Environment env; private final ResourceWatcherService watcherService; @Inject - public Factory(Settings settings, Environment env, ResourceWatcherService watcherService) { - super(TYPE, true); + public Factory(Settings settings, Environment env, ResourceWatcherService watcherService, RestController restController) { + super(TYPE, restController, true); this.settings = settings; this.env = env; this.watcherService = watcherService; diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/ldap/LdapRealm.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/ldap/LdapRealm.java index 36d38445060..3ec880f06c4 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/ldap/LdapRealm.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/ldap/LdapRealm.java @@ -8,6 +8,7 @@ package org.elasticsearch.shield.authc.ldap; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.rest.RestController; import org.elasticsearch.shield.ShieldSettingsFilter; import org.elasticsearch.shield.authc.RealmConfig; import org.elasticsearch.shield.authc.ldap.support.AbstractLdapRealm; @@ -35,8 +36,8 @@ public class LdapRealm extends AbstractLdapRealm { private final ClientSSLService clientSSLService; @Inject - public Factory(ResourceWatcherService watcherService, ClientSSLService clientSSLService) { - super(TYPE); + public Factory(ResourceWatcherService watcherService, ClientSSLService clientSSLService, RestController restController) { + super(TYPE, restController); this.watcherService = watcherService; this.clientSSLService = clientSSLService; } diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/ldap/support/AbstractLdapRealm.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/ldap/support/AbstractLdapRealm.java index f1d5465360e..f465ba8c866 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/ldap/support/AbstractLdapRealm.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/ldap/support/AbstractLdapRealm.java @@ -5,6 +5,7 @@ */ package org.elasticsearch.shield.authc.ldap.support; +import org.elasticsearch.rest.RestController; import org.elasticsearch.shield.User; import org.elasticsearch.shield.authc.RealmConfig; import org.elasticsearch.shield.authc.support.CachingUsernamePasswordRealm; @@ -92,8 +93,8 @@ public abstract class AbstractLdapRealm extends CachingUsernamePasswordRealm { public static abstract class Factory extends UsernamePasswordRealm.Factory { - public Factory(String type) { - super(type, false); + public Factory(String type, RestController restController) { + super(type, restController, false); } /** diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/pki/PkiRealm.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/pki/PkiRealm.java index 95c93b112f2..ecbc0c40e92 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/pki/PkiRealm.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/pki/PkiRealm.java @@ -9,8 +9,8 @@ import org.elasticsearch.common.Strings; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.logging.ESLogger; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.env.Environment; -import org.elasticsearch.rest.RestRequest; import org.elasticsearch.shield.ShieldSettingsFilter; import org.elasticsearch.shield.User; import org.elasticsearch.shield.authc.AuthenticationToken; @@ -20,7 +20,6 @@ import org.elasticsearch.shield.authc.support.DnRoleMapper; import org.elasticsearch.shield.transport.SSLClientAuth; import org.elasticsearch.shield.transport.netty.ShieldNettyHttpServerTransport; import org.elasticsearch.shield.transport.netty.ShieldNettyTransport; -import org.elasticsearch.transport.TransportMessage; import org.elasticsearch.watcher.ResourceWatcherService; import javax.net.ssl.TrustManager; @@ -66,13 +65,8 @@ public class PkiRealm extends Realm { } @Override - public X509AuthenticationToken token(RestRequest request) { - return token(request.getFromContext(PKI_CERT_HEADER_NAME), principalPattern, logger); - } - - @Override - public X509AuthenticationToken token(TransportMessage message) { - return token(message.getFromContext(PKI_CERT_HEADER_NAME), principalPattern, logger); + public X509AuthenticationToken token(ThreadContext context) { + return token(context.getTransient(PKI_CERT_HEADER_NAME), principalPattern, logger); } @Override diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/support/UsernamePasswordRealm.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/support/UsernamePasswordRealm.java index 2da565fadc7..960fa386c30 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/support/UsernamePasswordRealm.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/support/UsernamePasswordRealm.java @@ -5,11 +5,11 @@ */ package org.elasticsearch.shield.authc.support; -import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.common.util.concurrent.ThreadContext; +import org.elasticsearch.rest.RestController; import org.elasticsearch.shield.authc.AuthenticationToken; import org.elasticsearch.shield.authc.Realm; import org.elasticsearch.shield.authc.RealmConfig; -import org.elasticsearch.transport.TransportMessage; /** * @@ -21,13 +21,8 @@ public abstract class UsernamePasswordRealm extends Realm } @Override - public UsernamePasswordToken token(RestRequest request) { - return UsernamePasswordToken.extractToken(request, null); - } - - @Override - public UsernamePasswordToken token(TransportMessage message) { - return UsernamePasswordToken.extractToken(message, null); + public UsernamePasswordToken token(ThreadContext threadContext) { + return UsernamePasswordToken.extractToken(threadContext, null); } public boolean supports(AuthenticationToken token) { @@ -36,8 +31,9 @@ public abstract class UsernamePasswordRealm extends Realm public static abstract class Factory extends Realm.Factory { - protected Factory(String type, boolean internal) { + protected Factory(String type, RestController restController, boolean internal) { super(type, internal); + restController.registerRelevantHeaders(UsernamePasswordToken.BASIC_AUTH_HEADER); } } } diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/support/UsernamePasswordToken.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/support/UsernamePasswordToken.java index ad36f135f82..cf212830c1a 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/support/UsernamePasswordToken.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/support/UsernamePasswordToken.java @@ -6,10 +6,9 @@ package org.elasticsearch.shield.authc.support; import org.elasticsearch.common.Base64; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.shield.authc.AuthenticationToken; -import org.elasticsearch.transport.TransportMessage; -import org.elasticsearch.transport.TransportRequest; import java.io.IOException; import java.nio.CharBuffer; @@ -67,8 +66,8 @@ public class UsernamePasswordToken implements AuthenticationToken { return Objects.hash(username, password.hashCode()); } - public static UsernamePasswordToken extractToken(TransportMessage message, UsernamePasswordToken defaultToken) { - String authStr = message.getHeader(BASIC_AUTH_HEADER); + public static UsernamePasswordToken extractToken(ThreadContext context, UsernamePasswordToken defaultToken) { + String authStr = context.getHeader(BASIC_AUTH_HEADER); if (authStr == null) { return defaultToken; } @@ -108,8 +107,8 @@ public class UsernamePasswordToken implements AuthenticationToken { new SecuredString(Arrays.copyOfRange(userpasswd, i + 1, userpasswd.length))); } - public static void putTokenHeader(TransportRequest request, UsernamePasswordToken token) { - request.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue(token.username, token.password)); + public static void putTokenHeader(ThreadContext context, UsernamePasswordToken token) { + context.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue(token.username, token.password)); } public static String basicAuthHeaderValue(String username, SecuredString passwd) { diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authz/InternalAuthorizationService.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authz/InternalAuthorizationService.java index ffb390009f4..9a1f7768470 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authz/InternalAuthorizationService.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authz/InternalAuthorizationService.java @@ -19,6 +19,7 @@ import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.util.set.Sets; import org.elasticsearch.search.action.SearchServiceTransportAction; import org.elasticsearch.shield.User; @@ -35,6 +36,7 @@ import org.elasticsearch.shield.authz.permission.RunAsPermission; import org.elasticsearch.shield.authz.privilege.ClusterPrivilege; import org.elasticsearch.shield.authz.privilege.IndexPrivilege; import org.elasticsearch.shield.authz.store.RolesStore; +import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportRequest; import java.util.ArrayList; @@ -59,10 +61,12 @@ public class InternalAuthorizationService extends AbstractComponent implements A private final IndicesAndAliasesResolver[] indicesAndAliasesResolvers; private final AnonymousService anonymousService; private final AuthenticationFailureHandler authcFailureHandler; + private final ThreadContext threadContext; @Inject public InternalAuthorizationService(Settings settings, RolesStore rolesStore, ClusterService clusterService, - AuditTrail auditTrail, AnonymousService anonymousService, AuthenticationFailureHandler authcFailureHandler) { + AuditTrail auditTrail, AnonymousService anonymousService, + AuthenticationFailureHandler authcFailureHandler, ThreadPool threadPool) { super(settings); this.rolesStore = rolesStore; this.clusterService = clusterService; @@ -72,6 +76,7 @@ public class InternalAuthorizationService extends AbstractComponent implements A }; this.anonymousService = anonymousService; this.authcFailureHandler = authcFailureHandler; + this.threadContext = threadPool.getThreadContext(); } @Override @@ -106,7 +111,7 @@ public class InternalAuthorizationService extends AbstractComponent implements A // first we need to check if the user is the system. If it is, we'll just authorize the system access if (user.isSystem()) { if (SystemRole.INSTANCE.check(action)) { - request.putInContext(INDICES_PERMISSIONS_KEY, IndicesAccessControl.ALLOW_ALL); + setIndicesAccessControl(IndicesAccessControl.ALLOW_ALL); grant(user, action, request); return; } @@ -149,7 +154,7 @@ public class InternalAuthorizationService extends AbstractComponent implements A if (ClusterPrivilege.ACTION_MATCHER.test(action)) { ClusterPermission cluster = permission.cluster(); if (cluster != null && cluster.check(action)) { - request.putInContext(INDICES_PERMISSIONS_KEY, IndicesAccessControl.ALLOW_ALL); + setIndicesAccessControl(IndicesAccessControl.ALLOW_ALL); grant(user, action, request); return; } @@ -191,7 +196,7 @@ public class InternalAuthorizationService extends AbstractComponent implements A if (!indicesAccessControl.isGranted()) { throw denial(user, action, request); } else { - request.putInContext(INDICES_PERMISSIONS_KEY, indicesAccessControl); + setIndicesAccessControl(indicesAccessControl); } //if we are creating an index we need to authorize potential aliases created at the same time @@ -215,6 +220,12 @@ public class InternalAuthorizationService extends AbstractComponent implements A grant(user, action, request); } + private void setIndicesAccessControl(IndicesAccessControl accessControl) { + if (threadContext.getTransient(INDICES_PERMISSIONS_KEY) == null) { + threadContext.putTransient(INDICES_PERMISSIONS_KEY, accessControl); + } + } + private GlobalPermission permission(String[] roleNames) { if (roleNames.length == 0) { return GlobalPermission.NONE; diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authz/accesscontrol/OptOutQueryCache.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authz/accesscontrol/OptOutQueryCache.java index 11b70b3e773..2a1a0fccb7e 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authz/accesscontrol/OptOutQueryCache.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authz/accesscontrol/OptOutQueryCache.java @@ -45,7 +45,7 @@ public final class OptOutQueryCache extends AbstractIndexComponent implements Qu if (context == null) { throw new IllegalStateException("opting out of the query cache. current request can't be found"); } - final IndicesAccessControl indicesAccessControl = context.getRequest().getFromContext(InternalAuthorizationService.INDICES_PERMISSIONS_KEY); + IndicesAccessControl indicesAccessControl = context.getThreadContext().getTransient(InternalAuthorizationService.INDICES_PERMISSIONS_KEY); if (indicesAccessControl == null) { logger.debug("opting out of the query cache. current request doesn't hold indices permissions"); return weight; diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authz/accesscontrol/RequestContext.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authz/accesscontrol/RequestContext.java index 3835d01eef7..cb7accb36b7 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authz/accesscontrol/RequestContext.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authz/accesscontrol/RequestContext.java @@ -5,6 +5,7 @@ */ package org.elasticsearch.shield.authz.accesscontrol; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.transport.TransportRequest; import java.util.Objects; @@ -39,10 +40,12 @@ public final class RequestContext { current.remove(); } + private final ThreadContext threadContext; private final TransportRequest request; - public RequestContext(TransportRequest request) { + public RequestContext(TransportRequest request, ThreadContext threadContext) { this.request = Objects.requireNonNull(request); + this.threadContext = Objects.requireNonNull(threadContext); } /** @@ -51,4 +54,8 @@ public final class RequestContext { public TransportRequest getRequest() { return request; } + + public ThreadContext getThreadContext() { + return threadContext; + } } diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authz/accesscontrol/ShieldIndexSearcherWrapper.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authz/accesscontrol/ShieldIndexSearcherWrapper.java index 2a0264da4ff..cad848c3423 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authz/accesscontrol/ShieldIndexSearcherWrapper.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authz/accesscontrol/ShieldIndexSearcherWrapper.java @@ -26,6 +26,7 @@ import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.logging.ESLogger; import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.logging.support.LoggerMessageFormat; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.index.IndexSettings; import org.elasticsearch.index.cache.bitset.BitsetFilterCache; import org.elasticsearch.index.engine.EngineException; @@ -56,7 +57,7 @@ import static org.apache.lucene.search.BooleanClause.Occur.FILTER; /** * An {@link IndexSearcherWrapper} implementation that is used for field and document level security. *

- * Based on the {@link RequestContext} this class will enable field and/or document level security. + * Based on the {@link ThreadContext} this class will enable field and/or document level security. *

* Field level security is enabled by wrapping the original {@link DirectoryReader} in a {@link FieldSubsetReader} * in the {@link #wrap(DirectoryReader)} method. @@ -71,14 +72,17 @@ public class ShieldIndexSearcherWrapper extends IndexSearcherWrapper { private final QueryShardContext queryShardContext; private final BitsetFilterCache bitsetFilterCache; private final ShieldLicenseState shieldLicenseState; + private final ThreadContext threadContext; private final ESLogger logger; public ShieldIndexSearcherWrapper(IndexSettings indexSettings, QueryShardContext queryShardContext, - MapperService mapperService, BitsetFilterCache bitsetFilterCache, ShieldLicenseState shieldLicenseState) { + MapperService mapperService, BitsetFilterCache bitsetFilterCache, + ThreadContext threadContext, ShieldLicenseState shieldLicenseState) { this.logger = Loggers.getLogger(getClass(), indexSettings.getSettings()); this.mapperService = mapperService; this.queryShardContext = queryShardContext; this.bitsetFilterCache = bitsetFilterCache; + this.threadContext = threadContext; this.shieldLicenseState = shieldLicenseState; Set allowedMetaFields = new HashSet<>(); @@ -98,15 +102,8 @@ public class ShieldIndexSearcherWrapper extends IndexSearcherWrapper { final Set allowedMetaFields = this.allowedMetaFields; try { - RequestContext context = RequestContext.current(); - if (context == null) { - throw new IllegalStateException("can't locate the origin of the current request"); - } + final IndicesAccessControl indicesAccessControl = getIndicesAccessControl(); - IndicesAccessControl indicesAccessControl = context.getRequest().getFromContext(InternalAuthorizationService.INDICES_PERMISSIONS_KEY); - if (indicesAccessControl == null) { - throw Exceptions.authorizationError("no indices permissions found"); - } ShardId shardId = ShardUtils.extractShardId(reader); if (shardId == null) { throw new IllegalStateException(LoggerMessageFormat.format("couldn't extract shardId from reader [{}]", reader)); @@ -245,4 +242,11 @@ public class ShieldIndexSearcherWrapper extends IndexSearcherWrapper { } } + protected IndicesAccessControl getIndicesAccessControl() { + IndicesAccessControl indicesAccessControl = threadContext.getTransient(InternalAuthorizationService.INDICES_PERMISSIONS_KEY); + if (indicesAccessControl == null) { + throw Exceptions.authorizationError("no indices permissions found"); + } + return indicesAccessControl; + } } diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authz/esnative/ESNativeRolesStore.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authz/esnative/ESNativeRolesStore.java index 697a5e6ba1b..bedb1d50b23 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authz/esnative/ESNativeRolesStore.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authz/esnative/ESNativeRolesStore.java @@ -6,8 +6,11 @@ package org.elasticsearch.shield.authz.esnative; import org.elasticsearch.ElasticsearchException; -import org.elasticsearch.ElasticsearchSecurityException; +import org.elasticsearch.action.Action; import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.ActionRequest; +import org.elasticsearch.action.ActionRequestBuilder; +import org.elasticsearch.action.ActionResponse; import org.elasticsearch.action.LatchedActionListener; import org.elasticsearch.action.delete.DeleteRequest; import org.elasticsearch.action.delete.DeleteResponse; @@ -21,6 +24,7 @@ import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchScrollRequest; import org.elasticsearch.client.Client; +import org.elasticsearch.client.FilterClient; import org.elasticsearch.cluster.ClusterChangedEvent; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.ClusterStateListener; @@ -33,12 +37,12 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.util.concurrent.AbstractRunnable; import org.elasticsearch.common.util.concurrent.FutureUtils; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.gateway.GatewayService; import org.elasticsearch.index.IndexNotFoundException; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilders; -import org.elasticsearch.rest.RestStatus; import org.elasticsearch.search.SearchHit; import org.elasticsearch.shield.action.admin.role.AddRoleRequest; import org.elasticsearch.shield.action.admin.role.DeleteRoleRequest; @@ -52,7 +56,6 @@ import org.elasticsearch.shield.authz.RoleDescriptor; import org.elasticsearch.shield.authz.store.RolesStore; import org.elasticsearch.shield.client.ShieldClient; import org.elasticsearch.threadpool.ThreadPool; -import org.elasticsearch.transport.TransportMessage; import java.io.IOException; import java.util.ArrayList; @@ -110,16 +113,6 @@ public class ESNativeRolesStore extends AbstractComponent implements RolesStore, this.threadPool = threadPool; } - private final void attachUser(TransportMessage message) { - try { - authService.attachUserHeaderIfMissing(message, adminUser.user()); - } catch (IOException e) { - logger.error("failed to attach authorization to internal message!", e); - throw new ElasticsearchSecurityException("unable to attach administrative user to transport message", - RestStatus.SERVICE_UNAVAILABLE, e); - } - } - @Nullable private RoleDescriptor transformRole(GetResponse response) { if (response.isExists() == false) { @@ -161,7 +154,6 @@ public class ESNativeRolesStore extends AbstractComponent implements RolesStore, .setSize(scrollSize) .setFetchSource(true) .request(); - attachUser(request); request.indicesOptions().ignoreUnavailable(); // This function is MADNESS! But it works, don't think about it too hard... @@ -178,11 +170,9 @@ public class ESNativeRolesStore extends AbstractComponent implements RolesStore, } SearchScrollRequest scrollRequest = client.prepareSearchScroll(resp.getScrollId()) .setScroll(scrollKeepAlive).request(); - attachUser(scrollRequest); client.searchScroll(scrollRequest, this); } else { ClearScrollRequest clearScrollRequest = client.prepareClearScroll().addScrollId(resp.getScrollId()).request(); - attachUser(clearScrollRequest); client.clearScroll(clearScrollRequest, new ActionListener() { @Override public void onResponse(ClearScrollResponse response) { @@ -231,7 +221,6 @@ public class ESNativeRolesStore extends AbstractComponent implements RolesStore, try { GetRequest request = client.prepareGet(ShieldTemplateService.SHIELD_ADMIN_INDEX_NAME, INDEX_ROLE_TYPE, role).request(); request.indicesOptions().ignoreUnavailable(); - attachUser(request); client.get(request, listener); } catch (Exception e) { logger.error("unable to retrieve role", e); @@ -248,7 +237,6 @@ public class ESNativeRolesStore extends AbstractComponent implements RolesStore, DeleteRequest request = client.prepareDelete(ShieldTemplateService.SHIELD_ADMIN_INDEX_NAME, INDEX_ROLE_TYPE, deleteRoleRequest.role()).request(); request.indicesOptions().ignoreUnavailable(); - attachUser(request); client.delete(request, new ActionListener() { @Override public void onResponse(DeleteResponse deleteResponse) { @@ -324,7 +312,6 @@ public class ESNativeRolesStore extends AbstractComponent implements RolesStore, INDEX_ROLE_TYPE, addRoleRequest.name()) .setSource(addRoleRequest.toXContent(jsonBuilder(), ToXContent.EMPTY_PARAMS)) .request(); - attachUser(request); client.index(request, new ActionListener() { @Override public void onResponse(IndexResponse indexResponse) { @@ -379,9 +366,21 @@ public class ESNativeRolesStore extends AbstractComponent implements RolesStore, public void start() { try { if (state.compareAndSet(State.INITIALIZED, State.STARTING)) { - this.client = clientProvider.get(); - this.shieldClient = new ShieldClient(client); this.authService = authProvider.get(); + this.client = new FilterClient(clientProvider.get()) { + @Override + protected , Response extends ActionResponse, RequestBuilder extends ActionRequestBuilder> void doExecute(Action action, Request request, ActionListener listener) { + try (ThreadContext.StoredContext ctx = threadPool().getThreadContext().stashContext()) { + try { + authService.attachUserHeaderIfMissing(adminUser.user()); + } catch (IOException e) { + throw new ElasticsearchException("failed to set shield user", e); + } + super.doExecute(action, request, listener); + } + } + }; + this.shieldClient = new ShieldClient(client); this.scrollSize = settings.getAsInt("shield.authc.native.scroll.size", 1000); this.scrollKeepAlive = settings.getAsTime("shield.authc.native.scroll.keep_alive", TimeValue.timeValueSeconds(10L)); TimeValue pollInterval = settings.getAsTime("shield.authc.native.reload.interval", TimeValue.timeValueSeconds(30L)); @@ -435,7 +434,6 @@ public class ESNativeRolesStore extends AbstractComponent implements RolesStore, private void clearRoleCache(final String role, ActionListener listener, Response response) { ClearRolesCacheRequest request = new ClearRolesCacheRequest().roles(role); - attachUser(request); shieldClient.clearRolesCache(request, new ActionListener() { @Override public void onResponse(ClearRolesCacheResponse nodes) { @@ -504,7 +502,6 @@ public class ESNativeRolesStore extends AbstractComponent implements RolesStore, .setFetchSource(true) .setVersion(true) .request(); - attachUser(request); response = client.search(request).actionGet(); boolean keepScrolling = response.getHits().getHits().length > 0; @@ -529,7 +526,6 @@ public class ESNativeRolesStore extends AbstractComponent implements RolesStore, }); } SearchScrollRequest scrollRequest = client.prepareSearchScroll(response.getScrollId()).setScroll(scrollKeepAlive).request(); - attachUser(scrollRequest); response = client.searchScroll(scrollRequest).actionGet(); keepScrolling = response.getHits().getHits().length > 0; } @@ -545,7 +541,6 @@ public class ESNativeRolesStore extends AbstractComponent implements RolesStore, } finally { if (response != null) { ClearScrollRequest clearScrollRequest = client.prepareClearScroll().addScrollId(response.getScrollId()).request(); - attachUser(clearScrollRequest); client.clearScroll(clearScrollRequest).actionGet(); } } diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/rest/RemoteHostHeader.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/rest/RemoteHostHeader.java index f5e42bf1a7d..26f3190e0ed 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/rest/RemoteHostHeader.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/rest/RemoteHostHeader.java @@ -5,8 +5,8 @@ */ package org.elasticsearch.shield.rest; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.rest.RestRequest; -import org.elasticsearch.transport.TransportMessage; import java.net.InetSocketAddress; import java.net.SocketAddress; @@ -22,23 +22,23 @@ public class RemoteHostHeader { * Extracts the remote address from the given rest request and puts in the request context. This will * then be copied to the subsequent action requests. */ - public static void process(RestRequest request) { - request.putInContext(KEY, request.getRemoteAddress()); + public static void process(RestRequest request, ThreadContext threadContext) { + threadContext.putTransient(KEY, request.getRemoteAddress()); } /** * Extracts the rest remote address from the message context. If not found, returns {@code null}. transport * messages that were created by rest handlers, should have this in their context. */ - public static InetSocketAddress restRemoteAddress(TransportMessage message) { - SocketAddress address = message.getFromContext(KEY); + public static InetSocketAddress restRemoteAddress(ThreadContext threadContext) { + SocketAddress address = threadContext.getTransient(KEY); if (address != null && address instanceof InetSocketAddress) { return (InetSocketAddress) address; } return null; } - public static void putRestRemoteAddress(TransportMessage message, SocketAddress address) { - message.putInContext(KEY, address); + public static void putRestRemoteAddress(ThreadContext threadContext, SocketAddress address) { + threadContext.putTransient(KEY, address); } } diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/rest/ShieldRestFilter.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/rest/ShieldRestFilter.java index c47a3a6daca..88e0f793ef2 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/rest/ShieldRestFilter.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/rest/ShieldRestFilter.java @@ -10,6 +10,7 @@ import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.logging.ESLogger; import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.http.netty.NettyHttpRequest; import org.elasticsearch.rest.RestChannel; import org.elasticsearch.rest.RestController; @@ -21,6 +22,7 @@ import org.elasticsearch.shield.authc.pki.PkiRealm; import org.elasticsearch.shield.license.ShieldLicenseState; import org.elasticsearch.shield.transport.SSLClientAuth; import org.elasticsearch.shield.transport.netty.ShieldNettyHttpServerTransport; +import org.elasticsearch.threadpool.ThreadPool; import org.jboss.netty.handler.ssl.SslHandler; import javax.net.ssl.SSLPeerUnverifiedException; @@ -36,12 +38,15 @@ public class ShieldRestFilter extends RestFilter { private final AuthenticationService service; private final ESLogger logger; private final ShieldLicenseState licenseState; + private final ThreadContext threadContext; private final boolean extractClientCertificate; @Inject - public ShieldRestFilter(AuthenticationService service, RestController controller, Settings settings, ShieldLicenseState licenseState) { + public ShieldRestFilter(AuthenticationService service, RestController controller, Settings settings, + ThreadPool threadPool, ShieldLicenseState licenseState) { this.service = service; this.licenseState = licenseState; + this.threadContext = threadPool.getThreadContext(); controller.registerFilter(this); boolean ssl = settings.getAsBoolean(ShieldNettyHttpServerTransport.HTTP_SSL_SETTING, ShieldNettyHttpServerTransport.HTTP_SSL_DEFAULT); extractClientCertificate = ssl && SSLClientAuth.parse(settings.get(ShieldNettyHttpServerTransport.HTTP_CLIENT_AUTH_SETTING), ShieldNettyHttpServerTransport.HTTP_CLIENT_AUTH_DEFAULT).enabled(); @@ -60,18 +65,18 @@ public class ShieldRestFilter extends RestFilter { // CORS - allow for preflight unauthenticated OPTIONS request if (request.method() != RestRequest.Method.OPTIONS) { if (extractClientCertificate) { - putClientCertificateInContext(request, logger); + putClientCertificateInContext(request, threadContext, logger); } service.authenticate(request); } - RemoteHostHeader.process(request); + RemoteHostHeader.process(request, threadContext); } filterChain.continueProcessing(request, channel); } - static void putClientCertificateInContext(RestRequest request, ESLogger logger) throws Exception { + static void putClientCertificateInContext(RestRequest request, ThreadContext threadContext, ESLogger logger) throws Exception { assert request instanceof NettyHttpRequest; NettyHttpRequest nettyHttpRequest = (NettyHttpRequest) request; @@ -80,7 +85,7 @@ public class ShieldRestFilter extends RestFilter { try { Certificate[] certs = handler.getEngine().getSession().getPeerCertificates(); if (certs instanceof X509Certificate[]) { - request.putInContext(PkiRealm.PKI_CERT_HEADER_NAME, certs); + threadContext.putTransient(PkiRealm.PKI_CERT_HEADER_NAME, certs); } } catch (SSLPeerUnverifiedException e) { // this happens when we only request client authentication and the client does not provide it diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/rest/action/RestAuthenticateAction.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/rest/action/RestAuthenticateAction.java index 326e0144f9b..d9f48942801 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/rest/action/RestAuthenticateAction.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/rest/action/RestAuthenticateAction.java @@ -27,7 +27,7 @@ public class RestAuthenticateAction extends BaseRestHandler { private final AuthenticationService authenticationService; @Inject public RestAuthenticateAction(Settings settings, RestController controller, Client client, AuthenticationService authenticationService) { - super(settings, controller, client); + super(settings, client); this.authenticationService = authenticationService; controller.registerHandler(GET, "/_shield/authenticate", this); } diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/rest/action/RestShieldInfoAction.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/rest/action/RestShieldInfoAction.java index fb8c2f97db2..6513f9841dc 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/rest/action/RestShieldInfoAction.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/rest/action/RestShieldInfoAction.java @@ -33,7 +33,7 @@ public class RestShieldInfoAction extends BaseRestHandler { @Inject public RestShieldInfoAction(Settings settings, RestController controller, Client client, ClusterName clusterName, @Nullable ShieldLicenseState licenseState) { - super(settings, controller, client); + super(settings, client); this.clusterName = clusterName; this.shieldLicenseState = licenseState; this.shieldEnabled = ShieldPlugin.shieldEnabled(settings); diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/rest/action/authc/cache/RestClearRealmCacheAction.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/rest/action/authc/cache/RestClearRealmCacheAction.java index ac4736319c6..e25e79d8913 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/rest/action/authc/cache/RestClearRealmCacheAction.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/rest/action/authc/cache/RestClearRealmCacheAction.java @@ -28,7 +28,7 @@ public class RestClearRealmCacheAction extends BaseRestHandler { @Inject public RestClearRealmCacheAction(Settings settings, RestController controller, Client client) { - super(settings, controller, client); + super(settings, client); controller.registerHandler(POST, "/_shield/realm/{realms}/_cache/clear", this); } diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/rest/action/authz/cache/RestClearRolesCacheAction.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/rest/action/authz/cache/RestClearRolesCacheAction.java index 4e8c80723e4..62ede25dde2 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/rest/action/authz/cache/RestClearRolesCacheAction.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/rest/action/authz/cache/RestClearRolesCacheAction.java @@ -31,7 +31,7 @@ public class RestClearRolesCacheAction extends BaseRestHandler { @Inject public RestClearRolesCacheAction(Settings settings, RestController controller, Client client) { - super(settings, controller, client); + super(settings, client); controller.registerHandler(POST, "/_shield/roles/{roles}/_cache/clear", this); } diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/transport/ClientTransportFilter.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/transport/ClientTransportFilter.java index 8c23d344b3d..8a6beaea40c 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/transport/ClientTransportFilter.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/transport/ClientTransportFilter.java @@ -56,7 +56,7 @@ public interface ClientTransportFilter { the system user will be attached. There cannot be a request outgoing from this node that is not associated with a user. */ - authcService.attachUserHeaderIfMissing(request, User.SYSTEM); + authcService.attachUserHeaderIfMissing(User.SYSTEM); } } } diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/transport/ServerTransportFilter.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/transport/ServerTransportFilter.java index 24e79cbde0a..22fe7d4d919 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/transport/ServerTransportFilter.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/transport/ServerTransportFilter.java @@ -7,6 +7,7 @@ package org.elasticsearch.shield.transport; import org.elasticsearch.common.logging.ESLogger; import org.elasticsearch.common.logging.Loggers; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.shield.User; import org.elasticsearch.shield.action.ShieldActionMapper; import org.elasticsearch.shield.authc.AuthenticationService; @@ -51,12 +52,15 @@ public interface ServerTransportFilter { private final AuthenticationService authcService; private final AuthorizationService authzService; private final ShieldActionMapper actionMapper; + private final ThreadContext threadContext; private final boolean extractClientCert; - public NodeProfile(AuthenticationService authcService, AuthorizationService authzService, ShieldActionMapper actionMapper, boolean extractClientCert) { + public NodeProfile(AuthenticationService authcService, AuthorizationService authzService, + ShieldActionMapper actionMapper, ThreadContext threadContext, boolean extractClientCert) { this.authcService = authcService; this.authzService = authzService; this.actionMapper = actionMapper; + this.threadContext = threadContext; this.extractClientCert = extractClientCert; } @@ -78,14 +82,14 @@ public interface ServerTransportFilter { } if (extractClientCert && (unwrappedChannel instanceof NettyTransportChannel)) { - Channel channel = ((NettyTransportChannel)unwrappedChannel).getChannel(); + Channel channel = ((NettyTransportChannel) unwrappedChannel).getChannel(); SslHandler sslHandler = channel.getPipeline().get(SslHandler.class); assert sslHandler != null; try { Certificate[] certs = sslHandler.getEngine().getSession().getPeerCertificates(); if (certs instanceof X509Certificate[]) { - request.putInContext(PkiRealm.PKI_CERT_HEADER_NAME, certs); + threadContext.putTransient(PkiRealm.PKI_CERT_HEADER_NAME, certs); } } catch (SSLPeerUnverifiedException e) { // this happens when we only request client authentication and the client does not provide it @@ -110,8 +114,9 @@ public interface ServerTransportFilter { */ class ClientProfile extends NodeProfile { - public ClientProfile(AuthenticationService authcService, AuthorizationService authzService, ShieldActionMapper actionMapper, boolean extractClientCert) { - super(authcService, authzService, actionMapper, extractClientCert); + public ClientProfile(AuthenticationService authcService, AuthorizationService authzService, + ShieldActionMapper actionMapper, ThreadContext threadContext, boolean extractClientCert) { + super(authcService, authzService, actionMapper, threadContext, extractClientCert); } @Override diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/transport/ShieldServerTransportService.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/transport/ShieldServerTransportService.java index b5c6e10066b..af46ff45551 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/transport/ShieldServerTransportService.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/transport/ShieldServerTransportService.java @@ -8,11 +8,14 @@ package org.elasticsearch.shield.transport; import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.shield.action.ShieldActionMapper; import org.elasticsearch.shield.authc.AuthenticationService; import org.elasticsearch.shield.authz.AuthorizationService; import org.elasticsearch.shield.authz.accesscontrol.RequestContext; import org.elasticsearch.shield.license.ShieldLicenseState; +import org.elasticsearch.shield.support.AutomatonPredicate; +import org.elasticsearch.shield.support.Automatons; import org.elasticsearch.shield.transport.netty.ShieldNettyTransport; import org.elasticsearch.tasks.Task; import org.elasticsearch.threadpool.ThreadPool; @@ -30,6 +33,7 @@ import org.elasticsearch.transport.netty.NettyTransport; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.function.Predicate; import java.util.function.Supplier; import static org.elasticsearch.shield.transport.netty.ShieldNettyTransport.TRANSPORT_CLIENT_AUTH_DEFAULT; @@ -45,6 +49,8 @@ import static org.elasticsearch.shield.transport.netty.ShieldNettyTransport.TRAN public class ShieldServerTransportService extends TransportService { public static final String SETTING_NAME = "shield.type"; + // FIXME clean up this hack + static final Predicate INTERNAL_PREDICATE = new AutomatonPredicate(Automatons.patterns("internal:*")); protected final AuthenticationService authcService; protected final AuthorizationService authzService; @@ -72,29 +78,46 @@ public class ShieldServerTransportService extends TransportService { @Override public void sendRequest(DiscoveryNode node, String action, TransportRequest request, TransportRequestOptions options, TransportResponseHandler handler) { - try { - clientFilter.outbound(action, request); - super.sendRequest(node, action, request, options, handler); - } catch (Throwable t) { - handler.handleException(new TransportException("failed sending request", t)); + try (ThreadContext.StoredContext original = threadPool.getThreadContext().newStoredContext()) { + // FIXME this is really just a hack. What happens is that we send a request and we always copy headers over + // Sometimes a system action gets executed like a internal create index request or update mappings request + // which means that the user is copied over to system actions and these really fail for internal things... + if ((clientFilter instanceof ClientTransportFilter.Node) && INTERNAL_PREDICATE.test(action)) { + try (ThreadContext.StoredContext ctx = threadPool.getThreadContext().stashContext()) { + try { + clientFilter.outbound(action, request); + super.sendRequest(node, action, request, options, handler); + } catch (Throwable t) { + handler.handleException(new TransportException("failed sending request", t)); + } + } + } else { + try { + clientFilter.outbound(action, request); + super.sendRequest(node, action, request, options, handler); + } catch (Throwable t) { + handler.handleException(new TransportException("failed sending request", t)); + } + } } } @Override public void registerRequestHandler(String action, Supplier requestFactory, String executor, TransportRequestHandler handler) { - TransportRequestHandler wrappedHandler = new ProfileSecuredRequestHandler<>(action, handler, profileFilters, licenseState); + TransportRequestHandler wrappedHandler = new ProfileSecuredRequestHandler<>(action, handler, profileFilters, licenseState, threadPool.getThreadContext()); super.registerRequestHandler(action, requestFactory, executor, wrappedHandler); } @Override public void registerRequestHandler(String action, Supplier request, String executor, boolean forceExecution, TransportRequestHandler handler) { - TransportRequestHandler wrappedHandler = new ProfileSecuredRequestHandler<>(action, handler, profileFilters, licenseState); + TransportRequestHandler wrappedHandler = new ProfileSecuredRequestHandler<>(action, handler, profileFilters, licenseState, threadPool.getThreadContext()); super.registerRequestHandler(action, request, executor, forceExecution, wrappedHandler); } protected Map initializeProfileFilters() { if (!(transport instanceof ShieldNettyTransport)) { - return Collections.singletonMap(NettyTransport.DEFAULT_PROFILE, new ServerTransportFilter.NodeProfile(authcService, authzService, actionMapper, false)); + return Collections.singletonMap(NettyTransport.DEFAULT_PROFILE, + new ServerTransportFilter.NodeProfile(authcService, authzService, actionMapper, threadPool.getThreadContext(), false)); } Map profileSettingsMap = settings.getGroups("transport.profiles.", true); @@ -108,10 +131,10 @@ public class ShieldServerTransportService extends TransportService { String type = entry.getValue().get(SETTING_NAME, "node"); switch (type) { case "client": - profileFilters.put(entry.getKey(), new ServerTransportFilter.ClientProfile(authcService, authzService, actionMapper, extractClientCert)); + profileFilters.put(entry.getKey(), new ServerTransportFilter.ClientProfile(authcService, authzService, actionMapper, threadPool.getThreadContext(), extractClientCert)); break; default: - profileFilters.put(entry.getKey(), new ServerTransportFilter.NodeProfile(authcService, authzService, actionMapper, extractClientCert)); + profileFilters.put(entry.getKey(), new ServerTransportFilter.NodeProfile(authcService, authzService, actionMapper, threadPool.getThreadContext(), extractClientCert)); } } @@ -119,7 +142,7 @@ public class ShieldServerTransportService extends TransportService { final boolean profileSsl = settings.getAsBoolean(TRANSPORT_SSL_SETTING, TRANSPORT_SSL_DEFAULT); final boolean clientAuth = SSLClientAuth.parse(settings.get(TRANSPORT_CLIENT_AUTH_SETTING), TRANSPORT_CLIENT_AUTH_DEFAULT).enabled(); final boolean extractClientCert = profileSsl && clientAuth; - profileFilters.put(NettyTransport.DEFAULT_PROFILE, new ServerTransportFilter.NodeProfile(authcService, authzService, actionMapper, extractClientCert)); + profileFilters.put(NettyTransport.DEFAULT_PROFILE, new ServerTransportFilter.NodeProfile(authcService, authzService, actionMapper, threadPool.getThreadContext(), extractClientCert)); } return Collections.unmodifiableMap(profileFilters); @@ -135,17 +158,20 @@ public class ShieldServerTransportService extends TransportService { protected final TransportRequestHandler handler; private final Map profileFilters; private final ShieldLicenseState licenseState; + private final ThreadContext threadContext; - public ProfileSecuredRequestHandler(String action, TransportRequestHandler handler, Map profileFilters, ShieldLicenseState licenseState) { + public ProfileSecuredRequestHandler(String action, TransportRequestHandler handler, Map profileFilters, + ShieldLicenseState licenseState, ThreadContext threadContext) { this.action = action; this.handler = handler; this.profileFilters = profileFilters; this.licenseState = licenseState; + this.threadContext = threadContext; } @Override public void messageReceived(T request, TransportChannel channel, Task task) throws Exception { - try { + try (ThreadContext.StoredContext ctx = threadContext.newStoredContext()) { if (licenseState.securityEnabled()) { String profile = channel.getProfileName(); ServerTransportFilter filter = profileFilters.get(profile); @@ -161,7 +187,8 @@ public class ShieldServerTransportService extends TransportService { assert filter != null; filter.inbound(action, request, channel); } - RequestContext context = new RequestContext(request); + // FIXME we should remove the RequestContext completely since we have ThreadContext but cannot yet due to the query cache + RequestContext context = new RequestContext(request, threadContext); RequestContext.setCurrent(context); handler.messageReceived(request, channel, task); } catch (Throwable t) { diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/transport/netty/ShieldNettyHttpServerTransport.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/transport/netty/ShieldNettyHttpServerTransport.java index adc02c5ecdb..89fe349ecfb 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/transport/netty/ShieldNettyHttpServerTransport.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/transport/netty/ShieldNettyHttpServerTransport.java @@ -13,6 +13,7 @@ import org.elasticsearch.http.netty.NettyHttpServerTransport; import org.elasticsearch.shield.ssl.ServerSSLService; import org.elasticsearch.shield.transport.SSLClientAuth; import org.elasticsearch.shield.transport.filter.IPFilter; +import org.elasticsearch.threadpool.ThreadPool; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; @@ -40,8 +41,8 @@ public class ShieldNettyHttpServerTransport extends NettyHttpServerTransport { @Inject public ShieldNettyHttpServerTransport(Settings settings, NetworkService networkService, BigArrays bigArrays, - IPFilter ipFilter, ServerSSLService sslService) { - super(settings, networkService, bigArrays); + IPFilter ipFilter, ServerSSLService sslService, ThreadPool threadPool) { + super(settings, networkService, bigArrays, threadPool); this.ipFilter = ipFilter; this.ssl = settings.getAsBoolean(HTTP_SSL_SETTING, HTTP_SSL_DEFAULT); this.sslService = sslService; @@ -89,7 +90,7 @@ public class ShieldNettyHttpServerTransport extends NettyHttpServerTransport { private final SSLClientAuth clientAuth; public HttpSslChannelPipelineFactory(NettyHttpServerTransport transport) { - super(transport, detailedErrorsEnabled); + super(transport, detailedErrorsEnabled, threadPool.getThreadContext()); clientAuth = SSLClientAuth.parse(settings.get(HTTP_CLIENT_AUTH_SETTING), HTTP_CLIENT_AUTH_DEFAULT); } diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/BulkUpdateTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/BulkUpdateTests.java index 718ebe924c3..20f89f75bad 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/BulkUpdateTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/BulkUpdateTests.java @@ -38,7 +38,7 @@ public class BulkUpdateTests extends ShieldIntegTestCase { public void testThatBulkUpdateDoesNotLoseFields() { assertThat(client().prepareIndex("index1", "type").setSource("{\"test\": \"test\"}").setId("1").get().isCreated(), is(true)); GetResponse getResponse = internalCluster().transportClient().prepareGet("index1", "type", "1").setFields("test").get(); - assertThat((String) getResponse.getField("test").getValue(), equalTo("test")); + assertThat(getResponse.getField("test").getValue(), equalTo("test")); if (randomBoolean()) { flushAndRefresh(); diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/ClearRealmsCacheTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/ClearRealmsCacheTests.java index c4095bf7489..05475b69403 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/ClearRealmsCacheTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/ClearRealmsCacheTests.java @@ -140,11 +140,11 @@ public class ClearRealmsCacheTests extends ShieldIntegTestCase { public abstract void executeRequest() throws Exception; static void executeTransportRequest(ClearRealmCacheRequest request) throws Exception { - ShieldClient client = new ShieldClient(client()); + ShieldClient shieldClient = new ShieldClient(client()); final CountDownLatch latch = new CountDownLatch(1); final AtomicReference error = new AtomicReference<>(); - client.clearRealmCache(request, new ActionListener() { + shieldClient.clearRealmCache(request, new ActionListener() { @Override public void onResponse(ClearRealmCacheResponse response) { assertThat(response.getNodes().length, equalTo(internalCluster().getNodeNames().length)); diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/DocumentAndFieldLevelSecurityTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/DocumentAndFieldLevelSecurityTests.java index de52a543d3b..922aaeeb5ce 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/DocumentAndFieldLevelSecurityTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/DocumentAndFieldLevelSecurityTests.java @@ -13,6 +13,8 @@ import org.elasticsearch.shield.authc.support.Hasher; import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.test.ShieldIntegTestCase; +import java.util.Collections; + import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.BASIC_AUTH_HEADER; import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; @@ -88,16 +90,16 @@ public class DocumentAndFieldLevelSecurityTests extends ShieldIntegTestCase { .setRefresh(true) .get(); - SearchResponse response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) + SearchResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareSearch("test") .get(); assertHitCount(response, 1); assertSearchHits(response, "1"); assertThat(response.getHits().getAt(0).getSource().size(), equalTo(1)); assertThat(response.getHits().getAt(0).getSource().get("field1").toString(), equalTo("value1")); - response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .prepareSearch("test") .get(); assertHitCount(response, 1); assertSearchHits(response, "2"); @@ -120,15 +122,15 @@ public class DocumentAndFieldLevelSecurityTests extends ShieldIntegTestCase { // Both users have the same role query, but user3 has access to field2 and not field1, which should result in zero hits: int max = scaledRandomIntBetween(4, 32); for (int i = 0; i < max; i++) { - SearchResponse response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) + SearchResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareSearch("test") .get(); assertHitCount(response, 1); assertThat(response.getHits().getAt(0).getId(), equalTo("1")); assertThat(response.getHits().getAt(0).sourceAsMap().size(), equalTo(1)); assertThat(response.getHits().getAt(0).sourceAsMap().get("field1"), equalTo("value1")); - response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .prepareSearch("test") .get(); assertHitCount(response, 1); assertThat(response.getHits().getAt(0).getId(), equalTo("2")); @@ -137,8 +139,8 @@ public class DocumentAndFieldLevelSecurityTests extends ShieldIntegTestCase { // this is a bit weird the document level permission (all docs with field2:value2) don't match with the field level permissions (field1), // this results in document 2 being returned but no fields are visible: - response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)) + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD))) + .prepareSearch("test") .get(); assertHitCount(response, 1); assertThat(response.getHits().getAt(0).getId(), equalTo("2")); diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/DocumentLevelSecurityRandomTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/DocumentLevelSecurityRandomTests.java index 179e19cff69..81af5084634 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/DocumentLevelSecurityRandomTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/DocumentLevelSecurityRandomTests.java @@ -16,6 +16,7 @@ import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.test.ShieldIntegTestCase; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.BASIC_AUTH_HEADER; @@ -93,8 +94,8 @@ public class DocumentLevelSecurityRandomTests extends ShieldIntegTestCase { builder.get(); for (int roleI = 1; roleI <= numberOfRoles; roleI++) { - SearchResponse searchResponse1 = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user" + roleI, USERS_PASSWD)) + SearchResponse searchResponse1 = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user" + roleI, USERS_PASSWD))) + .prepareSearch("test") .get(); SearchResponse searchResponse2 = client().prepareSearch("alias" + roleI).get(); assertThat(searchResponse1.getHits().getTotalHits(), equalTo(searchResponse2.getHits().getTotalHits())); diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/DocumentLevelSecurityTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/DocumentLevelSecurityTests.java index ebe2854ce52..40681f9e1f9 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/DocumentLevelSecurityTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/DocumentLevelSecurityTests.java @@ -29,6 +29,8 @@ import org.elasticsearch.shield.authc.support.Hasher; import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.test.ShieldIntegTestCase; +import java.util.Collections; + import static org.elasticsearch.index.query.QueryBuilders.hasChildQuery; import static org.elasticsearch.index.query.QueryBuilders.hasParentQuery; import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; @@ -100,14 +102,14 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase { .setRefresh(true) .get(); - SearchResponse response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) + SearchResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareSearch("test") .setQuery(randomBoolean() ? QueryBuilders.termQuery("field1", "value1") : QueryBuilders.matchAllQuery()) .get(); assertHitCount(response, 1); assertSearchHits(response, "1"); - response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .prepareSearch("test") .setQuery(randomBoolean() ? QueryBuilders.termQuery("field2", "value2") : QueryBuilders.matchAllQuery()) .get(); assertHitCount(response, 1); @@ -125,31 +127,31 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase { .get(); Boolean realtime = randomFrom(true, false, null); - GetResponse response = client().prepareGet("test", "type1", "1") + GetResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareGet("test", "type1", "1") .setRealtime(realtime) .setRefresh(true) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .get(); assertThat(response.isExists(), is(true)); assertThat(response.getId(), equalTo("1")); - response = client().prepareGet("test", "type1", "2") + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .prepareGet("test", "type1", "2") .setRealtime(realtime) .setRefresh(true) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .get(); assertThat(response.isExists(), is(true)); assertThat(response.getId(), equalTo("2")); - response = client().prepareGet("test", "type1", "1") + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .prepareGet("test", "type1", "1") .setRealtime(realtime) .setRefresh(true) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .get(); assertThat(response.isExists(), is(false)); - response = client().prepareGet("test", "type1", "2") + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareGet("test", "type1", "2") .setRealtime(realtime) .setRefresh(true) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .get(); assertThat(response.isExists(), is(false)); } @@ -165,40 +167,40 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase { .get(); Boolean realtime = randomFrom(true, false, null); - MultiGetResponse response = client().prepareMultiGet() + MultiGetResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareMultiGet() .add("test", "type1", "1") .setRealtime(realtime) .setRefresh(true) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .get(); assertThat(response.getResponses()[0].isFailed(), is(false)); assertThat(response.getResponses()[0].getResponse().isExists(), is(true)); assertThat(response.getResponses()[0].getResponse().getId(), equalTo("1")); - response = client().prepareMultiGet() + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .prepareMultiGet() .add("test", "type1", "2") .setRealtime(realtime) .setRefresh(true) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .get(); assertThat(response.getResponses()[0].isFailed(), is(false)); assertThat(response.getResponses()[0].getResponse().isExists(), is(true)); assertThat(response.getResponses()[0].getResponse().getId(), equalTo("2")); - response = client().prepareMultiGet() + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .prepareMultiGet() .add("test", "type1", "1") .setRealtime(realtime) .setRefresh(true) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .get(); assertThat(response.getResponses()[0].isFailed(), is(false)); assertThat(response.getResponses()[0].getResponse().isExists(), is(false)); - response = client().prepareMultiGet() + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareMultiGet() .add("test", "type1", "2") .setRealtime(realtime) .setRefresh(true) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .get(); assertThat(response.getResponses()[0].isFailed(), is(false)); assertThat(response.getResponses()[0].getResponse().isExists(), is(false)); @@ -216,29 +218,29 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase { .get(); Boolean realtime = randomFrom(true, false, null); - TermVectorsResponse response = client().prepareTermVectors("test", "type1", "1") + TermVectorsResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareTermVectors("test", "type1", "1") .setRealtime(realtime) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .get(); assertThat(response.isExists(), is(true)); assertThat(response.getId(), is("1")); - response = client().prepareTermVectors("test", "type1", "2") + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .prepareTermVectors("test", "type1", "2") .setRealtime(realtime) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .get(); assertThat(response.isExists(), is(true)); assertThat(response.getId(), is("2")); - response = client().prepareTermVectors("test", "type1", "1") + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .prepareTermVectors("test", "type1", "1") .setRealtime(realtime) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .get(); assertThat(response.isExists(), is(false)); - response = client().prepareTermVectors("test", "type1", "2") + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareTermVectors("test", "type1", "2") .setRealtime(realtime) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .get(); assertThat(response.isExists(), is(false)); } @@ -255,32 +257,32 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase { .get(); Boolean realtime = randomFrom(true, false, null); - MultiTermVectorsResponse response = client().prepareMultiTermVectors() + MultiTermVectorsResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareMultiTermVectors() .add(new TermVectorsRequest("test", "type1", "1").realtime(realtime)) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .get(); assertThat(response.getResponses().length, equalTo(1)); assertThat(response.getResponses()[0].getResponse().isExists(), is(true)); assertThat(response.getResponses()[0].getResponse().getId(), is("1")); - response = client().prepareMultiTermVectors() + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .prepareMultiTermVectors() .add(new TermVectorsRequest("test", "type1", "2").realtime(realtime)) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .get(); assertThat(response.getResponses().length, equalTo(1)); assertThat(response.getResponses()[0].getResponse().isExists(), is(true)); assertThat(response.getResponses()[0].getResponse().getId(), is("2")); - response = client().prepareMultiTermVectors() + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .prepareMultiTermVectors() .add(new TermVectorsRequest("test", "type1", "1").realtime(realtime)) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .get(); assertThat(response.getResponses().length, equalTo(1)); assertThat(response.getResponses()[0].getResponse().isExists(), is(false)); - response = client().prepareMultiTermVectors() + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareMultiTermVectors() .add(new TermVectorsRequest("test", "type1", "2").realtime(realtime)) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .get(); assertThat(response.getResponses().length, equalTo(1)); assertThat(response.getResponses()[0].getResponse().isExists(), is(false)); @@ -309,9 +311,9 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase { assertThat(termsAgg.getBuckets().get(0).getKeyAsString(), equalTo("value2")); assertThat(termsAgg.getBuckets().get(0).getDocCount(), equalTo(1l)); - response = client().prepareSearch("test") + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareSearch("test") .addAggregation(AggregationBuilders.global("global").subAggregation(AggregationBuilders.terms("field2").field("field2"))) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .get(); assertHitCount(response, 1); assertSearchHits(response, "1"); @@ -349,11 +351,11 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase { assertThat(termsAgg.getBuckets().get(0).getKeyAsString(), equalTo("value3")); assertThat(termsAgg.getBuckets().get(0).getDocCount(), equalTo(1l)); - response = client().prepareSearch("test") + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareSearch("test") .setTypes("type1") .addAggregation(AggregationBuilders.children("children").childType("type2") .subAggregation(AggregationBuilders.terms("field3").field("field3"))) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .get(); assertHitCount(response, 1); assertSearchHits(response, "1"); @@ -392,27 +394,27 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase { assertThat(searchResponse.getHits().getAt(1).id(), equalTo("c2")); // Both user1 and user2 can't see field1 and field2, no parent/child query should yield results: - searchResponse = client().prepareSearch("test") + searchResponse = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareSearch("test") .setQuery(hasChildQuery("child", matchAllQuery())) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .get(); assertHitCount(searchResponse, 0l); - searchResponse = client().prepareSearch("test") + searchResponse = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .prepareSearch("test") .setQuery(hasChildQuery("child", matchAllQuery())) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .get(); assertHitCount(searchResponse, 0l); - searchResponse = client().prepareSearch("test") + searchResponse = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareSearch("test") .setQuery(hasParentQuery("parent", matchAllQuery())) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .get(); assertHitCount(searchResponse, 0l); - searchResponse = client().prepareSearch("test") + searchResponse = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .prepareSearch("test") .setQuery(hasParentQuery("parent", matchAllQuery())) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .get(); assertHitCount(searchResponse, 0l); } @@ -427,30 +429,30 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase { .get(); // Percolator without a query just evaluates all percolator queries that are loaded, so we have a match: - PercolateResponse response = client().preparePercolate() + PercolateResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .preparePercolate() .setDocumentType("type") .setPercolateDoc(new PercolateSourceBuilder.DocBuilder().setDoc("{}")) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .get(); assertThat(response.getCount(), equalTo(1l)); assertThat(response.getMatches()[0].getId().string(), equalTo("1")); // Percolator with a query on a document that the current user can see. Percolator will have one query to evaluate, so there is a match: - response = client().preparePercolate() + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .preparePercolate() .setDocumentType("type") .setPercolateQuery(termQuery("field1", "value1")) .setPercolateDoc(new PercolateSourceBuilder.DocBuilder().setDoc("{}")) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .get(); assertThat(response.getCount(), equalTo(1l)); assertThat(response.getMatches()[0].getId().string(), equalTo("1")); // Percolator with a query on a document that the current user can't see. Percolator will not have queries to evaluate, so there is no match: - response = client().preparePercolate() + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .preparePercolate() .setDocumentType("type") .setPercolateQuery(termQuery("field1", "value1")) .setPercolateDoc(new PercolateSourceBuilder.DocBuilder().setDoc("{}")) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .get(); assertThat(response.getCount(), equalTo(0l)); @@ -459,10 +461,10 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase { ensureGreen("test"); // Ensure that the query loading that happens at startup has permissions to load the percolator queries: - response = client().preparePercolate() + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .preparePercolate() .setDocumentType("type") .setPercolateDoc(new PercolateSourceBuilder.DocBuilder().setDoc("{}")) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .get(); assertThat(response.getCount(), equalTo(1l)); assertThat(response.getMatches()[0].getId().string(), equalTo("1")); @@ -482,19 +484,19 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase { int max = scaledRandomIntBetween(4, 32); for (int i = 0; i < max; i++) { Boolean requestCache = randomFrom(true, null); - SearchResponse response = client().prepareSearch("test") + SearchResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareSearch("test") .setSize(0) .setQuery(termQuery("field1", "value1")) .setRequestCache(requestCache) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .get(); assertNoFailures(response); assertHitCount(response, 1); - response = client().prepareSearch("test") + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .prepareSearch("test") .setSize(0) .setQuery(termQuery("field1", "value1")) .setRequestCache(requestCache) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .get(); assertNoFailures(response); assertHitCount(response, 0); @@ -511,8 +513,8 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase { // With document level security enabled the update is not allowed: try { - client().prepareUpdate("test", "type", "1").setDoc("field1", "value2") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) + client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareUpdate("test", "type", "1").setDoc("field1", "value2") .get(); fail("failed, because update request shouldn't be allowed if document level security is enabled"); } catch (ElasticsearchSecurityException e) { @@ -528,8 +530,8 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase { // With document level security enabled the update in bulk is not allowed: try { - client().prepareBulk() - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) + client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareBulk() .add(new UpdateRequest("test", "type", "1").doc("field1", "value3")) .get(); fail("failed, because bulk request with updates shouldn't be allowed if field or document level security is enabled"); diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/FieldLevelSecurityRandomTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/FieldLevelSecurityRandomTests.java index 2c66cf3b0bc..839878a663d 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/FieldLevelSecurityRandomTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/FieldLevelSecurityRandomTests.java @@ -16,6 +16,7 @@ import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.test.ShieldIntegTestCase; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -135,17 +136,17 @@ public class FieldLevelSecurityRandomTests extends ShieldIntegTestCase { for (String allowedField : allowedFields) { logger.info("Checking allowed field [{}]", allowedField); - SearchResponse response = client().prepareSearch("test") + SearchResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareSearch("test") .setQuery(matchQuery(allowedField, "value")) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .get(); assertHitCount(response, 1); } for (String disallowedField : disAllowedFields) { logger.info("Checking disallowed field [{}]", disallowedField); - SearchResponse response = client().prepareSearch("test") + SearchResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareSearch("test") .setQuery(matchQuery(disallowedField, "value")) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .get(); assertHitCount(response, 0); } @@ -165,8 +166,8 @@ public class FieldLevelSecurityRandomTests extends ShieldIntegTestCase { } indexRandom(true, requests); - SearchResponse actual = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) + SearchResponse actual = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .prepareSearch("test") .addSort("_uid", SortOrder.ASC) .setQuery(QueryBuilders.boolQuery() .should(QueryBuilders.termQuery("field1", "value")) @@ -186,8 +187,8 @@ public class FieldLevelSecurityRandomTests extends ShieldIntegTestCase { assertThat(actual.getHits().getAt(i).getId(), equalTo(expected.getHits().getAt(i).getId())); } - actual = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)) + actual = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD))) + .prepareSearch("test") .addSort("_uid", SortOrder.ASC) .setQuery(QueryBuilders.boolQuery() .should(QueryBuilders.termQuery("field1", "value")) @@ -207,8 +208,8 @@ public class FieldLevelSecurityRandomTests extends ShieldIntegTestCase { assertThat(actual.getHits().getAt(i).getId(), equalTo(expected.getHits().getAt(i).getId())); } - actual = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD)) + actual = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD))) + .prepareSearch("test") .addSort("_uid", SortOrder.ASC) .setQuery(QueryBuilders.boolQuery() .should(QueryBuilders.termQuery("field1", "value")) diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/FieldLevelSecurityTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/FieldLevelSecurityTests.java index fbd7864956f..8e8c1424755 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/FieldLevelSecurityTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/FieldLevelSecurityTests.java @@ -29,6 +29,8 @@ import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ShieldIntegTestCase; +import java.util.Collections; + import static org.elasticsearch.index.query.QueryBuilders.constantScoreQuery; import static org.elasticsearch.index.query.QueryBuilders.hasChildQuery; import static org.elasticsearch.index.query.QueryBuilders.matchQuery; @@ -127,63 +129,63 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase { .get(); // user1 has access to field1, so the query should match with the document: - SearchResponse response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) + SearchResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareSearch("test") .setQuery(matchQuery("field1", "value1")) .get(); assertHitCount(response, 1); // user2 has no access to field1, so the query should not match with the document: - response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .prepareSearch("test") .setQuery(matchQuery("field1", "value1")) .get(); assertHitCount(response, 0); // user3 has access to field1 and field2, so the query should match with the document: - response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)) + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD))) + .prepareSearch("test") .setQuery(matchQuery("field1", "value1")) .get(); assertHitCount(response, 1); // user4 has access to no fields, so the query should not match with the document: - response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD)) + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD))) + .prepareSearch("test") .setQuery(matchQuery("field1", "value1")) .get(); assertHitCount(response, 0); // user5 has no field level security configured, so the query should match with the document: - response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user5", USERS_PASSWD)) + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user5", USERS_PASSWD))) + .prepareSearch("test") .setQuery(matchQuery("field1", "value1")) .get(); assertHitCount(response, 1); // user1 has no access to field1, so the query should not match with the document: - response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareSearch("test") .setQuery(matchQuery("field2", "value2")) .get(); assertHitCount(response, 0); // user2 has access to field1, so the query should match with the document: - response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .prepareSearch("test") .setQuery(matchQuery("field2", "value2")) .get(); assertHitCount(response, 1); // user3 has access to field1 and field2, so the query should match with the document: - response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)) + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD))) + .prepareSearch("test") .setQuery(matchQuery("field2", "value2")) .get(); assertHitCount(response, 1); // user4 has access to no fields, so the query should not match with the document: - response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD)) + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD))) + .prepareSearch("test") .setQuery(matchQuery("field2", "value2")) .get(); assertHitCount(response, 0); // user5 has no field level security configured, so the query should match with the document: - response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user5", USERS_PASSWD)) + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user5", USERS_PASSWD))) + .prepareSearch("test") .setQuery(matchQuery("field2", "value2")) .get(); assertHitCount(response, 1); @@ -199,30 +201,30 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase { Boolean realtime = randomFrom(true, false, null); // user1 is granted access to field1 only: - GetResponse response = client().prepareGet("test", "type1", "1") + GetResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareGet("test", "type1", "1") .setRealtime(realtime) .setRefresh(true) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .get(); assertThat(response.isExists(), is(true)); assertThat(response.getSource().size(), equalTo(1)); assertThat(response.getSource().get("field1").toString(), equalTo("value1")); // user2 is granted access to field2 only: - response = client().prepareGet("test", "type1", "1") + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .prepareGet("test", "type1", "1") .setRealtime(realtime) .setRefresh(true) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .get(); assertThat(response.isExists(), is(true)); assertThat(response.getSource().size(), equalTo(1)); assertThat(response.getSource().get("field2").toString(), equalTo("value2")); // user3 is granted access to field1 and field2: - response = client().prepareGet("test", "type1", "1") + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD))) + .prepareGet("test", "type1", "1") .setRealtime(realtime) .setRefresh(true) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)) .get(); assertThat(response.isExists(), is(true)); assertThat(response.getSource().size(), equalTo(2)); @@ -230,19 +232,19 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase { assertThat(response.getSource().get("field2").toString(), equalTo("value2")); // user4 is granted access to no fields, so the get response does say the doc exist, but no fields are returned: - response = client().prepareGet("test", "type1", "1") + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD))) + .prepareGet("test", "type1", "1") .setRealtime(realtime) .setRefresh(true) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD)) .get(); assertThat(response.isExists(), is(true)); assertThat(response.getSource().size(), equalTo(0)); // user5 has no field level security configured, so all fields are returned: - response = client().prepareGet("test", "type1", "1") + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user5", USERS_PASSWD))) + .prepareGet("test", "type1", "1") .setRealtime(realtime) .setRefresh(true) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user5", USERS_PASSWD)) .get(); assertThat(response.isExists(), is(true)); assertThat(response.getSource().size(), equalTo(2)); @@ -259,11 +261,11 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase { Boolean realtime = randomFrom(true, false, null); // user1 is granted access to field1 only: - MultiGetResponse response = client().prepareMultiGet() + MultiGetResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareMultiGet() .add("test", "type1", "1") .setRealtime(realtime) .setRefresh(true) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .get(); assertThat(response.getResponses()[0].isFailed(), is(false)); assertThat(response.getResponses()[0].getResponse().isExists(), is(true)); @@ -271,11 +273,11 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase { assertThat(response.getResponses()[0].getResponse().getSource().get("field1").toString(), equalTo("value1")); // user2 is granted access to field2 only: - response = client().prepareMultiGet() + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .prepareMultiGet() .add("test", "type1", "1") .setRealtime(realtime) .setRefresh(true) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .get(); assertThat(response.getResponses()[0].isFailed(), is(false)); assertThat(response.getResponses()[0].getResponse().isExists(), is(true)); @@ -283,11 +285,11 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase { assertThat(response.getResponses()[0].getResponse().getSource().get("field2").toString(), equalTo("value2")); // user3 is granted access to field1 and field2: - response = client().prepareMultiGet() + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD))) + .prepareMultiGet() .add("test", "type1", "1") .setRealtime(realtime) .setRefresh(true) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)) .get(); assertThat(response.getResponses()[0].isFailed(), is(false)); assertThat(response.getResponses()[0].getResponse().isExists(), is(true)); @@ -296,22 +298,22 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase { assertThat(response.getResponses()[0].getResponse().getSource().get("field2").toString(), equalTo("value2")); // user4 is granted access to no fields, so the get response does say the doc exist, but no fields are returned: - response = client().prepareMultiGet() + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD))) + .prepareMultiGet() .add("test", "type1", "1") .setRealtime(realtime) .setRefresh(true) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD)) .get(); assertThat(response.getResponses()[0].isFailed(), is(false)); assertThat(response.getResponses()[0].getResponse().isExists(), is(true)); assertThat(response.getResponses()[0].getResponse().getSource().size(), equalTo(0)); // user5 has no field level security configured, so all fields are returned: - response = client().prepareMultiGet() + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user5", USERS_PASSWD))) + .prepareMultiGet() .add("test", "type1", "1") .setRealtime(realtime) .setRefresh(true) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user5", USERS_PASSWD)) .get(); assertThat(response.getResponses()[0].isFailed(), is(false)); assertThat(response.getResponses()[0].getResponse().isExists(), is(true)); @@ -329,41 +331,41 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase { .get(); // user1 is granted access to field1 only: - FieldStatsResponse response = client().prepareFieldStats() + FieldStatsResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareFieldStats() .setFields("field1", "field2") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .get(); assertThat(response.getAllFieldStats().size(), equalTo(1)); assertThat(response.getAllFieldStats().get("field1").getDocCount(), equalTo(1l)); // user2 is granted access to field2 only: - response = client().prepareFieldStats() + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .prepareFieldStats() .setFields("field1", "field2") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .get(); assertThat(response.getAllFieldStats().size(), equalTo(1)); assertThat(response.getAllFieldStats().get("field2").getDocCount(), equalTo(1l)); // user3 is granted access to field1 and field2: - response = client().prepareFieldStats() + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD))) + .prepareFieldStats() .setFields("field1", "field2") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)) .get(); assertThat(response.getAllFieldStats().size(), equalTo(2)); assertThat(response.getAllFieldStats().get("field1").getDocCount(), equalTo(1l)); assertThat(response.getAllFieldStats().get("field2").getDocCount(), equalTo(1l)); // user4 is granted access to no fields: - response = client().prepareFieldStats() + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD))) + .prepareFieldStats() .setFields("field1", "field2") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD)) .get(); assertThat(response.getAllFieldStats().size(), equalTo(0)); // user5 has no field level security configured: - response = client().prepareFieldStats() + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user5", USERS_PASSWD))) + .prepareFieldStats() .setFields("field1", "field2") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user5", USERS_PASSWD)) .get(); assertThat(response.getAllFieldStats().size(), equalTo(2)); assertThat(response.getAllFieldStats().get("field1").getDocCount(), equalTo(1l)); @@ -381,14 +383,14 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase { int max = scaledRandomIntBetween(4, 32); for (int i = 0; i < max; i++) { - SearchResponse response = client().prepareSearch("test") + SearchResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareSearch("test") .setQuery(constantScoreQuery(termQuery("field1", "value1"))) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .get(); assertHitCount(response, 1); - response = client().prepareSearch("test") + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .prepareSearch("test") .setQuery(constantScoreQuery(termQuery("field1", "value1"))) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .get(); assertHitCount(response, 0); } @@ -406,19 +408,19 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase { int max = scaledRandomIntBetween(4, 32); for (int i = 0; i < max; i++) { Boolean requestCache = randomFrom(true, null); - SearchResponse response = client().prepareSearch("test") + SearchResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareSearch("test") .setSize(0) .setQuery(termQuery("field1", "value1")) .setRequestCache(requestCache) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .get(); assertNoFailures(response); assertHitCount(response, 1); - response = client().prepareSearch("test") + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .prepareSearch("test") .setSize(0) .setQuery(termQuery("field1", "value1")) .setRequestCache(requestCache) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .get(); assertNoFailures(response); assertHitCount(response, 0); @@ -434,46 +436,46 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase { .get(); // user1 is granted access to field1 only: - SearchResponse response = client().prepareSearch("test") + SearchResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareSearch("test") .addField("field1") .addField("field2") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .get(); assertThat(response.getHits().getAt(0).fields().size(), equalTo(1)); assertThat(response.getHits().getAt(0).fields().get("field1").getValue(), equalTo("value1")); // user2 is granted access to field2 only: - response = client().prepareSearch("test") + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .prepareSearch("test") .addField("field1") .addField("field2") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .get(); assertThat(response.getHits().getAt(0).fields().size(), equalTo(1)); assertThat(response.getHits().getAt(0).fields().get("field2").getValue(), equalTo("value2")); // user3 is granted access to field1 and field2: - response = client().prepareSearch("test") + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD))) + .prepareSearch("test") .addField("field1") .addField("field2") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)) .get(); assertThat(response.getHits().getAt(0).fields().size(), equalTo(2)); assertThat(response.getHits().getAt(0).fields().get("field1").getValue(), equalTo("value1")); assertThat(response.getHits().getAt(0).fields().get("field2").getValue(), equalTo("value2")); // user4 is granted access to no fields: - response = client().prepareSearch("test") + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD))) + .prepareSearch("test") .addField("field1") .addField("field2") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD)) .get(); assertThat(response.getHits().getAt(0).fields().size(), equalTo(0)); // user5 has no field level security configured: - response = client().prepareSearch("test") + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user5", USERS_PASSWD))) + .prepareSearch("test") .addField("field1") .addField("field2") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user5", USERS_PASSWD)) .get(); assertThat(response.getHits().getAt(0).fields().size(), equalTo(2)); assertThat(response.getHits().getAt(0).fields().get("field1").getValue(), equalTo("value1")); @@ -489,36 +491,36 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase { .get(); // user1 is granted access to field1 only: - SearchResponse response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) + SearchResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareSearch("test") .get(); assertThat(response.getHits().getAt(0).sourceAsMap().size(), equalTo(1)); assertThat(response.getHits().getAt(0).sourceAsMap().get("field1").toString(), equalTo("value1")); // user2 is granted access to field2 only: - response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .prepareSearch("test") .get(); assertThat(response.getHits().getAt(0).sourceAsMap().size(), equalTo(1)); assertThat(response.getHits().getAt(0).sourceAsMap().get("field2").toString(), equalTo("value2")); // user3 is granted access to field1 and field2: - response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)) + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD))) + .prepareSearch("test") .get(); assertThat(response.getHits().getAt(0).sourceAsMap().size(), equalTo(2)); assertThat(response.getHits().getAt(0).sourceAsMap().get("field1").toString(), equalTo("value1")); assertThat(response.getHits().getAt(0).sourceAsMap().get("field2").toString(), equalTo("value2")); // user4 is granted access to no fields: - response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD)) + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD))) + .prepareSearch("test") .get(); assertThat(response.getHits().getAt(0).sourceAsMap().size(), equalTo(0)); // user5 has no field level security configured: - response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user5", USERS_PASSWD)) + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user5", USERS_PASSWD))) + .prepareSearch("test") .get(); assertThat(response.getHits().getAt(0).sourceAsMap().size(), equalTo(2)); assertThat(response.getHits().getAt(0).sourceAsMap().get("field1").toString(), equalTo("value1")); @@ -535,29 +537,29 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase { .get(); // user1 is granted to use field1, so it is included in the sort_values - SearchResponse response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) + SearchResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareSearch("test") .addSort("field1", SortOrder.ASC) .get(); assertThat((Long) response.getHits().getAt(0).sortValues()[0], equalTo(1l)); // user2 is not granted to use field1, so the default missing sort value is included - response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .prepareSearch("test") .addSort("field1", SortOrder.ASC) .get(); assertThat((Long) response.getHits().getAt(0).sortValues()[0], equalTo(Long.MAX_VALUE)); // user1 is not granted to use field2, so the default missing sort value is included - response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareSearch("test") .addSort("field2", SortOrder.ASC) .get(); assertThat((Long) response.getHits().getAt(0).sortValues()[0], equalTo(Long.MAX_VALUE)); // user2 is granted to use field2, so it is included in the sort_values - response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .prepareSearch("test") .addSort("field2", SortOrder.ASC) .get(); assertThat((Long) response.getHits().getAt(0).sortValues()[0], equalTo(2l)); @@ -572,29 +574,29 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase { .get(); // user1 is authorized to use field1, so buckets are include for a term agg on field1 - SearchResponse response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) + SearchResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareSearch("test") .addAggregation(AggregationBuilders.terms("_name").field("field1")) .get(); assertThat(((Terms) response.getAggregations().get("_name")).getBucketByKey("value1").getDocCount(), equalTo(1l)); // user2 is not authorized to use field1, so no buckets are include for a term agg on field1 - response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .prepareSearch("test") .addAggregation(AggregationBuilders.terms("_name").field("field1")) .get(); assertThat(((Terms) response.getAggregations().get("_name")).getBucketByKey("value1"), nullValue()); // user1 is not authorized to use field2, so no buckets are include for a term agg on field2 - response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareSearch("test") .addAggregation(AggregationBuilders.terms("_name").field("field2")) .get(); assertThat(((Terms) response.getAggregations().get("_name")).getBucketByKey("value2"), nullValue()); // user2 is authorized to use field2, so buckets are include for a term agg on field2 - response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .prepareSearch("test") .addAggregation(AggregationBuilders.terms("_name").field("field2")) .get(); assertThat(((Terms) response.getAggregations().get("_name")).getBucketByKey("value2").getDocCount(), equalTo(1l)); @@ -609,24 +611,24 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase { .get(); Boolean realtime = randomFrom(true, false, null); - TermVectorsResponse response = client().prepareTermVectors("test", "type1", "1") + TermVectorsResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareTermVectors("test", "type1", "1") .setRealtime(realtime) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .get(); assertThat(response.isExists(), is(true)); assertThat(response.getFields().size(), equalTo(1)); assertThat(response.getFields().terms("field1").size(), equalTo(1l)); - response = client().prepareTermVectors("test", "type1", "1") + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .prepareTermVectors("test", "type1", "1") .setRealtime(realtime) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .get(); assertThat(response.isExists(), is(true)); assertThat(response.getFields().size(), equalTo(1)); assertThat(response.getFields().terms("field2").size(), equalTo(1l)); - response = client().prepareTermVectors("test", "type1", "1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)) + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD))) + .prepareTermVectors("test", "type1", "1") .setRealtime(realtime) .get(); assertThat(response.isExists(), is(true)); @@ -634,8 +636,8 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase { assertThat(response.getFields().terms("field1").size(), equalTo(1l)); assertThat(response.getFields().terms("field2").size(), equalTo(1l)); - response = client().prepareTermVectors("test", "type1", "1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD)) + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD))) + .prepareTermVectors("test", "type1", "1") .setRealtime(realtime) .get(); assertThat(response.isExists(), is(true)); @@ -651,27 +653,27 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase { .get(); Boolean realtime = randomFrom(true, false, null); - MultiTermVectorsResponse response = client().prepareMultiTermVectors() + MultiTermVectorsResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareMultiTermVectors() .add(new TermVectorsRequest("test", "type1", "1").realtime(realtime)) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .get(); assertThat(response.getResponses().length, equalTo(1)); assertThat(response.getResponses()[0].getResponse().isExists(), is(true)); assertThat(response.getResponses()[0].getResponse().getFields().size(), equalTo(1)); assertThat(response.getResponses()[0].getResponse().getFields().terms("field1").size(), equalTo(1l)); - response = client().prepareMultiTermVectors() + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .prepareMultiTermVectors() .add(new TermVectorsRequest("test", "type1", "1").realtime(realtime)) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .get(); assertThat(response.getResponses().length, equalTo(1)); assertThat(response.getResponses()[0].getResponse().isExists(), is(true)); assertThat(response.getResponses()[0].getResponse().getFields().size(), equalTo(1)); assertThat(response.getResponses()[0].getResponse().getFields().terms("field2").size(), equalTo(1l)); - response = client().prepareMultiTermVectors() + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD))) + .prepareMultiTermVectors() .add(new TermVectorsRequest("test", "type1", "1").realtime(realtime)) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)) .get(); assertThat(response.getResponses().length, equalTo(1)); assertThat(response.getResponses()[0].getResponse().isExists(), is(true)); @@ -679,9 +681,9 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase { assertThat(response.getResponses()[0].getResponse().getFields().terms("field1").size(), equalTo(1l)); assertThat(response.getResponses()[0].getResponse().getFields().terms("field2").size(), equalTo(1l)); - response = client().prepareMultiTermVectors() + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD))) + .prepareMultiTermVectors() .add(new TermVectorsRequest("test", "type1", "1").realtime(realtime)) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD)) .get(); assertThat(response.getResponses().length, equalTo(1)); assertThat(response.getResponses()[0].getResponse().isExists(), is(true)); @@ -698,20 +700,20 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase { .get(); // Percolator without a query just evaluates all percolator queries that are loaded, so we have a match: - PercolateResponse response = client().preparePercolate() + PercolateResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .preparePercolate() .setDocumentType("type") .setPercolateDoc(new PercolateSourceBuilder.DocBuilder().setDoc("{}")) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .get(); assertThat(response.getCount(), equalTo(1l)); assertThat(response.getMatches()[0].getId().string(), equalTo("1")); // Percolator with a query on a field that the current user can't see. Percolator will not have queries to evaluate, so there is no match: - response = client().preparePercolate() + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .preparePercolate() .setDocumentType("type") .setPercolateQuery(termQuery("field1", "value1")) .setPercolateDoc(new PercolateSourceBuilder.DocBuilder().setDoc("{}")) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .get(); assertThat(response.getCount(), equalTo(0l)); @@ -720,10 +722,10 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase { ensureGreen("test"); // Ensure that the query loading that happens at startup has permissions to load the percolator queries: - response = client().preparePercolate() + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .preparePercolate() .setDocumentType("type") .setPercolateDoc(new PercolateSourceBuilder.DocBuilder().setDoc("{}")) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .get(); assertThat(response.getCount(), equalTo(1l)); assertThat(response.getMatches()[0].getId().string(), equalTo("1")); @@ -741,17 +743,17 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase { client().prepareIndex("test", "child", "c2").setSource("field1", "yellow").setParent("p1").get(); refresh(); - SearchResponse searchResponse = client().prepareSearch("test") + SearchResponse searchResponse = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareSearch("test") .setQuery(hasChildQuery("child", termQuery("field1", "yellow"))) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .get(); assertHitCount(searchResponse, 1l); assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); assertThat(searchResponse.getHits().getAt(0).id(), equalTo("p1")); - searchResponse = client().prepareSearch("test") + searchResponse = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))) + .prepareSearch("test") .setQuery(hasChildQuery("child", termQuery("field1", "yellow"))) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .get(); assertHitCount(searchResponse, 0l); } @@ -767,8 +769,8 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase { // With field level security enabled the update is not allowed: try { - client().prepareUpdate("test", "type", "1").setDoc("field2", "value2") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) + client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareUpdate("test", "type", "1").setDoc("field2", "value2") .get(); fail("failed, because update request shouldn't be allowed if field level security is enabled"); } catch (ElasticsearchSecurityException e) { @@ -784,8 +786,8 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase { // With field level security enabled the update in bulk is not allowed: try { - client().prepareBulk() - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) + client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareBulk() .add(new UpdateRequest("test", "type", "1").doc("field2", "value3")) .get(); fail("failed, because bulk request with updates shouldn't be allowed if field level security is enabled"); @@ -810,8 +812,8 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase { .get(); // user6 has access to all fields, so the query should match with the document: - SearchResponse response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user6", USERS_PASSWD)) + SearchResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user6", USERS_PASSWD))) + .prepareSearch("test") .setQuery(matchQuery("field1", "value1")) .get(); assertHitCount(response, 1); @@ -819,8 +821,8 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase { assertThat(response.getHits().getAt(0).sourceAsMap().get("field1").toString(), equalTo("value1")); assertThat(response.getHits().getAt(0).sourceAsMap().get("field2").toString(), equalTo("value2")); - response = client().prepareSearch("test") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user6", USERS_PASSWD)) + response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user6", USERS_PASSWD))) + .prepareSearch("test") .setQuery(matchQuery("field2", "value2")) .get(); assertHitCount(response, 1); diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/IndicesPermissionsWithAliasesWildcardsAndRegexsTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/IndicesPermissionsWithAliasesWildcardsAndRegexsTests.java index 0c2db3bcaab..bb1864591e2 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/IndicesPermissionsWithAliasesWildcardsAndRegexsTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/IndicesPermissionsWithAliasesWildcardsAndRegexsTests.java @@ -13,6 +13,8 @@ import org.elasticsearch.shield.authc.support.Hasher; import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.test.ShieldIntegTestCase; +import java.util.Collections; + import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.BASIC_AUTH_HEADER; import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; @@ -72,20 +74,20 @@ public class IndicesPermissionsWithAliasesWildcardsAndRegexsTests extends Shield .setRefresh(true) .get(); - GetResponse getResponse = client().prepareGet("test", "type1", "1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) + GetResponse getResponse = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareGet("test", "type1", "1") .get(); assertThat(getResponse.getSource().size(), equalTo(1)); assertThat((String) getResponse.getSource().get("field1"), equalTo("value1")); - getResponse = client().prepareGet("my_alias", "type1", "1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) + getResponse = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareGet("my_alias", "type1", "1") .get(); assertThat(getResponse.getSource().size(), equalTo(1)); assertThat((String) getResponse.getSource().get("field2"), equalTo("value2")); - getResponse = client().prepareGet("an_alias", "type1", "1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) + getResponse = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))) + .prepareGet("an_alias", "type1", "1") .get(); assertThat(getResponse.getSource().size(), equalTo(1)); assertThat((String) getResponse.getSource().get("field3"), equalTo("value3")); diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/LicensingTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/LicensingTests.java index 99ed4b94a2c..0b4f8832ed1 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/LicensingTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/LicensingTests.java @@ -14,7 +14,6 @@ import org.elasticsearch.action.admin.cluster.stats.ClusterStatsResponse; import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse; import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.client.Client; -import org.elasticsearch.client.support.Headers; import org.elasticsearch.client.transport.NoNodeAvailableException; import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.common.component.AbstractComponent; @@ -24,6 +23,7 @@ import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Module; import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.license.core.License.OperationMode; import org.elasticsearch.license.plugin.LicensePlugin; import org.elasticsearch.license.plugin.core.LicenseState; @@ -203,7 +203,7 @@ public class LicensingTests extends ShieldIntegTestCase { .put(internalCluster().transportClient().settings()); // remove user info builder.remove("shield.user"); - builder.remove(Headers.PREFIX + "." + UsernamePasswordToken.BASIC_AUTH_HEADER); + builder.remove(ThreadContext.PREFIX + "." + UsernamePasswordToken.BASIC_AUTH_HEADER); // basic has no auth try (TransportClient client = TransportClient.builder().settings(builder).addPlugin(XPackPlugin.class).build()) { diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/MultipleIndicesPermissionsTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/MultipleIndicesPermissionsTests.java index e9d5f503570..b46a9398071 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/MultipleIndicesPermissionsTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/MultipleIndicesPermissionsTests.java @@ -13,21 +13,23 @@ import org.elasticsearch.client.Client; import org.elasticsearch.rest.RestStatus; import org.elasticsearch.shield.authc.support.Hasher; import org.elasticsearch.shield.authc.support.SecuredString; -import org.elasticsearch.shield.authc.support.SecuredStringTests; -import org.elasticsearch.shield.authc.support.UsernamePasswordToken; import org.elasticsearch.test.ShieldIntegTestCase; import org.elasticsearch.test.ShieldSettingsSource; +import java.util.Collections; + import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.elasticsearch.index.query.QueryBuilders.indicesQuery; import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.BASIC_AUTH_HEADER; +import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures; import static org.hamcrest.Matchers.is; public class MultipleIndicesPermissionsTests extends ShieldIntegTestCase { - protected static final String USERS_PASSWD_HASHED = new String(Hasher.BCRYPT.hash(new SecuredString("passwd".toCharArray()))); + protected static final SecuredString PASSWD = new SecuredString("passwd".toCharArray()); + protected static final String USERS_PASSWD_HASHED = new String(Hasher.BCRYPT.hash(PASSWD)); @Override protected String configRoles() { @@ -154,8 +156,8 @@ public class MultipleIndicesPermissionsTests extends ShieldIntegTestCase { Client client = internalCluster().transportClient(); - SearchResponse response = client.prepareSearch("a") - .putHeader(BASIC_AUTH_HEADER, userHeader("user_a", "passwd")) + SearchResponse response = client.filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user_a", PASSWD))) + .prepareSearch("a") .get(); assertNoFailures(response); assertHitCount(response, 1); @@ -164,16 +166,16 @@ public class MultipleIndicesPermissionsTests extends ShieldIntegTestCase { new String[] { "_all"} : randomBoolean() ? new String[] { "*" } : new String[] {}; - response = client.prepareSearch(indices) - .putHeader(BASIC_AUTH_HEADER, userHeader("user_a", "passwd")) + response = client.filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user_a", PASSWD))) + .prepareSearch(indices) .get(); assertNoFailures(response); assertHitCount(response, 1); try { indices = randomBoolean() ? new String[] { "a", "b" } : new String[] { "b", "a" }; - client.prepareSearch(indices) - .putHeader(BASIC_AUTH_HEADER, userHeader("user_a", "passwd")) + client.filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user_a", PASSWD))) + .prepareSearch(indices) .get(); fail("expected an authorization excpetion when trying to search on multiple indices where there are no search permissions on one/some of them"); } catch (ElasticsearchSecurityException e) { @@ -181,15 +183,15 @@ public class MultipleIndicesPermissionsTests extends ShieldIntegTestCase { assertThat(e.status(), is(RestStatus.FORBIDDEN)); } - response = client.prepareSearch("b") - .putHeader(BASIC_AUTH_HEADER, userHeader("user_ab", "passwd")) + response = client.filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user_ab", PASSWD))) + .prepareSearch("b") .get(); assertNoFailures(response); assertHitCount(response, 1); indices = randomBoolean() ? new String[] { "a", "b" } : new String[] { "b", "a" }; - response = client.prepareSearch(indices) - .putHeader(BASIC_AUTH_HEADER, userHeader("user_ab", "passwd")) + response = client.filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user_ab", PASSWD))) + .prepareSearch(indices) .get(); assertNoFailures(response); assertHitCount(response, 2); @@ -198,14 +200,10 @@ public class MultipleIndicesPermissionsTests extends ShieldIntegTestCase { new String[] { "_all"} : randomBoolean() ? new String[] { "*" } : new String[] {}; - response = client.prepareSearch(indices) - .putHeader(BASIC_AUTH_HEADER, userHeader("user_ab", "passwd")) + response = client.filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user_ab", PASSWD))) + .prepareSearch(indices) .get(); assertNoFailures(response); assertHitCount(response, 2); } - - private static String userHeader(String username, String password) { - return UsernamePasswordToken.basicAuthHeaderValue(username, SecuredStringTests.build(password)); - } } diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/PermissionPrecedenceTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/PermissionPrecedenceTests.java index 8873726dfa0..f3f2e681ac4 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/PermissionPrecedenceTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/PermissionPrecedenceTests.java @@ -17,6 +17,7 @@ import org.elasticsearch.shield.authc.support.SecuredStringTests; import org.elasticsearch.shield.authc.support.UsernamePasswordToken; import org.elasticsearch.test.ShieldIntegTestCase; +import java.util.Collections; import java.util.List; import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue; @@ -92,9 +93,9 @@ public class PermissionPrecedenceTests extends ShieldIntegTestCase { // first lets try with "admin"... all should work - PutIndexTemplateResponse putResponse = client.admin().indices().preparePutTemplate("template1") + PutIndexTemplateResponse putResponse = client.filterWithHeader(Collections.singletonMap(UsernamePasswordToken.BASIC_AUTH_HEADER, basicAuthHeaderValue(transportClientUsername(), transportClientPassword()))) + .admin().indices().preparePutTemplate("template1") .setTemplate("test_*") - .putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, basicAuthHeaderValue(transportClientUsername(), transportClientPassword())) .get(); assertAcked(putResponse); @@ -106,9 +107,9 @@ public class PermissionPrecedenceTests extends ShieldIntegTestCase { // now lets try with "user" try { - client.admin().indices().preparePutTemplate("template1") + client.filterWithHeader(Collections.singletonMap(UsernamePasswordToken.BASIC_AUTH_HEADER, basicAuthHeaderValue("user", transportClientPassword()))) + .admin().indices().preparePutTemplate("template1") .setTemplate("test_*") - .putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, basicAuthHeaderValue("user", transportClientPassword())) .get(); fail("expected an authorization exception as template APIs should require cluster ALL permission"); } catch (ElasticsearchSecurityException e) { @@ -117,8 +118,8 @@ public class PermissionPrecedenceTests extends ShieldIntegTestCase { } try { - client.admin().indices().prepareGetTemplates("template1") - .putHeader("Authorization", basicAuthHeaderValue("user", SecuredStringTests.build("test123"))) + client.filterWithHeader(Collections.singletonMap(UsernamePasswordToken.BASIC_AUTH_HEADER, basicAuthHeaderValue("user", SecuredStringTests.build("test123")))) + .admin().indices().prepareGetTemplates("template1") .get(); fail("expected an authorization exception as template APIs should require cluster ALL permission"); } catch (ElasticsearchSecurityException e) { diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/SearchGetAndSuggestPermissionsTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/SearchGetAndSuggestPermissionsTests.java index e9429d0f07b..fd8ea1d3a90 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/SearchGetAndSuggestPermissionsTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/SearchGetAndSuggestPermissionsTests.java @@ -19,6 +19,8 @@ import org.elasticsearch.shield.authc.support.SecuredStringTests; import org.elasticsearch.shield.authc.support.UsernamePasswordToken; import org.elasticsearch.test.ShieldIntegTestCase; +import java.util.Collections; + import static org.elasticsearch.client.Requests.searchRequest; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.elasticsearch.test.ShieldTestsUtils.assertAuthorizationException; @@ -77,21 +79,21 @@ public class SearchGetAndSuggestPermissionsTests extends ShieldIntegTestCase { Client client = internalCluster().transportClient(); - SuggestResponse suggestResponse = client.prepareSuggest("a") - .putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("suggest_user", "passwd")) + SuggestResponse suggestResponse = client.filterWithHeader(Collections.singletonMap(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("suggest_user", "passwd"))) + .prepareSuggest("a") .addSuggestion(SuggestBuilders.termSuggestion("name").field("name").text("val")).get(); assertNoFailures(suggestResponse); assertThat(suggestResponse.getSuggest().size(), is(1)); - suggestResponse = client.prepareSuggest("a") - .putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("search_user", "passwd")) + suggestResponse = client.filterWithHeader(Collections.singletonMap(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("search_user", "passwd"))) + .prepareSuggest("a") .addSuggestion(SuggestBuilders.termSuggestion("name").field("name").text("val")).get(); assertNoFailures(suggestResponse); assertThat(suggestResponse.getSuggest().size(), is(1)); try { - client.prepareSearch("a") - .putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("suggest_user", "passwd")) + client.filterWithHeader(Collections.singletonMap(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("suggest_user", "passwd"))) + .prepareSearch("a") .get(); fail("a user with only a suggest privilege cannot execute search"); } catch (ElasticsearchSecurityException e) { @@ -115,8 +117,8 @@ public class SearchGetAndSuggestPermissionsTests extends ShieldIntegTestCase { Client client = internalCluster().transportClient(); try { - client.prepareGet("a", "type", indexResponse.getId()) - .putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("search_user", "passwd")) + client.filterWithHeader(Collections.singletonMap(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("search_user", "passwd"))) + .prepareGet("a", "type", indexResponse.getId()) .get(); fail("a user with only search privilege should not be authorized for a get request"); } catch (ElasticsearchSecurityException e) { @@ -140,16 +142,16 @@ public class SearchGetAndSuggestPermissionsTests extends ShieldIntegTestCase { Client client = internalCluster().transportClient(); - MultiGetResponse response = client.prepareMultiGet().add("a", "type", indexResponse.getId()) - .putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("get_user", "passwd")) + MultiGetResponse response = client.filterWithHeader(Collections.singletonMap(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("get_user", "passwd"))) + .prepareMultiGet().add("a", "type", indexResponse.getId()) .get(); assertNotNull(response); assertThat(response.getResponses().length, is(1)); assertThat(response.getResponses()[0].getId(), equalTo(indexResponse.getId())); try { - client.prepareMultiGet().add("a", "type", indexResponse.getId()) - .putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("search_user", "passwd")) + client.filterWithHeader(Collections.singletonMap(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("search_user", "passwd"))) + .prepareMultiGet().add("a", "type", indexResponse.getId()) .get(); fail("a user with only a search privilege should not be able to execute the mget API"); } catch (ElasticsearchSecurityException e) { @@ -173,8 +175,8 @@ public class SearchGetAndSuggestPermissionsTests extends ShieldIntegTestCase { Client client = internalCluster().transportClient(); - MultiSearchResponse response = client.prepareMultiSearch().add(searchRequest("a").types("type")) - .putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("search_user", "passwd")) + MultiSearchResponse response = client.filterWithHeader(Collections.singletonMap(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("search_user", "passwd"))) + .prepareMultiSearch().add(searchRequest("a").types("type")) .get(); assertNotNull(response); assertThat(response.getResponses().length, is(1)); diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/ShieldClearScrollTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/ShieldClearScrollTests.java index 48628bfcc95..2d274526678 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/ShieldClearScrollTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/ShieldClearScrollTests.java @@ -19,8 +19,11 @@ import org.junit.After; import org.junit.Before; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.BASIC_AUTH_HEADER; import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertThrows; import static org.hamcrest.Matchers.containsString; @@ -85,9 +88,11 @@ public class ShieldClearScrollTests extends ShieldIntegTestCase { public void testThatClearingAllScrollIdsWorks() throws Exception { String shieldUser = "allowed_user:change_me"; String basicAuth = basicAuthHeaderValue("allowed_user", new SecuredString("change_me".toCharArray())); - ClearScrollResponse clearScrollResponse = internalCluster().transportClient().prepareClearScroll() - .putHeader("shield.user", shieldUser) - .putHeader("Authorization", basicAuth) + Map headers = new HashMap<>(); + headers.put("shield.user", shieldUser); + headers.put(BASIC_AUTH_HEADER, basicAuth); + ClearScrollResponse clearScrollResponse = internalCluster().transportClient().filterWithHeader(headers) + .prepareClearScroll() .addScrollId("_all").get(); assertThat(clearScrollResponse.isSucceeded(), is(true)); @@ -97,10 +102,11 @@ public class ShieldClearScrollTests extends ShieldIntegTestCase { public void testThatClearingAllScrollIdsRequirePermissions() throws Exception { String shieldUser = "denied_user:change_me"; String basicAuth = basicAuthHeaderValue("denied_user", new SecuredString("change_me".toCharArray())); - - assertThrows(internalCluster().transportClient().prepareClearScroll() - .putHeader("shield.user", shieldUser) - .putHeader("Authorization", basicAuth) + Map headers = new HashMap<>(); + headers.put("shield.user", shieldUser); + headers.put(BASIC_AUTH_HEADER, basicAuth); + assertThrows(internalCluster().transportClient().filterWithHeader(headers) + .prepareClearScroll() .addScrollId("_all"), ElasticsearchSecurityException.class, "action [cluster:admin/indices/scroll/clear_all] is unauthorized for user [denied_user]"); // deletion of scroll ids should work diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/ldap/AbstractAdLdapRealmTestCase.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/ldap/AbstractAdLdapRealmTestCase.java index be15437bceb..4786cd26902 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/ldap/AbstractAdLdapRealmTestCase.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/integration/ldap/AbstractAdLdapRealmTestCase.java @@ -9,6 +9,7 @@ import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchSecurityException; import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.action.index.IndexResponse; +import org.elasticsearch.client.Client; import org.elasticsearch.common.logging.ESLoggerFactory; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.shield.authc.activedirectory.ActiveDirectoryRealm; @@ -24,6 +25,7 @@ import org.junit.BeforeClass; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Collections; import static org.elasticsearch.common.settings.Settings.settingsBuilder; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; @@ -107,20 +109,19 @@ abstract public class AbstractAdLdapRealmTestCase extends ShieldIntegTestCase { } protected void assertAccessAllowed(String user, String index) throws IOException { - IndexResponse indexResponse = client().prepareIndex(index, "type"). + Client client = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, userHeader(user, PASSWORD))); + IndexResponse indexResponse = client.prepareIndex(index, "type"). setSource(jsonBuilder() .startObject() .field("name", "value") .endObject()) - .putHeader(BASIC_AUTH_HEADER, userHeader(user, PASSWORD)) .execute().actionGet(); assertThat("user " + user + " should have write access to index " + index, indexResponse.isCreated(), is(true)); refresh(); - GetResponse getResponse = client().prepareGet(index, "type", indexResponse.getId()) - .putHeader(BASIC_AUTH_HEADER, userHeader(user, PASSWORD)) + GetResponse getResponse = client.prepareGet(index, "type", indexResponse.getId()) .get(); assertThat("user " + user + " should have read access to index " + index, getResponse.getId(), equalTo(indexResponse.getId())); @@ -128,12 +129,12 @@ abstract public class AbstractAdLdapRealmTestCase extends ShieldIntegTestCase { protected void assertAccessDenied(String user, String index) throws IOException { try { - client().prepareIndex(index, "type"). + client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, userHeader(user, PASSWORD))) + .prepareIndex(index, "type"). setSource(jsonBuilder() .startObject() .field("name", "value") .endObject()) - .putHeader(BASIC_AUTH_HEADER, userHeader(user, PASSWORD)) .execute().actionGet(); fail("Write access to index " + index + " should not be allowed for user " + user); } catch (ElasticsearchSecurityException e) { diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/action/ShieldActionFilterTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/action/ShieldActionFilterTests.java index ca700609290..66ffc51fac0 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/action/ShieldActionFilterTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/action/ShieldActionFilterTests.java @@ -11,6 +11,7 @@ import org.elasticsearch.action.ActionRequest; import org.elasticsearch.action.search.SearchScrollRequest; import org.elasticsearch.action.support.ActionFilterChain; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.shield.User; import org.elasticsearch.shield.action.interceptor.RequestInterceptor; import org.elasticsearch.shield.audit.AuditTrail; @@ -20,6 +21,7 @@ import org.elasticsearch.shield.crypto.CryptoService; import org.elasticsearch.shield.license.ShieldLicenseState; import org.elasticsearch.tasks.Task; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.threadpool.ThreadPool; import org.junit.Before; import java.util.HashSet; @@ -56,7 +58,9 @@ public class ShieldActionFilterTests extends ESTestCase { shieldLicenseState = mock(ShieldLicenseState.class); when(shieldLicenseState.securityEnabled()).thenReturn(true); when(shieldLicenseState.statsAndHealthEnabled()).thenReturn(true); - filter = new ShieldActionFilter(Settings.EMPTY, authcService, authzService, cryptoService, auditTrail, shieldLicenseState, new ShieldActionMapper(), new HashSet()); + ThreadPool threadPool = mock(ThreadPool.class); + when(threadPool.getThreadContext()).thenReturn(new ThreadContext(Settings.EMPTY)); + filter = new ShieldActionFilter(Settings.EMPTY, authcService, authzService, cryptoService, auditTrail, shieldLicenseState, new ShieldActionMapper(), new HashSet(), threadPool); } public void testApply() throws Exception { diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/admin/ESNativeTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/admin/ESNativeTests.java index 46946464de0..98c27737ea4 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/admin/ESNativeTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/admin/ESNativeTests.java @@ -29,6 +29,7 @@ import org.junit.After; import org.junit.Before; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue; @@ -197,7 +198,7 @@ public class ESNativeTests extends ShieldIntegTestCase { client().prepareIndex("idx", "doc", "1").setSource("body", "foo").setRefresh(true).get(); String token = basicAuthHeaderValue("joe", new SecuredString("s3krit".toCharArray())); - SearchResponse searchResp = client().prepareSearch("idx").putHeader("Authorization", token).get(); + SearchResponse searchResp = client().filterWithHeader(Collections.singletonMap("Authorization", token)).prepareSearch("idx").get(); assertEquals(searchResp.getHits().getTotalHits(), 1L); } @@ -223,7 +224,7 @@ public class ESNativeTests extends ShieldIntegTestCase { // Index a document with the default test user client().prepareIndex("idx", "doc", "1").setSource("body", "foo").setRefresh(true).get(); String token = basicAuthHeaderValue("joe", new SecuredString("s3krit".toCharArray())); - SearchResponse searchResp = client().prepareSearch("idx").putHeader("Authorization", token).get(); + SearchResponse searchResp = client().filterWithHeader(Collections.singletonMap("Authorization", token)).prepareSearch("idx").get(); assertEquals(searchResp.getHits().getTotalHits(), 1L); @@ -234,7 +235,7 @@ public class ESNativeTests extends ShieldIntegTestCase { .get(); try { - client().prepareSearch("idx").putHeader("Authorization", token).get(); + client().filterWithHeader(Collections.singletonMap("Authorization", token)).prepareSearch("idx").get(); fail("authentication with old credentials after an update to the user should fail!"); } catch (ElasticsearchSecurityException e) { // expected @@ -242,7 +243,7 @@ public class ESNativeTests extends ShieldIntegTestCase { } token = basicAuthHeaderValue("joe", new SecuredString("s3krit2".toCharArray())); - searchResp = client().prepareSearch("idx").putHeader("Authorization", token).get(); + searchResp = client().filterWithHeader(Collections.singletonMap("Authorization", token)).prepareSearch("idx").get(); assertEquals(searchResp.getHits().getTotalHits(), 1L); } @@ -267,14 +268,14 @@ public class ESNativeTests extends ShieldIntegTestCase { // Index a document with the default test user client().prepareIndex("idx", "doc", "1").setSource("body", "foo").setRefresh(true).get(); String token = basicAuthHeaderValue("joe", new SecuredString("s3krit".toCharArray())); - SearchResponse searchResp = client().prepareSearch("idx").putHeader("Authorization", token).get(); + SearchResponse searchResp = client().filterWithHeader(Collections.singletonMap("Authorization", token)).prepareSearch("idx").get(); assertEquals(searchResp.getHits().getTotalHits(), 1L); DeleteUserResponse response = c.prepareDeleteUser().user("joe").get(); assertThat(response.found(), is(true)); try { - client().prepareSearch("idx").putHeader("Authorization", token).get(); + client().filterWithHeader(Collections.singletonMap("Authorization", token)).prepareSearch("idx").get(); fail("authentication with a deleted user should fail!"); } catch (ElasticsearchSecurityException e) { // expected @@ -304,7 +305,7 @@ public class ESNativeTests extends ShieldIntegTestCase { if (authenticate) { final String token = basicAuthHeaderValue("joe", new SecuredString("s3krit".toCharArray())); - ClusterHealthResponse response = client().admin().cluster().prepareHealth().putHeader("Authorization", token).get(); + ClusterHealthResponse response = client().filterWithHeader(Collections.singletonMap("Authorization", token)).admin().cluster().prepareHealth().get(); assertFalse(response.isTimedOut()); c.prepareAddRole() .name("test_role") @@ -313,7 +314,7 @@ public class ESNativeTests extends ShieldIntegTestCase { new String[]{"body", "title"}, new BytesArray("{\"match_all\": {}}")) .get(); try { - client().admin().cluster().prepareHealth().putHeader("Authorization", token).get(); + client().filterWithHeader(Collections.singletonMap("Authorization", token)).admin().cluster().prepareHealth().get(); fail("user should not be able to execute any cluster actions!"); } catch (ElasticsearchSecurityException e) { assertThat(e.status(), is(RestStatus.FORBIDDEN)); @@ -356,11 +357,11 @@ public class ESNativeTests extends ShieldIntegTestCase { ensureGreen(ShieldTemplateService.SHIELD_ADMIN_INDEX_NAME); final String token = basicAuthHeaderValue("joe", new SecuredString("s3krit".toCharArray())); - ClusterHealthResponse response = client().admin().cluster().prepareHealth().putHeader("Authorization", token).get(); + ClusterHealthResponse response = client().filterWithHeader(Collections.singletonMap("Authorization", token)).admin().cluster().prepareHealth().get(); assertFalse(response.isTimedOut()); c.prepareDeleteRole().role("test_role").get(); try { - client().admin().cluster().prepareHealth().putHeader("Authorization", token).get(); + client().filterWithHeader(Collections.singletonMap("Authorization", token)).admin().cluster().prepareHealth().get(); fail("user should not be able to execute any actions!"); } catch (ElasticsearchSecurityException e) { assertThat(e.status(), is(RestStatus.FORBIDDEN)); diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/audit/index/IndexAuditTrailTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/audit/index/IndexAuditTrailTests.java index 1a19ed419eb..beb125a4364 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/audit/index/IndexAuditTrailTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/audit/index/IndexAuditTrailTests.java @@ -194,7 +194,7 @@ public class IndexAuditTrailTests extends ShieldIntegTestCase { } settings = builder.build(); - doThrow(new IllegalStateException("indexing user should not be attached when sending remotely")).when(authService).attachUserHeaderIfMissing(any(TransportMessage.class), eq(user.user())); + doThrow(new IllegalStateException("indexing user should not be attached when sending remotely")).when(authService).attachUserHeaderIfMissing(eq(user.user())); } settings = Settings.builder().put(settings).put("path.home", createTempDir()).build(); diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/audit/index/RemoteIndexAuditTrailStartingTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/audit/index/RemoteIndexAuditTrailStartingTests.java index d6a9d31db2a..e49146f8d70 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/audit/index/RemoteIndexAuditTrailStartingTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/audit/index/RemoteIndexAuditTrailStartingTests.java @@ -24,7 +24,6 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; -import java.util.function.Function; import static org.elasticsearch.test.InternalTestCluster.clusterName; import static org.hamcrest.Matchers.is; @@ -107,7 +106,8 @@ public class RemoteIndexAuditTrailStartingTests extends ShieldIntegTestCase { return builder.build(); } }; - remoteCluster = new InternalTestCluster("network", randomLong(), createTempDir(), numNodes, numNodes, cluster2Name, cluster2SettingsSource, 0, false, SECOND_CLUSTER_NODE_PREFIX, getMockPlugins(), Function.identity()); + remoteCluster = new InternalTestCluster("network", randomLong(), createTempDir(), numNodes, numNodes, cluster2Name, + cluster2SettingsSource, 0, false, SECOND_CLUSTER_NODE_PREFIX, getMockPlugins(), getClientWrapper()); remoteCluster.beforeTest(getRandom(), 0.5); } diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/audit/logfile/LoggingAuditTrailTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/audit/logfile/LoggingAuditTrailTests.java index e7309eb601b..5e5330e68a4 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/audit/logfile/LoggingAuditTrailTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/audit/logfile/LoggingAuditTrailTests.java @@ -17,6 +17,7 @@ import org.elasticsearch.common.transport.DummyTransportAddress; import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.common.transport.LocalTransportAddress; import org.elasticsearch.common.transport.TransportAddress; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.shield.User; import org.elasticsearch.shield.audit.logfile.CapturingLogger.Level; @@ -102,6 +103,7 @@ public class LoggingAuditTrailTests extends ESTestCase { private String prefix; private Settings settings; private Transport transport; + private ThreadContext threadContext; @Before public void init() throws Exception { @@ -118,10 +120,11 @@ public class LoggingAuditTrailTests extends ESTestCase { public void testAnonymousAccessDeniedTransport() throws Exception { for (Level level : Level.values()) { + threadContext = new ThreadContext(Settings.EMPTY); CapturingLogger logger = new CapturingLogger(level); - LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger).start(); - TransportMessage message = randomBoolean() ? new MockMessage() : new MockIndicesRequest(); - String origins = LoggingAuditTrail.originAttributes(message, transport); + LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger, threadContext).start(); + TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext); + String origins = LoggingAuditTrail.originAttributes(message, transport, threadContext); auditTrail.anonymousAccessDenied("_action", message); switch (level) { case ERROR: @@ -154,8 +157,9 @@ public class LoggingAuditTrailTests extends ESTestCase { String expectedMessage = prepareRestContent(request); for (Level level : Level.values()) { + threadContext = new ThreadContext(Settings.EMPTY); CapturingLogger logger = new CapturingLogger(level); - LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger).start(); + LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger, threadContext).start(); auditTrail.anonymousAccessDenied(request); switch (level) { case ERROR: @@ -174,10 +178,11 @@ public class LoggingAuditTrailTests extends ESTestCase { public void testAuthenticationFailed() throws Exception { for (Level level : Level.values()) { + threadContext = new ThreadContext(Settings.EMPTY); CapturingLogger logger = new CapturingLogger(level); - LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger).start(); - TransportMessage message = randomBoolean() ? new MockMessage() : new MockIndicesRequest(); - String origins = LoggingAuditTrail.originAttributes(message, transport);; + LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger, threadContext).start(); + TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext); + String origins = LoggingAuditTrail.originAttributes(message, transport, threadContext);; auditTrail.authenticationFailed(new MockToken(), "_action", message); switch (level) { case ERROR: @@ -202,10 +207,11 @@ public class LoggingAuditTrailTests extends ESTestCase { public void testAuthenticationFailedNoToken() throws Exception { for (Level level : Level.values()) { + threadContext = new ThreadContext(Settings.EMPTY); CapturingLogger logger = new CapturingLogger(level); - LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger).start(); - TransportMessage message = randomBoolean() ? new MockMessage() : new MockIndicesRequest(); - String origins = LoggingAuditTrail.originAttributes(message, transport);; + LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger, threadContext).start(); + TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext); + String origins = LoggingAuditTrail.originAttributes(message, transport, threadContext);; auditTrail.authenticationFailed("_action", message); switch (level) { case ERROR: @@ -230,13 +236,14 @@ public class LoggingAuditTrailTests extends ESTestCase { public void testAuthenticationFailedRest() throws Exception { for (Level level : Level.values()) { + threadContext = new ThreadContext(Settings.EMPTY); RestRequest request = mock(RestRequest.class); InetAddress address = forge("_hostname", randomBoolean() ? "127.0.0.1" : "::1"); when(request.getRemoteAddress()).thenReturn(new InetSocketAddress(address, 9200)); when(request.uri()).thenReturn("_uri"); String expectedMessage = prepareRestContent(request); CapturingLogger logger = new CapturingLogger(level); - LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger).start(); + LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger, threadContext).start(); auditTrail.authenticationFailed(new MockToken(), request); switch (level) { case ERROR: @@ -253,13 +260,14 @@ public class LoggingAuditTrailTests extends ESTestCase { public void testAuthenticationFailedRestNoToken() throws Exception { for (Level level : Level.values()) { + threadContext = new ThreadContext(Settings.EMPTY); RestRequest request = mock(RestRequest.class); InetAddress address = forge("_hostname", randomBoolean() ? "127.0.0.1" : "::1"); when(request.getRemoteAddress()).thenReturn(new InetSocketAddress(address, 9200)); when(request.uri()).thenReturn("_uri"); String expectedMessage = prepareRestContent(request); CapturingLogger logger = new CapturingLogger(level); - LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger).start(); + LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger, threadContext).start(); auditTrail.authenticationFailed(request); switch (level) { case ERROR: @@ -276,10 +284,11 @@ public class LoggingAuditTrailTests extends ESTestCase { public void testAuthenticationFailedRealm() throws Exception { for (Level level : Level.values()) { + threadContext = new ThreadContext(Settings.EMPTY); CapturingLogger logger = new CapturingLogger(level); - LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger).start(); - TransportMessage message = randomBoolean() ? new MockMessage() : new MockIndicesRequest(); - String origins = LoggingAuditTrail.originAttributes(message, transport);; + LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger, threadContext).start(); + TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext); + String origins = LoggingAuditTrail.originAttributes(message, transport, threadContext);; auditTrail.authenticationFailed("_realm", new MockToken(), "_action", message); switch (level) { case ERROR: @@ -300,13 +309,14 @@ public class LoggingAuditTrailTests extends ESTestCase { public void testAuthenticationFailedRealmRest() throws Exception { for (Level level : Level.values()) { + threadContext = new ThreadContext(Settings.EMPTY); RestRequest request = mock(RestRequest.class); InetAddress address = forge("_hostname", randomBoolean() ? "127.0.0.1" : "::1"); when(request.getRemoteAddress()).thenReturn(new InetSocketAddress(address, 9200)); when(request.uri()).thenReturn("_uri"); String expectedMessage = prepareRestContent(request); CapturingLogger logger = new CapturingLogger(level); - LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger).start(); + LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger, threadContext).start(); auditTrail.authenticationFailed("_realm", new MockToken(), request); switch (level) { case ERROR: @@ -323,10 +333,11 @@ public class LoggingAuditTrailTests extends ESTestCase { public void testAccessGranted() throws Exception { for (Level level : Level.values()) { + threadContext = new ThreadContext(Settings.EMPTY); CapturingLogger logger = new CapturingLogger(level); - LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger).start(); - TransportMessage message = randomBoolean() ? new MockMessage() : new MockIndicesRequest(); - String origins = LoggingAuditTrail.originAttributes(message, transport); + LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger, threadContext).start(); + TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext); + String origins = LoggingAuditTrail.originAttributes(message, transport, threadContext); boolean runAs = randomBoolean(); User user; if (runAs) { @@ -362,10 +373,11 @@ public class LoggingAuditTrailTests extends ESTestCase { public void testAccessGrantedInternalSystemAction() throws Exception { for (Level level : Level.values()) { + threadContext = new ThreadContext(Settings.EMPTY); CapturingLogger logger = new CapturingLogger(level); - LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger).start(); - TransportMessage message = randomBoolean() ? new MockMessage() : new MockIndicesRequest(); - String origins = LoggingAuditTrail.originAttributes(message, transport); + LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger, threadContext).start(); + TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext); + String origins = LoggingAuditTrail.originAttributes(message, transport, threadContext); auditTrail.accessGranted(User.SYSTEM, "internal:_action", message); switch (level) { case ERROR: @@ -386,10 +398,11 @@ public class LoggingAuditTrailTests extends ESTestCase { public void testAccessGrantedInternalSystemActionNonSystemUser() throws Exception { for (Level level : Level.values()) { + threadContext = new ThreadContext(Settings.EMPTY); CapturingLogger logger = new CapturingLogger(level); - LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger).start(); - TransportMessage message = randomBoolean() ? new MockMessage() : new MockIndicesRequest(); - String origins = LoggingAuditTrail.originAttributes(message, transport); + LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger, threadContext).start(); + TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext); + String origins = LoggingAuditTrail.originAttributes(message, transport, threadContext); boolean runAs = randomBoolean(); User user; if (runAs) { @@ -425,10 +438,11 @@ public class LoggingAuditTrailTests extends ESTestCase { public void testAccessDenied() throws Exception { for (Level level : Level.values()) { + threadContext = new ThreadContext(Settings.EMPTY); CapturingLogger logger = new CapturingLogger(level); - LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger).start(); - TransportMessage message = randomBoolean() ? new MockMessage() : new MockIndicesRequest(); - String origins = LoggingAuditTrail.originAttributes(message, transport); + LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger, threadContext).start(); + TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext); + String origins = LoggingAuditTrail.originAttributes(message, transport, threadContext); boolean runAs = randomBoolean(); User user; if (runAs) { @@ -462,11 +476,12 @@ public class LoggingAuditTrailTests extends ESTestCase { public void testTamperedRequest() throws Exception { String action = "_action"; - TransportMessage message = randomBoolean() ? new MockMessage() : new MockIndicesRequest(); - String origins = LoggingAuditTrail.originAttributes(message, transport); for (Level level : Level.values()) { + threadContext = new ThreadContext(Settings.EMPTY); + TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext); + String origins = LoggingAuditTrail.originAttributes(message, transport, threadContext); CapturingLogger logger = new CapturingLogger(level); - LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger).start(); + LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger, threadContext).start(); auditTrail.tamperedRequest(action, message); switch (level) { case ERROR: @@ -491,8 +506,6 @@ public class LoggingAuditTrailTests extends ESTestCase { public void testTamperedRequestWithUser() throws Exception { String action = "_action"; - TransportMessage message = randomBoolean() ? new MockMessage() : new MockIndicesRequest(); - String origins = LoggingAuditTrail.originAttributes(message, transport); final boolean runAs = randomBoolean(); User user; if (runAs) { @@ -502,8 +515,11 @@ public class LoggingAuditTrailTests extends ESTestCase { } String userInfo = runAs ? "principal=[running as], run_by_principal=[_username]" : "principal=[_username]"; for (Level level : Level.values()) { + threadContext = new ThreadContext(Settings.EMPTY); + TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext); + String origins = LoggingAuditTrail.originAttributes(message, transport, threadContext); CapturingLogger logger = new CapturingLogger(level); - LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger).start(); + LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger, threadContext).start(); auditTrail.tamperedRequest(user, action, message); switch (level) { case ERROR: @@ -528,8 +544,9 @@ public class LoggingAuditTrailTests extends ESTestCase { public void testConnectionDenied() throws Exception { for (Level level : Level.values()) { + threadContext = new ThreadContext(Settings.EMPTY); CapturingLogger logger = new CapturingLogger(level); - LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger).start(); + LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger, threadContext).start(); InetAddress inetAddress = InetAddress.getLoopbackAddress(); ShieldIpFilterRule rule = new ShieldIpFilterRule(false, "_all"); auditTrail.connectionDenied(inetAddress, "default", rule); @@ -548,8 +565,9 @@ public class LoggingAuditTrailTests extends ESTestCase { public void testConnectionGranted() throws Exception { for (Level level : Level.values()) { + threadContext = new ThreadContext(Settings.EMPTY); CapturingLogger logger = new CapturingLogger(level); - LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger).start(); + LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger, threadContext).start(); InetAddress inetAddress = InetAddress.getLoopbackAddress(); ShieldIpFilterRule rule = IPFilter.DEFAULT_PROFILE_ACCEPT_ALL; auditTrail.connectionGranted(inetAddress, "default", rule); @@ -570,10 +588,11 @@ public class LoggingAuditTrailTests extends ESTestCase { public void testRunAsGranted() throws Exception { for (Level level : Level.values()) { + threadContext = new ThreadContext(Settings.EMPTY); CapturingLogger logger = new CapturingLogger(level); - LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger).start(); - TransportMessage message = new MockMessage(); - String origins = LoggingAuditTrail.originAttributes(message, transport); + LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger, threadContext).start(); + TransportMessage message = new MockMessage(threadContext); + String origins = LoggingAuditTrail.originAttributes(message, transport, threadContext); User user = new User("_username", new String[]{"r1"}, new User("running as", new String[] {"r2"})); auditTrail.runAsGranted(user, "_action", message); switch (level) { @@ -593,10 +612,11 @@ public class LoggingAuditTrailTests extends ESTestCase { public void testRunAsDenied() throws Exception { for (Level level : Level.values()) { + threadContext = new ThreadContext(Settings.EMPTY); CapturingLogger logger = new CapturingLogger(level); - LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger).start(); - TransportMessage message = new MockMessage(); - String origins = LoggingAuditTrail.originAttributes(message, transport); + LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger, threadContext).start(); + TransportMessage message = new MockMessage(threadContext); + String origins = LoggingAuditTrail.originAttributes(message, transport, threadContext); User user = new User("_username", new String[]{"r1"}, new User("running as", new String[] {"r2"})); auditTrail.runAsDenied(user, "_action", message); switch (level) { @@ -615,9 +635,10 @@ public class LoggingAuditTrailTests extends ESTestCase { } public void testOriginAttributes() throws Exception { - MockMessage message = new MockMessage(); - String text = LoggingAuditTrail.originAttributes(message, transport);; - InetSocketAddress restAddress = RemoteHostHeader.restRemoteAddress(message); + threadContext = new ThreadContext(Settings.EMPTY); + MockMessage message = new MockMessage(threadContext); + String text = LoggingAuditTrail.originAttributes(message, transport, threadContext);; + InetSocketAddress restAddress = RemoteHostHeader.restRemoteAddress(threadContext); if (restAddress != null) { assertThat(text, equalTo("origin_type=[rest], origin_address=[" + NetworkAddress.formatAddress(restAddress.getAddress()) + "]")); return; @@ -662,7 +683,7 @@ public class LoggingAuditTrailTests extends ESTestCase { private static class MockMessage extends TransportMessage { - private MockMessage() throws IOException { + private MockMessage(ThreadContext threadContext) throws IOException { if (randomBoolean()) { if (randomBoolean()) { remoteAddress(new LocalTransportAddress("local_host")); @@ -671,19 +692,19 @@ public class LoggingAuditTrailTests extends ESTestCase { } } if (randomBoolean()) { - RemoteHostHeader.putRestRemoteAddress(this, new InetSocketAddress(forge("localhost", "127.0.0.1"), 1234)); + RemoteHostHeader.putRestRemoteAddress(threadContext, new InetSocketAddress(forge("localhost", "127.0.0.1"), 1234)); } } } private static class MockIndicesRequest extends TransportMessage implements IndicesRequest { - private MockIndicesRequest() throws IOException { + private MockIndicesRequest(ThreadContext threadContext) throws IOException { if (randomBoolean()) { remoteAddress(new LocalTransportAddress("_host")); } if (randomBoolean()) { - RemoteHostHeader.putRestRemoteAddress(this, new InetSocketAddress(forge("localhost", "127.0.0.1"), 1234)); + RemoteHostHeader.putRestRemoteAddress(threadContext, new InetSocketAddress(forge("localhost", "127.0.0.1"), 1234)); } } diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/InternalAuthenticationServiceTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/InternalAuthenticationServiceTests.java index cb614b0119f..98d9e7aa55f 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/InternalAuthenticationServiceTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/InternalAuthenticationServiceTests.java @@ -10,6 +10,7 @@ import org.elasticsearch.ElasticsearchSecurityException; import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.env.Environment; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.shield.ShieldSettingsFilter; @@ -21,6 +22,7 @@ import org.elasticsearch.shield.crypto.CryptoService; import org.elasticsearch.shield.license.ShieldLicenseState; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.rest.FakeRestRequest; +import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportMessage; import org.junit.Before; import org.junit.Rule; @@ -68,6 +70,8 @@ public class InternalAuthenticationServiceTests extends ESTestCase { AuthenticationToken token; CryptoService cryptoService; AnonymousService anonymousService; + ThreadPool threadPool; + ThreadContext threadContext; @Before public void init() throws Exception { @@ -95,13 +99,16 @@ public class InternalAuthenticationServiceTests extends ESTestCase { auditTrail = mock(AuditTrail.class); anonymousService = mock(AnonymousService.class); - service = new InternalAuthenticationService(Settings.EMPTY, realms, auditTrail, cryptoService, anonymousService, new DefaultAuthenticationFailureHandler()); + threadPool = mock(ThreadPool.class); + threadContext = new ThreadContext(Settings.EMPTY); + when(threadPool.getThreadContext()).thenReturn(threadContext); + service = new InternalAuthenticationService(Settings.EMPTY, realms, auditTrail, cryptoService, anonymousService, new DefaultAuthenticationFailureHandler(), threadPool); } @SuppressWarnings("unchecked") public void testTokenFirstMissingSecondFound() throws Exception { - when(firstRealm.token(message)).thenReturn(null); - when(secondRealm.token(message)).thenReturn(token); + when(firstRealm.token(threadContext)).thenReturn(null); + when(secondRealm.token(threadContext)).thenReturn(token); AuthenticationToken result = service.token("_action", message); assertThat(result, notNullValue()); @@ -113,19 +120,19 @@ public class InternalAuthenticationServiceTests extends ESTestCase { AuthenticationToken token = service.token("_action", message); assertThat(token, nullValue()); verifyNoMoreInteractions(auditTrail); - assertThat(message.getContext().get(InternalAuthenticationService.TOKEN_KEY), nullValue()); + assertThat(threadContext.getTransient(InternalAuthenticationService.TOKEN_KEY), nullValue()); } public void testTokenCached() throws Exception { - message.putInContext(InternalAuthenticationService.TOKEN_KEY, token); + threadContext.putTransient(InternalAuthenticationService.TOKEN_KEY, token); AuthenticationToken result = service.token("_action", message); assertThat(result, notNullValue()); assertThat(result, is(token)); verifyZeroInteractions(auditTrail); verifyZeroInteractions(firstRealm); verifyZeroInteractions(secondRealm); - assertThat(message.getContext().get(InternalAuthenticationService.TOKEN_KEY), notNullValue()); - assertThat(message.getContext().get(InternalAuthenticationService.TOKEN_KEY), is((Object) token)); + assertThat(threadContext.getTransient(InternalAuthenticationService.TOKEN_KEY), notNullValue()); + assertThat(threadContext.getTransient(InternalAuthenticationService.TOKEN_KEY), is((Object) token)); } @SuppressWarnings("unchecked") @@ -145,9 +152,10 @@ public class InternalAuthenticationServiceTests extends ESTestCase { assertThat(result, notNullValue()); assertThat(result, is(user)); verify(auditTrail).authenticationFailed("esusers", token, "_action", message); - assertThat(message.getContext().get(InternalAuthenticationService.USER_KEY), notNullValue()); - assertThat(message.getContext().get(InternalAuthenticationService.USER_KEY), sameInstance((Object) user)); - assertThat(message.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_encoded_user")); + User user1 = threadContext.getTransient(InternalAuthenticationService.USER_KEY); + assertThat(user1, notNullValue()); + assertThat(user1, sameInstance(user)); + assertThat(threadContext.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_encoded_user")); } public void testAuthenticateFirstNotSupportingSecondSucceeds() throws Exception { @@ -166,14 +174,15 @@ public class InternalAuthenticationServiceTests extends ESTestCase { assertThat(result, is(user)); verifyZeroInteractions(auditTrail); verify(firstRealm, never()).authenticate(token); - assertThat(message.getContext().get(InternalAuthenticationService.USER_KEY), notNullValue()); - assertThat(message.getContext().get(InternalAuthenticationService.USER_KEY), is((Object) user)); - assertThat(message.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_encoded_user")); + User user1 = threadContext.getTransient(InternalAuthenticationService.USER_KEY); + assertThat(user1, notNullValue()); + assertThat(user1, is((Object) user)); + assertThat(threadContext.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_encoded_user")); } public void testAuthenticateCached() throws Exception { User user = new User("_username", "r1"); - message.putInContext(InternalAuthenticationService.USER_KEY, user); + threadContext.putTransient(InternalAuthenticationService.USER_KEY, user); User result = service.authenticate("_action", message, null); assertThat(result, notNullValue()); assertThat(result, is(user)); @@ -181,12 +190,13 @@ public class InternalAuthenticationServiceTests extends ESTestCase { verifyZeroInteractions(firstRealm); verifyZeroInteractions(secondRealm); verifyZeroInteractions(cryptoService); - assertThat(message.getContext().get(InternalAuthenticationService.USER_KEY), notNullValue()); - assertThat(message.getContext().get(InternalAuthenticationService.USER_KEY), is((Object) user)); + User user1 = threadContext.getTransient(InternalAuthenticationService.USER_KEY); + assertThat(user1, notNullValue()); + assertThat(user1, is(user)); } public void testAuthenticateNonExistentRestRequestUserThrowsAuthenticationException() throws Exception { - when(firstRealm.token(restRequest)).thenReturn(new UsernamePasswordToken("idonotexist", new SecuredString("passwd".toCharArray()))); + when(firstRealm.token(threadContext)).thenReturn(new UsernamePasswordToken("idonotexist", new SecuredString("passwd".toCharArray()))); try { service.authenticate(restRequest); fail("Authentication was successful but should not"); @@ -197,17 +207,17 @@ public class InternalAuthenticationServiceTests extends ESTestCase { public void testTokenRestExists() throws Exception { AuthenticationToken token = mock(AuthenticationToken.class); - when(firstRealm.token(restRequest)).thenReturn(null); - when(secondRealm.token(restRequest)).thenReturn(token); - AuthenticationToken foundToken = service.token(restRequest); + when(firstRealm.token(threadContext)).thenReturn(null); + when(secondRealm.token(threadContext)).thenReturn(token); + AuthenticationToken foundToken = service.token(); assertThat(foundToken, is(token)); - assertThat(restRequest.getFromContext(InternalAuthenticationService.TOKEN_KEY), equalTo((Object) token)); + assertThat(threadContext.getTransient(InternalAuthenticationService.TOKEN_KEY), equalTo((Object) token)); } public void testTokenRestMissing() throws Exception { - when(firstRealm.token(restRequest)).thenReturn(null); - when(secondRealm.token(restRequest)).thenReturn(null); - AuthenticationToken token = service.token(restRequest); + when(firstRealm.token(threadContext)).thenReturn(null); + when(secondRealm.token(threadContext)).thenReturn(null); + AuthenticationToken token = service.token(); assertThat(token, nullValue()); } @@ -224,7 +234,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase { public void testUserHeader() throws Exception { User user = new User("_username", "r1"); - when(firstRealm.token(message)).thenReturn(token); + when(firstRealm.token(threadContext)).thenReturn(token); when(firstRealm.supports(token)).thenReturn(true); when(firstRealm.authenticate(token)).thenReturn(user); when(cryptoService.sign(InternalAuthenticationService.encodeUser(user, null))).thenReturn("_signed_user"); @@ -233,14 +243,14 @@ public class InternalAuthenticationServiceTests extends ESTestCase { User result = service.authenticate("_action", message, null); assertThat(result, notNullValue()); assertThat(result, is(user)); - String userStr = (String) message.getHeader(InternalAuthenticationService.USER_KEY); + String userStr = threadContext.getHeader(InternalAuthenticationService.USER_KEY); assertThat(userStr, notNullValue()); assertThat(userStr, equalTo("_signed_user")); } public void testAuthenticateTransportAnonymous() throws Exception { - when(firstRealm.token(message)).thenReturn(null); - when(secondRealm.token(message)).thenReturn(null); + when(firstRealm.token(threadContext)).thenReturn(null); + when(secondRealm.token(threadContext)).thenReturn(null); try { service.authenticate("_action", message, null); fail("expected an authentication exception when trying to authenticate an anonymous message"); @@ -252,8 +262,8 @@ public class InternalAuthenticationServiceTests extends ESTestCase { } public void testAuthenticateRestAnonymous() throws Exception { - when(firstRealm.token(restRequest)).thenReturn(null); - when(secondRealm.token(restRequest)).thenReturn(null); + when(firstRealm.token(threadContext)).thenReturn(null); + when(secondRealm.token(threadContext)).thenReturn(null); try { service.authenticate(restRequest); fail("expected an authentication exception when trying to authenticate an anonymous message"); @@ -265,65 +275,74 @@ public class InternalAuthenticationServiceTests extends ESTestCase { } public void testAuthenticateTransportFallback() throws Exception { - when(firstRealm.token(message)).thenReturn(null); - when(secondRealm.token(message)).thenReturn(null); + when(firstRealm.token(threadContext)).thenReturn(null); + when(secondRealm.token(threadContext)).thenReturn(null); User user1 = new User("username", "r1", "r2"); when(cryptoService.sign(InternalAuthenticationService.encodeUser(user1, null))).thenReturn("_signed_user"); User user2 = service.authenticate("_action", message, user1); assertThat(user1, sameInstance(user2)); - assertThat(message.getFromContext(InternalAuthenticationService.USER_KEY), sameInstance((Object) user2)); - assertThat(message.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_signed_user")); + User user3 = threadContext.getTransient(InternalAuthenticationService.USER_KEY); + assertThat(user3, sameInstance(user2)); + assertThat(threadContext.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_signed_user")); } public void testAuthenticateTransportSuccessNoFallback() throws Exception { User user1 = new User("username", "r1", "r2"); - when(firstRealm.token(message)).thenReturn(token); + when(firstRealm.token(threadContext)).thenReturn(token); when(firstRealm.supports(token)).thenReturn(true); when(firstRealm.authenticate(token)).thenReturn(user1); when(cryptoService.sign(InternalAuthenticationService.encodeUser(user1, null))).thenReturn("_signed_user"); User user2 = service.authenticate("_action", message, null); assertThat(user1, sameInstance(user2)); - assertThat(message.getFromContext(InternalAuthenticationService.USER_KEY), sameInstance((Object) user2)); - assertThat(message.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_signed_user")); + User user3 = threadContext.getTransient(InternalAuthenticationService.USER_KEY); + assertThat(user3, sameInstance(user2)); + assertThat(threadContext.getHeader(InternalAuthenticationService.USER_KEY), equalTo("_signed_user")); } public void testAuthenticateTransportSuccessWithFallback() throws Exception { User user1 = new User("username", "r1", "r2"); - when(firstRealm.token(message)).thenReturn(token); + when(firstRealm.token(threadContext)).thenReturn(token); when(firstRealm.supports(token)).thenReturn(true); when(firstRealm.authenticate(token)).thenReturn(user1); when(cryptoService.sign(InternalAuthenticationService.encodeUser(user1, null))).thenReturn("_signed_user"); User user2 = service.authenticate("_action", message, User.SYSTEM); assertThat(user1, sameInstance(user2)); - assertThat(message.getFromContext(InternalAuthenticationService.USER_KEY), sameInstance((Object) user2)); - assertThat(message.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_signed_user")); + User user3 = threadContext.getTransient(InternalAuthenticationService.USER_KEY); + assertThat(user3, sameInstance((Object) user2)); + assertThat(threadContext.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_signed_user")); } public void testAuthenticateRestSuccess() throws Exception { User user1 = new User("username", "r1", "r2"); - when(firstRealm.token(restRequest)).thenReturn(token); + when(firstRealm.token(threadContext)).thenReturn(token); when(firstRealm.supports(token)).thenReturn(true); when(firstRealm.authenticate(token)).thenReturn(user1); User user2 = service.authenticate(restRequest); assertThat(user1, sameInstance(user2)); - assertThat(restRequest.getFromContext(InternalAuthenticationService.USER_KEY), sameInstance((Object) user2)); + User user3 = threadContext.getTransient(InternalAuthenticationService.USER_KEY); + assertThat(user3, sameInstance(user2)); } public void testAutheticateTransportContextAndHeader() throws Exception { User user1 = new User("username", "r1", "r2"); - when(firstRealm.token(message)).thenReturn(token); + when(firstRealm.token(threadContext)).thenReturn(token); when(firstRealm.supports(token)).thenReturn(true); when(firstRealm.authenticate(token)).thenReturn(user1); when(cryptoService.sign(InternalAuthenticationService.encodeUser(user1, null))).thenReturn("_signed_user"); User user2 = service.authenticate("_action", message, User.SYSTEM); assertThat(user1, sameInstance(user2)); - assertThat(message.getFromContext(InternalAuthenticationService.USER_KEY), sameInstance((Object) user2)); - assertThat(message.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_signed_user")); + User user3 = threadContext.getTransient(InternalAuthenticationService.USER_KEY); + assertThat(user3, sameInstance(user2)); + assertThat(threadContext.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_signed_user")); reset(firstRealm); // checking authentication from the context InternalMessage message1 = new InternalMessage(); - message1.copyContextFrom(message); + ThreadContext threadContext1 = new ThreadContext(Settings.EMPTY); + when(threadPool.getThreadContext()).thenReturn(threadContext1); + service = new InternalAuthenticationService(Settings.EMPTY, realms, auditTrail, cryptoService, anonymousService, new DefaultAuthenticationFailureHandler(), threadPool); + + threadContext1.putTransient(InternalAuthenticationService.USER_KEY, threadContext.getTransient(InternalAuthenticationService.USER_KEY)); User user = service.authenticate("_action", message1, User.SYSTEM); assertThat(user, sameInstance(user1)); verifyZeroInteractions(firstRealm); @@ -331,35 +350,46 @@ public class InternalAuthenticationServiceTests extends ESTestCase { // checking authentication from the user header - message1.putHeader(InternalAuthenticationService.USER_KEY, message.getHeader(InternalAuthenticationService.USER_KEY)); + threadContext1 = new ThreadContext(Settings.EMPTY); + when(threadPool.getThreadContext()).thenReturn(threadContext1); + service = new InternalAuthenticationService(Settings.EMPTY, realms, auditTrail, cryptoService, anonymousService, new DefaultAuthenticationFailureHandler(), threadPool); + threadContext1.putHeader(InternalAuthenticationService.USER_KEY, threadContext.getHeader(InternalAuthenticationService.USER_KEY)); when(cryptoService.unsignAndVerify("_signed_user")).thenReturn(InternalAuthenticationService.encodeUser(user1, null)); + BytesStreamOutput output = new BytesStreamOutput(); - message1.writeTo(output); + threadContext1.writeTo(output); StreamInput input = StreamInput.wrap(output.bytes()); - InternalMessage message2 = new InternalMessage(); - message2.readFrom(input); - user = service.authenticate("_action", message2, User.SYSTEM); + threadContext1 = new ThreadContext(Settings.EMPTY); + threadContext1.readHeaders(input); + + when(threadPool.getThreadContext()).thenReturn(threadContext1); + service = new InternalAuthenticationService(Settings.EMPTY, realms, auditTrail, cryptoService, anonymousService, new DefaultAuthenticationFailureHandler(), threadPool); + user = service.authenticate("_action", new InternalMessage(), User.SYSTEM); assertThat(user, equalTo(user1)); verifyZeroInteractions(firstRealm); } public void testAutheticateTransportContextAndHeaderNoSigning() throws Exception { Settings settings = Settings.builder().put(InternalAuthenticationService.SETTING_SIGN_USER_HEADER, false).build(); - service = new InternalAuthenticationService(settings, realms, auditTrail, cryptoService, anonymousService, new DefaultAuthenticationFailureHandler()); + service = new InternalAuthenticationService(settings, realms, auditTrail, cryptoService, anonymousService, new DefaultAuthenticationFailureHandler(), threadPool); User user1 = new User("username", "r1", "r2"); when(firstRealm.supports(token)).thenReturn(true); - when(firstRealm.token(message)).thenReturn(token); + when(firstRealm.token(threadContext)).thenReturn(token); when(firstRealm.authenticate(token)).thenReturn(user1); User user2 = service.authenticate("_action", message, User.SYSTEM); assertThat(user1, sameInstance(user2)); - assertThat(message.getFromContext(InternalAuthenticationService.USER_KEY), sameInstance((Object) user2)); - assertThat(message.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) InternalAuthenticationService.encodeUser(user1, null))); + User user3 = threadContext.getTransient(InternalAuthenticationService.USER_KEY); + assertThat(user3, sameInstance(user2)); + assertThat(threadContext.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) InternalAuthenticationService.encodeUser(user1, null))); reset(firstRealm); // checking authentication from the context InternalMessage message1 = new InternalMessage(); - message1.copyContextFrom(message); + ThreadContext threadContext1 = new ThreadContext(Settings.EMPTY); + when(threadPool.getThreadContext()).thenReturn(threadContext1); + service = new InternalAuthenticationService(Settings.EMPTY, realms, auditTrail, cryptoService, anonymousService, new DefaultAuthenticationFailureHandler(), threadPool); + threadContext1.putTransient(InternalAuthenticationService.USER_KEY, threadContext.getTransient(InternalAuthenticationService.USER_KEY)); User user = service.authenticate("_action", message1, User.SYSTEM); assertThat(user, sameInstance(user1)); verifyZeroInteractions(firstRealm); @@ -367,13 +397,18 @@ public class InternalAuthenticationServiceTests extends ESTestCase { // checking authentication from the user header - message1.putHeader(InternalAuthenticationService.USER_KEY, message.getHeader(InternalAuthenticationService.USER_KEY)); + threadContext1 = new ThreadContext(Settings.EMPTY); + threadContext1.putHeader(InternalAuthenticationService.USER_KEY, threadContext.getHeader(InternalAuthenticationService.USER_KEY)); + BytesStreamOutput output = new BytesStreamOutput(); - message1.writeTo(output); + threadContext1.writeTo(output); StreamInput input = StreamInput.wrap(output.bytes()); - InternalMessage message2 = new InternalMessage(); - message2.readFrom(input); - user = service.authenticate("_action", message2, User.SYSTEM); + threadContext1 = new ThreadContext(Settings.EMPTY); + threadContext1.readHeaders(input); + + when(threadPool.getThreadContext()).thenReturn(threadContext1); + service = new InternalAuthenticationService(settings, realms, auditTrail, cryptoService, anonymousService, new DefaultAuthenticationFailureHandler(), threadPool); + user = service.authenticate("_action", new InternalMessage(), User.SYSTEM); assertThat(user, equalTo(user1)); verifyZeroInteractions(firstRealm); @@ -382,7 +417,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase { public void testAuthenticateTamperedUser() throws Exception { InternalMessage message = new InternalMessage(); - message.putHeader(InternalAuthenticationService.USER_KEY, "_signed_user"); + threadContext.putHeader(InternalAuthenticationService.USER_KEY, "_signed_user"); when(cryptoService.unsignAndVerify("_signed_user")).thenThrow(randomFrom(new RuntimeException(), new IllegalArgumentException(), new IllegalStateException())); try { @@ -394,32 +429,30 @@ public class InternalAuthenticationServiceTests extends ESTestCase { } } - public void testAttachIfMissingMissing() throws Exception { - User user = new User("username", "r1", "r2"); - assertThat(message.getFromContext(InternalAuthenticationService.USER_KEY), nullValue()); - assertThat(message.getHeader(InternalAuthenticationService.USER_KEY), nullValue()); + public void testAttachIfMissing() throws Exception { + User user; + if (randomBoolean()) { + user = User.SYSTEM; + } else { + user = new User("username", "r1", "r2"); + } + assertThat(threadContext.getTransient(InternalAuthenticationService.USER_KEY), nullValue()); + assertThat(threadContext.getHeader(InternalAuthenticationService.USER_KEY), nullValue()); when(cryptoService.sign(InternalAuthenticationService.encodeUser(user, null))).thenReturn("_signed_user"); - service.attachUserHeaderIfMissing(message, user); - assertThat(message.getFromContext(InternalAuthenticationService.USER_KEY), sameInstance((Object) user)); - assertThat(message.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_signed_user")); - - user = User.SYSTEM; - message = new InternalMessage(); - assertThat(message.getFromContext(InternalAuthenticationService.USER_KEY), nullValue()); - assertThat(message.getHeader(InternalAuthenticationService.USER_KEY), nullValue()); - when(cryptoService.sign(InternalAuthenticationService.encodeUser(user, null))).thenReturn("_signed_user"); - service.attachUserHeaderIfMissing(message, user); - assertThat(message.getFromContext(InternalAuthenticationService.USER_KEY), sameInstance((Object) user)); - assertThat(message.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_signed_user")); + service.attachUserHeaderIfMissing(user); + User user1 = threadContext.getTransient(InternalAuthenticationService.USER_KEY); + assertThat(user1, sameInstance((Object) user)); + assertThat(threadContext.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_signed_user")); } public void testAttachIfMissingExists() throws Exception { User user = new User("username", "r1", "r2"); - message.putInContext(InternalAuthenticationService.USER_KEY, user); - message.putHeader(InternalAuthenticationService.USER_KEY, "_signed_user"); - service.attachUserHeaderIfMissing(message, new User("username2", "r3", "r4")); - assertThat(message.getFromContext(InternalAuthenticationService.USER_KEY), sameInstance((Object) user)); - assertThat(message.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_signed_user")); + threadContext.putTransient(InternalAuthenticationService.USER_KEY, user); + threadContext.putHeader(InternalAuthenticationService.USER_KEY, "_signed_user"); + service.attachUserHeaderIfMissing(new User("username2", "r3", "r4")); + User user1 = threadContext.getTransient(InternalAuthenticationService.USER_KEY); + assertThat(user1, sameInstance(user)); + assertThat(threadContext.getHeader(InternalAuthenticationService.USER_KEY), equalTo("_signed_user")); } public void testAnonymousUserRest() throws Exception { @@ -431,13 +464,14 @@ public class InternalAuthenticationServiceTests extends ESTestCase { } Settings settings = builder.build(); AnonymousService holder = new AnonymousService(settings); - service = new InternalAuthenticationService(settings, realms, auditTrail, cryptoService, holder, new DefaultAuthenticationFailureHandler()); + service = new InternalAuthenticationService(settings, realms, auditTrail, cryptoService, holder, new DefaultAuthenticationFailureHandler(), threadPool); RestRequest request = new FakeRestRequest(); User user = service.authenticate(request); - assertThat(request.getFromContext(InternalAuthenticationService.USER_KEY), notNullValue()); - assertThat(request.getFromContext(InternalAuthenticationService.USER_KEY), sameInstance((Object) user)); + User user1 = threadContext.getTransient(InternalAuthenticationService.USER_KEY); + assertThat(user1, notNullValue()); + assertThat(user1, sameInstance((Object) user)); assertThat(user, notNullValue()); assertThat(user.principal(), equalTo(username)); assertThat(user.roles(), arrayContainingInAnyOrder("r1", "r2", "r3")); @@ -447,7 +481,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase { Settings settings = Settings.builder() .putArray("shield.authc.anonymous.roles", "r1", "r2", "r3") .build(); - service = new InternalAuthenticationService(settings, realms, auditTrail, cryptoService, new AnonymousService(settings), new DefaultAuthenticationFailureHandler()); + service = new InternalAuthenticationService(settings, realms, auditTrail, cryptoService, new AnonymousService(settings), new DefaultAuthenticationFailureHandler(), threadPool); InternalMessage message = new InternalMessage(); @@ -461,7 +495,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase { Settings settings = Settings.builder() .putArray("shield.authc.anonymous.roles", "r1", "r2", "r3") .build(); - service = new InternalAuthenticationService(settings, realms, auditTrail, cryptoService, new AnonymousService(settings), new DefaultAuthenticationFailureHandler()); + service = new InternalAuthenticationService(settings, realms, auditTrail, cryptoService, new AnonymousService(settings), new DefaultAuthenticationFailureHandler(), threadPool); InternalMessage message = new InternalMessage(); @@ -471,7 +505,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase { } public void testRealmTokenThrowingException() throws Exception { - when(firstRealm.token(message)).thenThrow(authenticationError("realm doesn't like tokens")); + when(firstRealm.token(threadContext)).thenThrow(authenticationError("realm doesn't like tokens")); try { service.authenticate("_action", message, null); fail("exception should bubble out"); @@ -482,7 +516,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase { } public void testRealmTokenThrowingExceptionRest() throws Exception { - when(firstRealm.token(restRequest)).thenThrow(authenticationError("realm doesn't like tokens")); + when(firstRealm.token(threadContext)).thenThrow(authenticationError("realm doesn't like tokens")); try { service.authenticate(restRequest); fail("exception should bubble out"); @@ -494,7 +528,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase { public void testRealmSupportsMethodThrowingException() throws Exception { AuthenticationToken token = mock(AuthenticationToken.class); - when(secondRealm.token(message)).thenReturn(token); + when(secondRealm.token(threadContext)).thenReturn(token); when(secondRealm.supports(token)).thenThrow(authenticationError("realm doesn't like supports")); try { service.authenticate("_action", message, null); @@ -507,7 +541,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase { public void testRealmSupportsMethodThrowingExceptionRest() throws Exception { AuthenticationToken token = mock(AuthenticationToken.class); - when(secondRealm.token(restRequest)).thenReturn(token); + when(secondRealm.token(threadContext)).thenReturn(token); when(secondRealm.supports(token)).thenThrow(authenticationError("realm doesn't like supports")); try { service.authenticate(restRequest); @@ -520,7 +554,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase { public void testRealmAuthenticateThrowingException() throws Exception { AuthenticationToken token = mock(AuthenticationToken.class); - when(secondRealm.token(message)).thenReturn(token); + when(secondRealm.token(threadContext)).thenReturn(token); when(secondRealm.supports(token)).thenReturn(true); when(secondRealm.authenticate(token)).thenThrow(authenticationError("realm doesn't like authenticate")); try { @@ -534,7 +568,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase { public void testRealmAuthenticateThrowingExceptionRest() throws Exception { AuthenticationToken token = mock(AuthenticationToken.class); - when(secondRealm.token(restRequest)).thenReturn(token); + when(secondRealm.token(threadContext)).thenReturn(token); when(secondRealm.supports(token)).thenReturn(true); when(secondRealm.authenticate(token)).thenThrow(authenticationError("realm doesn't like authenticate")); try { @@ -548,8 +582,8 @@ public class InternalAuthenticationServiceTests extends ESTestCase { public void testRealmLookupThrowingException() throws Exception { AuthenticationToken token = mock(AuthenticationToken.class); - message.putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, "run_as"); - when(secondRealm.token(message)).thenReturn(token); + threadContext.putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, "run_as"); + when(secondRealm.token(threadContext)).thenReturn(token); when(secondRealm.supports(token)).thenReturn(true); when(secondRealm.authenticate(token)).thenReturn(new User("lookup user", new String[]{"user"})); when(secondRealm.lookupUser("run_as")).thenThrow(authenticationError("realm doesn't want to lookup")); @@ -566,8 +600,8 @@ public class InternalAuthenticationServiceTests extends ESTestCase { public void testRealmLookupThrowingExceptionRest() throws Exception { AuthenticationToken token = mock(AuthenticationToken.class); - restRequest = new FakeRestRequest(Collections.singletonMap(InternalAuthenticationService.RUN_AS_USER_HEADER, "run_as"), Collections.emptyMap()); - when(secondRealm.token(restRequest)).thenReturn(token); + restRequest = new FakeRestRequest(Collections.singletonMap(InternalAuthenticationService.RUN_AS_USER_HEADER, "run_as")); + when(secondRealm.token(threadContext)).thenReturn(token); when(secondRealm.supports(token)).thenReturn(true); when(secondRealm.authenticate(token)).thenReturn(new User("lookup user", new String[]{"user"})); when(secondRealm.lookupUser("run_as")).thenThrow(authenticationError("realm doesn't want to lookup")); @@ -584,8 +618,8 @@ public class InternalAuthenticationServiceTests extends ESTestCase { public void testRunAsLookupSameRealm() throws Exception { AuthenticationToken token = mock(AuthenticationToken.class); - message.putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, "run_as"); - when(secondRealm.token(message)).thenReturn(token); + threadContext.putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, "run_as"); + when(secondRealm.token(threadContext)).thenReturn(token); when(secondRealm.supports(token)).thenReturn(true); when(secondRealm.authenticate(token)).thenReturn(new User("lookup user", new String[]{"user"})); when(secondRealm.lookupUser("run_as")).thenReturn(new User("looked up user", new String[]{"some role"})); @@ -599,13 +633,14 @@ public class InternalAuthenticationServiceTests extends ESTestCase { assertThat(authenticated.roles(), arrayContaining("user")); assertThat(authenticated.runAs().principal(), is("looked up user")); assertThat(authenticated.runAs().roles(), arrayContaining("some role")); - assertThat(message.getContext().get(InternalAuthenticationService.USER_KEY), sameInstance((Object) authenticated)); + User user1 = threadContext.getTransient(InternalAuthenticationService.USER_KEY); + assertThat(user1, sameInstance(authenticated)); } public void testRunAsLookupSameRealmRest() throws Exception { AuthenticationToken token = mock(AuthenticationToken.class); - restRequest = new FakeRestRequest(Collections.singletonMap(InternalAuthenticationService.RUN_AS_USER_HEADER, "run_as"), Collections.emptyMap()); - when(secondRealm.token(restRequest)).thenReturn(token); + restRequest = new FakeRestRequest(Collections.singletonMap(InternalAuthenticationService.RUN_AS_USER_HEADER, "run_as")); + when(secondRealm.token(threadContext)).thenReturn(token); when(secondRealm.supports(token)).thenReturn(true); when(secondRealm.authenticate(token)).thenReturn(new User("lookup user", new String[]{"user"})); when(secondRealm.lookupUser("run_as")).thenReturn(new User("looked up user", new String[]{"some role"})); @@ -619,13 +654,14 @@ public class InternalAuthenticationServiceTests extends ESTestCase { assertThat(authenticated.roles(), arrayContaining("user")); assertThat(authenticated.runAs().principal(), is("looked up user")); assertThat(authenticated.runAs().roles(), arrayContaining("some role")); - assertThat(restRequest.getContext().get(InternalAuthenticationService.USER_KEY), sameInstance((Object) authenticated)); + User user1 = threadContext.getTransient(InternalAuthenticationService.USER_KEY); + assertThat(user1, sameInstance(authenticated)); } public void testRunAsLookupDifferentRealm() throws Exception { AuthenticationToken token = mock(AuthenticationToken.class); - message.putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, "run_as"); - when(secondRealm.token(message)).thenReturn(token); + threadContext.putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, "run_as"); + when(secondRealm.token(threadContext)).thenReturn(token); when(secondRealm.supports(token)).thenReturn(true); when(secondRealm.authenticate(token)).thenReturn(new User("lookup user", new String[]{"user"})); when(firstRealm.userLookupSupported()).thenReturn(true); @@ -640,13 +676,14 @@ public class InternalAuthenticationServiceTests extends ESTestCase { assertThat(authenticated.roles(), arrayContaining("user")); assertThat(authenticated.runAs().principal(), is("looked up user")); assertThat(authenticated.runAs().roles(), arrayContaining("some role")); - assertThat(message.getContext().get(InternalAuthenticationService.USER_KEY), sameInstance((Object) authenticated)); + User user1 = threadContext.getTransient(InternalAuthenticationService.USER_KEY); + assertThat(user1, sameInstance(authenticated)); } public void testRunAsLookupDifferentRealmRest() throws Exception { AuthenticationToken token = mock(AuthenticationToken.class); - restRequest = new FakeRestRequest(Collections.singletonMap(InternalAuthenticationService.RUN_AS_USER_HEADER, "run_as"), Collections.emptyMap()); - when(secondRealm.token(restRequest)).thenReturn(token); + restRequest = new FakeRestRequest(Collections.singletonMap(InternalAuthenticationService.RUN_AS_USER_HEADER, "run_as")); + when(secondRealm.token(threadContext)).thenReturn(token); when(secondRealm.supports(token)).thenReturn(true); when(secondRealm.authenticate(token)).thenReturn(new User("lookup user", new String[]{"user"})); when(firstRealm.lookupUser("run_as")).thenReturn(new User("looked up user", new String[]{"some role"})); @@ -660,13 +697,14 @@ public class InternalAuthenticationServiceTests extends ESTestCase { assertThat(authenticated.roles(), arrayContaining("user")); assertThat(authenticated.runAs().principal(), is("looked up user")); assertThat(authenticated.runAs().roles(), arrayContaining("some role")); - assertThat(restRequest.getContext().get(InternalAuthenticationService.USER_KEY), sameInstance((Object) authenticated)); + User user1 = threadContext.getTransient(InternalAuthenticationService.USER_KEY); + assertThat(user1, sameInstance(authenticated)); } public void testRunAsWithEmptyRunAsUsernameRest() throws Exception { AuthenticationToken token = mock(AuthenticationToken.class); - restRequest = new FakeRestRequest(Collections.singletonMap(InternalAuthenticationService.RUN_AS_USER_HEADER, ""), Collections.emptyMap()); - when(secondRealm.token(restRequest)).thenReturn(token); + restRequest = new FakeRestRequest(Collections.singletonMap(InternalAuthenticationService.RUN_AS_USER_HEADER, "")); + when(secondRealm.token(threadContext)).thenReturn(token); when(secondRealm.supports(token)).thenReturn(true); when(secondRealm.authenticate(token)).thenReturn(new User("lookup user", new String[]{"user"})); when(secondRealm.userLookupSupported()).thenReturn(true); @@ -682,8 +720,8 @@ public class InternalAuthenticationServiceTests extends ESTestCase { public void testRunAsWithEmptyRunAsUsername() throws Exception { AuthenticationToken token = mock(AuthenticationToken.class); - message.putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, ""); - when(secondRealm.token(message)).thenReturn(token); + threadContext.putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, ""); + when(secondRealm.token(threadContext)).thenReturn(token); when(secondRealm.supports(token)).thenReturn(true); when(secondRealm.authenticate(token)).thenReturn(new User("lookup user", new String[]{"user"})); when(secondRealm.userLookupSupported()).thenReturn(true); diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/RealmsTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/RealmsTests.java index cdf4dfe6c7b..f9c63dd6715 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/RealmsTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/RealmsTests.java @@ -6,15 +6,14 @@ package org.elasticsearch.shield.authc; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.env.Environment; -import org.elasticsearch.rest.RestRequest; import org.elasticsearch.shield.ShieldSettingsFilter; import org.elasticsearch.shield.User; import org.elasticsearch.shield.authc.esusers.ESUsersRealm; import org.elasticsearch.shield.authc.ldap.LdapRealm; import org.elasticsearch.shield.license.ShieldLicenseState; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.transport.TransportMessage; import org.junit.Before; import java.util.ArrayList; @@ -236,12 +235,7 @@ public class RealmsTests extends ESTestCase { } @Override - public AuthenticationToken token(RestRequest request) { - return null; - } - - @Override - public AuthenticationToken token(TransportMessage message) { + public AuthenticationToken token(ThreadContext threadContext) { return null; } diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/RunAsIntegTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/RunAsIntegTests.java index 3e618da0099..81b92acb879 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/RunAsIntegTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/RunAsIntegTests.java @@ -22,6 +22,10 @@ import org.elasticsearch.test.ShieldSettingsSource; import org.elasticsearch.test.rest.client.http.HttpResponse; import org.elasticsearch.xpack.XPackPlugin; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; @@ -86,17 +90,19 @@ public class RunAsIntegTests extends ShieldIntegTestCase { // let's run as without authorization try { - client.admin().cluster().prepareHealth().putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, ShieldSettingsSource.DEFAULT_USER_NAME).get(); + client.filterWithHeader(Collections.singletonMap(InternalAuthenticationService.RUN_AS_USER_HEADER, ShieldSettingsSource.DEFAULT_USER_NAME)) + .admin().cluster().prepareHealth().get(); fail("run as should be unauthorized for the transport client user"); } catch (ElasticsearchSecurityException e) { assertThat(e.getMessage(), containsString("unauthorized")); assertThat(e.getMessage(), containsString("run as")); } + Map headers = new HashMap<>(); + headers.put("Authorization", UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER, new SecuredString(ShieldSettingsSource.DEFAULT_PASSWORD.toCharArray()))); + headers.put(InternalAuthenticationService.RUN_AS_USER_HEADER, ShieldSettingsSource.DEFAULT_USER_NAME); // lets set the user - ClusterHealthResponse response = client.admin().cluster().prepareHealth() - .putHeader("Authorization", UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER, new SecuredString(ShieldSettingsSource.DEFAULT_PASSWORD.toCharArray()))) - .putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, ShieldSettingsSource.DEFAULT_USER_NAME).get(); + ClusterHealthResponse response = client.filterWithHeader(headers).admin().cluster().prepareHealth().get(); assertThat(response.isTimedOut(), is(false)); } } @@ -134,9 +140,11 @@ public class RunAsIntegTests extends ShieldIntegTestCase { }); try { - client.admin().cluster().prepareHealth() - .putHeader("Authorization", UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER, new SecuredString(ShieldSettingsSource.DEFAULT_PASSWORD.toCharArray()))) - .putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, "").get(); + Map headers = new HashMap<>(); + headers.put("Authorization", UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER, new SecuredString(ShieldSettingsSource.DEFAULT_PASSWORD.toCharArray()))); + headers.put(InternalAuthenticationService.RUN_AS_USER_HEADER, ""); + + client.filterWithHeader(headers).admin().cluster().prepareHealth().get(); fail("run as header should not be allowed to be empty"); } catch (ElasticsearchSecurityException e) { assertThat(e.getMessage(), containsString("unable to authenticate")); @@ -161,9 +169,11 @@ public class RunAsIntegTests extends ShieldIntegTestCase { }); try { - client.admin().cluster().prepareHealth() - .putHeader("Authorization", UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER, new SecuredString(ShieldSettingsSource.DEFAULT_PASSWORD.toCharArray()))) - .putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, "idontexist").get(); + Map headers = new HashMap<>(); + headers.put("Authorization", UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER, new SecuredString(ShieldSettingsSource.DEFAULT_PASSWORD.toCharArray()))); + headers.put(InternalAuthenticationService.RUN_AS_USER_HEADER, "idontexist"); + + client.filterWithHeader(headers).admin().cluster().prepareHealth().get(); fail("run as header should not accept non-existent users"); } catch (ElasticsearchSecurityException e) { assertThat(e.getMessage(), containsString("unauthorized")); diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/esusers/ESUsersRealmTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/esusers/ESUsersRealmTests.java index 50481a15240..63971d2b6a4 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/esusers/ESUsersRealmTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/esusers/ESUsersRealmTests.java @@ -13,8 +13,8 @@ import org.elasticsearch.client.AdminClient; import org.elasticsearch.client.Client; import org.elasticsearch.client.ClusterAdminClient; import org.elasticsearch.client.IndicesAdminClient; -import org.elasticsearch.client.support.Headers; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.RestChannel; import org.elasticsearch.rest.RestController; @@ -118,10 +118,10 @@ public class ESUsersRealmTests extends ESTestCase { when(userRolesStore.roles("user1")).thenReturn(new String[]{"role1", "role2"}); ESUsersRealm realm = new ESUsersRealm(config, userPasswdStore, userRolesStore); - TransportRequest request = new TransportRequest() {}; - UsernamePasswordToken.putTokenHeader(request, new UsernamePasswordToken("user1", SecuredStringTests.build("test123"))); + ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + UsernamePasswordToken.putTokenHeader(threadContext, new UsernamePasswordToken("user1", SecuredStringTests.build("test123"))); - UsernamePasswordToken token = realm.token(request); + UsernamePasswordToken token = realm.token(threadContext); assertThat(token, notNullValue()); assertThat(token.principal(), equalTo("user1")); assertThat(token.credentials(), notNullValue()); @@ -178,39 +178,6 @@ public class ESUsersRealmTests extends ESTestCase { assertThat(user5, sameInstance(user6)); } - @SuppressWarnings("unchecked") - public void testAuthorizationHeaderIsNotCopied() throws Exception { - RestController restController = mock(RestController.class); - RealmConfig config = new RealmConfig("esusers-test", Settings.EMPTY, globalSettings); - new ESUsersRealm(config, new UserPasswdStore(config), new UserRolesStore(config)); - when(restController.relevantHeaders()).thenReturn(emptySet()); - when(client.admin()).thenReturn(adminClient); - when(client.settings()).thenReturn(Settings.EMPTY); - when(client.headers()).thenReturn(Headers.EMPTY); - when(adminClient.cluster()).thenReturn(mock(ClusterAdminClient.class)); - when(adminClient.indices()).thenReturn(mock(IndicesAdminClient.class)); - final ActionRequest request = new ActionRequest() { - @Override - public ActionRequestValidationException validate() { - return null; - } - }; - RestRequest restRequest = mock(RestRequest.class); - final Action action = mock(Action.class); - final ActionListener listener = mock(ActionListener.class); - BaseRestHandler handler = new BaseRestHandler(Settings.EMPTY, restController, client) { - @Override - protected void handleRequest(RestRequest restRequest, RestChannel channel, Client client) throws Exception { - client.execute(action, request, listener); - } - }; - - when(restRequest.header(UsernamePasswordToken.BASIC_AUTH_HEADER)).thenReturn("foobar"); - RestChannel channel = mock(RestChannel.class); - handler.handleRequest(restRequest, channel); - assertThat(request.getHeader(UsernamePasswordToken.BASIC_AUTH_HEADER), is(nullValue())); - } - static class UserPasswdStore extends FileUserPasswdStore { public UserPasswdStore(RealmConfig config) { super(config, mock(ResourceWatcherService.class)); diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/pki/PkiRealmTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/pki/PkiRealmTests.java index b2bb67571a6..778800b5d42 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/pki/PkiRealmTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/pki/PkiRealmTests.java @@ -6,7 +6,7 @@ package org.elasticsearch.shield.authc.pki; import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.shield.User; import org.elasticsearch.shield.authc.RealmConfig; import org.elasticsearch.shield.authc.support.DnRoleMapper; @@ -14,7 +14,6 @@ import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.shield.authc.support.UsernamePasswordToken; import org.elasticsearch.shield.support.NoOpLogger; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.test.rest.FakeRestRequest; import org.elasticsearch.transport.TransportMessage; import org.junit.Before; @@ -53,25 +52,13 @@ public class PkiRealmTests extends ESTestCase { assertThat(realm.supports(new X509AuthenticationToken(new X509Certificate[0], "", "")), is(true)); } - public void testExtractTokenFromRestRequest() throws Exception { + public void testExtractToken() throws Exception { X509Certificate certificate = readCert(getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.cert")); - RestRequest restRequest = new FakeRestRequest(); - restRequest.putInContext(PkiRealm.PKI_CERT_HEADER_NAME, new X509Certificate[] { certificate }); + ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + threadContext.putTransient(PkiRealm.PKI_CERT_HEADER_NAME, new X509Certificate[] { certificate }); PkiRealm realm = new PkiRealm(new RealmConfig("", Settings.EMPTY, globalSettings), mock(DnRoleMapper.class)); - X509AuthenticationToken token = realm.token(restRequest); - assertThat(token, is(notNullValue())); - assertThat(token.dn(), is("CN=Elasticsearch Test Node, OU=elasticsearch, O=org")); - assertThat(token.principal(), is("Elasticsearch Test Node")); - } - - public void testExtractTokenFromTransportMessage() throws Exception { - X509Certificate certificate = readCert(getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.cert")); - Message message = new Message(); - message.putInContext(PkiRealm.PKI_CERT_HEADER_NAME, new X509Certificate[]{certificate}); - PkiRealm realm = new PkiRealm(new RealmConfig("", Settings.EMPTY, globalSettings), mock(DnRoleMapper.class)); - - X509AuthenticationToken token = realm.token(message); + X509AuthenticationToken token = realm.token(threadContext); assertThat(token, is(notNullValue())); assertThat(token.dn(), is("CN=Elasticsearch Test Node, OU=elasticsearch, O=org")); assertThat(token.principal(), is("Elasticsearch Test Node")); @@ -96,10 +83,10 @@ public class PkiRealmTests extends ESTestCase { DnRoleMapper roleMapper = mock(DnRoleMapper.class); PkiRealm realm = new PkiRealm(new RealmConfig("", Settings.builder().put("username_pattern", "OU=(.*?),").build(), globalSettings), roleMapper); when(roleMapper.resolveRoles(anyString(), anyList())).thenReturn(Collections.emptySet()); - FakeRestRequest restRequest = new FakeRestRequest(); - restRequest.putInContext(PkiRealm.PKI_CERT_HEADER_NAME, new X509Certificate[] { certificate }); + ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + threadContext.putTransient(PkiRealm.PKI_CERT_HEADER_NAME, new X509Certificate[] { certificate }); - X509AuthenticationToken token = realm.token(restRequest); + X509AuthenticationToken token = realm.token(threadContext); User user = realm.authenticate(token); assertThat(user, is(notNullValue())); assertThat(user.principal(), is("elasticsearch")); @@ -117,10 +104,10 @@ public class PkiRealmTests extends ESTestCase { PkiRealm realm = new PkiRealm(new RealmConfig("", settings, globalSettings), roleMapper); when(roleMapper.resolveRoles(anyString(), anyList())).thenReturn(Collections.emptySet()); - FakeRestRequest restRequest = new FakeRestRequest(); - restRequest.putInContext(PkiRealm.PKI_CERT_HEADER_NAME, new X509Certificate[] { certificate }); + ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + threadContext.putTransient(PkiRealm.PKI_CERT_HEADER_NAME, new X509Certificate[] { certificate }); - X509AuthenticationToken token = realm.token(restRequest); + X509AuthenticationToken token = realm.token(threadContext); User user = realm.authenticate(token); assertThat(user, is(notNullValue())); assertThat(user.principal(), is("Elasticsearch Test Node")); @@ -138,10 +125,10 @@ public class PkiRealmTests extends ESTestCase { PkiRealm realm = new PkiRealm(new RealmConfig("", settings, globalSettings), roleMapper); when(roleMapper.resolveRoles(anyString(), anyList())).thenReturn(Collections.emptySet()); - FakeRestRequest restRequest = new FakeRestRequest(); - restRequest.putInContext(PkiRealm.PKI_CERT_HEADER_NAME, new X509Certificate[] { certificate }); + ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + threadContext.putTransient(PkiRealm.PKI_CERT_HEADER_NAME, new X509Certificate[] { certificate }); - X509AuthenticationToken token = realm.token(restRequest); + X509AuthenticationToken token = realm.token(threadContext); User user = realm.authenticate(token); assertThat(user, is(nullValue())); } diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/support/UsernamePasswordTokenTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/support/UsernamePasswordTokenTests.java index fcab37e1f9d..25f3ade1187 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/support/UsernamePasswordTokenTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/support/UsernamePasswordTokenTests.java @@ -7,9 +7,10 @@ package org.elasticsearch.shield.authc.support; import org.elasticsearch.ElasticsearchSecurityException; import org.elasticsearch.common.Base64; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.transport.TransportRequest; import org.junit.Rule; import org.junit.rules.ExpectedException; @@ -31,9 +32,9 @@ public class UsernamePasswordTokenTests extends ESTestCase { public ExpectedException thrown = ExpectedException.none(); public void testPutToken() throws Exception { - TransportRequest request = new TransportRequest() {}; - UsernamePasswordToken.putTokenHeader(request, new UsernamePasswordToken("user1", SecuredStringTests.build("test123"))); - String header = request.getHeader(UsernamePasswordToken.BASIC_AUTH_HEADER); + ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + UsernamePasswordToken.putTokenHeader(threadContext, new UsernamePasswordToken("user1", SecuredStringTests.build("test123"))); + String header = threadContext.getHeader(UsernamePasswordToken.BASIC_AUTH_HEADER); assertThat(header, notNullValue()); assertTrue(header.startsWith("Basic ")); String token = header.substring("Basic ".length()); @@ -47,10 +48,10 @@ public class UsernamePasswordTokenTests extends ESTestCase { } public void testExtractToken() throws Exception { - TransportRequest request = new TransportRequest() {}; + ThreadContext threadContext = new ThreadContext(Settings.EMPTY); String header = "Basic " + Base64.encodeBytes("user1:test123".getBytes(StandardCharsets.UTF_8)); - request.putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, header); - UsernamePasswordToken token = UsernamePasswordToken.extractToken(request, null); + threadContext.putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, header); + UsernamePasswordToken token = UsernamePasswordToken.extractToken(threadContext, null); assertThat(token, notNullValue()); assertThat(token.principal(), equalTo("user1")); assertThat(new String(token.credentials().internalChars()), equalTo("test123")); @@ -59,10 +60,10 @@ public class UsernamePasswordTokenTests extends ESTestCase { public void testExtractTokenInvalid() throws Exception { String[] invalidValues = { "Basic", "Basic ", "Basic f" }; for (String value : invalidValues) { - TransportRequest request = new TransportRequest() {}; - request.putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, value); + ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + threadContext.putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, value); try { - UsernamePasswordToken.extractToken(request, null); + UsernamePasswordToken.extractToken(threadContext, null); fail("Expected an authentication exception for invalid basic auth token [" + value + "]"); } catch (ElasticsearchSecurityException e) { // expected @@ -72,11 +73,11 @@ public class UsernamePasswordTokenTests extends ESTestCase { } public void testThatAuthenticationExceptionContainsResponseHeaders() { - TransportRequest request = new TransportRequest() {}; + ThreadContext threadContext = new ThreadContext(Settings.EMPTY); String header = "BasicBroken"; - request.putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, header); + threadContext.putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, header); try { - UsernamePasswordToken.extractToken(request, null); + UsernamePasswordToken.extractToken(threadContext, null); fail("Expected exception but did not happen"); } catch (ElasticsearchSecurityException e) { assertAuthenticationException(e); diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authz/AnalyzeTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authz/AnalyzeTests.java index e684ff9ffce..6d1d249378d 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authz/AnalyzeTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authz/AnalyzeTests.java @@ -10,6 +10,8 @@ import org.elasticsearch.shield.authc.support.Hasher; import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.test.ShieldIntegTestCase; +import java.util.Collections; + import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.BASIC_AUTH_HEADER; import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.elasticsearch.test.ShieldTestsUtils.assertAuthorizationException; @@ -51,21 +53,21 @@ public class AnalyzeTests extends ShieldIntegTestCase { ensureGreen(); //ok: user has permissions for analyze on test_* - client().admin().indices().prepareAnalyze("this is my text").setIndex("test_1").setAnalyzer("standard") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("analyze_indices", new SecuredString("test123".toCharArray()))).get(); + client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("analyze_indices", new SecuredString("test123".toCharArray())))) + .admin().indices().prepareAnalyze("this is my text").setIndex("test_1").setAnalyzer("standard").get(); try { //fails: user doesn't have permissions for analyze on index non_authorized - client().admin().indices().prepareAnalyze("this is my text").setIndex("non_authorized").setAnalyzer("standard") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("analyze_indices", new SecuredString("test123".toCharArray()))).get(); + client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("analyze_indices", new SecuredString("test123".toCharArray())))) + .admin().indices().prepareAnalyze("this is my text").setIndex("non_authorized").setAnalyzer("standard").get(); } catch(ElasticsearchSecurityException e) { assertAuthorizationException(e, containsString("action [indices:admin/analyze] is unauthorized for user [analyze_indices]")); } try { //fails: user doesn't have permissions for cluster level analyze - client().admin().indices().prepareAnalyze("this is my text").setAnalyzer("standard") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("analyze_indices", new SecuredString("test123".toCharArray()))).get(); + client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("analyze_indices", new SecuredString("test123".toCharArray())))) + .admin().indices().prepareAnalyze("this is my text").setAnalyzer("standard").get(); } catch(ElasticsearchSecurityException e) { assertAuthorizationException(e, containsString("action [cluster:admin/analyze] is unauthorized for user [analyze_indices]")); } @@ -76,13 +78,13 @@ public class AnalyzeTests extends ShieldIntegTestCase { try { //fails: user doesn't have permissions for analyze on index test_1 - client().admin().indices().prepareAnalyze("this is my text").setIndex("test_1").setAnalyzer("standard") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("analyze_cluster", new SecuredString("test123".toCharArray()))).get(); + client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("analyze_cluster", new SecuredString("test123".toCharArray())))) + .admin().indices().prepareAnalyze("this is my text").setIndex("test_1").setAnalyzer("standard").get(); } catch(ElasticsearchSecurityException e) { assertAuthorizationException(e, containsString("action [indices:admin/analyze] is unauthorized for user [analyze_cluster]")); } - client().admin().indices().prepareAnalyze("this is my text").setAnalyzer("standard") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("analyze_cluster", new SecuredString("test123".toCharArray()))).get(); + client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("analyze_cluster", new SecuredString("test123".toCharArray())))) + .admin().indices().prepareAnalyze("this is my text").setAnalyzer("standard").get(); } } diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authz/IndexAliasesTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authz/IndexAliasesTests.java index 0986c9c1615..c86eed96fd2 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authz/IndexAliasesTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authz/IndexAliasesTests.java @@ -10,12 +10,16 @@ import org.elasticsearch.action.admin.indices.alias.Alias; import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequestBuilder; import org.elasticsearch.action.admin.indices.alias.get.GetAliasesResponse; import org.elasticsearch.action.support.IndicesOptions; +import org.elasticsearch.client.Client; import org.elasticsearch.index.IndexNotFoundException; import org.elasticsearch.shield.authc.support.Hasher; import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.test.ShieldIntegTestCase; import org.junit.Before; +import java.util.Collections; +import java.util.Map; + import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.BASIC_AUTH_HEADER; import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.elasticsearch.test.ShieldTestsUtils.assertAuthorizationException; @@ -85,20 +89,18 @@ public class IndexAliasesTests extends ShieldIntegTestCase { public void testCreateIndexThenAliasesCreateOnlyPermission() { //user has create permission only: allows to create indices, manage_aliases is required to add/remove aliases - assertAcked(client().admin().indices().prepareCreate("test_1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray())))); + Map headers = Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray()))); + assertAcked(client().filterWithHeader(headers).admin().indices().prepareCreate("test_1").get()); try { - client().admin().indices().prepareAliases().addAlias("test_1", "test_alias") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray()))).get(); + client().filterWithHeader(headers).admin().indices().prepareAliases().addAlias("test_1", "test_alias").get(); fail("add alias should have failed due to missing manage_aliases privileges"); } catch(ElasticsearchSecurityException e) { assertAuthorizationException(e, containsString("action [indices:admin/aliases] is unauthorized for user [create_only]")); } try { - client().admin().indices().prepareAliases().addAlias("test_*", "test_alias") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray()))).get(); + client().filterWithHeader(headers).admin().indices().prepareAliases().addAlias("test_*", "test_alias").get(); fail("add alias should have failed due to missing manage_aliases privileges"); } catch(IndexNotFoundException e) { assertThat(e.toString(), containsString("[test_*]")); @@ -107,9 +109,9 @@ public class IndexAliasesTests extends ShieldIntegTestCase { public void testCreateIndexAndAliasesCreateOnlyPermission() { //user has create permission only: allows to create indices, manage_aliases is required to add aliases although they are part of the same create index request + Map headers = Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray()))); try { - client().admin().indices().prepareCreate("test_1").addAlias(new Alias("test_2")) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray()))).get(); + client().filterWithHeader(headers).admin().indices().prepareCreate("test_1").addAlias(new Alias("test_2")).get(); fail("create index should have failed due to missing manage_aliases privileges"); } catch(ElasticsearchSecurityException e) { assertAuthorizationException(e, containsString("action [indices:admin/aliases] is unauthorized for user [create_only]")); @@ -118,25 +120,23 @@ public class IndexAliasesTests extends ShieldIntegTestCase { public void testDeleteAliasesCreateOnlyPermission() { //user has create permission only: allows to create indices, manage_aliases is required to add/remove aliases + Map headers = Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray()))); try { - client().admin().indices().prepareAliases().removeAlias("test_1", "alias_1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray()))).get(); + client().filterWithHeader(headers).admin().indices().prepareAliases().removeAlias("test_1", "alias_1").get(); fail("remove alias should have failed due to missing manage_aliases privileges"); } catch(ElasticsearchSecurityException e) { assertAuthorizationException(e, containsString("action [indices:admin/aliases] is unauthorized for user [create_only]")); } try { - client().admin().indices().prepareAliases().removeAlias("test_1", "alias_*") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray()))).get(); + client().filterWithHeader(headers).admin().indices().prepareAliases().removeAlias("test_1", "alias_*").get(); fail("remove alias should have failed due to missing manage_aliases privileges"); } catch(IndexNotFoundException e) { assertThat(e.toString(), containsString("[alias_*")); } try { - client().admin().indices().prepareAliases().removeAlias("test_1", "_all") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray()))).get(); + client().filterWithHeader(headers).admin().indices().prepareAliases().removeAlias("test_1", "_all").get(); fail("remove alias should have failed due to missing manage_aliases privileges"); } catch(IndexNotFoundException e) { assertThat(e.toString(), containsString("[_all]")); @@ -145,41 +145,37 @@ public class IndexAliasesTests extends ShieldIntegTestCase { public void testGetAliasesCreateOnlyPermission() { //user has create permission only: allows to create indices, manage_aliases is required to retrieve aliases though + Map headers = Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray()))); try { - client().admin().indices().prepareGetAliases("test_1").setIndices("test_1").setIndicesOptions(IndicesOptions.lenientExpandOpen()) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray()))).get(); + client().filterWithHeader(headers).admin().indices().prepareGetAliases("test_1").setIndices("test_1").setIndicesOptions(IndicesOptions.lenientExpandOpen()).get(); fail("get alias should have failed due to missing manage_aliases privileges"); } catch(ElasticsearchSecurityException e) { assertAuthorizationException(e, containsString("action [indices:admin/aliases/get] is unauthorized for user [create_only]")); } try { - client().admin().indices().prepareGetAliases("_all").setIndices("test_1").setIndicesOptions(IndicesOptions.lenientExpandOpen()) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray()))).get(); + client().filterWithHeader(headers).admin().indices().prepareGetAliases("_all").setIndices("test_1").setIndicesOptions(IndicesOptions.lenientExpandOpen()).get(); fail("get alias should have failed due to missing manage_aliases privileges"); } catch(IndexNotFoundException e) { assertThat(e.toString(), containsString("[_all]")); } try { - client().admin().indices().prepareGetAliases().setIndices("test_1").setIndicesOptions(IndicesOptions.lenientExpandOpen()) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray()))).get(); + client().filterWithHeader(headers).admin().indices().prepareGetAliases().setIndices("test_1").setIndicesOptions(IndicesOptions.lenientExpandOpen()).get(); fail("get alias should have failed due to missing manage_aliases privileges"); } catch(IndexNotFoundException e) { assertThat(e.toString(), containsString("[_all]")); } try { - client().admin().indices().prepareGetAliases("test_alias").setIndices("test_*").setIndicesOptions(IndicesOptions.lenientExpandOpen()) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray()))).get(); + client().filterWithHeader(headers).admin().indices().prepareGetAliases("test_alias").setIndices("test_*").setIndicesOptions(IndicesOptions.lenientExpandOpen()).get(); fail("get alias should have failed due to missing manage_aliases privileges"); } catch(IndexNotFoundException e) { assertThat(e.toString(), containsString("[test_*]")); } try { - client().admin().indices().prepareGetAliases() - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray()))).get(); + client().filterWithHeader(headers).admin().indices().prepareGetAliases().get(); fail("get alias should have failed due to missing manage_aliases privileges"); } catch(IndexNotFoundException e) { assertThat(e.toString(), containsString("[_all]")); @@ -188,21 +184,19 @@ public class IndexAliasesTests extends ShieldIntegTestCase { public void testCreateIndexThenAliasesCreateAndAliasesPermission() { //user has create and manage_aliases permission on test_*. manage_aliases is required to add/remove aliases on both aliases and indices - assertAcked(client().admin().indices().prepareCreate("test_1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray())))); + Map headers = Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))); + + assertAcked(client().filterWithHeader(headers).admin().indices().prepareCreate("test_1").get()); //ok: user has manage_aliases on test_* - assertAcked(client().admin().indices().prepareAliases().addAlias("test_1", "test_alias") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray())))); + assertAcked(client().filterWithHeader(headers).admin().indices().prepareAliases().addAlias("test_1", "test_alias").get()); //ok: user has manage_aliases on test_* - assertAcked(client().admin().indices().prepareAliases().addAlias("test_*", "test_alias_2") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray())))); + assertAcked(client().filterWithHeader(headers).admin().indices().prepareAliases().addAlias("test_*", "test_alias_2").get()); try { //fails: user doesn't have manage_aliases on alias_1 - client().admin().indices().prepareAliases().addAlias("test_1", "alias_1").addAlias("test_1", "test_alias") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))).get(); + client().filterWithHeader(headers).admin().indices().prepareAliases().addAlias("test_1", "alias_1").addAlias("test_1", "test_alias").get(); fail("add alias should have failed due to missing manage_aliases privileges on alias_1"); } catch(ElasticsearchSecurityException e) { assertAuthorizationException(e, containsString("action [indices:admin/aliases] is unauthorized for user [create_test_aliases_test]")); @@ -212,13 +206,12 @@ public class IndexAliasesTests extends ShieldIntegTestCase { public void testCreateIndexAndAliasesCreateAndAliasesPermission() { //user has create and manage_aliases permission on test_*. manage_aliases is required to add/remove aliases on both aliases and indices //ok: user has manage_aliases on test_* - assertAcked(client().admin().indices().prepareCreate("test_1").addAlias(new Alias("test_alias")) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray())))); + Map headers = Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))); + assertAcked(client().filterWithHeader(headers).admin().indices().prepareCreate("test_1").addAlias(new Alias("test_alias")).get()); try { //fails: user doesn't have manage_aliases on alias_1 - client().admin().indices().prepareCreate("test_2").addAlias(new Alias("test_alias")).addAlias(new Alias("alias_2")) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))).get(); + client().filterWithHeader(headers).admin().indices().prepareCreate("test_2").addAlias(new Alias("test_alias")).addAlias(new Alias("alias_2")).get(); fail("create index should have failed due to missing manage_aliases privileges on alias_2"); } catch(ElasticsearchSecurityException e) { assertAuthorizationException(e, containsString("action [indices:admin/aliases] is unauthorized for user [create_test_aliases_test]")); @@ -228,23 +221,20 @@ public class IndexAliasesTests extends ShieldIntegTestCase { public void testDeleteAliasesCreateAndAliasesPermission() { //user has create and manage_aliases permission on test_*. manage_aliases is required to add/remove aliases on both aliases and indices //ok: user has manage_aliases on test_* - assertAcked(client().admin().indices().prepareCreate("test_1").addAlias(new Alias("test_alias_1")).addAlias(new Alias("test_alias_2")) - .addAlias(new Alias("test_alias_3")).addAlias(new Alias("test_alias_4")) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray())))); + Map headers = Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))); + + assertAcked(client().filterWithHeader(headers).admin().indices().prepareCreate("test_1").addAlias(new Alias("test_alias_1")).addAlias(new Alias("test_alias_2")) + .addAlias(new Alias("test_alias_3")).addAlias(new Alias("test_alias_4")).get()); //ok: user has manage_aliases on test_* - assertAcked(client().admin().indices().prepareAliases().removeAlias("test_1", "test_alias_1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray())))); + assertAcked(client().filterWithHeader(headers).admin().indices().prepareAliases().removeAlias("test_1", "test_alias_1").get()); //ok: user has manage_aliases on test_* - assertAcked(client().admin().indices().prepareAliases().removeAlias("test_*", "test_alias_2") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray())))); + assertAcked(client().filterWithHeader(headers).admin().indices().prepareAliases().removeAlias("test_*", "test_alias_2").get()); //ok: user has manage_aliases on test_* - assertAcked(client().admin().indices().prepareAliases().removeAlias("test_1", "test_alias_*") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray())))); + assertAcked(client().filterWithHeader(headers).admin().indices().prepareAliases().removeAlias("test_1", "test_alias_*").get()); try { //fails: all aliases have been deleted, no existing aliases match test_alias_* - client().admin().indices().prepareAliases().removeAlias("test_1", "test_alias_*") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))).get(); + client().filterWithHeader(headers).admin().indices().prepareAliases().removeAlias("test_1", "test_alias_*").get(); fail("remove alias should have failed due to no existing matching aliases to expand test_alias_* to"); } catch(IndexNotFoundException e) { assertThat(e.toString(), containsString("[test_alias_*]")); @@ -252,8 +242,7 @@ public class IndexAliasesTests extends ShieldIntegTestCase { try { //fails: all aliases have been deleted, no existing aliases match _all - client().admin().indices().prepareAliases().removeAlias("test_1", "_all") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))).get(); + client().filterWithHeader(headers).admin().indices().prepareAliases().removeAlias("test_1", "_all").get(); fail("remove alias should have failed due to no existing matching aliases to expand _all to"); } catch(IndexNotFoundException e) { assertThat(e.toString(), containsString("[_all]")); @@ -261,8 +250,7 @@ public class IndexAliasesTests extends ShieldIntegTestCase { try { //fails: user doesn't have manage_aliases on alias_1 - client().admin().indices().prepareAliases().removeAlias("test_1", "alias_1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))).get(); + client().filterWithHeader(headers).admin().indices().prepareAliases().removeAlias("test_1", "alias_1").get(); fail("remove alias should have failed due to missing manage_aliases privileges on alias_1"); } catch(ElasticsearchSecurityException e) { assertAuthorizationException(e, containsString("action [indices:admin/aliases] is unauthorized for user [create_test_aliases_test]")); @@ -270,8 +258,7 @@ public class IndexAliasesTests extends ShieldIntegTestCase { try { //fails: user doesn't have manage_aliases on alias_1 - client().admin().indices().prepareAliases().removeAlias("test_1", new String[]{"_all", "alias_1"}) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))).get(); + client().filterWithHeader(headers).admin().indices().prepareAliases().removeAlias("test_1", new String[]{"_all", "alias_1"}).get(); fail("remove alias should have failed due to missing manage_aliases privileges on alias_1"); } catch(ElasticsearchSecurityException e) { assertAuthorizationException(e, containsString("action [indices:admin/aliases] is unauthorized for user [create_test_aliases_test]")); @@ -280,54 +267,45 @@ public class IndexAliasesTests extends ShieldIntegTestCase { public void testGetAliasesCreateAndAliasesPermission() { //user has create and manage_aliases permission on test_*. manage_aliases is required to retrieve aliases on both aliases and indices - - assertAcked(client().admin().indices().prepareCreate("test_1").addAlias(new Alias("test_alias")) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray())))); + Map headers = Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))); + final Client client = client().filterWithHeader(headers); + assertAcked(client.admin().indices().prepareCreate("test_1").addAlias(new Alias("test_alias")).get()); //ok: user has manage_aliases on test_* - assertAliases(client().admin().indices().prepareGetAliases().setAliases("test_alias").setIndices("test_1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))), + assertAliases(client.admin().indices().prepareGetAliases().setAliases("test_alias").setIndices("test_1"), "test_1", "test_alias"); //ok: user has manage_aliases on test_*, test_* gets resolved to test_1 - assertAliases(client().admin().indices().prepareGetAliases().setAliases("test_alias").setIndices("test_*") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))), + assertAliases(client.admin().indices().prepareGetAliases().setAliases("test_alias").setIndices("test_*"), "test_1", "test_alias"); //ok: user has manage_aliases on test_*, empty indices gets resolved to _all indices (thus test_1) - assertAliases(client().admin().indices().prepareGetAliases().setAliases("test_alias") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))), + assertAliases(client.admin().indices().prepareGetAliases().setAliases("test_alias"), "test_1", "test_alias"); //ok: user has manage_aliases on test_*, _all aliases gets resolved to test_alias and empty indices gets resolved to _all indices (thus test_1) - assertAliases(client().admin().indices().prepareGetAliases().setAliases("_all").setIndices("test_1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))), + assertAliases(client.admin().indices().prepareGetAliases().setAliases("_all").setIndices("test_1"), "test_1", "test_alias"); //ok: user has manage_aliases on test_*, empty aliases gets resolved to test_alias and empty indices gets resolved to _all indices (thus test_1) - assertAliases(client().admin().indices().prepareGetAliases().setIndices("test_1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))), + assertAliases(client.admin().indices().prepareGetAliases().setIndices("test_1"), "test_1", "test_alias"); //ok: user has manage_aliases on test_*, test_* aliases gets resolved to test_alias and empty indices gets resolved to _all indices (thus test_1) - assertAliases(client().admin().indices().prepareGetAliases().setAliases("test_*").setIndices("test_1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))), + assertAliases(client.admin().indices().prepareGetAliases().setAliases("test_*").setIndices("test_1"), "test_1", "test_alias"); //ok: user has manage_aliases on test_*, _all aliases gets resolved to test_alias and _all indices becomes test_1 - assertAliases(client().admin().indices().prepareGetAliases().setAliases("_all").setIndices("_all") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))), + assertAliases(client.admin().indices().prepareGetAliases().setAliases("_all").setIndices("_all"), "test_1", "test_alias"); //ok: user has manage_aliases on test_*, empty aliases gets resolved to test_alias and empty indices becomes test_1 - assertAliases(client().admin().indices().prepareGetAliases() - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))), + assertAliases(client.admin().indices().prepareGetAliases(), "test_1", "test_alias"); try { //fails: user has manage_aliases on test_*, although _all aliases and empty indices can be resolved, the explicit non authorized alias (alias_1) causes the request to fail - client().admin().indices().prepareGetAliases().setAliases("_all", "alias_1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))).get(); + client.admin().indices().prepareGetAliases().setAliases("_all", "alias_1").get(); fail("get alias should have failed due to missing manage_aliases privileges on alias_1"); } catch(ElasticsearchSecurityException e) { assertAuthorizationException(e, containsString("action [indices:admin/aliases/get] is unauthorized for user [create_test_aliases_test]")); @@ -335,8 +313,7 @@ public class IndexAliasesTests extends ShieldIntegTestCase { try { //fails: user doesn't have manage_aliases on alias_1 - client().admin().indices().prepareGetAliases().setAliases("alias_1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))).get(); + client.admin().indices().prepareGetAliases().setAliases("alias_1").get(); fail("get alias should have failed due to missing manage_aliases privileges on alias_1"); } catch(ElasticsearchSecurityException e) { assertAuthorizationException(e, containsString("action [indices:admin/aliases/get] is unauthorized for user [create_test_aliases_test]")); @@ -344,14 +321,15 @@ public class IndexAliasesTests extends ShieldIntegTestCase { } public void testCreateIndexThenAliasesCreateAndAliasesPermission2() { + Map headers = Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))); + final Client client = client().filterWithHeader(headers); + //user has create permission on test_* and manage_aliases permission on alias_*. manage_aliases is required to add/remove aliases on both aliases and indices - assertAcked(client().admin().indices().prepareCreate("test_1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray())))); + assertAcked(client.admin().indices().prepareCreate("test_1")); try { //fails: user doesn't have manage aliases on test_1 - client().admin().indices().prepareAliases().addAlias("test_1", "test_alias") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))).get(); + client.admin().indices().prepareAliases().addAlias("test_1", "test_alias").get(); fail("add alias should have failed due to missing manage_aliases privileges on test_alias and test_1"); } catch(ElasticsearchSecurityException e) { assertAuthorizationException(e, containsString("action [indices:admin/aliases] is unauthorized for user [create_test_aliases_alias]")); @@ -359,8 +337,7 @@ public class IndexAliasesTests extends ShieldIntegTestCase { try { //fails: user doesn't have manage aliases on test_1 - client().admin().indices().prepareAliases().addAlias("test_1", "alias_1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))).get(); + client.admin().indices().prepareAliases().addAlias("test_1", "alias_1").get(); fail("add alias should have failed due to missing manage_aliases privileges on test_1"); } catch(ElasticsearchSecurityException e) { assertAuthorizationException(e, containsString("action [indices:admin/aliases] is unauthorized for user [create_test_aliases_alias]")); @@ -368,8 +345,7 @@ public class IndexAliasesTests extends ShieldIntegTestCase { try { //fails: user doesn't have manage aliases on test_*, no matching indices to replace wildcards - client().admin().indices().prepareAliases().addAlias("test_*", "alias_1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))).get(); + client.admin().indices().prepareAliases().addAlias("test_*", "alias_1").get(); fail("add alias should have failed due to missing manage_aliases privileges on test_1"); } catch(IndexNotFoundException e) { assertThat(e.toString(), containsString("[test_*]")); @@ -377,11 +353,13 @@ public class IndexAliasesTests extends ShieldIntegTestCase { } public void testCreateIndexAndAliasesCreateAndAliasesPermission2() { + Map headers = Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))); + final Client client = client().filterWithHeader(headers); + //user has create permission on test_* and manage_aliases permission on alias_*. manage_aliases is required to add/remove aliases on both aliases and indices try { //fails: user doesn't have manage_aliases on test_1, create index is rejected as a whole - client().admin().indices().prepareCreate("test_1").addAlias(new Alias("test_alias")) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))).get(); + client.admin().indices().prepareCreate("test_1").addAlias(new Alias("test_alias")).get(); fail("create index should have failed due to missing manage_aliases privileges on test_1 and test_alias"); } catch(ElasticsearchSecurityException e) { assertAuthorizationException(e, containsString("action [indices:admin/aliases] is unauthorized for user [create_test_aliases_alias]")); @@ -389,8 +367,7 @@ public class IndexAliasesTests extends ShieldIntegTestCase { try { //fails: user doesn't have manage_aliases on test_*, create index is rejected as a whole - client().admin().indices().prepareCreate("test_1").addAlias(new Alias("test_alias")).addAlias(new Alias("alias_1")) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))).get(); + client.admin().indices().prepareCreate("test_1").addAlias(new Alias("test_alias")).addAlias(new Alias("alias_1")).get(); fail("create index should have failed due to missing manage_aliases privileges on test_1 and test_alias"); } catch(ElasticsearchSecurityException e) { assertAuthorizationException(e, containsString("action [indices:admin/aliases] is unauthorized for user [create_test_aliases_alias]")); @@ -398,11 +375,13 @@ public class IndexAliasesTests extends ShieldIntegTestCase { } public void testDeleteAliasesCreateAndAliasesPermission2() { + Map headers = Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))); + final Client client = client().filterWithHeader(headers); + //user has create permission on test_* and manage_aliases permission on alias_*. manage_aliases is required to add/remove aliases on both aliases and indices try { //fails: user doesn't have manage_aliases on test_1 - client().admin().indices().prepareAliases().removeAlias("test_1", "test_alias") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))).get(); + client.admin().indices().prepareAliases().removeAlias("test_1", "test_alias").get(); fail("remove alias should have failed due to missing manage_aliases privileges on test_alias and test_1"); } catch(ElasticsearchSecurityException e) { assertAuthorizationException(e, containsString("action [indices:admin/aliases] is unauthorized for user [create_test_aliases_alias]")); @@ -410,8 +389,7 @@ public class IndexAliasesTests extends ShieldIntegTestCase { try { //fails: user doesn't have manage_aliases on test_1 - client().admin().indices().prepareAliases().removeAlias("test_1", "alias_1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))).get(); + client.admin().indices().prepareAliases().removeAlias("test_1", "alias_1").get(); fail("remove alias should have failed due to missing manage_aliases privileges on test_1"); } catch(ElasticsearchSecurityException e) { assertAuthorizationException(e, containsString("action [indices:admin/aliases] is unauthorized for user [create_test_aliases_alias]")); @@ -419,8 +397,7 @@ public class IndexAliasesTests extends ShieldIntegTestCase { try { //fails: user doesn't have manage_aliases on test_*, wildcards can't get replaced - client().admin().indices().prepareAliases().removeAlias("test_*", "alias_1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))).get(); + client.admin().indices().prepareAliases().removeAlias("test_*", "alias_1").get(); fail("remove alias should have failed due to missing manage_aliases privileges on test_*"); } catch(IndexNotFoundException e) { assertThat(e.toString(), containsString("[test_*]")); @@ -428,14 +405,15 @@ public class IndexAliasesTests extends ShieldIntegTestCase { } public void testGetAliasesCreateAndAliasesPermission2() { + Map headers = Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))); + final Client client = client().filterWithHeader(headers); + //user has create permission on test_* and manage_aliases permission on alias_*. manage_aliases is required to retrieve aliases on both aliases and indices - assertAcked(client().admin().indices().prepareCreate("test_1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray())))); + assertAcked(client.admin().indices().prepareCreate("test_1")); try { //fails: user doesn't have manage aliases on test_1, nor test_alias - client().admin().indices().prepareGetAliases().setAliases("test_alias").setIndices("test_1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))).get(); + client.admin().indices().prepareGetAliases().setAliases("test_alias").setIndices("test_1").get(); fail("get alias should have failed due to missing manage_aliases privileges on test_alias and test_1"); } catch(ElasticsearchSecurityException e) { assertAuthorizationException(e, containsString("action [indices:admin/aliases/get] is unauthorized for user [create_test_aliases_alias]")); @@ -443,8 +421,7 @@ public class IndexAliasesTests extends ShieldIntegTestCase { try { //fails: user doesn't have manage aliases on test_*, no matching indices to replace wildcards - client().admin().indices().prepareGetAliases().setIndices("test_*").setAliases("test_alias") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))).get(); + client.admin().indices().prepareGetAliases().setIndices("test_*").setAliases("test_alias").get(); fail("get alias should have failed due to missing manage_aliases privileges on test_*"); } catch(IndexNotFoundException e) { assertThat(e.toString(), containsString("[test_*]")); @@ -452,8 +429,7 @@ public class IndexAliasesTests extends ShieldIntegTestCase { try { //fails: no existing indices to replace empty indices (thus _all) - client().admin().indices().prepareGetAliases().setAliases("test_alias") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))).get(); + client.admin().indices().prepareGetAliases().setAliases("test_alias").get(); fail("get alias should have failed due to missing manage_aliases privileges on any index"); } catch(IndexNotFoundException e) { assertThat(e.toString(), containsString("[_all]")); @@ -461,8 +437,7 @@ public class IndexAliasesTests extends ShieldIntegTestCase { try { //fails: no existing aliases to replace wildcards - client().admin().indices().prepareGetAliases().setIndices("test_1").setAliases("test_*") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))).get(); + client.admin().indices().prepareGetAliases().setIndices("test_1").setAliases("test_*").get(); fail("get alias should have failed due to missing manage_aliases privileges on test_1"); } catch(IndexNotFoundException e) { assertThat(e.toString(), containsString("[test_*]")); @@ -470,8 +445,7 @@ public class IndexAliasesTests extends ShieldIntegTestCase { try { //fails: no existing aliases to replace _all - client().admin().indices().prepareGetAliases().setIndices("test_1").setAliases("_all") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))).get(); + client.admin().indices().prepareGetAliases().setIndices("test_1").setAliases("_all").get(); fail("get alias should have failed due to missing manage_aliases privileges on test_1"); } catch(IndexNotFoundException e) { assertThat(e.toString(), containsString("[_all]")); @@ -479,8 +453,7 @@ public class IndexAliasesTests extends ShieldIntegTestCase { try { //fails: no existing aliases to replace empty aliases - client().admin().indices().prepareGetAliases().setIndices("test_1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))).get(); + client.admin().indices().prepareGetAliases().setIndices("test_1").get(); fail("get alias should have failed due to missing manage_aliases privileges on test_1"); } catch(IndexNotFoundException e) { assertThat(e.toString(), containsString("[_all]")); @@ -488,8 +461,7 @@ public class IndexAliasesTests extends ShieldIntegTestCase { try { //fails: no existing aliases to replace empty aliases - client().admin().indices().prepareGetAliases() - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))).get(); + client.admin().indices().prepareGetAliases().get(); fail("get alias should have failed due to missing manage_aliases privileges on test_1"); } catch(IndexNotFoundException e) { assertThat(e.toString(), containsString("[_all]")); @@ -497,55 +469,52 @@ public class IndexAliasesTests extends ShieldIntegTestCase { } public void testCreateIndexThenAliasesCreateAndAliasesPermission3() { + Map headers = Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))); + final Client client = client().filterWithHeader(headers); + //user has create permission on test_* and manage_aliases permission on test_*,alias_*. All good. - assertAcked(client().admin().indices().prepareCreate("test_1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray())))); + assertAcked(client.admin().indices().prepareCreate("test_1")); - assertAcked(client().admin().indices().prepareAliases().addAlias("test_1", "test_alias") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray())))); + assertAcked(client.admin().indices().prepareAliases().addAlias("test_1", "test_alias")); - assertAcked(client().admin().indices().prepareAliases().addAlias("test_1", "alias_1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray())))); + assertAcked(client.admin().indices().prepareAliases().addAlias("test_1", "alias_1")); - assertAcked(client().admin().indices().prepareAliases().addAlias("test_*", "alias_2") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray())))); + assertAcked(client.admin().indices().prepareAliases().addAlias("test_*", "alias_2")); } public void testCreateIndexAndAliasesCreateAndAliasesPermission3() { - //user has create permission on test_* and manage_aliases permission on test_*,alias_*. All good. - assertAcked(client().admin().indices().prepareCreate("test_1").addAlias(new Alias("test_alias")) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray())))); + Map headers = Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))); + final Client client = client().filterWithHeader(headers); - assertAcked(client().admin().indices().prepareCreate("test_2").addAlias(new Alias("test_alias_2")).addAlias(new Alias("alias_2")) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray())))); + //user has create permission on test_* and manage_aliases permission on test_*,alias_*. All good. + assertAcked(client.admin().indices().prepareCreate("test_1").addAlias(new Alias("test_alias"))); + + assertAcked(client.admin().indices().prepareCreate("test_2").addAlias(new Alias("test_alias_2")).addAlias(new Alias("alias_2"))); } public void testDeleteAliasesCreateAndAliasesPermission3() { + Map headers = Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))); + final Client client = client().filterWithHeader(headers); + //user has create permission on test_* and manage_aliases permission on test_*,alias_*. All good. - assertAcked(client().admin().indices().prepareCreate("test_1").addAlias(new Alias("test_alias")).addAlias(new Alias("alias_1")) - .addAlias(new Alias("alias_2")).addAlias(new Alias("alias_3")) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray())))); + assertAcked(client.admin().indices().prepareCreate("test_1").addAlias(new Alias("test_alias")).addAlias(new Alias("alias_1")) + .addAlias(new Alias("alias_2")).addAlias(new Alias("alias_3"))); try { //fails: user doesn't have manage_aliases privilege on non_authorized - client().admin().indices().prepareAliases().removeAlias("test_1", "non_authorized").removeAlias("test_1", "test_alias") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))).get(); + client.admin().indices().prepareAliases().removeAlias("test_1", "non_authorized").removeAlias("test_1", "test_alias").get(); fail("remove alias should have failed due to missing manage_aliases privileges on non_authorized"); } catch(ElasticsearchSecurityException e) { assertAuthorizationException(e, containsString("action [indices:admin/aliases] is unauthorized for user [create_test_aliases_test_alias]")); } - assertAcked(client().admin().indices().prepareAliases().removeAlias("test_1", "alias_1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray())))); - - assertAcked(client().admin().indices().prepareAliases().removeAlias("test_*", "_all") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray())))); + assertAcked(client.admin().indices().prepareAliases().removeAlias("test_1", "alias_1")); + assertAcked(client.admin().indices().prepareAliases().removeAlias("test_*", "_all")); try { //fails: all aliases have been deleted, _all can't be resolved to any existing authorized aliases - client().admin().indices().prepareAliases().removeAlias("test_1", "_all") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))).get(); + client.admin().indices().prepareAliases().removeAlias("test_1", "_all").get(); fail("remove alias should have failed due to no existing aliases matching _all"); } catch(IndexNotFoundException e) { assertThat(e.toString(), containsString("[_all]")); @@ -553,51 +522,43 @@ public class IndexAliasesTests extends ShieldIntegTestCase { } public void testGetAliasesCreateAndAliasesPermission3() { + Map headers = Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))); + final Client client = client().filterWithHeader(headers); + //user has create permission on test_* and manage_aliases permission on test_*,alias_*. All good. - assertAcked(client().admin().indices().prepareCreate("test_1").addAlias(new Alias("test_alias")).addAlias(new Alias("alias_1")) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray())))); + assertAcked(client.admin().indices().prepareCreate("test_1").addAlias(new Alias("test_alias")).addAlias(new Alias("alias_1"))); - assertAliases(client().admin().indices().prepareGetAliases().setAliases("test_alias").setIndices("test_1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))), + assertAliases(client.admin().indices().prepareGetAliases().setAliases("test_alias").setIndices("test_1"), "test_1", "test_alias"); - assertAliases(client().admin().indices().prepareGetAliases().setAliases("alias_1").setIndices("test_1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))), + assertAliases(client.admin().indices().prepareGetAliases().setAliases("alias_1").setIndices("test_1"), "test_1", "alias_1"); - assertAliases(client().admin().indices().prepareGetAliases().setAliases("alias_1").setIndices("test_*") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))), + assertAliases(client.admin().indices().prepareGetAliases().setAliases("alias_1").setIndices("test_*"), "test_1", "alias_1"); - assertAliases(client().admin().indices().prepareGetAliases().setAliases("test_*").setIndices("test_1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))), + assertAliases(client.admin().indices().prepareGetAliases().setAliases("test_*").setIndices("test_1"), "test_1", "test_alias"); - assertAliases(client().admin().indices().prepareGetAliases().setAliases("_all").setIndices("test_1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))), + assertAliases(client.admin().indices().prepareGetAliases().setAliases("_all").setIndices("test_1"), "test_1", "alias_1", "test_alias"); - assertAliases(client().admin().indices().prepareGetAliases().setAliases("_all") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))), + assertAliases(client.admin().indices().prepareGetAliases().setAliases("_all"), "test_1", "alias_1", "test_alias"); - assertAliases(client().admin().indices().prepareGetAliases().setIndices("test_1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))), + assertAliases(client.admin().indices().prepareGetAliases().setIndices("test_1"), "test_1", "alias_1", "test_alias"); - assertAliases(client().admin().indices().prepareGetAliases() - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))), - "test_1", "alias_1", "test_alias"); + assertAliases(client.admin().indices().prepareGetAliases(), "test_1", "alias_1", "test_alias"); - assertAliases(client().admin().indices().prepareGetAliases().setAliases("alias_*").setIndices("test_*") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))), + assertAliases(client.admin().indices().prepareGetAliases().setAliases("alias_*").setIndices("test_*"), "test_1", "alias_1"); } public void testCreateIndexAliasesOnlyPermission() { try { - client().admin().indices().prepareCreate("test_1") - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("aliases_only", new SecuredString("test123".toCharArray()))).get(); + client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("aliases_only", new SecuredString("test123".toCharArray())))) + .admin().indices().prepareCreate("test_1").get(); fail("Expected ElasticsearchSecurityException"); } catch (ElasticsearchSecurityException e) { assertThat(e.getMessage(), is("action [indices:admin/create] is unauthorized for user [aliases_only]")); @@ -605,25 +566,24 @@ public class IndexAliasesTests extends ShieldIntegTestCase { } public void testGetAliasesAliasesOnlyPermission() { + Map headers = Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("aliases_only", new SecuredString("test123".toCharArray()))); + final Client client = client().filterWithHeader(headers); //user has manage_aliases only permissions on both alias_* and test_* //ok: manage_aliases on both test_* and alias_* - GetAliasesResponse getAliasesResponse = client().admin().indices().prepareGetAliases("alias_1").addIndices("test_1").setIndicesOptions(IndicesOptions.lenientExpandOpen()) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("aliases_only", new SecuredString("test123".toCharArray()))).get(); + GetAliasesResponse getAliasesResponse = client.admin().indices().prepareGetAliases("alias_1").addIndices("test_1").setIndicesOptions(IndicesOptions.lenientExpandOpen()).get(); assertThat(getAliasesResponse.getAliases().isEmpty(), is(true)); try { //fails: no manage_aliases privilege on non_authorized alias - client().admin().indices().prepareGetAliases("non_authorized").addIndices("test_1").setIndicesOptions(IndicesOptions.lenientExpandOpen()) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("aliases_only", new SecuredString("test123".toCharArray()))).get(); + client.admin().indices().prepareGetAliases("non_authorized").addIndices("test_1").setIndicesOptions(IndicesOptions.lenientExpandOpen()).get(); } catch(ElasticsearchSecurityException e) { assertAuthorizationException(e, containsString("action [indices:admin/aliases/get] is unauthorized for user [aliases_only]")); } try { //fails: no manage_aliases privilege on non_authorized index - client().admin().indices().prepareGetAliases("alias_1").addIndices("non_authorized").setIndicesOptions(IndicesOptions.lenientExpandOpen()) - .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("aliases_only", new SecuredString("test123".toCharArray()))).get(); + client.admin().indices().prepareGetAliases("alias_1").addIndices("non_authorized").setIndicesOptions(IndicesOptions.lenientExpandOpen()).get(); } catch(ElasticsearchSecurityException e) { assertAuthorizationException(e, containsString("action [indices:admin/aliases/get] is unauthorized for user [aliases_only]")); } diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authz/InternalAuthorizationServiceTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authz/InternalAuthorizationServiceTests.java index b89f442d757..6591c3c26cb 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authz/InternalAuthorizationServiceTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authz/InternalAuthorizationServiceTests.java @@ -23,6 +23,7 @@ import org.elasticsearch.cluster.metadata.AliasMetaData; import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.search.action.SearchServiceTransportAction; import org.elasticsearch.shield.User; import org.elasticsearch.shield.audit.AuditTrail; @@ -34,6 +35,7 @@ import org.elasticsearch.shield.authz.privilege.GeneralPrivilege; import org.elasticsearch.shield.authz.privilege.IndexPrivilege; import org.elasticsearch.shield.authz.store.RolesStore; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportRequest; import org.junit.Before; @@ -56,6 +58,8 @@ public class InternalAuthorizationServiceTests extends ESTestCase { private RolesStore rolesStore; private ClusterService clusterService; private InternalAuthorizationService internalAuthorizationService; + private ThreadContext threadContext; + private ThreadPool threadPool; @Before public void setup() { @@ -63,7 +67,12 @@ public class InternalAuthorizationServiceTests extends ESTestCase { clusterService = mock(ClusterService.class); auditTrail = mock(AuditTrail.class); AnonymousService anonymousService = new AnonymousService(Settings.EMPTY); - internalAuthorizationService = new InternalAuthorizationService(Settings.EMPTY, rolesStore, clusterService, auditTrail, anonymousService, new DefaultAuthenticationFailureHandler()); + threadContext = new ThreadContext(Settings.EMPTY); + threadPool = mock(ThreadPool.class); + when(threadPool.getThreadContext()).thenReturn(threadContext); + + internalAuthorizationService = new InternalAuthorizationService(Settings.EMPTY, rolesStore, clusterService, + auditTrail, anonymousService, new DefaultAuthenticationFailureHandler(), threadPool); } public void testActionsSystemUserIsAuthorized() { @@ -297,7 +306,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase { TransportRequest request = new IndicesExistsRequest("b"); ClusterState state = mock(ClusterState.class); AnonymousService anonymousService = new AnonymousService(Settings.builder().put("shield.authc.anonymous.roles", "a_all").build()); - internalAuthorizationService = new InternalAuthorizationService(Settings.EMPTY, rolesStore, clusterService, auditTrail, anonymousService, new DefaultAuthenticationFailureHandler()); + internalAuthorizationService = new InternalAuthorizationService(Settings.EMPTY, rolesStore, clusterService, auditTrail, anonymousService, new DefaultAuthenticationFailureHandler(), threadPool); when(rolesStore.role("a_all")).thenReturn(Role.builder("a_all").add(IndexPrivilege.ALL, "a").build()); when(clusterService.state()).thenReturn(state); @@ -322,7 +331,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase { .put("shield.authc.anonymous.roles", "a_all") .put(AnonymousService.SETTING_AUTHORIZATION_EXCEPTION_ENABLED, false) .build()); - internalAuthorizationService = new InternalAuthorizationService(Settings.EMPTY, rolesStore, clusterService, auditTrail, anonymousService, new DefaultAuthenticationFailureHandler()); + internalAuthorizationService = new InternalAuthorizationService(Settings.EMPTY, rolesStore, clusterService, auditTrail, anonymousService, new DefaultAuthenticationFailureHandler(), threadPool); when(rolesStore.role("a_all")).thenReturn(Role.builder("a_all").add(IndexPrivilege.ALL, "a").build()); when(clusterService.state()).thenReturn(state); diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authz/accesscontrol/ShieldIndexSearcherWrapperIntegrationTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authz/accesscontrol/ShieldIndexSearcherWrapperIntegrationTests.java index 2294b197e1c..a0139d20cb8 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authz/accesscontrol/ShieldIndexSearcherWrapperIntegrationTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authz/accesscontrol/ShieldIndexSearcherWrapperIntegrationTests.java @@ -24,6 +24,7 @@ import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.lucene.index.ElasticsearchDirectoryReader; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.index.Index; import org.elasticsearch.index.IndexSettings; import org.elasticsearch.index.cache.bitset.BitsetFilterCache; @@ -36,7 +37,6 @@ import org.elasticsearch.shield.authz.InternalAuthorizationService; import org.elasticsearch.shield.license.ShieldLicenseState; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.IndexSettingsModule; -import org.elasticsearch.transport.TransportRequest; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; @@ -65,10 +65,8 @@ public class ShieldIndexSearcherWrapperIntegrationTests extends ESTestCase { } }); - TransportRequest request = new TransportRequest.Empty(); - RequestContext.setCurrent(new RequestContext(request)); + ThreadContext threadContext = new ThreadContext(Settings.EMPTY); IndicesAccessControl.IndexAccessControl indexAccessControl = new IndicesAccessControl.IndexAccessControl(true, null, singleton(new BytesArray("{}"))); - request.putInContext(InternalAuthorizationService.INDICES_PERMISSIONS_KEY, new IndicesAccessControl(true, singletonMap("_index", indexAccessControl))); IndexSettings indexSettings = IndexSettingsModule.newIndexSettings(shardId.index(), Settings.EMPTY); QueryShardContext queryShardContext = mock(QueryShardContext.class); IndexSettings settings = IndexSettingsModule.newIndexSettings(new Index("_index"), Settings.EMPTY); @@ -85,12 +83,17 @@ public class ShieldIndexSearcherWrapperIntegrationTests extends ESTestCase { }); ShieldLicenseState licenseState = mock(ShieldLicenseState.class); when(licenseState.documentAndFieldLevelSecurityEnabled()).thenReturn(true); - ShieldIndexSearcherWrapper wrapper = new ShieldIndexSearcherWrapper(indexSettings, queryShardContext, mapperService, bitsetFilterCache, licenseState) { + ShieldIndexSearcherWrapper wrapper = new ShieldIndexSearcherWrapper(indexSettings, queryShardContext, mapperService, bitsetFilterCache, threadContext, licenseState) { @Override protected QueryShardContext copyQueryShardContext(QueryShardContext context) { return queryShardContext; } + + @Override + protected IndicesAccessControl getIndicesAccessControl() { + return new IndicesAccessControl(true, singletonMap("_index", indexAccessControl)); + } }; Directory directory = newDirectory(); diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authz/accesscontrol/ShieldIndexSearcherWrapperUnitTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authz/accesscontrol/ShieldIndexSearcherWrapperUnitTests.java index 9d5bdc8dec3..88aaf4e715e 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authz/accesscontrol/ShieldIndexSearcherWrapperUnitTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authz/accesscontrol/ShieldIndexSearcherWrapperUnitTests.java @@ -30,6 +30,7 @@ import org.apache.lucene.util.SparseFixedBitSet; import org.elasticsearch.common.compress.CompressedXContent; import org.elasticsearch.common.lucene.index.ElasticsearchDirectoryReader; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.index.Index; import org.elasticsearch.index.IndexSettings; @@ -43,11 +44,9 @@ import org.elasticsearch.index.similarity.SimilarityService; import org.elasticsearch.indices.IndicesModule; import org.elasticsearch.indices.IndicesWarmer; import org.elasticsearch.search.aggregations.LeafBucketCollector; -import org.elasticsearch.shield.authz.InternalAuthorizationService; import org.elasticsearch.shield.license.ShieldLicenseState; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.IndexSettingsModule; -import org.elasticsearch.transport.TransportRequest; import org.junit.After; import org.junit.Before; @@ -68,16 +67,17 @@ import static org.mockito.Mockito.when; public class ShieldIndexSearcherWrapperUnitTests extends ESTestCase { - private TransportRequest request; + private ThreadContext threadContext; private MapperService mapperService; private ShieldIndexSearcherWrapper shieldIndexSearcherWrapper; private ElasticsearchDirectoryReader esIn; private ShieldLicenseState licenseState; + private IndexSettings indexSettings; @Before public void before() throws Exception { Index index = new Index("_index"); - IndexSettings indexSettings = IndexSettingsModule.newIndexSettings(index, Settings.EMPTY); + indexSettings = IndexSettingsModule.newIndexSettings(index, Settings.EMPTY); AnalysisService analysisService = new AnalysisService(indexSettings, Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap()); SimilarityService similarityService = new SimilarityService(indexSettings, Collections.emptyMap()); @@ -86,13 +86,10 @@ public class ShieldIndexSearcherWrapperUnitTests extends ESTestCase { ShardId shardId = new ShardId(index, 0); licenseState = mock(ShieldLicenseState.class); when(licenseState.documentAndFieldLevelSecurityEnabled()).thenReturn(true); - shieldIndexSearcherWrapper = new ShieldIndexSearcherWrapper(indexSettings, null, mapperService, null, licenseState); + threadContext = new ThreadContext(Settings.EMPTY); IndexShard indexShard = mock(IndexShard.class); when(indexShard.shardId()).thenReturn(shardId); - request = new TransportRequest.Empty(); - RequestContext.setCurrent(new RequestContext(request)); - Directory directory = new RAMDirectory(); IndexWriter writer = new IndexWriter(directory, newIndexWriterConfig()); writer.close(); @@ -106,16 +103,6 @@ public class ShieldIndexSearcherWrapperUnitTests extends ESTestCase { esIn.close(); } - public void testUnkownOriginOfCurrentCall() { - RequestContext.setCurrent(null); - try { - shieldIndexSearcherWrapper.wrap(esIn); - fail("exception expected"); - } catch (IllegalStateException e) { - assertThat(e.getMessage(), equalTo("can't locate the origin of the current request")); - } - } - public void testDefaultMetaFields() throws Exception { XContentBuilder mappingSource = jsonBuilder().startObject().startObject("type") .startObject("properties") @@ -123,8 +110,13 @@ public class ShieldIndexSearcherWrapperUnitTests extends ESTestCase { .endObject().endObject(); mapperService.merge("type", new CompressedXContent(mappingSource.string()), MapperService.MergeReason.MAPPING_UPDATE, false); - IndicesAccessControl.IndexAccessControl indexAccessControl = new IndicesAccessControl.IndexAccessControl(true, emptySet(), null); - request.putInContext(InternalAuthorizationService.INDICES_PERMISSIONS_KEY, new IndicesAccessControl(true, singletonMap("_index", indexAccessControl))); + shieldIndexSearcherWrapper = new ShieldIndexSearcherWrapper(indexSettings, null, mapperService, null, threadContext, licenseState) { + @Override + protected IndicesAccessControl getIndicesAccessControl() { + IndicesAccessControl.IndexAccessControl indexAccessControl = new IndicesAccessControl.IndexAccessControl(true, emptySet(), null); + return new IndicesAccessControl(true, singletonMap("_index", indexAccessControl)); + } + }; FieldSubsetReader.FieldSubsetDirectoryReader result = (FieldSubsetReader.FieldSubsetDirectoryReader) shieldIndexSearcherWrapper.wrap(esIn); assertThat(result.getFieldNames().size(), equalTo(11)); @@ -144,12 +136,14 @@ public class ShieldIndexSearcherWrapperUnitTests extends ESTestCase { public void testWrapReaderWhenFeatureDisabled() throws Exception { when(licenseState.documentAndFieldLevelSecurityEnabled()).thenReturn(false); + shieldIndexSearcherWrapper = new ShieldIndexSearcherWrapper(indexSettings, null, mapperService, null, threadContext, licenseState); DirectoryReader reader = shieldIndexSearcherWrapper.wrap(esIn); assertThat(reader, sameInstance(esIn)); } public void testWrapSearcherWhenFeatureDisabled() throws Exception { ShardId shardId = new ShardId("_index", 0); + shieldIndexSearcherWrapper = new ShieldIndexSearcherWrapper(indexSettings, null, mapperService, null, threadContext, licenseState); IndexSearcher indexSearcher = new IndexSearcher(esIn); IndexSearcher result = shieldIndexSearcherWrapper.wrap(indexSearcher); assertThat(result, sameInstance(indexSearcher)); @@ -262,6 +256,7 @@ public class ShieldIndexSearcherWrapperUnitTests extends ESTestCase { }); DirectoryReader directoryReader = DocumentSubsetReader.wrap(esIn, bitsetFilterCache, new MatchAllDocsQuery()); IndexSearcher indexSearcher = new IndexSearcher(directoryReader); + shieldIndexSearcherWrapper = new ShieldIndexSearcherWrapper(indexSettings, null, mapperService, null, threadContext, licenseState); IndexSearcher result = shieldIndexSearcherWrapper.wrap(indexSearcher); assertThat(result, not(sameInstance(indexSearcher))); assertThat(result.getSimilarity(true), sameInstance(indexSearcher.getSimilarity(true))); @@ -269,6 +264,7 @@ public class ShieldIndexSearcherWrapperUnitTests extends ESTestCase { } public void testIntersectScorerAndRoleBits() throws Exception { + shieldIndexSearcherWrapper = new ShieldIndexSearcherWrapper(indexSettings, null, mapperService, null, threadContext, licenseState); final Directory directory = newDirectory(); IndexWriter iw = new IndexWriter( directory, @@ -356,8 +352,13 @@ public class ShieldIndexSearcherWrapperUnitTests extends ESTestCase { } private void assertResolvedFields(String expression, String... expectedFields) { - IndicesAccessControl.IndexAccessControl indexAccessControl = new IndicesAccessControl.IndexAccessControl(true, singleton(expression), null); - request.putInContext(InternalAuthorizationService.INDICES_PERMISSIONS_KEY, new IndicesAccessControl(true, singletonMap("_index", indexAccessControl))); + shieldIndexSearcherWrapper = new ShieldIndexSearcherWrapper(indexSettings, null, mapperService, null, threadContext, licenseState) { + @Override + protected IndicesAccessControl getIndicesAccessControl() { + IndicesAccessControl.IndexAccessControl indexAccessControl = new IndicesAccessControl.IndexAccessControl(true, singleton(expression), null); + return new IndicesAccessControl(true, singletonMap("_index", indexAccessControl)); + } + }; FieldSubsetReader.FieldSubsetDirectoryReader result = (FieldSubsetReader.FieldSubsetDirectoryReader) shieldIndexSearcherWrapper.wrap(esIn); assertThat(result.getFieldNames().size() - shieldIndexSearcherWrapper.getAllowedMetaFields().size(), equalTo(expectedFields.length)); for (String expectedField : expectedFields) { diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/rest/ShieldRestFilterTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/rest/ShieldRestFilterTests.java index 1f246eaa677..5696f9ec9bd 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/rest/ShieldRestFilterTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/rest/ShieldRestFilterTests.java @@ -7,6 +7,7 @@ package org.elasticsearch.shield.rest; import org.elasticsearch.ElasticsearchSecurityException; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.rest.RestChannel; import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestFilterChain; @@ -15,6 +16,7 @@ import org.elasticsearch.shield.User; import org.elasticsearch.shield.authc.AuthenticationService; import org.elasticsearch.shield.license.ShieldLicenseState; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.threadpool.ThreadPool; import org.junit.Before; import static org.elasticsearch.shield.support.Exceptions.authenticationError; @@ -42,7 +44,9 @@ public class ShieldRestFilterTests extends ESTestCase { chain = mock(RestFilterChain.class); licenseState = mock(ShieldLicenseState.class); when(licenseState.securityEnabled()).thenReturn(true); - filter = new ShieldRestFilter(authcService, restController, Settings.EMPTY, licenseState); + ThreadPool threadPool = mock(ThreadPool.class); + when(threadPool.getThreadContext()).thenReturn(new ThreadContext(Settings.EMPTY)); + filter = new ShieldRestFilter(authcService, restController, Settings.EMPTY, threadPool, licenseState); verify(restController).registerFilter(filter); } diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/transport/ClientTransportFilterTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/transport/ClientTransportFilterTests.java index dee14a7a33a..dc4db2031d8 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/transport/ClientTransportFilterTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/transport/ClientTransportFilterTests.java @@ -30,6 +30,6 @@ public class ClientTransportFilterTests extends ESTestCase { public void testOutbound() throws Exception { TransportRequest request = mock(TransportRequest.class); filter.outbound("_action", request); - verify(authcService).attachUserHeaderIfMissing(request, User.SYSTEM); + verify(authcService).attachUserHeaderIfMissing(User.SYSTEM); } } diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/transport/ServerTransportFilterTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/transport/ServerTransportFilterTests.java index 244e1b36036..c9c24466244 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/transport/ServerTransportFilterTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/transport/ServerTransportFilterTests.java @@ -6,6 +6,8 @@ package org.elasticsearch.shield.transport; import org.elasticsearch.ElasticsearchSecurityException; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.shield.User; import org.elasticsearch.shield.action.ShieldActionMapper; import org.elasticsearch.shield.authc.AuthenticationService; @@ -40,7 +42,7 @@ public class ServerTransportFilterTests extends ESTestCase { authzService = mock(AuthorizationService.class); channel = mock(NettyTransportChannel.class); when(channel.getProfileName()).thenReturn(NettyTransport.DEFAULT_PROFILE); - filter = new ServerTransportFilter.NodeProfile(authcService, authzService, new ShieldActionMapper(), false); + filter = new ServerTransportFilter.NodeProfile(authcService, authzService, new ShieldActionMapper(), new ThreadContext(Settings.EMPTY), false); } public void testInbound() throws Exception { diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/transport/netty/ShieldNettyHttpServerTransportTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/transport/netty/ShieldNettyHttpServerTransportTests.java index f601cf0b5ca..98679a994dd 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/transport/netty/ShieldNettyHttpServerTransportTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/transport/netty/ShieldNettyHttpServerTransportTests.java @@ -16,6 +16,7 @@ import org.elasticsearch.shield.ssl.ServerSSLService; import org.elasticsearch.shield.transport.SSLClientAuth; import org.elasticsearch.shield.transport.filter.IPFilter; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.threadpool.ThreadPool; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.handler.ssl.SslHandler; import org.junit.Before; @@ -45,7 +46,7 @@ public class ShieldNettyHttpServerTransportTests extends ESTestCase { public void testDefaultClientAuth() throws Exception { Settings settings = Settings.builder().put(ShieldNettyHttpServerTransport.HTTP_SSL_SETTING, true).build(); - ShieldNettyHttpServerTransport transport = new ShieldNettyHttpServerTransport(settings, mock(NetworkService.class), mock(BigArrays.class), mock(IPFilter.class), serverSSLService); + ShieldNettyHttpServerTransport transport = new ShieldNettyHttpServerTransport(settings, mock(NetworkService.class), mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class)); NettyHttpMockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory(); assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(false)); @@ -57,7 +58,7 @@ public class ShieldNettyHttpServerTransportTests extends ESTestCase { Settings settings = Settings.builder() .put(ShieldNettyHttpServerTransport.HTTP_SSL_SETTING, true) .put(ShieldNettyHttpServerTransport.HTTP_CLIENT_AUTH_SETTING, value).build(); - ShieldNettyHttpServerTransport transport = new ShieldNettyHttpServerTransport(settings, mock(NetworkService.class), mock(BigArrays.class), mock(IPFilter.class), serverSSLService); + ShieldNettyHttpServerTransport transport = new ShieldNettyHttpServerTransport(settings, mock(NetworkService.class), mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class)); NettyHttpMockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory(); assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(false)); @@ -69,7 +70,7 @@ public class ShieldNettyHttpServerTransportTests extends ESTestCase { Settings settings = Settings.builder() .put(ShieldNettyHttpServerTransport.HTTP_SSL_SETTING, true) .put(ShieldNettyHttpServerTransport.HTTP_CLIENT_AUTH_SETTING, value).build(); - ShieldNettyHttpServerTransport transport = new ShieldNettyHttpServerTransport(settings, mock(NetworkService.class), mock(BigArrays.class), mock(IPFilter.class), serverSSLService); + ShieldNettyHttpServerTransport transport = new ShieldNettyHttpServerTransport(settings, mock(NetworkService.class), mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class)); NettyHttpMockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory(); assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(true)); @@ -81,7 +82,7 @@ public class ShieldNettyHttpServerTransportTests extends ESTestCase { Settings settings = Settings.builder() .put(ShieldNettyHttpServerTransport.HTTP_SSL_SETTING, true) .put(ShieldNettyHttpServerTransport.HTTP_CLIENT_AUTH_SETTING, value).build(); - ShieldNettyHttpServerTransport transport = new ShieldNettyHttpServerTransport(settings, mock(NetworkService.class), mock(BigArrays.class), mock(IPFilter.class), serverSSLService); + ShieldNettyHttpServerTransport transport = new ShieldNettyHttpServerTransport(settings, mock(NetworkService.class), mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class)); NettyHttpMockUtil.setOpenChannelsHandlerToMock(transport); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory(); assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(false)); diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/test/ShieldIntegTestCase.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/test/ShieldIntegTestCase.java index 2f3483be9a1..6059bc7853b 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/test/ShieldIntegTestCase.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/test/ShieldIntegTestCase.java @@ -9,8 +9,8 @@ import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse; import org.elasticsearch.action.admin.cluster.node.info.NodeInfo; import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse; import org.elasticsearch.client.Client; +import org.elasticsearch.client.node.NodeClient; import org.elasticsearch.cluster.health.ClusterHealthStatus; -import org.elasticsearch.common.Nullable; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.plugins.Plugin; import org.elasticsearch.shield.authc.support.SecuredString; @@ -26,10 +26,14 @@ import org.junit.rules.ExternalResource; import java.nio.file.Path; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; +import java.util.Map; import java.util.Set; +import java.util.function.Function; import java.util.stream.Collectors; +import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoTimeout; import static org.hamcrest.CoreMatchers.is; @@ -303,4 +307,10 @@ public abstract class ShieldIntegTestCase extends ESIntegTestCase { assertNoTimeout(clusterHealthResponse); assertThat(clusterHealthResponse.getStatus(), is(ClusterHealthStatus.GREEN)); } + + @Override + protected Function getClientWrapper() { + Map headers = Collections.singletonMap("Authorization", basicAuthHeaderValue(nodeClientUsername(), nodeClientPassword())); + return client -> (client instanceof NodeClient) ? client.filterWithHeader(headers) : client; + } } \ No newline at end of file diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/test/ShieldSettingsSource.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/test/ShieldSettingsSource.java index 36fb1293674..78b673a74a9 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/test/ShieldSettingsSource.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/test/ShieldSettingsSource.java @@ -6,9 +6,9 @@ package org.elasticsearch.test; import org.elasticsearch.ElasticsearchException; -import org.elasticsearch.client.support.Headers; import org.elasticsearch.common.io.PathUtils; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.index.IndexModule; import org.elasticsearch.plugins.Plugin; import org.elasticsearch.shield.ShieldPlugin; @@ -16,7 +16,6 @@ import org.elasticsearch.shield.authc.esusers.ESUsersRealm; import org.elasticsearch.shield.authc.esnative.ESNativeRealm; import org.elasticsearch.shield.authc.support.Hasher; import org.elasticsearch.shield.authc.support.SecuredString; -import org.elasticsearch.shield.authc.support.UsernamePasswordToken; import org.elasticsearch.shield.crypto.InternalCryptoService; import org.elasticsearch.shield.test.ShieldTestUtils; import org.elasticsearch.shield.transport.netty.ShieldNettyHttpServerTransport; @@ -134,13 +133,11 @@ public class ShieldSettingsSource extends ClusterDiscoveryConfiguration.UnicastZ .put("shield.authc.realms.index.type", ESNativeRealm.TYPE) .put("shield.authc.realms.index.order", "1") .put("shield.authz.store.files.roles", writeFile(folder, "roles.yml", configRoles())) - // Test framework sometimes randomily selects the 'index' or 'none' cache and that makes the + // Test framework sometimes randomly selects the 'index' or 'none' cache and that makes the // validation in ShieldPlugin fail. .put(IndexModule.INDEX_QUERY_CACHE_TYPE_SETTING.getKey(), ShieldPlugin.OPT_OUT_QUERY_CACHE) .put(getNodeSSLSettings()); - setUser(builder, nodeClientUsername(), nodeClientPassword()); - return builder.build(); } @@ -148,7 +145,11 @@ public class ShieldSettingsSource extends ClusterDiscoveryConfiguration.UnicastZ public Settings transportClientSettings() { Settings.Builder builder = settingsBuilder().put(super.transportClientSettings()) .put(getClientSSLSettings()); - setUser(builder, transportClientUsername(), transportClientPassword()); + if (randomBoolean()) { + builder.put("shield.user", transportClientUsername() + ":" + new String(transportClientPassword().internalChars())); + } else { + builder.put(ThreadContext.PREFIX + ".Authorization", basicAuthHeaderValue(transportClientUsername(), transportClientPassword())); + } return builder.build(); } @@ -198,14 +199,6 @@ public class ShieldSettingsSource extends ClusterDiscoveryConfiguration.UnicastZ return XPackPlugin.class; } - private void setUser(Settings.Builder builder, String username, SecuredString password) { - if (randomBoolean()) { - builder.put(Headers.PREFIX + "." + UsernamePasswordToken.BASIC_AUTH_HEADER, basicAuthHeaderValue(username, password)); - } else { - builder.put("shield.user", username + ":" + new String(password.internalChars())); - } - } - private static byte[] generateKey() { try { return InternalCryptoService.generateKey(); diff --git a/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/test/rest/XPackRestTestCase.java b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/test/rest/XPackRestTestCase.java index 3e62ff9c939..7010174def7 100644 --- a/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/test/rest/XPackRestTestCase.java +++ b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/test/rest/XPackRestTestCase.java @@ -15,8 +15,8 @@ import org.apache.http.client.methods.HttpPut; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.BasicHttpClientConnectionManager; -import org.elasticsearch.client.support.Headers; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.test.rest.ESRestTestCase; import org.elasticsearch.test.rest.RestTestCandidate; @@ -67,7 +67,7 @@ public abstract class XPackRestTestCase extends ESRestTestCase { protected Settings restClientSettings() { String token = basicAuthHeaderValue("test_user", new SecuredString("changeme".toCharArray())); return Settings.builder() - .put(Headers.PREFIX + ".Authorization", token) + .put(ThreadContext.PREFIX + ".Authorization", token) .build(); } } diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/client/WatcherClient.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/client/WatcherClient.java index b5304798ef4..91b16fd2667 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/client/WatcherClient.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/client/WatcherClient.java @@ -8,7 +8,6 @@ package org.elasticsearch.watcher.client; import org.elasticsearch.action.ActionFuture; import org.elasticsearch.action.ActionListener; import org.elasticsearch.client.Client; -import org.elasticsearch.client.ElasticsearchClient; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.watcher.transport.actions.ack.AckWatchAction; import org.elasticsearch.watcher.transport.actions.ack.AckWatchRequest; @@ -43,11 +42,13 @@ import org.elasticsearch.watcher.transport.actions.stats.WatcherStatsRequest; import org.elasticsearch.watcher.transport.actions.stats.WatcherStatsRequestBuilder; import org.elasticsearch.watcher.transport.actions.stats.WatcherStatsResponse; +import java.util.Map; + /** */ public class WatcherClient { - private final ElasticsearchClient client; + private final Client client; @Inject public WatcherClient(Client client) { @@ -323,4 +324,7 @@ public class WatcherClient { return client.execute(ExecuteWatchAction.INSTANCE, request); } + public WatcherClient filterWithHeader(Map headers) { + return new WatcherClient(client.filterWithHeader(headers)); + } } diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/execution/ExecutionService.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/execution/ExecutionService.java index 23f89ce342f..9d5183f0484 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/execution/ExecutionService.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/execution/ExecutionService.java @@ -149,7 +149,8 @@ public class ExecutionService extends AbstractComponent { } public List queuedWatches() { - List snapshot = new ArrayList<>(executor.queue()); + List snapshot = new ArrayList<>(); + executor.tasks().forEach(t -> snapshot.add(t)); if (snapshot.isEmpty()) { return Collections.emptyList(); } diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/execution/InternalWatchExecutor.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/execution/InternalWatchExecutor.java index 0a772c29b83..b34cbd074d1 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/execution/InternalWatchExecutor.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/execution/InternalWatchExecutor.java @@ -14,6 +14,9 @@ import org.elasticsearch.watcher.WatcherPlugin; import org.elasticsearch.watcher.support.ThreadPoolSettingsBuilder; import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.stream.Stream; /** * @@ -48,6 +51,11 @@ public class InternalWatchExecutor implements WatchExecutor { return executor().getQueue(); } + @Override + public Stream tasks() { + return executor().getTasks(); + } + @Override public long largestPoolSize() { return executor().getLargestPoolSize(); diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/execution/WatchExecutor.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/execution/WatchExecutor.java index 5ab926f57b4..06a9818dcf8 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/execution/WatchExecutor.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/execution/WatchExecutor.java @@ -6,6 +6,7 @@ package org.elasticsearch.watcher.execution; import java.util.concurrent.BlockingQueue; +import java.util.stream.Stream; /** * @@ -14,6 +15,8 @@ public interface WatchExecutor { BlockingQueue queue(); + Stream tasks(); + long largestPoolSize(); void execute(Runnable runnable); diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/WatcherRestHandler.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/WatcherRestHandler.java index 31d6c4d4f01..8ab90ffc56b 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/WatcherRestHandler.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/WatcherRestHandler.java @@ -20,8 +20,8 @@ public abstract class WatcherRestHandler extends BaseRestHandler { protected static String URI_BASE = "_watcher"; - public WatcherRestHandler(Settings settings, RestController controller, Client client) { - super(settings, controller, client); + public WatcherRestHandler(Settings settings, Client client) { + super(settings, client); } @Override diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestAckWatchAction.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestAckWatchAction.java index 8825a3769ae..a3c6a382054 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestAckWatchAction.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestAckWatchAction.java @@ -30,7 +30,7 @@ public class RestAckWatchAction extends WatcherRestHandler { @Inject public RestAckWatchAction(Settings settings, RestController controller, Client client) { - super(settings, controller, client); + super(settings, client); controller.registerHandler(RestRequest.Method.PUT, URI_BASE + "/watch/{id}/_ack", this); controller.registerHandler(RestRequest.Method.POST, URI_BASE + "/watch/{id}/_ack", this); controller.registerHandler(RestRequest.Method.PUT, URI_BASE + "/watch/{id}/{actions}/_ack", this); diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestActivateWatchAction.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestActivateWatchAction.java index 7e3af4120ef..7bfbf61afae 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestActivateWatchAction.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestActivateWatchAction.java @@ -30,10 +30,10 @@ public class RestActivateWatchAction extends WatcherRestHandler { @Inject public RestActivateWatchAction(Settings settings, RestController controller, Client client) { - super(settings, controller, client); + super(settings, client); controller.registerHandler(RestRequest.Method.PUT, URI_BASE + "/watch/{id}/_activate", this); controller.registerHandler(RestRequest.Method.POST, URI_BASE + "/watch/{id}/_activate", this); - DeactivateRestHandler deactivateRestHandler = new DeactivateRestHandler(settings, controller, client); + DeactivateRestHandler deactivateRestHandler = new DeactivateRestHandler(settings, client); controller.registerHandler(RestRequest.Method.PUT, URI_BASE + "/watch/{id}/_deactivate", deactivateRestHandler); controller.registerHandler(RestRequest.Method.POST, URI_BASE + "/watch/{id}/_deactivate", deactivateRestHandler); } @@ -53,8 +53,8 @@ public class RestActivateWatchAction extends WatcherRestHandler { static class DeactivateRestHandler extends WatcherRestHandler { - public DeactivateRestHandler(Settings settings, RestController controller, Client client) { - super(settings, controller, client); + public DeactivateRestHandler(Settings settings, Client client) { + super(settings, client); } @Override diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestDeleteWatchAction.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestDeleteWatchAction.java index 516442d3626..fdf71c46e01 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestDeleteWatchAction.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestDeleteWatchAction.java @@ -31,7 +31,7 @@ public class RestDeleteWatchAction extends WatcherRestHandler { @Inject public RestDeleteWatchAction(Settings settings, RestController controller, Client client) { - super(settings, controller, client); + super(settings, client); controller.registerHandler(DELETE, URI_BASE + "/watch/{id}", this); } diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestExecuteWatchAction.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestExecuteWatchAction.java index 02121efd06d..eaf4a8d5a95 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestExecuteWatchAction.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestExecuteWatchAction.java @@ -40,7 +40,7 @@ public class RestExecuteWatchAction extends WatcherRestHandler { @Inject public RestExecuteWatchAction(Settings settings, RestController controller, Client client, TriggerService triggerService) { - super(settings, controller, client); + super(settings, client); controller.registerHandler(RestRequest.Method.POST, URI_BASE + "/watch/{id}/_execute", this); controller.registerHandler(RestRequest.Method.PUT, URI_BASE + "/watch/{id}/_execute", this); controller.registerHandler(RestRequest.Method.POST, URI_BASE + "/watch/_execute", this); diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestGetWatchAction.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestGetWatchAction.java index 64650a324a8..d752ab77d46 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestGetWatchAction.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestGetWatchAction.java @@ -31,7 +31,7 @@ public class RestGetWatchAction extends WatcherRestHandler { @Inject public RestGetWatchAction(Settings settings, RestController controller, Client client) { - super(settings, controller, client); + super(settings, client); controller.registerHandler(GET, URI_BASE + "/watch/{id}", this); } diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestHijackOperationAction.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestHijackOperationAction.java index 3aba01f9242..61a421c9568 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestHijackOperationAction.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestHijackOperationAction.java @@ -27,9 +27,9 @@ public class RestHijackOperationAction extends WatcherRestHandler { @Inject public RestHijackOperationAction(Settings settings, RestController controller, Client client) { - super(settings, controller, client); + super(settings, client); if (!settings.getAsBoolean(ALLOW_DIRECT_ACCESS_TO_WATCH_INDEX_SETTING, false)) { - WatcherRestHandler unsupportedHandler = new UnsupportedHandler(settings, controller, client); + WatcherRestHandler unsupportedHandler = new UnsupportedHandler(settings, client); controller.registerHandler(RestRequest.Method.POST, WatchStore.INDEX + "/watch", this); controller.registerHandler(RestRequest.Method.POST, WatchStore.INDEX + "/watch/{id}", this); controller.registerHandler(RestRequest.Method.PUT, WatchStore.INDEX + "/watch/{id}", this); @@ -56,10 +56,10 @@ public class RestHijackOperationAction extends WatcherRestHandler { channel.sendResponse(new BytesRestResponse(RestStatus.BAD_REQUEST, jsonBuilder)); } - public static class UnsupportedHandler extends WatcherRestHandler{ + public static class UnsupportedHandler extends WatcherRestHandler { - public UnsupportedHandler(Settings settings, RestController controller, Client client) { - super(settings, controller, client); + public UnsupportedHandler(Settings settings, Client client) { + super(settings, client); } @Override diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestPutWatchAction.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestPutWatchAction.java index 2aff394001b..1af012a78fa 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestPutWatchAction.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestPutWatchAction.java @@ -32,7 +32,7 @@ public class RestPutWatchAction extends WatcherRestHandler { @Inject public RestPutWatchAction(Settings settings, RestController controller, Client client) { - super(settings, controller, client); + super(settings, client); controller.registerHandler(POST, URI_BASE + "/watch/{id}", this); controller.registerHandler(PUT, URI_BASE + "/watch/{id}", this); } diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestWatchServiceAction.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestWatchServiceAction.java index 66ae9168769..b38d992adc4 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestWatchServiceAction.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestWatchServiceAction.java @@ -23,10 +23,10 @@ public class RestWatchServiceAction extends WatcherRestHandler { @Inject public RestWatchServiceAction(Settings settings, RestController controller, Client client) { - super(settings, controller, client); + super(settings, client); controller.registerHandler(RestRequest.Method.PUT, URI_BASE + "/_restart", this); - controller.registerHandler(RestRequest.Method.PUT, URI_BASE + "/_start", new StartRestHandler(settings, controller, client)); - controller.registerHandler(RestRequest.Method.PUT, URI_BASE + "/_stop", new StopRestHandler(settings, controller, client)); + controller.registerHandler(RestRequest.Method.PUT, URI_BASE + "/_start", new StartRestHandler(settings, client)); + controller.registerHandler(RestRequest.Method.PUT, URI_BASE + "/_stop", new StopRestHandler(settings, client)); } @Override @@ -36,8 +36,8 @@ public class RestWatchServiceAction extends WatcherRestHandler { static class StartRestHandler extends WatcherRestHandler { - public StartRestHandler(Settings settings, RestController controller, Client client) { - super(settings, controller, client); + public StartRestHandler(Settings settings, Client client) { + super(settings, client); } @Override @@ -48,8 +48,8 @@ public class RestWatchServiceAction extends WatcherRestHandler { static class StopRestHandler extends WatcherRestHandler { - public StopRestHandler(Settings settings, RestController controller, Client client) { - super(settings, controller, client); + public StopRestHandler(Settings settings, Client client) { + super(settings, client); } @Override diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestWatcherInfoAction.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestWatcherInfoAction.java index 5578fd2c4b8..c714312b10c 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestWatcherInfoAction.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestWatcherInfoAction.java @@ -28,7 +28,7 @@ public class RestWatcherInfoAction extends WatcherRestHandler { @Inject public RestWatcherInfoAction(Settings settings, RestController controller, Client client) { - super(settings, controller, client); + super(settings, client); controller.registerHandler(GET, URI_BASE, this); } diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestWatcherStatsAction.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestWatcherStatsAction.java index dd9f3a399fb..655d1b3274e 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestWatcherStatsAction.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/rest/action/RestWatcherStatsAction.java @@ -30,7 +30,7 @@ public class RestWatcherStatsAction extends WatcherRestHandler { @Inject public RestWatcherStatsAction(Settings settings, RestController controller, Client client) { - super(settings, controller, client); + super(settings, client); controller.registerHandler(GET, URI_BASE + "/stats", this); controller.registerHandler(GET, URI_BASE + "/stats/{metric}", this); } diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/shield/ShieldIntegration.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/shield/ShieldIntegration.java index 4bd8c6dd1ff..b6c2b02bbc6 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/shield/ShieldIntegration.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/shield/ShieldIntegration.java @@ -6,14 +6,12 @@ package org.elasticsearch.watcher.shield; import org.elasticsearch.ElasticsearchException; -import org.elasticsearch.common.HasContext; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Injector; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.shield.ShieldPlugin; import org.elasticsearch.shield.ShieldSettingsFilter; import org.elasticsearch.shield.authc.AuthenticationService; -import org.elasticsearch.transport.TransportMessage; import java.io.IOException; @@ -33,26 +31,19 @@ public class ShieldIntegration { settingsFilter = enabled ? injector.getInstance(ShieldSettingsFilter.class) : null; } - public void bindWatcherUser(TransportMessage message) { - if (authcService != null) { - try { - authcService.attachUserHeaderIfMissing(message, InternalWatcherUser.INSTANCE); - } catch (IOException e) { - throw new ElasticsearchException("failed to attach watcher user to request", e); - } - } - } - public void filterOutSettings(String... patterns) { if (settingsFilter != null) { settingsFilter.filterOut(patterns); } } - // TODO this is a hack that needs to go away with proper fixes in core - public void putUserInContext(HasContext context) { + public void setWatcherUser() { if (enabled) { - context.putInContext("_shield_user", InternalWatcherUser.INSTANCE); + try { + authcService.attachUserHeaderIfMissing(InternalWatcherUser.INSTANCE); + } catch (IOException e) { + throw new ElasticsearchException("failed to attach watcher user to request", e); + } } } diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/support/WatcherUtils.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/support/WatcherUtils.java index 97a250807a6..dba5026a618 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/support/WatcherUtils.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/support/WatcherUtils.java @@ -61,7 +61,7 @@ public final class WatcherUtils { } public static SearchRequest createSearchRequestFromPrototype(SearchRequest requestPrototype, WatchExecutionContext ctx, Payload payload) throws IOException { - SearchRequest request = new SearchRequest(requestPrototype) + SearchRequest request = new SearchRequest() .indicesOptions(requestPrototype.indicesOptions()) .searchType(requestPrototype.searchType()) .indices(requestPrototype.indices()) diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/support/init/proxy/ClientProxy.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/support/init/proxy/ClientProxy.java index b7cdf864946..2df0c973cbb 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/support/init/proxy/ClientProxy.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/support/init/proxy/ClientProxy.java @@ -5,7 +5,11 @@ */ package org.elasticsearch.watcher.support.init.proxy; +import org.elasticsearch.action.Action; import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.ActionRequest; +import org.elasticsearch.action.ActionRequestBuilder; +import org.elasticsearch.action.ActionResponse; import org.elasticsearch.action.admin.indices.refresh.RefreshRequest; import org.elasticsearch.action.admin.indices.refresh.RefreshResponse; import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest; @@ -25,10 +29,12 @@ import org.elasticsearch.action.update.UpdateRequest; import org.elasticsearch.action.update.UpdateResponse; import org.elasticsearch.client.AdminClient; import org.elasticsearch.client.Client; +import org.elasticsearch.client.FilterClient; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Injector; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.transport.TransportMessage; import org.elasticsearch.watcher.shield.ShieldIntegration; import org.elasticsearch.watcher.support.init.InitializingService; @@ -65,6 +71,17 @@ public class ClientProxy implements InitializingService.Initializable { @Override public void init(Injector injector) { client = injector.getInstance(Client.class); + if (shieldIntegration != null) { + client = new FilterClient(client) { + @Override + protected , Response extends ActionResponse, RequestBuilder extends ActionRequestBuilder> void doExecute(Action action, Request request, ActionListener listener) { + try (ThreadContext.StoredContext ctx = threadPool().getThreadContext().stashContext()) { + shieldIntegration.setWatcherUser(); + super.doExecute(action, request, listener); + } + } + }; + } } public AdminClient admin() { @@ -129,10 +146,6 @@ public class ClientProxy implements InitializingService.Initializable { } M preProcess(M message) { - if (shieldIntegration != null) { - shieldIntegration.bindWatcherUser(message); - } return message; } - } diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/support/init/proxy/ScriptServiceProxy.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/support/init/proxy/ScriptServiceProxy.java index 42314479487..af3d9f9afd3 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/support/init/proxy/ScriptServiceProxy.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/support/init/proxy/ScriptServiceProxy.java @@ -5,12 +5,13 @@ */ package org.elasticsearch.watcher.support.init.proxy; -import org.elasticsearch.common.ContextAndHeaderHolder; import org.elasticsearch.common.inject.Injector; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.script.CompiledScript; import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.ScriptContext; import org.elasticsearch.script.ScriptService; +import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.watcher.shield.ShieldIntegration; import org.elasticsearch.watcher.support.Script; import org.elasticsearch.watcher.support.init.InitializingService; @@ -25,7 +26,8 @@ import java.util.Map; public class ScriptServiceProxy implements InitializingService.Initializable { private ScriptService service; - private ContextAndHeaderHolder contextAndHeaderHolder = new ContextAndHeaderHolder(); + private ThreadContext threadContext; + private ShieldIntegration shieldIntegration; /** * Creates a proxy to the given script service (can be used for testing) @@ -39,27 +41,49 @@ public class ScriptServiceProxy implements InitializingService.Initializable { @Override public void init(Injector injector) { this.service = injector.getInstance(ScriptService.class); - ShieldIntegration shieldIntegration = injector.getInstance(ShieldIntegration.class); - if (shieldIntegration != null) { - shieldIntegration.putUserInContext(contextAndHeaderHolder); - } + this.threadContext = injector.getInstance(ThreadPool.class).getThreadContext(); + this.shieldIntegration = injector.getInstance(ShieldIntegration.class); } public CompiledScript compile(Script script) { + if (shieldIntegration != null) { + try (ThreadContext.StoredContext ctx = threadContext.stashContext()) { + shieldIntegration.setWatcherUser(); + return compile(new org.elasticsearch.script.Script(script.script(), script.type(), script.lang(), script.params())); + } + } return compile(new org.elasticsearch.script.Script(script.script(), script.type(), script.lang(), script.params())); } public CompiledScript compile(org.elasticsearch.script.Script script) { - return service.compile(script, WatcherScriptContext.CTX, contextAndHeaderHolder, Collections.emptyMap()); + if (shieldIntegration != null) { + try (ThreadContext.StoredContext ctx = threadContext.stashContext()) { + shieldIntegration.setWatcherUser(); + return service.compile(script, WatcherScriptContext.CTX, Collections.emptyMap()); + } + } + return service.compile(script, WatcherScriptContext.CTX, Collections.emptyMap()); } public ExecutableScript executable(CompiledScript compiledScript, Map vars) { + if (shieldIntegration != null) { + try (ThreadContext.StoredContext ctx = threadContext.stashContext()) { + shieldIntegration.setWatcherUser(); + return service.executable(compiledScript, vars); + } + } return service.executable(compiledScript, vars); } public ExecutableScript executable(org.elasticsearch.script.Script script) { - return service.executable(script, WatcherScriptContext.CTX, contextAndHeaderHolder, Collections.emptyMap()); + if (shieldIntegration != null) { + try (ThreadContext.StoredContext ctx = threadContext.stashContext()) { + shieldIntegration.setWatcherUser(); + return service.executable(script, WatcherScriptContext.CTX, Collections.emptyMap()); + } + } + return service.executable(script, WatcherScriptContext.CTX, Collections.emptyMap()); } public static final ScriptContext.Plugin INSTANCE = new ScriptContext.Plugin("elasticsearch-watcher", "watch"); diff --git a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/watcher/shield/BasicShieldTests.java b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/watcher/shield/BasicShieldTests.java index bc6952d12dd..9fac6f061f6 100644 --- a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/watcher/shield/BasicShieldTests.java +++ b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/watcher/shield/BasicShieldTests.java @@ -19,6 +19,8 @@ import org.elasticsearch.watcher.trigger.schedule.IntervalSchedule; import org.elasticsearch.watcher.trigger.schedule.ScheduleTriggerEvent; import org.joda.time.DateTime; +import java.util.Collections; + import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.elasticsearch.watcher.client.WatchSourceBuilders.watchBuilder; import static org.elasticsearch.watcher.trigger.TriggerBuilders.schedule; @@ -56,8 +58,7 @@ public class BasicShieldTests extends AbstractWatcherIntegrationTestCase { // stats and get watch apis require at least monitor role: String token = basicAuthHeaderValue("test", new SecuredString("changeme".toCharArray())); try { - watcherClient().prepareWatcherStats() - .putHeader("Authorization", token) + watcherClient().filterWithHeader(Collections.singletonMap("Authorization", token)).prepareWatcherStats() .get(); fail("authentication failure should have occurred"); } catch (Exception e) { @@ -65,8 +66,7 @@ public class BasicShieldTests extends AbstractWatcherIntegrationTestCase { } try { - watcherClient().prepareGetWatch("_id") - .putHeader("Authorization", token) + watcherClient().filterWithHeader(Collections.singletonMap("Authorization", token)).prepareGetWatch("_id") .get(); fail("authentication failure should have occurred"); } catch (Exception e) { @@ -75,20 +75,17 @@ public class BasicShieldTests extends AbstractWatcherIntegrationTestCase { // stats and get watch are allowed by role monitor: token = basicAuthHeaderValue("monitor", new SecuredString("changeme".toCharArray())); - WatcherStatsResponse statsResponse = watcherClient().prepareWatcherStats() - .putHeader("Authorization", token) + WatcherStatsResponse statsResponse = watcherClient().filterWithHeader(Collections.singletonMap("Authorization", token)).prepareWatcherStats() .get(); assertThat(statsResponse.getWatcherState(), equalTo(WatcherState.STARTED)); - GetWatchResponse getWatchResponse = watcherClient().prepareGetWatch("_id") - .putHeader("Authorization", token) + GetWatchResponse getWatchResponse = watcherClient().filterWithHeader(Collections.singletonMap("Authorization", token)).prepareGetWatch("_id") .get(); assertThat(getWatchResponse.isFound(), is(false)); // but put watch isn't allowed by monitor: try { - watcherClient().preparePutWatch("_id") + watcherClient().filterWithHeader(Collections.singletonMap("Authorization", token)).preparePutWatch("_id") .setSource(watchBuilder().trigger(schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS)))) - .putHeader("Authorization", token) .get(); fail("authentication failure should have occurred"); } catch (Exception e) { @@ -100,9 +97,8 @@ public class BasicShieldTests extends AbstractWatcherIntegrationTestCase { // put, execute and delete watch apis requires watcher admin role: String token = basicAuthHeaderValue("test", new SecuredString("changeme".toCharArray())); try { - watcherClient().preparePutWatch("_id") + watcherClient().filterWithHeader(Collections.singletonMap("Authorization", token)).preparePutWatch("_id") .setSource(watchBuilder().trigger(schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS)))) - .putHeader("Authorization", token) .get(); fail("authentication failure should have occurred"); } catch (Exception e) { @@ -111,9 +107,8 @@ public class BasicShieldTests extends AbstractWatcherIntegrationTestCase { TriggerEvent triggerEvent = new ScheduleTriggerEvent(new DateTime(UTC), new DateTime(UTC)); try { - watcherClient().prepareExecuteWatch("_id") + watcherClient().filterWithHeader(Collections.singletonMap("Authorization", token)).prepareExecuteWatch("_id") .setTriggerEvent(triggerEvent) - .putHeader("Authorization", token) .get(); fail("authentication failure should have occurred"); } catch (Exception e) { @@ -121,8 +116,7 @@ public class BasicShieldTests extends AbstractWatcherIntegrationTestCase { } try { - watcherClient().prepareDeleteWatch("_id") - .putHeader("Authorization", token) + watcherClient().filterWithHeader(Collections.singletonMap("Authorization", token)).prepareDeleteWatch("_id") .get(); fail("authentication failure should have occurred"); } catch (Exception e) { @@ -131,29 +125,29 @@ public class BasicShieldTests extends AbstractWatcherIntegrationTestCase { // put, execute and delete watch apis are allowed by role admin: token = basicAuthHeaderValue("admin", new SecuredString("changeme".toCharArray())); - PutWatchResponse putWatchResponse = watcherClient().preparePutWatch("_id") + PutWatchResponse putWatchResponse = watcherClient().filterWithHeader(Collections.singletonMap("Authorization", token)) + .preparePutWatch("_id") .setSource(watchBuilder().trigger(schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS)))) - .putHeader("Authorization", token) .get(); assertThat(putWatchResponse.getVersion(), equalTo(1l)); - ExecuteWatchResponse executeWatchResponse = watcherClient().prepareExecuteWatch("_id") + ExecuteWatchResponse executeWatchResponse = watcherClient().filterWithHeader(Collections.singletonMap("Authorization", token)) + .prepareExecuteWatch("_id") .setTriggerEvent(triggerEvent) - .putHeader("Authorization", token) .get(); - DeleteWatchResponse deleteWatchResponse = watcherClient().prepareDeleteWatch("_id") - .putHeader("Authorization", token) + DeleteWatchResponse deleteWatchResponse = watcherClient().filterWithHeader(Collections.singletonMap("Authorization", token)) + .prepareDeleteWatch("_id") .get(); assertThat(deleteWatchResponse.getVersion(), equalTo(2l)); assertThat(deleteWatchResponse.isFound(), is(true)); // stats and get watch are also allowed by role monitor: token = basicAuthHeaderValue("admin", new SecuredString("changeme".toCharArray())); - WatcherStatsResponse statsResponse = watcherClient().prepareWatcherStats() - .putHeader("Authorization", token) + WatcherStatsResponse statsResponse = watcherClient().filterWithHeader(Collections.singletonMap("Authorization", token)) + .prepareWatcherStats() .get(); assertThat(statsResponse.getWatcherState(), equalTo(WatcherState.STARTED)); - GetWatchResponse getWatchResponse = watcherClient().prepareGetWatch("_id") - .putHeader("Authorization", token) + GetWatchResponse getWatchResponse = watcherClient().filterWithHeader(Collections.singletonMap("Authorization", token)) + .prepareGetWatch("_id") .get(); assertThat(getWatchResponse.isFound(), is(false)); } diff --git a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/watcher/test/AbstractWatcherIntegrationTestCase.java b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/watcher/test/AbstractWatcherIntegrationTestCase.java index 9e0bde3e732..573b4d87fab 100644 --- a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/watcher/test/AbstractWatcherIntegrationTestCase.java +++ b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/watcher/test/AbstractWatcherIntegrationTestCase.java @@ -10,6 +10,8 @@ import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResp import org.elasticsearch.action.search.SearchRequestBuilder; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.support.IndicesOptions; +import org.elasticsearch.client.Client; +import org.elasticsearch.client.node.NodeClient; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.routing.IndexRoutingTable; @@ -43,7 +45,6 @@ import org.elasticsearch.watcher.actions.email.service.Authentication; import org.elasticsearch.watcher.actions.email.service.Email; import org.elasticsearch.watcher.actions.email.service.EmailService; import org.elasticsearch.watcher.actions.email.service.Profile; -import org.elasticsearch.watcher.actions.email.service.support.EmailServer; import org.elasticsearch.watcher.client.WatcherClient; import org.elasticsearch.watcher.execution.ExecutionService; import org.elasticsearch.watcher.execution.ExecutionState; @@ -74,15 +75,18 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; import static org.elasticsearch.index.query.QueryBuilders.boolQuery; import static org.elasticsearch.index.query.QueryBuilders.matchQuery; +import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.elasticsearch.test.ESIntegTestCase.Scope.SUITE; import static org.elasticsearch.watcher.WatcherModule.HISTORY_TEMPLATE_NAME; import static org.elasticsearch.watcher.WatcherModule.TRIGGERED_TEMPLATE_NAME; @@ -161,6 +165,16 @@ public abstract class AbstractWatcherIntegrationTestCase extends ESIntegTestCase return nodePlugins(); } + @Override + protected Function getClientWrapper() { + if (shieldEnabled == false) { + return Function.identity(); + } + Map headers = Collections.singletonMap("Authorization", + basicAuthHeaderValue(ShieldSettings.TEST_USERNAME, new SecuredString(ShieldSettings.TEST_PASSWORD.toCharArray()))); + return client -> (client instanceof NodeClient) ? client.filterWithHeader(headers) : client; + } + protected List> pluginTypes() { List> types = new ArrayList<>(); if (timeWarped()) { @@ -284,8 +298,7 @@ public abstract class AbstractWatcherIntegrationTestCase extends ESIntegTestCase } protected long docCount(String index, String type, SearchSourceBuilder source) { - SearchRequestBuilder builder = client().prepareSearch(index) -.setSource(source).setSize(0); + SearchRequestBuilder builder = client().prepareSearch(index).setSource(source).setSize(0); if (type != null) { builder.setTypes(type); } @@ -665,7 +678,6 @@ public abstract class AbstractWatcherIntegrationTestCase extends ESIntegTestCase Path folder = createTempDir().resolve("watcher_shield"); Files.createDirectories(folder); return builder.put("shield.enabled", true) - .put("shield.user", "test:changeme") .put("shield.authc.realms.esusers.type", ESUsersRealm.TYPE) .put("shield.authc.realms.esusers.order", 0) .put("shield.authc.realms.esusers.files.users", writeFile(folder, "users", USERS)) diff --git a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/watcher/test/TimeWarpedWatcherPlugin.java b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/watcher/test/TimeWarpedWatcherPlugin.java index b2293fede05..df692da248c 100644 --- a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/watcher/test/TimeWarpedWatcherPlugin.java +++ b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/watcher/test/TimeWarpedWatcherPlugin.java @@ -24,6 +24,7 @@ import java.util.Collection; import java.util.List; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; +import java.util.stream.Stream; /** * @@ -91,6 +92,11 @@ public class TimeWarpedWatcherPlugin extends WatcherPlugin { public static class SameThreadExecutor implements WatchExecutor { + @Override + public Stream tasks() { + return Stream.empty(); + } + @Override public BlockingQueue queue() { return new ArrayBlockingQueue<>(1);