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@87d2966d93
This commit is contained in:
jaymode 2016-01-13 10:07:01 -05:00
parent d02ddece8f
commit e82c969959
119 changed files with 1443 additions and 1200 deletions

View File

@ -95,9 +95,9 @@ public class ShieldCachePermissionTests extends ShieldIntegTestCase {
// Repeat with unauthorized user!!!! // Repeat with unauthorized user!!!!
try { 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")))) QueryBuilders.termsLookupQuery("token", new TermsLookup("tokens", "tokens", "1", "tokens"))))
.putHeader("Authorization", basicAuthHeaderValue(READ_ONE_IDX_USER, new SecuredString("changeme".toCharArray())))
.execute().actionGet(); .execute().actionGet();
fail("search phase exception should have been thrown! response was:\n" + response.toString()); fail("search phase exception should have been thrown! response was:\n" + response.toString());
} catch (SearchPhaseExecutionException e) { } catch (SearchPhaseExecutionException e) {
@ -115,9 +115,9 @@ public class ShieldCachePermissionTests extends ShieldIntegTestCase {
// Repeat with unauthorized user!!!! // Repeat with unauthorized user!!!!
try { 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.<String, Object>singletonMap("name", "token"))) .setTemplate(new Template("testTemplate", ScriptService.ScriptType.INDEXED, MustacheScriptEngineService.NAME, null, Collections.<String, Object>singletonMap("name", "token")))
.putHeader("Authorization", basicAuthHeaderValue(READ_ONE_IDX_USER, new SecuredString("changeme".toCharArray())))
.execute().actionGet(); .execute().actionGet();
fail("search phase exception should have been thrown! response was:\n" + response.toString()); fail("search phase exception should have been thrown! response was:\n" + response.toString());
} catch (SearchPhaseExecutionException e) { } catch (SearchPhaseExecutionException e) {

View File

@ -90,7 +90,8 @@ public class ShieldTransportClientIT extends ESIntegTestCase {
// this checks that the transport client is really running in a limited state // this checks that the transport client is really running in a limited state
ClusterHealthResponse response; ClusterHealthResponse response;
if (useTransportUser) { 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 { } else {
response = client.admin().cluster().prepareHealth().get(); response = client.admin().cluster().prepareHealth().get();
} }

View File

@ -7,8 +7,8 @@ package org.elasticsearch.shield;
import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.client.support.Headers;
import org.elasticsearch.common.settings.Settings; 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.SecuredString;
import org.elasticsearch.test.rest.ESRestTestCase; import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.test.rest.RestTestCandidate; import org.elasticsearch.test.rest.RestTestCandidate;
@ -36,7 +36,7 @@ public class RestIT extends ESRestTestCase {
protected Settings restClientSettings() { protected Settings restClientSettings() {
String token = basicAuthHeaderValue(USER, new SecuredString(PASS.toCharArray())); String token = basicAuthHeaderValue(USER, new SecuredString(PASS.toCharArray()));
return Settings.builder() return Settings.builder()
.put(Headers.PREFIX + ".Authorization", token) .put(ThreadContext.PREFIX + ".Authorization", token)
.build(); .build();
} }
} }

View File

@ -5,14 +5,13 @@
*/ */
package org.elasticsearch.example.realm; 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.User;
import org.elasticsearch.shield.authc.AuthenticationToken; import org.elasticsearch.shield.authc.AuthenticationToken;
import org.elasticsearch.shield.authc.Realm; import org.elasticsearch.shield.authc.Realm;
import org.elasticsearch.shield.authc.RealmConfig; import org.elasticsearch.shield.authc.RealmConfig;
import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.shield.authc.support.UsernamePasswordToken; import org.elasticsearch.shield.authc.support.UsernamePasswordToken;
import org.elasticsearch.transport.TransportMessage;
public class CustomRealm extends Realm<UsernamePasswordToken> { public class CustomRealm extends Realm<UsernamePasswordToken> {
@ -35,22 +34,10 @@ public class CustomRealm extends Realm<UsernamePasswordToken> {
} }
@Override @Override
public UsernamePasswordToken token(RestRequest request) { public UsernamePasswordToken token(ThreadContext threadContext) {
String user = request.header(USER_HEADER); String user = threadContext.getHeader(USER_HEADER);
if (user != null) { if (user != null) {
String password = request.header(PW_HEADER); String password = threadContext.getHeader(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);
if (password != null) { if (password != null) {
return new UsernamePasswordToken(user, new SecuredString(password.toCharArray())); return new UsernamePasswordToken(user, new SecuredString(password.toCharArray()));
} }

View File

@ -5,13 +5,17 @@
*/ */
package org.elasticsearch.example.realm; 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.Realm;
import org.elasticsearch.shield.authc.RealmConfig; import org.elasticsearch.shield.authc.RealmConfig;
public class CustomRealmFactory extends Realm.Factory<CustomRealm> { public class CustomRealmFactory extends Realm.Factory<CustomRealm> {
public CustomRealmFactory() { @Inject
public CustomRealmFactory(RestController controller) {
super(CustomRealm.TYPE, false); super(CustomRealm.TYPE, false);
controller.registerRelevantHeaders(CustomRealm.USER_HEADER, CustomRealm.PW_HEADER);
} }
@Override @Override

View File

@ -8,11 +8,11 @@ package org.elasticsearch.example.realm;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse; 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.NodeInfo;
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse; 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.NoNodeAvailableException;
import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.rest.client.http.HttpResponse; import org.elasticsearch.test.rest.client.http.HttpResponse;
@ -30,8 +30,8 @@ public class CustomRealmIT extends ESIntegTestCase {
@Override @Override
protected Settings externalClusterClientSettings() { protected Settings externalClusterClientSettings() {
return Settings.builder() return Settings.builder()
.put(Headers.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER) .put(ThreadContext.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER)
.put(Headers.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW) .put(ThreadContext.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW)
.build(); .build();
} }
@ -64,8 +64,8 @@ public class CustomRealmIT extends ESIntegTestCase {
Settings settings = Settings.builder() Settings settings = Settings.builder()
.put("cluster.name", clusterName) .put("cluster.name", clusterName)
.put(Headers.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER) .put(ThreadContext.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER)
.put(Headers.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW) .put(ThreadContext.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW)
.build(); .build();
try (TransportClient client = TransportClient.builder().settings(settings).addPlugin(XPackPlugin.class).build()) { try (TransportClient client = TransportClient.builder().settings(settings).addPlugin(XPackPlugin.class).build()) {
client.addTransportAddress(publishAddress); client.addTransportAddress(publishAddress);
@ -83,8 +83,8 @@ public class CustomRealmIT extends ESIntegTestCase {
Settings settings = Settings.builder() Settings settings = Settings.builder()
.put("cluster.name", clusterName) .put("cluster.name", clusterName)
.put(Headers.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER + randomAsciiOfLength(1)) .put(ThreadContext.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER + randomAsciiOfLength(1))
.put(Headers.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW) .put(ThreadContext.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW)
.build(); .build();
try (TransportClient client = TransportClient.builder().addPlugin(XPackPlugin.class).settings(settings).build()) { try (TransportClient client = TransportClient.builder().addPlugin(XPackPlugin.class).settings(settings).build()) {
client.addTransportAddress(publishAddress); client.addTransportAddress(publishAddress);

View File

@ -8,9 +8,9 @@ package org.elasticsearch.smoketest;
import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.client.support.Headers;
import org.elasticsearch.common.io.PathUtils; import org.elasticsearch.common.io.PathUtils;
import org.elasticsearch.common.settings.Settings; 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.SecuredString;
import org.elasticsearch.test.rest.ESRestTestCase; import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.test.rest.RestTestCandidate; import org.elasticsearch.test.rest.RestTestCandidate;
@ -64,7 +64,7 @@ public class SmokeTestPluginsSslIT extends ESRestTestCase {
protected Settings restClientSettings() { protected Settings restClientSettings() {
String token = basicAuthHeaderValue(USER, new SecuredString(PASS.toCharArray())); String token = basicAuthHeaderValue(USER, new SecuredString(PASS.toCharArray()));
return Settings.builder() return Settings.builder()
.put(Headers.PREFIX + ".Authorization", token) .put(ThreadContext.PREFIX + ".Authorization", token)
.put(RestClient.PROTOCOL, "https") .put(RestClient.PROTOCOL, "https")
.put(RestClient.TRUSTSTORE_PATH, keyStore) .put(RestClient.TRUSTSTORE_PATH, keyStore)
.put(RestClient.TRUSTSTORE_PASSWORD, KEYSTORE_PASS) .put(RestClient.TRUSTSTORE_PASSWORD, KEYSTORE_PASS)

View File

@ -7,8 +7,8 @@ package org.elasticsearch.smoketest;
import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.client.support.Headers;
import org.elasticsearch.common.settings.Settings; 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.SecuredString;
import org.elasticsearch.test.rest.ESRestTestCase; import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.test.rest.RestTestCandidate; import org.elasticsearch.test.rest.RestTestCandidate;
@ -36,7 +36,7 @@ public class SmokeTestPluginsIT extends ESRestTestCase {
protected Settings restClientSettings() { protected Settings restClientSettings() {
String token = basicAuthHeaderValue(USER, new SecuredString(PASS.toCharArray())); String token = basicAuthHeaderValue(USER, new SecuredString(PASS.toCharArray()));
return Settings.builder() return Settings.builder()
.put(Headers.PREFIX + ".Authorization", token) .put(ThreadContext.PREFIX + ".Authorization", token)
.build(); .build();
} }
} }

View File

@ -15,8 +15,8 @@ import org.apache.http.client.methods.HttpPut;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.BasicHttpClientConnectionManager; import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
import org.elasticsearch.client.support.Headers;
import org.elasticsearch.common.settings.Settings; 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.SecuredString;
import org.elasticsearch.shield.authc.support.UsernamePasswordToken; import org.elasticsearch.shield.authc.support.UsernamePasswordToken;
import org.elasticsearch.test.rest.ESRestTestCase; import org.elasticsearch.test.rest.ESRestTestCase;
@ -67,7 +67,7 @@ public class WatcherWithShieldIT extends ESRestTestCase {
protected Settings restClientSettings() { protected Settings restClientSettings() {
String token = basicAuthHeaderValue("watcher_manager", new SecuredString("changeme".toCharArray())); String token = basicAuthHeaderValue("watcher_manager", new SecuredString("changeme".toCharArray()));
return Settings.builder() return Settings.builder()
.put(Headers.PREFIX + ".Authorization", token) .put(ThreadContext.PREFIX + ".Authorization", token)
.build(); .build();
} }
@ -75,7 +75,7 @@ public class WatcherWithShieldIT extends ESRestTestCase {
protected Settings restAdminSettings() { protected Settings restAdminSettings() {
String token = basicAuthHeaderValue(TEST_ADMIN_USERNAME, new SecuredString(TEST_ADMIN_PASSWORD.toCharArray())); String token = basicAuthHeaderValue(TEST_ADMIN_USERNAME, new SecuredString(TEST_ADMIN_PASSWORD.toCharArray()));
return Settings.builder() return Settings.builder()
.put(Headers.PREFIX + ".Authorization", token) .put(ThreadContext.PREFIX + ".Authorization", token)
.build(); .build();
} }
} }

View File

@ -23,7 +23,7 @@ public class RestDeleteLicenseAction extends BaseRestHandler {
@Inject @Inject
public RestDeleteLicenseAction(Settings settings, RestController controller, Client client) { public RestDeleteLicenseAction(Settings settings, RestController controller, Client client) {
super(settings, controller, client); super(settings, client);
controller.registerHandler(DELETE, "/_license", this); controller.registerHandler(DELETE, "/_license", this);
} }

View File

@ -32,7 +32,7 @@ public class RestGetLicenseAction extends BaseRestHandler {
@Inject @Inject
public RestGetLicenseAction(Settings settings, RestController controller, Client client) { public RestGetLicenseAction(Settings settings, RestController controller, Client client) {
super(settings, controller, client); super(settings, client);
controller.registerHandler(GET, "/_license", this); controller.registerHandler(GET, "/_license", this);
} }

View File

@ -29,7 +29,7 @@ public class RestPutLicenseAction extends BaseRestHandler {
@Inject @Inject
public RestPutLicenseAction(Settings settings, RestController controller, Client client) { public RestPutLicenseAction(Settings settings, RestController controller, Client client) {
super(settings, controller, client); super(settings, client);
controller.registerHandler(PUT, "/_license", this); controller.registerHandler(PUT, "/_license", this);
controller.registerHandler(POST, "/_license", this); controller.registerHandler(POST, "/_license", this);
} }

View File

@ -6,13 +6,13 @@
package org.elasticsearch.marvel.shield; package org.elasticsearch.marvel.shield;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.inject.Injector; import org.elasticsearch.common.inject.Injector;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.shield.ShieldPlugin; import org.elasticsearch.shield.ShieldPlugin;
import org.elasticsearch.shield.ShieldSettingsFilter; import org.elasticsearch.shield.ShieldSettingsFilter;
import org.elasticsearch.shield.authc.AuthenticationService; import org.elasticsearch.shield.authc.AuthenticationService;
import org.elasticsearch.transport.TransportMessage;
import java.io.IOException; import java.io.IOException;
@ -24,18 +24,24 @@ public class MarvelShieldIntegration {
private final boolean enabled; private final boolean enabled;
private final AuthenticationService authcService; private final AuthenticationService authcService;
private final ShieldSettingsFilter settingsFilter; private final ShieldSettingsFilter settingsFilter;
private final Client client;
@Inject @Inject
public MarvelShieldIntegration(Settings settings, Injector injector) { public MarvelShieldIntegration(Settings settings, Injector injector) {
enabled = enabled(settings); enabled = enabled(settings);
authcService = enabled ? injector.getInstance(AuthenticationService.class) : null; authcService = enabled ? injector.getInstance(AuthenticationService.class) : null;
settingsFilter = enabled ? injector.getInstance(ShieldSettingsFilter.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) { if (authcService != null) {
try { try {
authcService.attachUserHeaderIfMissing(message, InternalMarvelUser.INSTANCE); authcService.attachUserHeaderIfMissing(InternalMarvelUser.INSTANCE);
} catch (IOException e) { } catch (IOException e) {
throw new ElasticsearchException("failed to attach marvel user to request", e); throw new ElasticsearchException("failed to attach marvel user to request", e);
} }

View File

@ -13,6 +13,7 @@ import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.elasticsearch.client.FilterClient; import org.elasticsearch.client.FilterClient;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.util.concurrent.ThreadContext;
/** /**
* *
@ -29,8 +30,10 @@ public class SecuredClient extends FilterClient {
@Override @Override
protected <Request extends ActionRequest<Request>, Response extends ActionResponse, RequestBuilder extends ActionRequestBuilder<Request, Response, RequestBuilder>> void doExecute( protected <Request extends ActionRequest<Request>, Response extends ActionResponse, RequestBuilder extends ActionRequestBuilder<Request, Response, RequestBuilder>> void doExecute(
Action<Request, Response, RequestBuilder> action, Request request, ActionListener<Response> listener) { Action<Request, Response, RequestBuilder> action, Request request, ActionListener<Response> listener) {
this.shieldIntegration.bindInternalMarvelUser(request); try (ThreadContext.StoredContext ctx = threadPool().getThreadContext().stashContext()) {
super.doExecute(action, request, listener); this.shieldIntegration.bindInternalMarvelUser();
super.doExecute(action, request, listener);
}
} }
} }

View File

@ -66,12 +66,14 @@ public class AbstractCollectorTestCase extends MarvelIntegTestCase {
public SecuredClient securedClient() { public SecuredClient securedClient() {
MarvelShieldIntegration integration = internalCluster().getInstance(MarvelShieldIntegration.class); 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) { public SecuredClient securedClient(String nodeId) {
MarvelShieldIntegration integration = internalCluster().getInstance(MarvelShieldIntegration.class); MarvelShieldIntegration integration = internalCluster().getInstance(MarvelShieldIntegration.class, nodeId);
return new SecuredClient(client(nodeId), integration); // we must get the client from the same node!
return new SecuredClient(integration.getClient(), integration);
} }
protected void assertCanCollect(AbstractCollector collector) { protected void assertCanCollect(AbstractCollector collector) {

View File

@ -6,6 +6,8 @@
package org.elasticsearch.marvel.test; package org.elasticsearch.marvel.test;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.cluster.metadata.IndexTemplateMetaData; import org.elasticsearch.cluster.metadata.IndexTemplateMetaData;
import org.elasticsearch.common.Strings; import org.elasticsearch.common.Strings;
import org.elasticsearch.common.io.Streams; import org.elasticsearch.common.io.Streams;
@ -44,7 +46,9 @@ import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit; 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.assertAcked;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures;
import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.allOf;
@ -116,6 +120,16 @@ public abstract class MarvelIntegTestCase extends ESIntegTestCase {
return nodePlugins(); return nodePlugins();
} }
@Override
protected Function<Client,Client> getClientWrapper() {
if (shieldEnabled == false) {
return Function.identity();
}
Map<String, String> 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 * 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.remove("index.queries.cache.type");
builder.put("shield.enabled", true) builder.put("shield.enabled", true)
.put("shield.user", "test:changeme")
.put("shield.authc.realms.esusers.type", ESUsersRealm.TYPE) .put("shield.authc.realms.esusers.type", ESUsersRealm.TYPE)
.put("shield.authc.realms.esusers.order", 0) .put("shield.authc.realms.esusers.order", 0)
.put("shield.authc.realms.esusers.files.users", writeFile(folder, "users", USERS)) .put("shield.authc.realms.esusers.files.users", writeFile(folder, "users", USERS))

View File

@ -7,12 +7,12 @@ package org.elasticsearch.shield;
import org.elasticsearch.action.ActionModule; import org.elasticsearch.action.ActionModule;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.elasticsearch.client.support.Headers;
import org.elasticsearch.common.component.LifecycleComponent; import org.elasticsearch.common.component.LifecycleComponent;
import org.elasticsearch.common.inject.Module; import org.elasticsearch.common.inject.Module;
import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsModule; import org.elasticsearch.common.settings.SettingsModule;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.Environment; import org.elasticsearch.env.Environment;
import org.elasticsearch.index.IndexModule; import org.elasticsearch.index.IndexModule;
import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.Plugin;
@ -194,7 +194,8 @@ public class ShieldPlugin extends Plugin {
if (flsDlsEnabled(settings)) { if (flsDlsEnabled(settings)) {
module.setSearcherWrapper((indexService) -> new ShieldIndexSearcherWrapper(indexService.getIndexSettings(), module.setSearcherWrapper((indexService) -> new ShieldIndexSearcherWrapper(indexService.getIndexSettings(),
indexService.getQueryShardContext(), indexService.mapperService(), indexService.getQueryShardContext(), indexService.mapperService(),
indexService.cache().bitsetFilterCache(), shieldLicenseState)); indexService.cache().bitsetFilterCache(), indexService.getIndexServices().getThreadPool().getThreadContext(),
shieldLicenseState));
} }
if (clientMode == false) { if (clientMode == false) {
module.registerQueryCache(ShieldPlugin.OPT_OUT_QUERY_CACHE, OptOutQueryCache::new); module.registerQueryCache(ShieldPlugin.OPT_OUT_QUERY_CACHE, OptOutQueryCache::new);
@ -263,7 +264,7 @@ public class ShieldPlugin extends Plugin {
} }
private void addUserSettings(Settings.Builder settingsBuilder) { 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) { if (settings.get(authHeaderSettingName) != null) {
return; return;
} }

View File

@ -16,6 +16,7 @@ import org.elasticsearch.action.support.ActionFilterChain;
import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.license.plugin.core.LicenseUtils; import org.elasticsearch.license.plugin.core.LicenseUtils;
import org.elasticsearch.shield.ShieldPlugin; import org.elasticsearch.shield.ShieldPlugin;
import org.elasticsearch.shield.User; 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.authz.privilege.HealthAndStatsPrivilege;
import org.elasticsearch.shield.crypto.CryptoService; import org.elasticsearch.shield.crypto.CryptoService;
import org.elasticsearch.shield.license.ShieldLicenseState; 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.tasks.Task;
import org.elasticsearch.threadpool.ThreadPool;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
@ -42,6 +46,8 @@ import static org.elasticsearch.shield.support.Exceptions.authorizationError;
public class ShieldActionFilter extends AbstractComponent implements ActionFilter { public class ShieldActionFilter extends AbstractComponent implements ActionFilter {
private static final Predicate<String> LICENSE_EXPIRATION_ACTION_MATCHER = HealthAndStatsPrivilege.INSTANCE.predicate(); private static final Predicate<String> LICENSE_EXPIRATION_ACTION_MATCHER = HealthAndStatsPrivilege.INSTANCE.predicate();
// FIXME clean up this hack
static final Predicate<String> INTERNAL_PREDICATE = new AutomatonPredicate(Automatons.patterns("internal:*"));
private final AuthenticationService authcService; private final AuthenticationService authcService;
private final AuthorizationService authzService; private final AuthorizationService authzService;
@ -50,10 +56,12 @@ public class ShieldActionFilter extends AbstractComponent implements ActionFilte
private final ShieldActionMapper actionMapper; private final ShieldActionMapper actionMapper;
private final Set<RequestInterceptor> requestInterceptors; private final Set<RequestInterceptor> requestInterceptors;
private final ShieldLicenseState licenseState; private final ShieldLicenseState licenseState;
private final ThreadContext threadContext;
@Inject @Inject
public ShieldActionFilter(Settings settings, AuthenticationService authcService, AuthorizationService authzService, CryptoService cryptoService, public ShieldActionFilter(Settings settings, AuthenticationService authcService, AuthorizationService authzService, CryptoService cryptoService,
AuditTrail auditTrail, ShieldLicenseState licenseState, ShieldActionMapper actionMapper, Set<RequestInterceptor> requestInterceptors) { AuditTrail auditTrail, ShieldLicenseState licenseState, ShieldActionMapper actionMapper, Set<RequestInterceptor> requestInterceptors,
ThreadPool threadPool) {
super(settings); super(settings);
this.authcService = authcService; this.authcService = authcService;
this.authzService = authzService; this.authzService = authzService;
@ -62,6 +70,7 @@ public class ShieldActionFilter extends AbstractComponent implements ActionFilte
this.actionMapper = actionMapper; this.actionMapper = actionMapper;
this.licenseState = licenseState; this.licenseState = licenseState;
this.requestInterceptors = requestInterceptors; this.requestInterceptors = requestInterceptors;
this.threadContext = threadPool.getThreadContext();
} }
@Override @Override
@ -78,8 +87,56 @@ public class ShieldActionFilter extends AbstractComponent implements ActionFilte
throw LicenseUtils.newComplianceException(ShieldPlugin.NAME); throw LicenseUtils.newComplianceException(ShieldPlugin.NAME);
} }
try { try (ThreadContext.StoredContext original = threadContext.newStoredContext()) {
if (licenseState.securityEnabled()) { 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 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 the system itself (e.g. pings, update mappings, share relocation, etc...) and were not originated

View File

@ -27,7 +27,7 @@ public class RestAddRoleAction extends BaseRestHandler {
@Inject @Inject
public RestAddRoleAction(Settings settings, RestController controller, Client client) { 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.POST, "/_shield/role/{role}", this);
controller.registerHandler(RestRequest.Method.PUT, "/_shield/role/{role}", this); controller.registerHandler(RestRequest.Method.PUT, "/_shield/role/{role}", this);
} }

View File

@ -26,7 +26,7 @@ public class RestDeleteRoleAction extends BaseRestHandler {
@Inject @Inject
public RestDeleteRoleAction(Settings settings, RestController controller, Client client) { public RestDeleteRoleAction(Settings settings, RestController controller, Client client) {
super(settings, controller, client); super(settings, client);
controller.registerHandler(RestRequest.Method.DELETE, "/_shield/role/{role}", this); controller.registerHandler(RestRequest.Method.DELETE, "/_shield/role/{role}", this);
} }

View File

@ -28,7 +28,7 @@ public class RestGetRolesAction extends BaseRestHandler {
@Inject @Inject
public RestGetRolesAction(Settings settings, RestController controller, Client client) { 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/", this);
controller.registerHandler(RestRequest.Method.GET, "/_shield/role/{roles}", this); controller.registerHandler(RestRequest.Method.GET, "/_shield/role/{roles}", this);
controller.registerHandler(RestRequest.Method.GET, "/_shield/roles/", this); controller.registerHandler(RestRequest.Method.GET, "/_shield/roles/", this);

View File

@ -30,7 +30,7 @@ public class RestAddUserAction extends BaseRestHandler {
@Inject @Inject
public RestAddUserAction(Settings settings, RestController controller, Client client) { 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.POST, "/_shield/user/{username}", this);
controller.registerHandler(RestRequest.Method.PUT, "/_shield/user/{username}", this); controller.registerHandler(RestRequest.Method.PUT, "/_shield/user/{username}", this);
} }

View File

@ -30,7 +30,7 @@ public class RestDeleteUserAction extends BaseRestHandler {
@Inject @Inject
public RestDeleteUserAction(Settings settings, RestController controller, Client client) { public RestDeleteUserAction(Settings settings, RestController controller, Client client) {
super(settings, controller, client); super(settings, client);
controller.registerHandler(RestRequest.Method.DELETE, "/_shield/user/{username}", this); controller.registerHandler(RestRequest.Method.DELETE, "/_shield/user/{username}", this);
} }

View File

@ -29,7 +29,7 @@ public class RestGetUsersAction extends BaseRestHandler {
@Inject @Inject
public RestGetUsersAction(Settings settings, RestController controller, Client client) { 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/", this);
controller.registerHandler(RestRequest.Method.GET, "/_shield/user/{user}", this); controller.registerHandler(RestRequest.Method.GET, "/_shield/user/{user}", this);
controller.registerHandler(RestRequest.Method.GET, "/_shield/users/", this); controller.registerHandler(RestRequest.Method.GET, "/_shield/users/", this);

View File

@ -93,7 +93,7 @@ public class ClearRealmCacheRequest extends BaseNodesRequest<ClearRealmCacheRequ
} }
Node(ClearRealmCacheRequest request, String nodeId) { Node(ClearRealmCacheRequest request, String nodeId) {
super(request, nodeId); super(nodeId);
this.realms = request.realms; this.realms = request.realms;
this.usernames = request.usernames; this.usernames = request.usernames;
} }

View File

@ -55,7 +55,7 @@ public class ClearRolesCacheRequest extends BaseNodesRequest<ClearRolesCacheRequ
} }
public Node(ClearRolesCacheRequest request, String nodeId) { public Node(ClearRolesCacheRequest request, String nodeId) {
super(request, nodeId); super(nodeId);
this.roles = request.roles(); this.roles = request.roles();
} }

View File

@ -12,10 +12,12 @@ import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.rest.RestStatus; import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.shield.User; import org.elasticsearch.shield.User;
import org.elasticsearch.shield.authz.InternalAuthorizationService; import org.elasticsearch.shield.authz.InternalAuthorizationService;
import org.elasticsearch.shield.authz.accesscontrol.IndicesAccessControl; import org.elasticsearch.shield.authz.accesscontrol.IndicesAccessControl;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportRequest; import org.elasticsearch.transport.TransportRequest;
/** /**
@ -23,13 +25,16 @@ import org.elasticsearch.transport.TransportRequest;
*/ */
public class BulkRequestInterceptor extends AbstractComponent implements RequestInterceptor<BulkRequest> { public class BulkRequestInterceptor extends AbstractComponent implements RequestInterceptor<BulkRequest> {
private final ThreadContext threadContext;
@Inject @Inject
public BulkRequestInterceptor(Settings settings) { public BulkRequestInterceptor(Settings settings, ThreadPool threadPool) {
super(settings); super(settings);
this.threadContext = threadPool.getThreadContext();
} }
public void intercept(BulkRequest request, User user) { 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 (IndicesRequest indicesRequest : request.subRequests()) {
for (String index : indicesRequest.indices()) { for (String index : indicesRequest.indices()) {
IndicesAccessControl.IndexAccessControl indexAccessControl = indicesAccessControl.getIndexPermissions(index); IndicesAccessControl.IndexAccessControl indexAccessControl = indicesAccessControl.getIndexPermissions(index);

View File

@ -10,6 +10,7 @@ import org.elasticsearch.action.IndicesRequest;
import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.logging.support.LoggerMessageFormat; import org.elasticsearch.common.logging.support.LoggerMessageFormat;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.shield.User; import org.elasticsearch.shield.User;
import org.elasticsearch.shield.authz.InternalAuthorizationService; import org.elasticsearch.shield.authz.InternalAuthorizationService;
import org.elasticsearch.shield.authz.accesscontrol.IndicesAccessControl; import org.elasticsearch.shield.authz.accesscontrol.IndicesAccessControl;
@ -24,8 +25,11 @@ import java.util.List;
*/ */
public abstract class FieldAndDocumentLevelSecurityRequestInterceptor<Request> extends AbstractComponent implements RequestInterceptor<Request> { public abstract class FieldAndDocumentLevelSecurityRequestInterceptor<Request> extends AbstractComponent implements RequestInterceptor<Request> {
public FieldAndDocumentLevelSecurityRequestInterceptor(Settings settings) { private final ThreadContext threadContext;
public FieldAndDocumentLevelSecurityRequestInterceptor(Settings settings, ThreadContext threadContext) {
super(settings); super(settings);
this.threadContext = threadContext;
} }
public void intercept(Request request, User user) { public void intercept(Request request, User user) {
@ -37,7 +41,7 @@ public abstract class FieldAndDocumentLevelSecurityRequestInterceptor<Request> e
} else { } else {
throw new IllegalArgumentException(LoggerMessageFormat.format("Expected a request of type [{}] or [{}] but got [{}] instead", CompositeIndicesRequest.class, IndicesRequest.class, request.getClass())); 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 (IndicesRequest indicesRequest : indicesRequests) {
for (String index : indicesRequest.indices()) { for (String index : indicesRequest.indices()) {
IndicesAccessControl.IndexAccessControl indexAccessControl = indicesAccessControl.getIndexPermissions(index); IndicesAccessControl.IndexAccessControl indexAccessControl = indicesAccessControl.getIndexPermissions(index);

View File

@ -8,6 +8,7 @@ package org.elasticsearch.shield.action.interceptor;
import org.elasticsearch.action.RealtimeRequest; import org.elasticsearch.action.RealtimeRequest;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportRequest; import org.elasticsearch.transport.TransportRequest;
/** /**
@ -17,8 +18,8 @@ import org.elasticsearch.transport.TransportRequest;
public class RealtimeRequestInterceptor extends FieldAndDocumentLevelSecurityRequestInterceptor<RealtimeRequest> { public class RealtimeRequestInterceptor extends FieldAndDocumentLevelSecurityRequestInterceptor<RealtimeRequest> {
@Inject @Inject
public RealtimeRequestInterceptor(Settings settings) { public RealtimeRequestInterceptor(Settings settings, ThreadPool threadPool) {
super(settings); super(settings, threadPool.getThreadContext());
} }
@Override @Override

View File

@ -8,6 +8,7 @@ package org.elasticsearch.shield.action.interceptor;
import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportRequest; import org.elasticsearch.transport.TransportRequest;
/** /**
@ -16,8 +17,8 @@ import org.elasticsearch.transport.TransportRequest;
public class SearchRequestInterceptor extends FieldAndDocumentLevelSecurityRequestInterceptor<SearchRequest> { public class SearchRequestInterceptor extends FieldAndDocumentLevelSecurityRequestInterceptor<SearchRequest> {
@Inject @Inject
public SearchRequestInterceptor(Settings settings) { public SearchRequestInterceptor(Settings settings, ThreadPool threadPool) {
super(settings); super(settings, threadPool.getThreadContext());
} }
@Override @Override

View File

@ -10,6 +10,7 @@ import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.rest.RestStatus; import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportRequest; import org.elasticsearch.transport.TransportRequest;
/** /**
@ -22,8 +23,8 @@ import org.elasticsearch.transport.TransportRequest;
public class UpdateRequestInterceptor extends FieldAndDocumentLevelSecurityRequestInterceptor<UpdateRequest> { public class UpdateRequestInterceptor extends FieldAndDocumentLevelSecurityRequestInterceptor<UpdateRequest> {
@Inject @Inject
public UpdateRequestInterceptor(Settings settings) { public UpdateRequestInterceptor(Settings settings, ThreadPool threadPool) {
super(settings); super(settings, threadPool.getThreadContext());
} }
@Override @Override

View File

@ -6,9 +6,15 @@
package org.elasticsearch.shield.admin; package org.elasticsearch.shield.admin;
import org.elasticsearch.ElasticsearchException; 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.PutIndexTemplateRequest;
import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateResponse; import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateResponse;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.elasticsearch.client.FilterClient;
import org.elasticsearch.cluster.ClusterChangedEvent; import org.elasticsearch.cluster.ClusterChangedEvent;
import org.elasticsearch.cluster.ClusterService; import org.elasticsearch.cluster.ClusterService;
import org.elasticsearch.cluster.ClusterState; 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.io.Streams;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.AbstractRunnable; import org.elasticsearch.common.util.concurrent.AbstractRunnable;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.gateway.GatewayService; import org.elasticsearch.gateway.GatewayService;
import org.elasticsearch.shield.authc.AuthenticationService; import org.elasticsearch.shield.authc.AuthenticationService;
import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.threadpool.ThreadPool;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@ -58,8 +66,7 @@ public class ShieldTemplateService extends AbstractComponent implements ClusterS
} }
private void createShieldTemplate() { private void createShieldTemplate() {
Client client = this.clientProvider.get(); final Client client = getClient();
AuthenticationService authService = this.authProvider.get();
try (InputStream is = getClass().getResourceAsStream("/" + SHIELD_TEMPLATE_NAME + ".json")) { try (InputStream is = getClass().getResourceAsStream("/" + SHIELD_TEMPLATE_NAME + ".json")) {
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
Streams.copy(is, out); Streams.copy(is, out);
@ -67,7 +74,6 @@ public class ShieldTemplateService extends AbstractComponent implements ClusterS
logger.info("--> putting the shield index template"); logger.info("--> putting the shield index template");
PutIndexTemplateRequest putTemplateRequest = client.admin().indices() PutIndexTemplateRequest putTemplateRequest = client.admin().indices()
.preparePutTemplate(SHIELD_TEMPLATE_NAME).setSource(template).request(); .preparePutTemplate(SHIELD_TEMPLATE_NAME).setSource(template).request();
authService.attachUserHeaderIfMissing(putTemplateRequest, adminUser.user());
PutIndexTemplateResponse templateResponse = client.admin().indices().putTemplate(putTemplateRequest).get(); PutIndexTemplateResponse templateResponse = client.admin().indices().putTemplate(putTemplateRequest).get();
if (templateResponse.isAcknowledged() == false) { if (templateResponse.isAcknowledged() == false) {
throw new ElasticsearchException("adding template for shield admin index was not acknowledged"); 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 <Request extends ActionRequest<Request>, Response extends ActionResponse, RequestBuilder extends ActionRequestBuilder<Request, Response, RequestBuilder>> void doExecute(Action<Request, Response, RequestBuilder> action, Request request, ActionListener<Response> 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 @Override
public void clusterChanged(ClusterChangedEvent event) { public void clusterChanged(ClusterChangedEvent event) {
if (event.state().blocks().hasGlobalBlock(GatewayService.STATE_NOT_RECOVERED_BLOCK)) { if (event.state().blocks().hasGlobalBlock(GatewayService.STATE_NOT_RECOVERED_BLOCK)) {

View File

@ -6,6 +6,11 @@
package org.elasticsearch.shield.audit.index; package org.elasticsearch.shield.audit.index;
import org.elasticsearch.ElasticsearchException; 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.cluster.state.ClusterStateResponse;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsRequest; import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsRequest;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; 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.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.elasticsearch.client.FilterClient;
import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.cluster.ClusterChangedEvent; import org.elasticsearch.cluster.ClusterChangedEvent;
import org.elasticsearch.cluster.ClusterService; 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.unit.TimeValue;
import org.elasticsearch.common.util.concurrent.AbstractRunnable; import org.elasticsearch.common.util.concurrent.AbstractRunnable;
import org.elasticsearch.common.util.concurrent.EsExecutors; 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.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentBuilderString; import org.elasticsearch.common.xcontent.XContentBuilderString;
import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentFactory;
@ -525,7 +532,7 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail, Cl
Message msg = new Message().start(); Message msg = new Message().start();
common("transport", type, msg.builder); common("transport", type, msg.builder);
originAttributes(message, msg.builder, transport); originAttributes(message, msg.builder, transport, threadPool.getThreadContext());
if (action != null) { if (action != null) {
msg.builder.field(Field.ACTION, action); msg.builder.field(Field.ACTION, action);
@ -557,7 +564,7 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail, Cl
Message msg = new Message().start(); Message msg = new Message().start();
common("transport", type, msg.builder); common("transport", type, msg.builder);
originAttributes(message, msg.builder, transport); originAttributes(message, msg.builder, transport, threadPool.getThreadContext());
if (action != null) { if (action != null) {
msg.builder.field(Field.ACTION, action); msg.builder.field(Field.ACTION, action);
@ -631,10 +638,10 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail, Cl
return builder; 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 // first checking if the message originated in a rest call
InetSocketAddress restAddress = RemoteHostHeader.restRemoteAddress(message); InetSocketAddress restAddress = RemoteHostHeader.restRemoteAddress(threadContext);
if (restAddress != null) { if (restAddress != null) {
builder.field(Field.ORIGIN_TYPE, "rest"); builder.field(Field.ORIGIN_TYPE, "rest");
builder.field(Field.ORIGIN_ADDRESS, NetworkAddress.formatAddress(restAddress.getAddress())); builder.field(Field.ORIGIN_ADDRESS, NetworkAddress.formatAddress(restAddress.getAddress()));
@ -677,7 +684,20 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail, Cl
private void initializeClient() { private void initializeClient() {
if (indexToRemoteCluster == false) { if (indexToRemoteCluster == false) {
// in the absence of client settings for remote indexing, fall back to the client that was passed in. // 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 <Request extends ActionRequest<Request>, Response extends ActionResponse, RequestBuilder extends ActionRequestBuilder<Request, Response, RequestBuilder>> void doExecute(Action<Request, Response, RequestBuilder> action, Request request, ActionListener<Response> 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 { } else {
Settings clientSettings = settings.getByPrefix("shield.audit.index.client."); Settings clientSettings = settings.getByPrefix("shield.audit.index.client.");
String[] hosts = clientSettings.getAsArray("hosts"); 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!!!"; assert !Thread.currentThread().isInterrupted() : "current thread has been interrupted before putting index template!!!";
if (!indexToRemoteCluster) { if (!indexToRemoteCluster) {
authenticationService.attachUserHeaderIfMissing(request, auditUser.user()); authenticationService.attachUserHeaderIfMissing(auditUser.user());
} }
PutIndexTemplateResponse response = client.admin().indices().putTemplate(request).actionGet(); PutIndexTemplateResponse response = client.admin().indices().putTemplate(request).actionGet();
if (!response.isAcknowledged()) { if (!response.isAcknowledged()) {
@ -780,18 +800,10 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail, Cl
} }
String index = resolve(INDEX_NAME_PREFIX, dateTime, rollover); String index = resolve(INDEX_NAME_PREFIX, dateTime, rollover);
IndicesExistsRequest existsRequest = new IndicesExistsRequest(index); 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()) { if (client.admin().indices().exists(existsRequest).get().isExists()) {
logger.debug("index [{}] exists so we need to update mappings", index); 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)); 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(); PutMappingResponse putMappingResponse = client.admin().indices().putMapping(putMappingRequest).get();
if (!putMappingResponse.isAcknowledged()) { if (!putMappingResponse.isAcknowledged()) {
throw new IllegalStateException("failed to put mappings for audit logging index [" + index + "]"); 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() { bulkProcessor = BulkProcessor.builder(client, new BulkProcessor.Listener() {
@Override @Override
public void beforeBulk(long executionId, BulkRequest request) { 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);
}
}
@Override @Override
public void afterBulk(long executionId, BulkRequest request, BulkResponse response) { 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() IndexRequest indexRequest = client.prepareIndex()
.setIndex(resolve(INDEX_NAME_PREFIX, message.timestamp, rollover)) .setIndex(resolve(INDEX_NAME_PREFIX, message.timestamp, rollover))
.setType(DOC_TYPE).setSource(message.builder).request(); .setType(DOC_TYPE).setSource(message.builder).request();
if (!indexToRemoteCluster) {
authenticationService.attachUserHeaderIfMissing(indexRequest, auditUser.user());
}
bulkProcessor.add(indexRequest); bulkProcessor.add(indexRequest);
} catch (InterruptedException e) { } catch (InterruptedException e) {
logger.debug("index audit queue consumer interrupted", e); logger.debug("index audit queue consumer interrupted", e);

View File

@ -15,6 +15,7 @@ import org.elasticsearch.common.network.NetworkAddress;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.shield.User; import org.elasticsearch.shield.User;
import org.elasticsearch.shield.admin.ShieldInternalUserHolder; 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.authz.privilege.SystemPrivilege;
import org.elasticsearch.shield.rest.RemoteHostHeader; import org.elasticsearch.shield.rest.RemoteHostHeader;
import org.elasticsearch.shield.transport.filter.ShieldIpFilterRule; import org.elasticsearch.shield.transport.filter.ShieldIpFilterRule;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.Transport; import org.elasticsearch.transport.Transport;
import org.elasticsearch.transport.TransportMessage; import org.elasticsearch.transport.TransportMessage;
@ -44,6 +46,7 @@ public class LoggingAuditTrail extends AbstractLifecycleComponent<LoggingAuditTr
private final ESLogger logger; private final ESLogger logger;
private final Transport transport; private final Transport transport;
private final ThreadContext threadContext;
private String prefix; private String prefix;
@ -53,19 +56,20 @@ public class LoggingAuditTrail extends AbstractLifecycleComponent<LoggingAuditTr
} }
@Inject @Inject
public LoggingAuditTrail(Settings settings, Transport transport) { public LoggingAuditTrail(Settings settings, Transport transport, ThreadPool threadPool) {
this(settings, transport, Loggers.getLogger(LoggingAuditTrail.class)); this(settings, transport, Loggers.getLogger(LoggingAuditTrail.class), threadPool.getThreadContext());
} }
LoggingAuditTrail(Settings settings, Transport transport, ESLogger logger) { LoggingAuditTrail(Settings settings, Transport transport, ESLogger logger, ThreadContext threadContext) {
this("", settings, transport, logger); this("", settings, transport, logger, threadContext);
} }
LoggingAuditTrail(String prefix, Settings settings, Transport transport, ESLogger logger) { LoggingAuditTrail(String prefix, Settings settings, Transport transport, ESLogger logger, ThreadContext threadContext) {
super(settings); super(settings);
this.logger = logger; this.logger = logger;
this.prefix = prefix; this.prefix = prefix;
this.transport = transport; this.transport = transport;
this.threadContext = threadContext;
} }
@ -96,15 +100,15 @@ public class LoggingAuditTrail extends AbstractLifecycleComponent<LoggingAuditTr
String indices = indicesString(message); String indices = indicesString(message);
if (indices != null) { if (indices != null) {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("{}[transport] [anonymous_access_denied]\t{}, action=[{}], indices=[{}], request=[{}]", prefix, originAttributes(message, transport), action, indices, message.getClass().getSimpleName()); logger.debug("{}[transport] [anonymous_access_denied]\t{}, action=[{}], indices=[{}], request=[{}]", prefix, originAttributes(message, transport, threadContext), action, indices, message.getClass().getSimpleName());
} else { } else {
logger.warn("{}[transport] [anonymous_access_denied]\t{}, action=[{}], indices=[{}]", prefix, originAttributes(message, transport), action, indices); logger.warn("{}[transport] [anonymous_access_denied]\t{}, action=[{}], indices=[{}]", prefix, originAttributes(message, transport, threadContext), action, indices);
} }
} else { } else {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("{}[transport] [anonymous_access_denied]\t{}, action=[{}], request=[{}]", prefix, originAttributes(message, transport), action, message.getClass().getSimpleName()); logger.debug("{}[transport] [anonymous_access_denied]\t{}, action=[{}], request=[{}]", prefix, originAttributes(message, transport, threadContext), action, message.getClass().getSimpleName());
} else { } else {
logger.warn("{}[transport] [anonymous_access_denied]\t{}, action=[{}]", prefix, originAttributes(message, transport), action); logger.warn("{}[transport] [anonymous_access_denied]\t{}, action=[{}]", prefix, originAttributes(message, transport, threadContext), action);
} }
} }
} }
@ -123,15 +127,15 @@ public class LoggingAuditTrail extends AbstractLifecycleComponent<LoggingAuditTr
String indices = indicesString(message); String indices = indicesString(message);
if (indices != null) { if (indices != null) {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("{}[transport] [authentication_failed]\t{}, principal=[{}], action=[{}], indices=[{}], request=[{}]", prefix, originAttributes(message, transport), token.principal(), action, indices, message.getClass().getSimpleName()); logger.debug("{}[transport] [authentication_failed]\t{}, principal=[{}], action=[{}], indices=[{}], request=[{}]", prefix, originAttributes(message, transport, threadContext), token.principal(), action, indices, message.getClass().getSimpleName());
} else { } else {
logger.error("{}[transport] [authentication_failed]\t{}, principal=[{}], action=[{}], indices=[{}]", prefix, originAttributes(message, transport), token.principal(), action, indices); logger.error("{}[transport] [authentication_failed]\t{}, principal=[{}], action=[{}], indices=[{}]", prefix, originAttributes(message, transport, threadContext), token.principal(), action, indices);
} }
} else { } else {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("{}[transport] [authentication_failed]\t{}, principal=[{}], action=[{}], request=[{}]", prefix, originAttributes(message, transport), token.principal(), action, message.getClass().getSimpleName()); logger.debug("{}[transport] [authentication_failed]\t{}, principal=[{}], action=[{}], request=[{}]", prefix, originAttributes(message, transport, threadContext), token.principal(), action, message.getClass().getSimpleName());
} else { } else {
logger.error("{}[transport] [authentication_failed]\t{}, principal=[{}], action=[{}]", prefix, originAttributes(message, transport), token.principal(), action); logger.error("{}[transport] [authentication_failed]\t{}, principal=[{}], action=[{}]", prefix, originAttributes(message, transport, threadContext), token.principal(), action);
} }
} }
} }
@ -150,15 +154,15 @@ public class LoggingAuditTrail extends AbstractLifecycleComponent<LoggingAuditTr
String indices = indicesString(message); String indices = indicesString(message);
if (indices != null) { if (indices != null) {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("{}[transport] [authentication_failed]\t{}, action=[{}], indices=[{}], request=[{}]", prefix, originAttributes(message, transport), action, indices, message.getClass().getSimpleName()); logger.debug("{}[transport] [authentication_failed]\t{}, action=[{}], indices=[{}], request=[{}]", prefix, originAttributes(message, transport, threadContext), action, indices, message.getClass().getSimpleName());
} else { } else {
logger.error("{}[transport] [authentication_failed]\t{}, action=[{}], indices=[{}]", prefix, originAttributes(message, transport), action, indices); logger.error("{}[transport] [authentication_failed]\t{}, action=[{}], indices=[{}]", prefix, originAttributes(message, transport, threadContext), action, indices);
} }
} else { } else {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("{}[transport] [authentication_failed]\t{}, action=[{}], request=[{}]", prefix, originAttributes(message, transport), action, message.getClass().getSimpleName()); logger.debug("{}[transport] [authentication_failed]\t{}, action=[{}], request=[{}]", prefix, originAttributes(message, transport, threadContext), action, message.getClass().getSimpleName());
} else { } else {
logger.error("{}[transport] [authentication_failed]\t{}, action=[{}]", prefix, originAttributes(message, transport), action); logger.error("{}[transport] [authentication_failed]\t{}, action=[{}]", prefix, originAttributes(message, transport, threadContext), action);
} }
} }
} }
@ -177,9 +181,9 @@ public class LoggingAuditTrail extends AbstractLifecycleComponent<LoggingAuditTr
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
String indices = indicesString(message); String indices = indicesString(message);
if (indices != null) { if (indices != null) {
logger.trace("{}[transport] [authentication_failed]\trealm=[{}], {}, principal=[{}], action=[{}], indices=[{}], request=[{}]", prefix, realm, originAttributes(message, transport), token.principal(), action, indices, message.getClass().getSimpleName()); logger.trace("{}[transport] [authentication_failed]\trealm=[{}], {}, principal=[{}], action=[{}], indices=[{}], request=[{}]", prefix, realm, originAttributes(message, transport, threadContext), token.principal(), action, indices, message.getClass().getSimpleName());
} else { } else {
logger.trace("{}[transport] [authentication_failed]\trealm=[{}], {}, principal=[{}], action=[{}], request=[{}]", prefix, realm, originAttributes(message, transport), token.principal(), action, message.getClass().getSimpleName()); logger.trace("{}[transport] [authentication_failed]\trealm=[{}], {}, principal=[{}], action=[{}], request=[{}]", prefix, realm, originAttributes(message, transport, threadContext), token.principal(), action, message.getClass().getSimpleName());
} }
} }
} }
@ -199,9 +203,9 @@ public class LoggingAuditTrail extends AbstractLifecycleComponent<LoggingAuditTr
if ((user.isSystem() && SystemPrivilege.INSTANCE.predicate().test(action)) || ShieldInternalUserHolder.isShieldInternalUser(user)) { if ((user.isSystem() && SystemPrivilege.INSTANCE.predicate().test(action)) || ShieldInternalUserHolder.isShieldInternalUser(user)) {
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
if (indices != null) { if (indices != null) {
logger.trace("{}[transport] [access_granted]\t{}, {}, action=[{}], indices=[{}], request=[{}]", prefix, originAttributes(message, transport), principal(user), action, indices, message.getClass().getSimpleName()); logger.trace("{}[transport] [access_granted]\t{}, {}, action=[{}], indices=[{}], request=[{}]", prefix, originAttributes(message, transport, threadContext), principal(user), action, indices, message.getClass().getSimpleName());
} else { } else {
logger.trace("{}[transport] [access_granted]\t{}, {}, action=[{}], request=[{}]", prefix, originAttributes(message, transport), principal(user), action, message.getClass().getSimpleName()); logger.trace("{}[transport] [access_granted]\t{}, {}, action=[{}], request=[{}]", prefix, originAttributes(message, transport, threadContext), principal(user), action, message.getClass().getSimpleName());
} }
} }
return; return;
@ -209,15 +213,15 @@ public class LoggingAuditTrail extends AbstractLifecycleComponent<LoggingAuditTr
if (indices != null) { if (indices != null) {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("{}[transport] [access_granted]\t{}, {}, action=[{}], indices=[{}], request=[{}]", prefix, originAttributes(message, transport), principal(user), action, indices, message.getClass().getSimpleName()); logger.debug("{}[transport] [access_granted]\t{}, {}, action=[{}], indices=[{}], request=[{}]", prefix, originAttributes(message, transport, threadContext), principal(user), action, indices, message.getClass().getSimpleName());
} else { } else {
logger.info("{}[transport] [access_granted]\t{}, {}, action=[{}], indices=[{}]", prefix, originAttributes(message, transport), principal(user), action, indices); logger.info("{}[transport] [access_granted]\t{}, {}, action=[{}], indices=[{}]", prefix, originAttributes(message, transport, threadContext), principal(user), action, indices);
} }
} else { } else {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("{}[transport] [access_granted]\t{}, {}, action=[{}], request=[{}]", prefix, originAttributes(message, transport), principal(user), action, message.getClass().getSimpleName()); logger.debug("{}[transport] [access_granted]\t{}, {}, action=[{}], request=[{}]", prefix, originAttributes(message, transport, threadContext), principal(user), action, message.getClass().getSimpleName());
} else { } else {
logger.info("{}[transport] [access_granted]\t{}, {}, action=[{}]", prefix, originAttributes(message, transport), principal(user), action); logger.info("{}[transport] [access_granted]\t{}, {}, action=[{}]", prefix, originAttributes(message, transport, threadContext), principal(user), action);
} }
} }
} }
@ -227,15 +231,15 @@ public class LoggingAuditTrail extends AbstractLifecycleComponent<LoggingAuditTr
String indices = indicesString(message); String indices = indicesString(message);
if (indices != null) { if (indices != null) {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("{}[transport] [access_denied]\t{}, {}, action=[{}], indices=[{}], request=[{}]", prefix, originAttributes(message, transport), principal(user), action, indices, message.getClass().getSimpleName()); logger.debug("{}[transport] [access_denied]\t{}, {}, action=[{}], indices=[{}], request=[{}]", prefix, originAttributes(message, transport, threadContext), principal(user), action, indices, message.getClass().getSimpleName());
} else { } else {
logger.error("{}[transport] [access_denied]\t{}, {}, action=[{}], indices=[{}]", prefix, originAttributes(message, transport), principal(user), action, indices); logger.error("{}[transport] [access_denied]\t{}, {}, action=[{}], indices=[{}]", prefix, originAttributes(message, transport, threadContext), principal(user), action, indices);
} }
} else { } else {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("{}[transport] [access_denied]\t{}, {}, action=[{}], request=[{}]", prefix, originAttributes(message, transport), principal(user), action, message.getClass().getSimpleName()); logger.debug("{}[transport] [access_denied]\t{}, {}, action=[{}], request=[{}]", prefix, originAttributes(message, transport, threadContext), principal(user), action, message.getClass().getSimpleName());
} else { } else {
logger.error("{}[transport] [access_denied]\t{}, {}, action=[{}]", prefix, originAttributes(message, transport), principal(user), action); logger.error("{}[transport] [access_denied]\t{}, {}, action=[{}]", prefix, originAttributes(message, transport, threadContext), principal(user), action);
} }
} }
} }
@ -245,15 +249,15 @@ public class LoggingAuditTrail extends AbstractLifecycleComponent<LoggingAuditTr
String indices = indicesString(message); String indices = indicesString(message);
if (indices != null) { if (indices != null) {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("{}[transport] [tampered_request]\t{}, action=[{}], indices=[{}], request=[{}]", prefix, originAttributes(message, transport), action, indices, message.getClass().getSimpleName()); logger.debug("{}[transport] [tampered_request]\t{}, action=[{}], indices=[{}], request=[{}]", prefix, originAttributes(message, transport, threadContext), action, indices, message.getClass().getSimpleName());
} else { } else {
logger.error("{}[transport] [tampered_request]\t{}, action=[{}], indices=[{}]", prefix, originAttributes(message, transport), action, indices); logger.error("{}[transport] [tampered_request]\t{}, action=[{}], indices=[{}]", prefix, originAttributes(message, transport, threadContext), action, indices);
} }
} else { } else {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("{}[transport] [tampered_request]\t{}, action=[{}], request=[{}]", prefix, originAttributes(message, transport), action, message.getClass().getSimpleName()); logger.debug("{}[transport] [tampered_request]\t{}, action=[{}], request=[{}]", prefix, originAttributes(message, transport, threadContext), action, message.getClass().getSimpleName());
} else { } else {
logger.error("{}[transport] [tampered_request]\t{}, action=[{}]", prefix, originAttributes(message, transport), action); logger.error("{}[transport] [tampered_request]\t{}, action=[{}]", prefix, originAttributes(message, transport, threadContext), action);
} }
} }
} }
@ -263,15 +267,15 @@ public class LoggingAuditTrail extends AbstractLifecycleComponent<LoggingAuditTr
String indices = indicesString(request); String indices = indicesString(request);
if (indices != null) { if (indices != null) {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("{}[transport] [tampered_request]\t{}, {}, action=[{}], indices=[{}], request=[{}]", prefix, originAttributes(request, transport), principal(user), action, indices, request.getClass().getSimpleName()); logger.debug("{}[transport] [tampered_request]\t{}, {}, action=[{}], indices=[{}], request=[{}]", prefix, originAttributes(request, transport, threadContext), principal(user), action, indices, request.getClass().getSimpleName());
} else { } else {
logger.error("{}[transport] [tampered_request]\t{}, {}, action=[{}], indices=[{}]", prefix, originAttributes(request, transport), principal(user), action, indices); logger.error("{}[transport] [tampered_request]\t{}, {}, action=[{}], indices=[{}]", prefix, originAttributes(request, transport, threadContext), principal(user), action, indices);
} }
} else { } else {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("{}[transport] [tampered_request]\t{}, {}, action=[{}], request=[{}]", prefix, originAttributes(request, transport), principal(user), action, request.getClass().getSimpleName()); logger.debug("{}[transport] [tampered_request]\t{}, {}, action=[{}], request=[{}]", prefix, originAttributes(request, transport, threadContext), principal(user), action, request.getClass().getSimpleName());
} else { } else {
logger.error("{}[transport] [tampered_request]\t{}, {}, action=[{}]", prefix, originAttributes(request, transport), principal(user), action); logger.error("{}[transport] [tampered_request]\t{}, {}, action=[{}]", prefix, originAttributes(request, transport, threadContext), principal(user), action);
} }
} }
} }
@ -291,18 +295,18 @@ public class LoggingAuditTrail extends AbstractLifecycleComponent<LoggingAuditTr
@Override @Override
public void runAsGranted(User user, String action, TransportMessage<?> message) { public void runAsGranted(User user, String action, TransportMessage<?> message) {
if (logger.isDebugEnabled()) { 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 { } 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 @Override
public void runAsDenied(User user, String action, TransportMessage<?> message) { public void runAsDenied(User user, String action, TransportMessage<?> message) {
if (logger.isDebugEnabled()) { 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 { } 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<LoggingAuditTr
return "origin_address=[" + formattedAddress + "]"; return "origin_address=[" + formattedAddress + "]";
} }
static String originAttributes(TransportMessage message, Transport transport) { static String originAttributes(TransportMessage message, Transport transport, ThreadContext threadContext) {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
// first checking if the message originated in a rest call // first checking if the message originated in a rest call
InetSocketAddress restAddress = RemoteHostHeader.restRemoteAddress(message); InetSocketAddress restAddress = RemoteHostHeader.restRemoteAddress(threadContext);
if (restAddress != null) { if (restAddress != null) {
builder.append("origin_type=[rest], origin_address=[").append(NetworkAddress.formatAddress(restAddress.getAddress())).append("]"); builder.append("origin_type=[rest], origin_address=[").append(NetworkAddress.formatAddress(restAddress.getAddress())).append("]");
return builder.toString(); return builder.toString();

View File

@ -6,7 +6,6 @@
package org.elasticsearch.shield.authc; package org.elasticsearch.shield.authc;
import org.elasticsearch.ElasticsearchSecurityException; import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.common.ContextAndHeaderHolder;
import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.shield.User; import org.elasticsearch.shield.User;
import org.elasticsearch.transport.TransportMessage; import org.elasticsearch.transport.TransportMessage;
@ -27,8 +26,9 @@ public interface AuthenticationService {
* @return The authenticated user * @return The authenticated user
* @throws ElasticsearchSecurityException If no user was associated with the request or if the associated * @throws ElasticsearchSecurityException If no user was associated with the request or if the associated
* user credentials were found to be invalid * user credentials were found to be invalid
* @throws IOException If an error occurs when reading or writing
*/ */
User authenticate(RestRequest request) throws ElasticsearchSecurityException; User authenticate(RestRequest request) throws IOException, ElasticsearchSecurityException;
/** /**
* Authenticates the user that is associated with the given message. If the user was authenticated successfully (i.e. * Authenticates the user that is associated with the given message. If the user was authenticated successfully (i.e.
@ -55,8 +55,7 @@ public interface AuthenticationService {
* Checks if there's already a user header attached to the given message. If missing, a new header is * Checks if there's already a user header attached to the given message. If missing, a new header is
* set on the message with the given user (encoded). * set on the message with the given user (encoded).
* *
* @param message The message
* @param user The user to be attached if the header is missing * @param user The user to be attached if the header is missing
*/ */
void attachUserHeaderIfMissing(ContextAndHeaderHolder message, User user) throws IOException; void attachUserHeaderIfMissing(User user) throws IOException;
} }

View File

@ -7,7 +7,6 @@ package org.elasticsearch.shield.authc;
import org.elasticsearch.ElasticsearchSecurityException; import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.common.Base64; import org.elasticsearch.common.Base64;
import org.elasticsearch.common.ContextAndHeaderHolder;
import org.elasticsearch.common.Strings; import org.elasticsearch.common.Strings;
import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
@ -15,10 +14,12 @@ import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.logging.ESLogger; import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.shield.User; import org.elasticsearch.shield.User;
import org.elasticsearch.shield.audit.AuditTrail; import org.elasticsearch.shield.audit.AuditTrail;
import org.elasticsearch.shield.crypto.CryptoService; import org.elasticsearch.shield.crypto.CryptoService;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportMessage; import org.elasticsearch.transport.TransportMessage;
import java.io.IOException; import java.io.IOException;
@ -44,32 +45,35 @@ public class InternalAuthenticationService extends AbstractComponent implements
private final CryptoService cryptoService; private final CryptoService cryptoService;
private final AnonymousService anonymousService; private final AnonymousService anonymousService;
private final AuthenticationFailureHandler failureHandler; private final AuthenticationFailureHandler failureHandler;
private final ThreadContext threadContext;
private final boolean signUserHeader; private final boolean signUserHeader;
private final boolean runAsEnabled; private final boolean runAsEnabled;
@Inject @Inject
public InternalAuthenticationService(Settings settings, Realms realms, AuditTrail auditTrail, CryptoService cryptoService, public InternalAuthenticationService(Settings settings, Realms realms, AuditTrail auditTrail, CryptoService cryptoService,
AnonymousService anonymousService, AuthenticationFailureHandler failureHandler) { AnonymousService anonymousService, AuthenticationFailureHandler failureHandler,
ThreadPool threadPool) {
super(settings); super(settings);
this.realms = realms; this.realms = realms;
this.auditTrail = auditTrail; this.auditTrail = auditTrail;
this.cryptoService = cryptoService; this.cryptoService = cryptoService;
this.anonymousService = anonymousService; this.anonymousService = anonymousService;
this.failureHandler = failureHandler; this.failureHandler = failureHandler;
this.threadContext = threadPool.getThreadContext();
this.signUserHeader = settings.getAsBoolean(SETTING_SIGN_USER_HEADER, true); this.signUserHeader = settings.getAsBoolean(SETTING_SIGN_USER_HEADER, true);
this.runAsEnabled = settings.getAsBoolean(SETTING_RUN_AS_ENABLED, true); this.runAsEnabled = settings.getAsBoolean(SETTING_RUN_AS_ENABLED, true);
} }
@Override @Override
public User authenticate(RestRequest request) throws ElasticsearchSecurityException { public User authenticate(RestRequest request) throws IOException, ElasticsearchSecurityException {
User user = getUserFromContext(request); User user = getUserFromContext();
if (user != null) { if (user != null) {
return user; return user;
} }
AuthenticationToken token; AuthenticationToken token;
try { try {
token = token(request); token = token();
} catch (Exception e) { } catch (Exception e) {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("failed to extract token from request", e); logger.debug("failed to extract token from request", e);
@ -84,7 +88,7 @@ public class InternalAuthenticationService extends AbstractComponent implements
if (anonymousService.enabled()) { if (anonymousService.enabled()) {
// we must put the user in the request context, so it'll be copied to the // we must put the user in the request context, so it'll be copied to the
// transport request - without it, the transport will assume system user // transport request - without it, the transport will assume system user
request.putInContext(USER_KEY, anonymousService.anonymousUser()); putUserInContext(anonymousService.anonymousUser());
return anonymousService.anonymousUser(); return anonymousService.anonymousUser();
} }
auditTrail.anonymousAccessDenied(request); auditTrail.anonymousAccessDenied(request);
@ -144,17 +148,17 @@ public class InternalAuthenticationService extends AbstractComponent implements
// we must put the user in the request context, so it'll be copied to the // we must put the user in the request context, so it'll be copied to the
// transport request - without it, the transport will assume system user // transport request - without it, the transport will assume system user
request.putInContext(USER_KEY, user); putUserInContext(user);
return user; return user;
} }
@Override @Override
public User authenticate(String action, TransportMessage message, User fallbackUser) throws IOException { public User authenticate(String action, TransportMessage message, User fallbackUser) throws IOException {
User user = getUserFromContext(message); User user = getUserFromContext();
if (user != null) { if (user != null) {
return user; return user;
} }
String header = message.getHeader(USER_KEY); String header = threadContext.getHeader(USER_KEY);
if (header != null) { if (header != null) {
if (signUserHeader) { if (signUserHeader) {
try { try {
@ -168,36 +172,46 @@ public class InternalAuthenticationService extends AbstractComponent implements
} }
if (user == null) { if (user == null) {
user = authenticateWithRealms(action, message, fallbackUser); user = authenticateWithRealms(action, message, fallbackUser);
header = signUserHeader ? cryptoService.sign(encodeUser(user, logger)) : encodeUser(user, logger); setUserHeader(user);
message.putHeader(USER_KEY, header);
} }
message.putInContext(USER_KEY, user); putUserInContext(user);
return user; return user;
} }
@Override @Override
public void attachUserHeaderIfMissing(ContextAndHeaderHolder message, User user) throws IOException { public void attachUserHeaderIfMissing(User user) throws IOException {
if (message.hasHeader(USER_KEY)) { if (threadContext.getHeader(USER_KEY) != null) {
return; return;
} }
User userFromContext = message.getFromContext(USER_KEY); User transientUser = threadContext.getTransient(USER_KEY);
if (userFromContext != null) { if (transientUser != null) {
String userHeader = signUserHeader ? cryptoService.sign(encodeUser(userFromContext, logger)) : encodeUser(userFromContext, logger); setUserHeader(transientUser);
message.putHeader(USER_KEY, userHeader);
return; return;
} }
message.putInContext(USER_KEY, user); setUser(user);
String userHeader = signUserHeader ? cryptoService.sign(encodeUser(user, logger)) : encodeUser(user, logger);
message.putHeader(USER_KEY, userHeader);
} }
User getUserFromContext(ContextAndHeaderHolder message) { void setUserHeader(User user) throws IOException {
User user = message.getFromContext(USER_KEY); String userHeader = signUserHeader ? cryptoService.sign(encodeUser(user, logger)) : encodeUser(user, logger);
if (user != null) { threadContext.putHeader(USER_KEY, userHeader);
return user; }
void setUser(User user) throws IOException {
putUserInContext(user);
setUserHeader(user);
}
void putUserInContext(User user) {
if (threadContext.getTransient(USER_KEY) != null) {
User ctxUser = threadContext.getTransient(USER_KEY);
throw new IllegalArgumentException("context already has user [" + ctxUser.principal() + "]. trying to set user [" + user.principal() + "]");
} }
return null; threadContext.putTransient(USER_KEY, user);
}
User getUserFromContext() {
return threadContext.getTransient(USER_KEY);
} }
static User decodeUser(String text) { static User decodeUser(String text) {
@ -283,7 +297,7 @@ public class InternalAuthenticationService extends AbstractComponent implements
} }
if (runAsEnabled) { if (runAsEnabled) {
String runAsUsername = message.getHeader(RUN_AS_USER_HEADER); String runAsUsername = threadContext.getHeader(RUN_AS_USER_HEADER);
if (runAsUsername != null) { if (runAsUsername != null) {
if (runAsUsername.isEmpty()) { if (runAsUsername.isEmpty()) {
logger.warn("user [{}] attempted to runAs with an empty username", user.principal()); logger.warn("user [{}] attempted to runAs with an empty username", user.principal());
@ -359,11 +373,12 @@ public class InternalAuthenticationService extends AbstractComponent implements
} }
} }
AuthenticationToken token(RestRequest request) throws ElasticsearchSecurityException { AuthenticationToken token() throws ElasticsearchSecurityException {
assert threadContext.getTransient(TOKEN_KEY) == null;
for (Realm realm : realms) { for (Realm realm : realms) {
AuthenticationToken token = realm.token(request); AuthenticationToken token = realm.token(threadContext);
if (token != null) { if (token != null) {
request.putInContext(TOKEN_KEY, token); threadContext.putTransient(TOKEN_KEY, token);
return token; return token;
} }
} }
@ -372,19 +387,19 @@ public class InternalAuthenticationService extends AbstractComponent implements
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
AuthenticationToken token(String action, TransportMessage<?> message) { AuthenticationToken token(String action, TransportMessage<?> message) {
AuthenticationToken token = message.getFromContext(TOKEN_KEY); AuthenticationToken token = threadContext.getTransient(TOKEN_KEY);
if (token != null) { if (token != null) {
return token; return token;
} }
for (Realm realm : realms) { for (Realm realm : realms) {
token = realm.token(message); token = realm.token(threadContext);
if (token != null) { if (token != null) {
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
logger.trace("realm [{}] resolved authentication token [{}] from transport request with action [{}]", realm, token.principal(), action); 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; return token;
} }
} }

View File

@ -6,10 +6,9 @@
package org.elasticsearch.shield.authc; package org.elasticsearch.shield.authc;
import org.elasticsearch.common.logging.ESLogger; 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.ShieldSettingsFilter;
import org.elasticsearch.shield.User; 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} * An authentication mechanism to which the default authentication {@link org.elasticsearch.shield.authc.AuthenticationService service}
@ -60,22 +59,13 @@ public abstract class Realm<T extends AuthenticationToken> implements Comparable
public abstract boolean supports(AuthenticationToken token); 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. * 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 * @return The authentication token or {@code null} if not found
*/ */
public abstract T token(RestRequest request); public abstract T token(ThreadContext context);
/**
* 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);
/** /**
* Authenticates the given token. A successful authentication will return the User associated * Authenticates the given token. A successful authentication will return the User associated

View File

@ -6,6 +6,7 @@
package org.elasticsearch.shield.authc.activedirectory; package org.elasticsearch.shield.authc.activedirectory;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.shield.ShieldSettingsFilter; import org.elasticsearch.shield.ShieldSettingsFilter;
import org.elasticsearch.shield.authc.RealmConfig; import org.elasticsearch.shield.authc.RealmConfig;
import org.elasticsearch.shield.authc.ldap.support.AbstractLdapRealm; import org.elasticsearch.shield.authc.ldap.support.AbstractLdapRealm;
@ -33,8 +34,8 @@ public class ActiveDirectoryRealm extends AbstractLdapRealm {
private final ClientSSLService clientSSLService; private final ClientSSLService clientSSLService;
@Inject @Inject
public Factory(ResourceWatcherService watcherService, ClientSSLService clientSSLService) { public Factory(ResourceWatcherService watcherService, ClientSSLService clientSSLService, RestController restController) {
super(ActiveDirectoryRealm.TYPE); super(ActiveDirectoryRealm.TYPE, restController);
this.watcherService = watcherService; this.watcherService = watcherService;
this.clientSSLService = clientSSLService; this.clientSSLService = clientSSLService;
} }

View File

@ -11,9 +11,12 @@ import com.carrotsearch.hppc.ObjectLongMap;
import com.carrotsearch.hppc.cursors.ObjectCursor; import com.carrotsearch.hppc.cursors.ObjectCursor;
import com.carrotsearch.hppc.cursors.ObjectLongCursor; import com.carrotsearch.hppc.cursors.ObjectLongCursor;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.ExceptionsHelper; import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.action.Action;
import org.elasticsearch.action.ActionListener; 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.LatchedActionListener;
import org.elasticsearch.action.delete.DeleteRequest; import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse; 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.SearchResponse;
import org.elasticsearch.action.search.SearchScrollRequest; import org.elasticsearch.action.search.SearchScrollRequest;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.elasticsearch.client.FilterClient;
import org.elasticsearch.cluster.ClusterChangedEvent; import org.elasticsearch.cluster.ClusterChangedEvent;
import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.ClusterStateListener; 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.unit.TimeValue;
import org.elasticsearch.common.util.concurrent.AbstractRunnable; import org.elasticsearch.common.util.concurrent.AbstractRunnable;
import org.elasticsearch.common.util.concurrent.FutureUtils; import org.elasticsearch.common.util.concurrent.FutureUtils;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.gateway.GatewayService; import org.elasticsearch.gateway.GatewayService;
import org.elasticsearch.index.IndexNotFoundException; import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHit;
import org.elasticsearch.shield.User; import org.elasticsearch.shield.User;
import org.elasticsearch.shield.action.admin.user.AddUserRequest; 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.authc.support.SecuredString;
import org.elasticsearch.shield.client.ShieldClient; import org.elasticsearch.shield.client.ShieldClient;
import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportMessage;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
@ -116,16 +119,6 @@ public class ESNativeUsersStore extends AbstractComponent implements ClusterStat
this.threadPool = threadPool; 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 @Nullable
private UserAndPassword transformUser(Map<String, Object> sourceMap) { private UserAndPassword transformUser(Map<String, Object> sourceMap) {
if (sourceMap == null) { if (sourceMap == null) {
@ -207,7 +200,6 @@ public class ESNativeUsersStore extends AbstractComponent implements ClusterStat
.setSize(scrollSize) .setSize(scrollSize)
.setFetchSource(true) .setFetchSource(true)
.request(); .request();
attachUser(request);
request.indicesOptions().ignoreUnavailable(); request.indicesOptions().ignoreUnavailable();
// This function is MADNESS! But it works, don't think about it too hard... // 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()) SearchScrollRequest scrollRequest = client.prepareSearchScroll(resp.getScrollId())
.setScroll(scrollKeepAlive).request(); .setScroll(scrollKeepAlive).request();
attachUser(scrollRequest);
client.searchScroll(scrollRequest, this); client.searchScroll(scrollRequest, this);
} else { } else {
ClearScrollRequest clearScrollRequest = client.prepareClearScroll().addScrollId(resp.getScrollId()).request(); ClearScrollRequest clearScrollRequest = client.prepareClearScroll().addScrollId(resp.getScrollId()).request();
attachUser(clearScrollRequest);
client.clearScroll(clearScrollRequest, new ActionListener<ClearScrollResponse>() { client.clearScroll(clearScrollRequest, new ActionListener<ClearScrollResponse>() {
@Override @Override
public void onResponse(ClearScrollResponse response) { public void onResponse(ClearScrollResponse response) {
@ -291,7 +281,6 @@ public class ESNativeUsersStore extends AbstractComponent implements ClusterStat
try { try {
GetRequest request = client.prepareGet(ShieldTemplateService.SHIELD_ADMIN_INDEX_NAME, INDEX_USER_TYPE, user).request(); GetRequest request = client.prepareGet(ShieldTemplateService.SHIELD_ADMIN_INDEX_NAME, INDEX_USER_TYPE, user).request();
request.indicesOptions().ignoreUnavailable(); request.indicesOptions().ignoreUnavailable();
attachUser(request);
client.get(request, new ActionListener<GetResponse>() { client.get(request, new ActionListener<GetResponse>() {
@Override @Override
public void onResponse(GetResponse getFields) { public void onResponse(GetResponse getFields) {
@ -332,7 +321,6 @@ public class ESNativeUsersStore extends AbstractComponent implements ClusterStat
"password", String.valueOf(addUserRequest.passwordHash()), "password", String.valueOf(addUserRequest.passwordHash()),
"roles", addUserRequest.roles()) "roles", addUserRequest.roles())
.request(); .request();
attachUser(request);
client.index(request, new ActionListener<IndexResponse>() { client.index(request, new ActionListener<IndexResponse>() {
@Override @Override
@ -367,7 +355,6 @@ public class ESNativeUsersStore extends AbstractComponent implements ClusterStat
DeleteRequest request = client.prepareDelete(ShieldTemplateService.SHIELD_ADMIN_INDEX_NAME, DeleteRequest request = client.prepareDelete(ShieldTemplateService.SHIELD_ADMIN_INDEX_NAME,
INDEX_USER_TYPE, deleteUserRequest.user()).request(); INDEX_USER_TYPE, deleteUserRequest.user()).request();
request.indicesOptions().ignoreUnavailable(); request.indicesOptions().ignoreUnavailable();
attachUser(request);
client.delete(request, new ActionListener<DeleteResponse>() { client.delete(request, new ActionListener<DeleteResponse>() {
@Override @Override
public void onResponse(DeleteResponse deleteResponse) { public void onResponse(DeleteResponse deleteResponse) {
@ -420,8 +407,20 @@ public class ESNativeUsersStore extends AbstractComponent implements ClusterStat
public void start() { public void start() {
try { try {
if (state.compareAndSet(State.INITIALIZED, State.STARTING)) { if (state.compareAndSet(State.INITIALIZED, State.STARTING)) {
this.client = clientProvider.get();
this.authService = authProvider.get(); this.authService = authProvider.get();
this.client = new FilterClient(clientProvider.get()) {
@Override
protected <Request extends ActionRequest<Request>, Response extends ActionResponse, RequestBuilder extends ActionRequestBuilder<Request, Response, RequestBuilder>> void doExecute(Action<Request, Response, RequestBuilder> action, Request request, ActionListener<Response> 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.scrollSize = settings.getAsInt("shield.authc.native.scroll.size", 1000);
this.scrollKeepAlive = settings.getAsTime("shield.authc.native.scroll.keep_alive", TimeValue.timeValueSeconds(10L)); 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); ShieldClient shieldClient = new ShieldClient(client);
ClearRealmCacheRequest request = shieldClient.prepareClearRealmCache() ClearRealmCacheRequest request = shieldClient.prepareClearRealmCache()
.usernames(username).request(); .usernames(username).request();
attachUser(request);
shieldClient.clearRealmCache(request, new ActionListener<ClearRealmCacheResponse>() { shieldClient.clearRealmCache(request, new ActionListener<ClearRealmCacheResponse>() {
@Override @Override
public void onResponse(ClearRealmCacheResponse nodes) { public void onResponse(ClearRealmCacheResponse nodes) {
@ -628,7 +626,6 @@ public class ESNativeUsersStore extends AbstractComponent implements ClusterStat
.setVersion(true) .setVersion(true)
.setFetchSource(true) .setFetchSource(true)
.request(); .request();
attachUser(request);
response = client.search(request).actionGet(); response = client.search(request).actionGet();
boolean keepScrolling = response.getHits().getHits().length > 0; boolean keepScrolling = response.getHits().getHits().length > 0;
@ -639,7 +636,6 @@ public class ESNativeUsersStore extends AbstractComponent implements ClusterStat
map.put(username, version); map.put(username, version);
} }
SearchScrollRequest scrollRequest = client.prepareSearchScroll(response.getScrollId()).setScroll(scrollKeepAlive).request(); SearchScrollRequest scrollRequest = client.prepareSearchScroll(response.getScrollId()).setScroll(scrollKeepAlive).request();
attachUser(scrollRequest);
response = client.searchScroll(scrollRequest).actionGet(); response = client.searchScroll(scrollRequest).actionGet();
keepScrolling = response.getHits().getHits().length > 0; keepScrolling = response.getHits().getHits().length > 0;
} }
@ -648,7 +644,6 @@ public class ESNativeUsersStore extends AbstractComponent implements ClusterStat
} finally { } finally {
if (response != null) { if (response != null) {
ClearScrollRequest clearScrollRequest = client.prepareClearScroll().addScrollId(response.getScrollId()).request(); ClearScrollRequest clearScrollRequest = client.prepareClearScroll().addScrollId(response.getScrollId()).request();
attachUser(clearScrollRequest);
client.clearScroll(clearScrollRequest).actionGet(); client.clearScroll(clearScrollRequest).actionGet();
} }
} }

View File

@ -8,11 +8,12 @@ package org.elasticsearch.shield.authc.esusers;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment; import org.elasticsearch.env.Environment;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.shield.User; import org.elasticsearch.shield.User;
import org.elasticsearch.shield.authc.Realm;
import org.elasticsearch.shield.authc.RealmConfig; import org.elasticsearch.shield.authc.RealmConfig;
import org.elasticsearch.shield.authc.support.CachingUsernamePasswordRealm; import org.elasticsearch.shield.authc.support.CachingUsernamePasswordRealm;
import org.elasticsearch.shield.authc.support.RefreshListener; import org.elasticsearch.shield.authc.support.RefreshListener;
import org.elasticsearch.shield.authc.support.UsernamePasswordRealm;
import org.elasticsearch.shield.authc.support.UsernamePasswordToken; import org.elasticsearch.shield.authc.support.UsernamePasswordToken;
import org.elasticsearch.watcher.ResourceWatcherService; import org.elasticsearch.watcher.ResourceWatcherService;
@ -66,15 +67,15 @@ public class ESUsersRealm extends CachingUsernamePasswordRealm {
} }
} }
public static class Factory extends Realm.Factory<ESUsersRealm> { public static class Factory extends UsernamePasswordRealm.Factory<ESUsersRealm> {
private final Settings settings; private final Settings settings;
private final Environment env; private final Environment env;
private final ResourceWatcherService watcherService; private final ResourceWatcherService watcherService;
@Inject @Inject
public Factory(Settings settings, Environment env, ResourceWatcherService watcherService) { public Factory(Settings settings, Environment env, ResourceWatcherService watcherService, RestController restController) {
super(TYPE, true); super(TYPE, restController, true);
this.settings = settings; this.settings = settings;
this.env = env; this.env = env;
this.watcherService = watcherService; this.watcherService = watcherService;

View File

@ -8,6 +8,7 @@ package org.elasticsearch.shield.authc.ldap;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.shield.ShieldSettingsFilter; import org.elasticsearch.shield.ShieldSettingsFilter;
import org.elasticsearch.shield.authc.RealmConfig; import org.elasticsearch.shield.authc.RealmConfig;
import org.elasticsearch.shield.authc.ldap.support.AbstractLdapRealm; import org.elasticsearch.shield.authc.ldap.support.AbstractLdapRealm;
@ -35,8 +36,8 @@ public class LdapRealm extends AbstractLdapRealm {
private final ClientSSLService clientSSLService; private final ClientSSLService clientSSLService;
@Inject @Inject
public Factory(ResourceWatcherService watcherService, ClientSSLService clientSSLService) { public Factory(ResourceWatcherService watcherService, ClientSSLService clientSSLService, RestController restController) {
super(TYPE); super(TYPE, restController);
this.watcherService = watcherService; this.watcherService = watcherService;
this.clientSSLService = clientSSLService; this.clientSSLService = clientSSLService;
} }

View File

@ -5,6 +5,7 @@
*/ */
package org.elasticsearch.shield.authc.ldap.support; package org.elasticsearch.shield.authc.ldap.support;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.shield.User; import org.elasticsearch.shield.User;
import org.elasticsearch.shield.authc.RealmConfig; import org.elasticsearch.shield.authc.RealmConfig;
import org.elasticsearch.shield.authc.support.CachingUsernamePasswordRealm; import org.elasticsearch.shield.authc.support.CachingUsernamePasswordRealm;
@ -92,8 +93,8 @@ public abstract class AbstractLdapRealm extends CachingUsernamePasswordRealm {
public static abstract class Factory<R extends AbstractLdapRealm> extends UsernamePasswordRealm.Factory<R> { public static abstract class Factory<R extends AbstractLdapRealm> extends UsernamePasswordRealm.Factory<R> {
public Factory(String type) { public Factory(String type, RestController restController) {
super(type, false); super(type, restController, false);
} }
/** /**

View File

@ -9,8 +9,8 @@ import org.elasticsearch.common.Strings;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.logging.ESLogger; import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.Environment; import org.elasticsearch.env.Environment;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.shield.ShieldSettingsFilter; import org.elasticsearch.shield.ShieldSettingsFilter;
import org.elasticsearch.shield.User; import org.elasticsearch.shield.User;
import org.elasticsearch.shield.authc.AuthenticationToken; 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.SSLClientAuth;
import org.elasticsearch.shield.transport.netty.ShieldNettyHttpServerTransport; import org.elasticsearch.shield.transport.netty.ShieldNettyHttpServerTransport;
import org.elasticsearch.shield.transport.netty.ShieldNettyTransport; import org.elasticsearch.shield.transport.netty.ShieldNettyTransport;
import org.elasticsearch.transport.TransportMessage;
import org.elasticsearch.watcher.ResourceWatcherService; import org.elasticsearch.watcher.ResourceWatcherService;
import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManager;
@ -66,13 +65,8 @@ public class PkiRealm extends Realm<X509AuthenticationToken> {
} }
@Override @Override
public X509AuthenticationToken token(RestRequest request) { public X509AuthenticationToken token(ThreadContext context) {
return token(request.getFromContext(PKI_CERT_HEADER_NAME), principalPattern, logger); return token(context.getTransient(PKI_CERT_HEADER_NAME), principalPattern, logger);
}
@Override
public X509AuthenticationToken token(TransportMessage<?> message) {
return token(message.getFromContext(PKI_CERT_HEADER_NAME), principalPattern, logger);
} }
@Override @Override

View File

@ -5,11 +5,11 @@
*/ */
package org.elasticsearch.shield.authc.support; 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.AuthenticationToken;
import org.elasticsearch.shield.authc.Realm; import org.elasticsearch.shield.authc.Realm;
import org.elasticsearch.shield.authc.RealmConfig; import org.elasticsearch.shield.authc.RealmConfig;
import org.elasticsearch.transport.TransportMessage;
/** /**
* *
@ -21,13 +21,8 @@ public abstract class UsernamePasswordRealm extends Realm<UsernamePasswordToken>
} }
@Override @Override
public UsernamePasswordToken token(RestRequest request) { public UsernamePasswordToken token(ThreadContext threadContext) {
return UsernamePasswordToken.extractToken(request, null); return UsernamePasswordToken.extractToken(threadContext, null);
}
@Override
public UsernamePasswordToken token(TransportMessage<?> message) {
return UsernamePasswordToken.extractToken(message, null);
} }
public boolean supports(AuthenticationToken token) { public boolean supports(AuthenticationToken token) {
@ -36,8 +31,9 @@ public abstract class UsernamePasswordRealm extends Realm<UsernamePasswordToken>
public static abstract class Factory<R extends UsernamePasswordRealm> extends Realm.Factory<R> { public static abstract class Factory<R extends UsernamePasswordRealm> extends Realm.Factory<R> {
protected Factory(String type, boolean internal) { protected Factory(String type, RestController restController, boolean internal) {
super(type, internal); super(type, internal);
restController.registerRelevantHeaders(UsernamePasswordToken.BASIC_AUTH_HEADER);
} }
} }
} }

View File

@ -6,10 +6,9 @@
package org.elasticsearch.shield.authc.support; package org.elasticsearch.shield.authc.support;
import org.elasticsearch.common.Base64; import org.elasticsearch.common.Base64;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.shield.authc.AuthenticationToken; import org.elasticsearch.shield.authc.AuthenticationToken;
import org.elasticsearch.transport.TransportMessage;
import org.elasticsearch.transport.TransportRequest;
import java.io.IOException; import java.io.IOException;
import java.nio.CharBuffer; import java.nio.CharBuffer;
@ -67,8 +66,8 @@ public class UsernamePasswordToken implements AuthenticationToken {
return Objects.hash(username, password.hashCode()); return Objects.hash(username, password.hashCode());
} }
public static UsernamePasswordToken extractToken(TransportMessage<?> message, UsernamePasswordToken defaultToken) { public static UsernamePasswordToken extractToken(ThreadContext context, UsernamePasswordToken defaultToken) {
String authStr = message.getHeader(BASIC_AUTH_HEADER); String authStr = context.getHeader(BASIC_AUTH_HEADER);
if (authStr == null) { if (authStr == null) {
return defaultToken; return defaultToken;
} }
@ -108,8 +107,8 @@ public class UsernamePasswordToken implements AuthenticationToken {
new SecuredString(Arrays.copyOfRange(userpasswd, i + 1, userpasswd.length))); new SecuredString(Arrays.copyOfRange(userpasswd, i + 1, userpasswd.length)));
} }
public static void putTokenHeader(TransportRequest request, UsernamePasswordToken token) { public static void putTokenHeader(ThreadContext context, UsernamePasswordToken token) {
request.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue(token.username, token.password)); context.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue(token.username, token.password));
} }
public static String basicAuthHeaderValue(String username, SecuredString passwd) { public static String basicAuthHeaderValue(String username, SecuredString passwd) {

View File

@ -19,6 +19,7 @@ import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.common.util.set.Sets; import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.search.action.SearchServiceTransportAction; import org.elasticsearch.search.action.SearchServiceTransportAction;
import org.elasticsearch.shield.User; 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.ClusterPrivilege;
import org.elasticsearch.shield.authz.privilege.IndexPrivilege; import org.elasticsearch.shield.authz.privilege.IndexPrivilege;
import org.elasticsearch.shield.authz.store.RolesStore; import org.elasticsearch.shield.authz.store.RolesStore;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportRequest; import org.elasticsearch.transport.TransportRequest;
import java.util.ArrayList; import java.util.ArrayList;
@ -59,10 +61,12 @@ public class InternalAuthorizationService extends AbstractComponent implements A
private final IndicesAndAliasesResolver[] indicesAndAliasesResolvers; private final IndicesAndAliasesResolver[] indicesAndAliasesResolvers;
private final AnonymousService anonymousService; private final AnonymousService anonymousService;
private final AuthenticationFailureHandler authcFailureHandler; private final AuthenticationFailureHandler authcFailureHandler;
private final ThreadContext threadContext;
@Inject @Inject
public InternalAuthorizationService(Settings settings, RolesStore rolesStore, ClusterService clusterService, public InternalAuthorizationService(Settings settings, RolesStore rolesStore, ClusterService clusterService,
AuditTrail auditTrail, AnonymousService anonymousService, AuthenticationFailureHandler authcFailureHandler) { AuditTrail auditTrail, AnonymousService anonymousService,
AuthenticationFailureHandler authcFailureHandler, ThreadPool threadPool) {
super(settings); super(settings);
this.rolesStore = rolesStore; this.rolesStore = rolesStore;
this.clusterService = clusterService; this.clusterService = clusterService;
@ -72,6 +76,7 @@ public class InternalAuthorizationService extends AbstractComponent implements A
}; };
this.anonymousService = anonymousService; this.anonymousService = anonymousService;
this.authcFailureHandler = authcFailureHandler; this.authcFailureHandler = authcFailureHandler;
this.threadContext = threadPool.getThreadContext();
} }
@Override @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 // 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 (user.isSystem()) {
if (SystemRole.INSTANCE.check(action)) { if (SystemRole.INSTANCE.check(action)) {
request.putInContext(INDICES_PERMISSIONS_KEY, IndicesAccessControl.ALLOW_ALL); setIndicesAccessControl(IndicesAccessControl.ALLOW_ALL);
grant(user, action, request); grant(user, action, request);
return; return;
} }
@ -149,7 +154,7 @@ public class InternalAuthorizationService extends AbstractComponent implements A
if (ClusterPrivilege.ACTION_MATCHER.test(action)) { if (ClusterPrivilege.ACTION_MATCHER.test(action)) {
ClusterPermission cluster = permission.cluster(); ClusterPermission cluster = permission.cluster();
if (cluster != null && cluster.check(action)) { if (cluster != null && cluster.check(action)) {
request.putInContext(INDICES_PERMISSIONS_KEY, IndicesAccessControl.ALLOW_ALL); setIndicesAccessControl(IndicesAccessControl.ALLOW_ALL);
grant(user, action, request); grant(user, action, request);
return; return;
} }
@ -191,7 +196,7 @@ public class InternalAuthorizationService extends AbstractComponent implements A
if (!indicesAccessControl.isGranted()) { if (!indicesAccessControl.isGranted()) {
throw denial(user, action, request); throw denial(user, action, request);
} else { } 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 //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); 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) { private GlobalPermission permission(String[] roleNames) {
if (roleNames.length == 0) { if (roleNames.length == 0) {
return GlobalPermission.NONE; return GlobalPermission.NONE;

View File

@ -45,7 +45,7 @@ public final class OptOutQueryCache extends AbstractIndexComponent implements Qu
if (context == null) { if (context == null) {
throw new IllegalStateException("opting out of the query cache. current request can't be found"); 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) { if (indicesAccessControl == null) {
logger.debug("opting out of the query cache. current request doesn't hold indices permissions"); logger.debug("opting out of the query cache. current request doesn't hold indices permissions");
return weight; return weight;

View File

@ -5,6 +5,7 @@
*/ */
package org.elasticsearch.shield.authz.accesscontrol; package org.elasticsearch.shield.authz.accesscontrol;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.transport.TransportRequest; import org.elasticsearch.transport.TransportRequest;
import java.util.Objects; import java.util.Objects;
@ -39,10 +40,12 @@ public final class RequestContext {
current.remove(); current.remove();
} }
private final ThreadContext threadContext;
private final TransportRequest request; private final TransportRequest request;
public RequestContext(TransportRequest request) { public RequestContext(TransportRequest request, ThreadContext threadContext) {
this.request = Objects.requireNonNull(request); this.request = Objects.requireNonNull(request);
this.threadContext = Objects.requireNonNull(threadContext);
} }
/** /**
@ -51,4 +54,8 @@ public final class RequestContext {
public TransportRequest getRequest() { public TransportRequest getRequest() {
return request; return request;
} }
public ThreadContext getThreadContext() {
return threadContext;
}
} }

View File

@ -26,6 +26,7 @@ import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.logging.ESLogger; import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.logging.support.LoggerMessageFormat; import org.elasticsearch.common.logging.support.LoggerMessageFormat;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.index.IndexSettings; import org.elasticsearch.index.IndexSettings;
import org.elasticsearch.index.cache.bitset.BitsetFilterCache; import org.elasticsearch.index.cache.bitset.BitsetFilterCache;
import org.elasticsearch.index.engine.EngineException; 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. * An {@link IndexSearcherWrapper} implementation that is used for field and document level security.
* <p> * <p>
* 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.
* <p> * <p>
* Field level security is enabled by wrapping the original {@link DirectoryReader} in a {@link FieldSubsetReader} * Field level security is enabled by wrapping the original {@link DirectoryReader} in a {@link FieldSubsetReader}
* in the {@link #wrap(DirectoryReader)} method. * in the {@link #wrap(DirectoryReader)} method.
@ -71,14 +72,17 @@ public class ShieldIndexSearcherWrapper extends IndexSearcherWrapper {
private final QueryShardContext queryShardContext; private final QueryShardContext queryShardContext;
private final BitsetFilterCache bitsetFilterCache; private final BitsetFilterCache bitsetFilterCache;
private final ShieldLicenseState shieldLicenseState; private final ShieldLicenseState shieldLicenseState;
private final ThreadContext threadContext;
private final ESLogger logger; private final ESLogger logger;
public ShieldIndexSearcherWrapper(IndexSettings indexSettings, QueryShardContext queryShardContext, 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.logger = Loggers.getLogger(getClass(), indexSettings.getSettings());
this.mapperService = mapperService; this.mapperService = mapperService;
this.queryShardContext = queryShardContext; this.queryShardContext = queryShardContext;
this.bitsetFilterCache = bitsetFilterCache; this.bitsetFilterCache = bitsetFilterCache;
this.threadContext = threadContext;
this.shieldLicenseState = shieldLicenseState; this.shieldLicenseState = shieldLicenseState;
Set<String> allowedMetaFields = new HashSet<>(); Set<String> allowedMetaFields = new HashSet<>();
@ -98,15 +102,8 @@ public class ShieldIndexSearcherWrapper extends IndexSearcherWrapper {
final Set<String> allowedMetaFields = this.allowedMetaFields; final Set<String> allowedMetaFields = this.allowedMetaFields;
try { try {
RequestContext context = RequestContext.current(); final IndicesAccessControl indicesAccessControl = getIndicesAccessControl();
if (context == null) {
throw new IllegalStateException("can't locate the origin of the current request");
}
IndicesAccessControl indicesAccessControl = context.getRequest().getFromContext(InternalAuthorizationService.INDICES_PERMISSIONS_KEY);
if (indicesAccessControl == null) {
throw Exceptions.authorizationError("no indices permissions found");
}
ShardId shardId = ShardUtils.extractShardId(reader); ShardId shardId = ShardUtils.extractShardId(reader);
if (shardId == null) { if (shardId == null) {
throw new IllegalStateException(LoggerMessageFormat.format("couldn't extract shardId from reader [{}]", reader)); 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;
}
} }

View File

@ -6,8 +6,11 @@
package org.elasticsearch.shield.authz.esnative; package org.elasticsearch.shield.authz.esnative;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.ElasticsearchSecurityException; import org.elasticsearch.action.Action;
import org.elasticsearch.action.ActionListener; 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.LatchedActionListener;
import org.elasticsearch.action.delete.DeleteRequest; import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse; 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.SearchResponse;
import org.elasticsearch.action.search.SearchScrollRequest; import org.elasticsearch.action.search.SearchScrollRequest;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.elasticsearch.client.FilterClient;
import org.elasticsearch.cluster.ClusterChangedEvent; import org.elasticsearch.cluster.ClusterChangedEvent;
import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.ClusterStateListener; 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.unit.TimeValue;
import org.elasticsearch.common.util.concurrent.AbstractRunnable; import org.elasticsearch.common.util.concurrent.AbstractRunnable;
import org.elasticsearch.common.util.concurrent.FutureUtils; import org.elasticsearch.common.util.concurrent.FutureUtils;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.gateway.GatewayService; import org.elasticsearch.gateway.GatewayService;
import org.elasticsearch.index.IndexNotFoundException; import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHit;
import org.elasticsearch.shield.action.admin.role.AddRoleRequest; import org.elasticsearch.shield.action.admin.role.AddRoleRequest;
import org.elasticsearch.shield.action.admin.role.DeleteRoleRequest; 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.authz.store.RolesStore;
import org.elasticsearch.shield.client.ShieldClient; import org.elasticsearch.shield.client.ShieldClient;
import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportMessage;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
@ -110,16 +113,6 @@ public class ESNativeRolesStore extends AbstractComponent implements RolesStore,
this.threadPool = threadPool; 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 @Nullable
private RoleDescriptor transformRole(GetResponse response) { private RoleDescriptor transformRole(GetResponse response) {
if (response.isExists() == false) { if (response.isExists() == false) {
@ -161,7 +154,6 @@ public class ESNativeRolesStore extends AbstractComponent implements RolesStore,
.setSize(scrollSize) .setSize(scrollSize)
.setFetchSource(true) .setFetchSource(true)
.request(); .request();
attachUser(request);
request.indicesOptions().ignoreUnavailable(); request.indicesOptions().ignoreUnavailable();
// This function is MADNESS! But it works, don't think about it too hard... // 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()) SearchScrollRequest scrollRequest = client.prepareSearchScroll(resp.getScrollId())
.setScroll(scrollKeepAlive).request(); .setScroll(scrollKeepAlive).request();
attachUser(scrollRequest);
client.searchScroll(scrollRequest, this); client.searchScroll(scrollRequest, this);
} else { } else {
ClearScrollRequest clearScrollRequest = client.prepareClearScroll().addScrollId(resp.getScrollId()).request(); ClearScrollRequest clearScrollRequest = client.prepareClearScroll().addScrollId(resp.getScrollId()).request();
attachUser(clearScrollRequest);
client.clearScroll(clearScrollRequest, new ActionListener<ClearScrollResponse>() { client.clearScroll(clearScrollRequest, new ActionListener<ClearScrollResponse>() {
@Override @Override
public void onResponse(ClearScrollResponse response) { public void onResponse(ClearScrollResponse response) {
@ -231,7 +221,6 @@ public class ESNativeRolesStore extends AbstractComponent implements RolesStore,
try { try {
GetRequest request = client.prepareGet(ShieldTemplateService.SHIELD_ADMIN_INDEX_NAME, INDEX_ROLE_TYPE, role).request(); GetRequest request = client.prepareGet(ShieldTemplateService.SHIELD_ADMIN_INDEX_NAME, INDEX_ROLE_TYPE, role).request();
request.indicesOptions().ignoreUnavailable(); request.indicesOptions().ignoreUnavailable();
attachUser(request);
client.get(request, listener); client.get(request, listener);
} catch (Exception e) { } catch (Exception e) {
logger.error("unable to retrieve role", 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, DeleteRequest request = client.prepareDelete(ShieldTemplateService.SHIELD_ADMIN_INDEX_NAME,
INDEX_ROLE_TYPE, deleteRoleRequest.role()).request(); INDEX_ROLE_TYPE, deleteRoleRequest.role()).request();
request.indicesOptions().ignoreUnavailable(); request.indicesOptions().ignoreUnavailable();
attachUser(request);
client.delete(request, new ActionListener<DeleteResponse>() { client.delete(request, new ActionListener<DeleteResponse>() {
@Override @Override
public void onResponse(DeleteResponse deleteResponse) { public void onResponse(DeleteResponse deleteResponse) {
@ -324,7 +312,6 @@ public class ESNativeRolesStore extends AbstractComponent implements RolesStore,
INDEX_ROLE_TYPE, addRoleRequest.name()) INDEX_ROLE_TYPE, addRoleRequest.name())
.setSource(addRoleRequest.toXContent(jsonBuilder(), ToXContent.EMPTY_PARAMS)) .setSource(addRoleRequest.toXContent(jsonBuilder(), ToXContent.EMPTY_PARAMS))
.request(); .request();
attachUser(request);
client.index(request, new ActionListener<IndexResponse>() { client.index(request, new ActionListener<IndexResponse>() {
@Override @Override
public void onResponse(IndexResponse indexResponse) { public void onResponse(IndexResponse indexResponse) {
@ -379,9 +366,21 @@ public class ESNativeRolesStore extends AbstractComponent implements RolesStore,
public void start() { public void start() {
try { try {
if (state.compareAndSet(State.INITIALIZED, State.STARTING)) { if (state.compareAndSet(State.INITIALIZED, State.STARTING)) {
this.client = clientProvider.get();
this.shieldClient = new ShieldClient(client);
this.authService = authProvider.get(); this.authService = authProvider.get();
this.client = new FilterClient(clientProvider.get()) {
@Override
protected <Request extends ActionRequest<Request>, Response extends ActionResponse, RequestBuilder extends ActionRequestBuilder<Request, Response, RequestBuilder>> void doExecute(Action<Request, Response, RequestBuilder> action, Request request, ActionListener<Response> 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.scrollSize = settings.getAsInt("shield.authc.native.scroll.size", 1000);
this.scrollKeepAlive = settings.getAsTime("shield.authc.native.scroll.keep_alive", TimeValue.timeValueSeconds(10L)); 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)); TimeValue pollInterval = settings.getAsTime("shield.authc.native.reload.interval", TimeValue.timeValueSeconds(30L));
@ -435,7 +434,6 @@ public class ESNativeRolesStore extends AbstractComponent implements RolesStore,
private <Response> void clearRoleCache(final String role, ActionListener<Response> listener, Response response) { private <Response> void clearRoleCache(final String role, ActionListener<Response> listener, Response response) {
ClearRolesCacheRequest request = new ClearRolesCacheRequest().roles(role); ClearRolesCacheRequest request = new ClearRolesCacheRequest().roles(role);
attachUser(request);
shieldClient.clearRolesCache(request, new ActionListener<ClearRolesCacheResponse>() { shieldClient.clearRolesCache(request, new ActionListener<ClearRolesCacheResponse>() {
@Override @Override
public void onResponse(ClearRolesCacheResponse nodes) { public void onResponse(ClearRolesCacheResponse nodes) {
@ -504,7 +502,6 @@ public class ESNativeRolesStore extends AbstractComponent implements RolesStore,
.setFetchSource(true) .setFetchSource(true)
.setVersion(true) .setVersion(true)
.request(); .request();
attachUser(request);
response = client.search(request).actionGet(); response = client.search(request).actionGet();
boolean keepScrolling = response.getHits().getHits().length > 0; 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(); SearchScrollRequest scrollRequest = client.prepareSearchScroll(response.getScrollId()).setScroll(scrollKeepAlive).request();
attachUser(scrollRequest);
response = client.searchScroll(scrollRequest).actionGet(); response = client.searchScroll(scrollRequest).actionGet();
keepScrolling = response.getHits().getHits().length > 0; keepScrolling = response.getHits().getHits().length > 0;
} }
@ -545,7 +541,6 @@ public class ESNativeRolesStore extends AbstractComponent implements RolesStore,
} finally { } finally {
if (response != null) { if (response != null) {
ClearScrollRequest clearScrollRequest = client.prepareClearScroll().addScrollId(response.getScrollId()).request(); ClearScrollRequest clearScrollRequest = client.prepareClearScroll().addScrollId(response.getScrollId()).request();
attachUser(clearScrollRequest);
client.clearScroll(clearScrollRequest).actionGet(); client.clearScroll(clearScrollRequest).actionGet();
} }
} }

View File

@ -5,8 +5,8 @@
*/ */
package org.elasticsearch.shield.rest; package org.elasticsearch.shield.rest;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.transport.TransportMessage;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.SocketAddress; 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 * 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. * then be copied to the subsequent action requests.
*/ */
public static void process(RestRequest request) { public static void process(RestRequest request, ThreadContext threadContext) {
request.putInContext(KEY, request.getRemoteAddress()); threadContext.putTransient(KEY, request.getRemoteAddress());
} }
/** /**
* Extracts the rest remote address from the message context. If not found, returns {@code null}. transport * 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. * messages that were created by rest handlers, should have this in their context.
*/ */
public static InetSocketAddress restRemoteAddress(TransportMessage message) { public static InetSocketAddress restRemoteAddress(ThreadContext threadContext) {
SocketAddress address = message.getFromContext(KEY); SocketAddress address = threadContext.getTransient(KEY);
if (address != null && address instanceof InetSocketAddress) { if (address != null && address instanceof InetSocketAddress) {
return (InetSocketAddress) address; return (InetSocketAddress) address;
} }
return null; return null;
} }
public static void putRestRemoteAddress(TransportMessage message, SocketAddress address) { public static void putRestRemoteAddress(ThreadContext threadContext, SocketAddress address) {
message.putInContext(KEY, address); threadContext.putTransient(KEY, address);
} }
} }

View File

@ -10,6 +10,7 @@ import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.logging.ESLogger; import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.http.netty.NettyHttpRequest; import org.elasticsearch.http.netty.NettyHttpRequest;
import org.elasticsearch.rest.RestChannel; import org.elasticsearch.rest.RestChannel;
import org.elasticsearch.rest.RestController; 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.license.ShieldLicenseState;
import org.elasticsearch.shield.transport.SSLClientAuth; import org.elasticsearch.shield.transport.SSLClientAuth;
import org.elasticsearch.shield.transport.netty.ShieldNettyHttpServerTransport; import org.elasticsearch.shield.transport.netty.ShieldNettyHttpServerTransport;
import org.elasticsearch.threadpool.ThreadPool;
import org.jboss.netty.handler.ssl.SslHandler; import org.jboss.netty.handler.ssl.SslHandler;
import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.SSLPeerUnverifiedException;
@ -36,12 +38,15 @@ public class ShieldRestFilter extends RestFilter {
private final AuthenticationService service; private final AuthenticationService service;
private final ESLogger logger; private final ESLogger logger;
private final ShieldLicenseState licenseState; private final ShieldLicenseState licenseState;
private final ThreadContext threadContext;
private final boolean extractClientCertificate; private final boolean extractClientCertificate;
@Inject @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.service = service;
this.licenseState = licenseState; this.licenseState = licenseState;
this.threadContext = threadPool.getThreadContext();
controller.registerFilter(this); controller.registerFilter(this);
boolean ssl = settings.getAsBoolean(ShieldNettyHttpServerTransport.HTTP_SSL_SETTING, ShieldNettyHttpServerTransport.HTTP_SSL_DEFAULT); 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(); 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 // CORS - allow for preflight unauthenticated OPTIONS request
if (request.method() != RestRequest.Method.OPTIONS) { if (request.method() != RestRequest.Method.OPTIONS) {
if (extractClientCertificate) { if (extractClientCertificate) {
putClientCertificateInContext(request, logger); putClientCertificateInContext(request, threadContext, logger);
} }
service.authenticate(request); service.authenticate(request);
} }
RemoteHostHeader.process(request); RemoteHostHeader.process(request, threadContext);
} }
filterChain.continueProcessing(request, channel); 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; assert request instanceof NettyHttpRequest;
NettyHttpRequest nettyHttpRequest = (NettyHttpRequest) request; NettyHttpRequest nettyHttpRequest = (NettyHttpRequest) request;
@ -80,7 +85,7 @@ public class ShieldRestFilter extends RestFilter {
try { try {
Certificate[] certs = handler.getEngine().getSession().getPeerCertificates(); Certificate[] certs = handler.getEngine().getSession().getPeerCertificates();
if (certs instanceof X509Certificate[]) { if (certs instanceof X509Certificate[]) {
request.putInContext(PkiRealm.PKI_CERT_HEADER_NAME, certs); threadContext.putTransient(PkiRealm.PKI_CERT_HEADER_NAME, certs);
} }
} catch (SSLPeerUnverifiedException e) { } catch (SSLPeerUnverifiedException e) {
// this happens when we only request client authentication and the client does not provide it // this happens when we only request client authentication and the client does not provide it

View File

@ -27,7 +27,7 @@ public class RestAuthenticateAction extends BaseRestHandler {
private final AuthenticationService authenticationService; private final AuthenticationService authenticationService;
@Inject @Inject
public RestAuthenticateAction(Settings settings, RestController controller, Client client, AuthenticationService authenticationService) { public RestAuthenticateAction(Settings settings, RestController controller, Client client, AuthenticationService authenticationService) {
super(settings, controller, client); super(settings, client);
this.authenticationService = authenticationService; this.authenticationService = authenticationService;
controller.registerHandler(GET, "/_shield/authenticate", this); controller.registerHandler(GET, "/_shield/authenticate", this);
} }

View File

@ -33,7 +33,7 @@ public class RestShieldInfoAction extends BaseRestHandler {
@Inject @Inject
public RestShieldInfoAction(Settings settings, RestController controller, Client client, ClusterName clusterName, @Nullable ShieldLicenseState licenseState) { public RestShieldInfoAction(Settings settings, RestController controller, Client client, ClusterName clusterName, @Nullable ShieldLicenseState licenseState) {
super(settings, controller, client); super(settings, client);
this.clusterName = clusterName; this.clusterName = clusterName;
this.shieldLicenseState = licenseState; this.shieldLicenseState = licenseState;
this.shieldEnabled = ShieldPlugin.shieldEnabled(settings); this.shieldEnabled = ShieldPlugin.shieldEnabled(settings);

View File

@ -28,7 +28,7 @@ public class RestClearRealmCacheAction extends BaseRestHandler {
@Inject @Inject
public RestClearRealmCacheAction(Settings settings, RestController controller, Client client) { public RestClearRealmCacheAction(Settings settings, RestController controller, Client client) {
super(settings, controller, client); super(settings, client);
controller.registerHandler(POST, "/_shield/realm/{realms}/_cache/clear", this); controller.registerHandler(POST, "/_shield/realm/{realms}/_cache/clear", this);
} }

View File

@ -31,7 +31,7 @@ public class RestClearRolesCacheAction extends BaseRestHandler {
@Inject @Inject
public RestClearRolesCacheAction(Settings settings, RestController controller, Client client) { public RestClearRolesCacheAction(Settings settings, RestController controller, Client client) {
super(settings, controller, client); super(settings, client);
controller.registerHandler(POST, "/_shield/roles/{roles}/_cache/clear", this); controller.registerHandler(POST, "/_shield/roles/{roles}/_cache/clear", this);
} }

View File

@ -56,7 +56,7 @@ public interface ClientTransportFilter {
the system user will be attached. There cannot be a request outgoing from this the system user will be attached. There cannot be a request outgoing from this
node that is not associated with a user. node that is not associated with a user.
*/ */
authcService.attachUserHeaderIfMissing(request, User.SYSTEM); authcService.attachUserHeaderIfMissing(User.SYSTEM);
} }
} }
} }

View File

@ -7,6 +7,7 @@ package org.elasticsearch.shield.transport;
import org.elasticsearch.common.logging.ESLogger; import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.shield.User; import org.elasticsearch.shield.User;
import org.elasticsearch.shield.action.ShieldActionMapper; import org.elasticsearch.shield.action.ShieldActionMapper;
import org.elasticsearch.shield.authc.AuthenticationService; import org.elasticsearch.shield.authc.AuthenticationService;
@ -51,12 +52,15 @@ public interface ServerTransportFilter {
private final AuthenticationService authcService; private final AuthenticationService authcService;
private final AuthorizationService authzService; private final AuthorizationService authzService;
private final ShieldActionMapper actionMapper; private final ShieldActionMapper actionMapper;
private final ThreadContext threadContext;
private final boolean extractClientCert; 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.authcService = authcService;
this.authzService = authzService; this.authzService = authzService;
this.actionMapper = actionMapper; this.actionMapper = actionMapper;
this.threadContext = threadContext;
this.extractClientCert = extractClientCert; this.extractClientCert = extractClientCert;
} }
@ -78,14 +82,14 @@ public interface ServerTransportFilter {
} }
if (extractClientCert && (unwrappedChannel instanceof NettyTransportChannel)) { if (extractClientCert && (unwrappedChannel instanceof NettyTransportChannel)) {
Channel channel = ((NettyTransportChannel)unwrappedChannel).getChannel(); Channel channel = ((NettyTransportChannel) unwrappedChannel).getChannel();
SslHandler sslHandler = channel.getPipeline().get(SslHandler.class); SslHandler sslHandler = channel.getPipeline().get(SslHandler.class);
assert sslHandler != null; assert sslHandler != null;
try { try {
Certificate[] certs = sslHandler.getEngine().getSession().getPeerCertificates(); Certificate[] certs = sslHandler.getEngine().getSession().getPeerCertificates();
if (certs instanceof X509Certificate[]) { if (certs instanceof X509Certificate[]) {
request.putInContext(PkiRealm.PKI_CERT_HEADER_NAME, certs); threadContext.putTransient(PkiRealm.PKI_CERT_HEADER_NAME, certs);
} }
} catch (SSLPeerUnverifiedException e) { } catch (SSLPeerUnverifiedException e) {
// this happens when we only request client authentication and the client does not provide it // 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 { class ClientProfile extends NodeProfile {
public ClientProfile(AuthenticationService authcService, AuthorizationService authzService, ShieldActionMapper actionMapper, boolean extractClientCert) { public ClientProfile(AuthenticationService authcService, AuthorizationService authzService,
super(authcService, authzService, actionMapper, extractClientCert); ShieldActionMapper actionMapper, ThreadContext threadContext, boolean extractClientCert) {
super(authcService, authzService, actionMapper, threadContext, extractClientCert);
} }
@Override @Override

View File

@ -8,11 +8,14 @@ package org.elasticsearch.shield.transport;
import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.shield.action.ShieldActionMapper; import org.elasticsearch.shield.action.ShieldActionMapper;
import org.elasticsearch.shield.authc.AuthenticationService; import org.elasticsearch.shield.authc.AuthenticationService;
import org.elasticsearch.shield.authz.AuthorizationService; import org.elasticsearch.shield.authz.AuthorizationService;
import org.elasticsearch.shield.authz.accesscontrol.RequestContext; import org.elasticsearch.shield.authz.accesscontrol.RequestContext;
import org.elasticsearch.shield.license.ShieldLicenseState; 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.shield.transport.netty.ShieldNettyTransport;
import org.elasticsearch.tasks.Task; import org.elasticsearch.tasks.Task;
import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.threadpool.ThreadPool;
@ -30,6 +33,7 @@ import org.elasticsearch.transport.netty.NettyTransport;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.function.Predicate;
import java.util.function.Supplier; import java.util.function.Supplier;
import static org.elasticsearch.shield.transport.netty.ShieldNettyTransport.TRANSPORT_CLIENT_AUTH_DEFAULT; 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 class ShieldServerTransportService extends TransportService {
public static final String SETTING_NAME = "shield.type"; public static final String SETTING_NAME = "shield.type";
// FIXME clean up this hack
static final Predicate<String> INTERNAL_PREDICATE = new AutomatonPredicate(Automatons.patterns("internal:*"));
protected final AuthenticationService authcService; protected final AuthenticationService authcService;
protected final AuthorizationService authzService; protected final AuthorizationService authzService;
@ -72,29 +78,46 @@ public class ShieldServerTransportService extends TransportService {
@Override @Override
public <T extends TransportResponse> void sendRequest(DiscoveryNode node, String action, TransportRequest request, TransportRequestOptions options, TransportResponseHandler<T> handler) { public <T extends TransportResponse> void sendRequest(DiscoveryNode node, String action, TransportRequest request, TransportRequestOptions options, TransportResponseHandler<T> handler) {
try { try (ThreadContext.StoredContext original = threadPool.getThreadContext().newStoredContext()) {
clientFilter.outbound(action, request); // FIXME this is really just a hack. What happens is that we send a request and we always copy headers over
super.sendRequest(node, action, request, options, handler); // Sometimes a system action gets executed like a internal create index request or update mappings request
} catch (Throwable t) { // which means that the user is copied over to system actions and these really fail for internal things...
handler.handleException(new TransportException("failed sending request", t)); 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 @Override
public <Request extends TransportRequest> void registerRequestHandler(String action, Supplier<Request> requestFactory, String executor, TransportRequestHandler<Request> handler) { public <Request extends TransportRequest> void registerRequestHandler(String action, Supplier<Request> requestFactory, String executor, TransportRequestHandler<Request> handler) {
TransportRequestHandler<Request> wrappedHandler = new ProfileSecuredRequestHandler<>(action, handler, profileFilters, licenseState); TransportRequestHandler<Request> wrappedHandler = new ProfileSecuredRequestHandler<>(action, handler, profileFilters, licenseState, threadPool.getThreadContext());
super.registerRequestHandler(action, requestFactory, executor, wrappedHandler); super.registerRequestHandler(action, requestFactory, executor, wrappedHandler);
} }
@Override @Override
public <Request extends TransportRequest> void registerRequestHandler(String action, Supplier<Request> request, String executor, boolean forceExecution, TransportRequestHandler<Request> handler) { public <Request extends TransportRequest> void registerRequestHandler(String action, Supplier<Request> request, String executor, boolean forceExecution, TransportRequestHandler<Request> handler) {
TransportRequestHandler<Request> wrappedHandler = new ProfileSecuredRequestHandler<>(action, handler, profileFilters, licenseState); TransportRequestHandler<Request> wrappedHandler = new ProfileSecuredRequestHandler<>(action, handler, profileFilters, licenseState, threadPool.getThreadContext());
super.registerRequestHandler(action, request, executor, forceExecution, wrappedHandler); super.registerRequestHandler(action, request, executor, forceExecution, wrappedHandler);
} }
protected Map<String, ServerTransportFilter> initializeProfileFilters() { protected Map<String, ServerTransportFilter> initializeProfileFilters() {
if (!(transport instanceof ShieldNettyTransport)) { if (!(transport instanceof ShieldNettyTransport)) {
return Collections.<String, ServerTransportFilter>singletonMap(NettyTransport.DEFAULT_PROFILE, new ServerTransportFilter.NodeProfile(authcService, authzService, actionMapper, false)); return Collections.<String, ServerTransportFilter>singletonMap(NettyTransport.DEFAULT_PROFILE,
new ServerTransportFilter.NodeProfile(authcService, authzService, actionMapper, threadPool.getThreadContext(), false));
} }
Map<String, Settings> profileSettingsMap = settings.getGroups("transport.profiles.", true); Map<String, Settings> profileSettingsMap = settings.getGroups("transport.profiles.", true);
@ -108,10 +131,10 @@ public class ShieldServerTransportService extends TransportService {
String type = entry.getValue().get(SETTING_NAME, "node"); String type = entry.getValue().get(SETTING_NAME, "node");
switch (type) { switch (type) {
case "client": 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; break;
default: 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 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 clientAuth = SSLClientAuth.parse(settings.get(TRANSPORT_CLIENT_AUTH_SETTING), TRANSPORT_CLIENT_AUTH_DEFAULT).enabled();
final boolean extractClientCert = profileSsl && clientAuth; 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); return Collections.unmodifiableMap(profileFilters);
@ -135,17 +158,20 @@ public class ShieldServerTransportService extends TransportService {
protected final TransportRequestHandler<T> handler; protected final TransportRequestHandler<T> handler;
private final Map<String, ServerTransportFilter> profileFilters; private final Map<String, ServerTransportFilter> profileFilters;
private final ShieldLicenseState licenseState; private final ShieldLicenseState licenseState;
private final ThreadContext threadContext;
public ProfileSecuredRequestHandler(String action, TransportRequestHandler<T> handler, Map<String, ServerTransportFilter> profileFilters, ShieldLicenseState licenseState) { public ProfileSecuredRequestHandler(String action, TransportRequestHandler<T> handler, Map<String, ServerTransportFilter> profileFilters,
ShieldLicenseState licenseState, ThreadContext threadContext) {
this.action = action; this.action = action;
this.handler = handler; this.handler = handler;
this.profileFilters = profileFilters; this.profileFilters = profileFilters;
this.licenseState = licenseState; this.licenseState = licenseState;
this.threadContext = threadContext;
} }
@Override @Override
public void messageReceived(T request, TransportChannel channel, Task task) throws Exception { public void messageReceived(T request, TransportChannel channel, Task task) throws Exception {
try { try (ThreadContext.StoredContext ctx = threadContext.newStoredContext()) {
if (licenseState.securityEnabled()) { if (licenseState.securityEnabled()) {
String profile = channel.getProfileName(); String profile = channel.getProfileName();
ServerTransportFilter filter = profileFilters.get(profile); ServerTransportFilter filter = profileFilters.get(profile);
@ -161,7 +187,8 @@ public class ShieldServerTransportService extends TransportService {
assert filter != null; assert filter != null;
filter.inbound(action, request, channel); 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); RequestContext.setCurrent(context);
handler.messageReceived(request, channel, task); handler.messageReceived(request, channel, task);
} catch (Throwable t) { } catch (Throwable t) {

View File

@ -13,6 +13,7 @@ import org.elasticsearch.http.netty.NettyHttpServerTransport;
import org.elasticsearch.shield.ssl.ServerSSLService; import org.elasticsearch.shield.ssl.ServerSSLService;
import org.elasticsearch.shield.transport.SSLClientAuth; import org.elasticsearch.shield.transport.SSLClientAuth;
import org.elasticsearch.shield.transport.filter.IPFilter; import org.elasticsearch.shield.transport.filter.IPFilter;
import org.elasticsearch.threadpool.ThreadPool;
import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelPipelineFactory;
@ -40,8 +41,8 @@ public class ShieldNettyHttpServerTransport extends NettyHttpServerTransport {
@Inject @Inject
public ShieldNettyHttpServerTransport(Settings settings, NetworkService networkService, BigArrays bigArrays, public ShieldNettyHttpServerTransport(Settings settings, NetworkService networkService, BigArrays bigArrays,
IPFilter ipFilter, ServerSSLService sslService) { IPFilter ipFilter, ServerSSLService sslService, ThreadPool threadPool) {
super(settings, networkService, bigArrays); super(settings, networkService, bigArrays, threadPool);
this.ipFilter = ipFilter; this.ipFilter = ipFilter;
this.ssl = settings.getAsBoolean(HTTP_SSL_SETTING, HTTP_SSL_DEFAULT); this.ssl = settings.getAsBoolean(HTTP_SSL_SETTING, HTTP_SSL_DEFAULT);
this.sslService = sslService; this.sslService = sslService;
@ -89,7 +90,7 @@ public class ShieldNettyHttpServerTransport extends NettyHttpServerTransport {
private final SSLClientAuth clientAuth; private final SSLClientAuth clientAuth;
public HttpSslChannelPipelineFactory(NettyHttpServerTransport transport) { 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); clientAuth = SSLClientAuth.parse(settings.get(HTTP_CLIENT_AUTH_SETTING), HTTP_CLIENT_AUTH_DEFAULT);
} }

View File

@ -38,7 +38,7 @@ public class BulkUpdateTests extends ShieldIntegTestCase {
public void testThatBulkUpdateDoesNotLoseFields() { public void testThatBulkUpdateDoesNotLoseFields() {
assertThat(client().prepareIndex("index1", "type").setSource("{\"test\": \"test\"}").setId("1").get().isCreated(), is(true)); 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(); 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()) { if (randomBoolean()) {
flushAndRefresh(); flushAndRefresh();

View File

@ -140,11 +140,11 @@ public class ClearRealmsCacheTests extends ShieldIntegTestCase {
public abstract void executeRequest() throws Exception; public abstract void executeRequest() throws Exception;
static void executeTransportRequest(ClearRealmCacheRequest request) 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 CountDownLatch latch = new CountDownLatch(1);
final AtomicReference<Throwable> error = new AtomicReference<>(); final AtomicReference<Throwable> error = new AtomicReference<>();
client.clearRealmCache(request, new ActionListener<ClearRealmCacheResponse>() { shieldClient.clearRealmCache(request, new ActionListener<ClearRealmCacheResponse>() {
@Override @Override
public void onResponse(ClearRealmCacheResponse response) { public void onResponse(ClearRealmCacheResponse response) {
assertThat(response.getNodes().length, equalTo(internalCluster().getNodeNames().length)); assertThat(response.getNodes().length, equalTo(internalCluster().getNodeNames().length));

View File

@ -13,6 +13,8 @@ import org.elasticsearch.shield.authc.support.Hasher;
import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.test.ShieldIntegTestCase; 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.BASIC_AUTH_HEADER;
import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
@ -88,16 +90,16 @@ public class DocumentAndFieldLevelSecurityTests extends ShieldIntegTestCase {
.setRefresh(true) .setRefresh(true)
.get(); .get();
SearchResponse response = client().prepareSearch("test") SearchResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .prepareSearch("test")
.get(); .get();
assertHitCount(response, 1); assertHitCount(response, 1);
assertSearchHits(response, "1"); assertSearchHits(response, "1");
assertThat(response.getHits().getAt(0).getSource().size(), equalTo(1)); assertThat(response.getHits().getAt(0).getSource().size(), equalTo(1));
assertThat(response.getHits().getAt(0).getSource().get("field1").toString(), equalTo("value1")); assertThat(response.getHits().getAt(0).getSource().get("field1").toString(), equalTo("value1"));
response = client().prepareSearch("test") response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .prepareSearch("test")
.get(); .get();
assertHitCount(response, 1); assertHitCount(response, 1);
assertSearchHits(response, "2"); 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: // 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); int max = scaledRandomIntBetween(4, 32);
for (int i = 0; i < max; i++) { 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)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .prepareSearch("test")
.get(); .get();
assertHitCount(response, 1); assertHitCount(response, 1);
assertThat(response.getHits().getAt(0).getId(), equalTo("1")); assertThat(response.getHits().getAt(0).getId(), equalTo("1"));
assertThat(response.getHits().getAt(0).sourceAsMap().size(), equalTo(1)); assertThat(response.getHits().getAt(0).sourceAsMap().size(), equalTo(1));
assertThat(response.getHits().getAt(0).sourceAsMap().get("field1"), equalTo("value1")); assertThat(response.getHits().getAt(0).sourceAsMap().get("field1"), equalTo("value1"));
response = client().prepareSearch("test") response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .prepareSearch("test")
.get(); .get();
assertHitCount(response, 1); assertHitCount(response, 1);
assertThat(response.getHits().getAt(0).getId(), equalTo("2")); 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 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: // this results in document 2 being returned but no fields are visible:
response = client().prepareSearch("test") response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)) .prepareSearch("test")
.get(); .get();
assertHitCount(response, 1); assertHitCount(response, 1);
assertThat(response.getHits().getAt(0).getId(), equalTo("2")); assertThat(response.getHits().getAt(0).getId(), equalTo("2"));

View File

@ -16,6 +16,7 @@ import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.test.ShieldIntegTestCase; import org.elasticsearch.test.ShieldIntegTestCase;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.BASIC_AUTH_HEADER; import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.BASIC_AUTH_HEADER;
@ -93,8 +94,8 @@ public class DocumentLevelSecurityRandomTests extends ShieldIntegTestCase {
builder.get(); builder.get();
for (int roleI = 1; roleI <= numberOfRoles; roleI++) { for (int roleI = 1; roleI <= numberOfRoles; roleI++) {
SearchResponse searchResponse1 = client().prepareSearch("test") SearchResponse searchResponse1 = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user" + roleI, USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user" + roleI, USERS_PASSWD)) .prepareSearch("test")
.get(); .get();
SearchResponse searchResponse2 = client().prepareSearch("alias" + roleI).get(); SearchResponse searchResponse2 = client().prepareSearch("alias" + roleI).get();
assertThat(searchResponse1.getHits().getTotalHits(), equalTo(searchResponse2.getHits().getTotalHits())); assertThat(searchResponse1.getHits().getTotalHits(), equalTo(searchResponse2.getHits().getTotalHits()));

View File

@ -29,6 +29,8 @@ import org.elasticsearch.shield.authc.support.Hasher;
import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.test.ShieldIntegTestCase; import org.elasticsearch.test.ShieldIntegTestCase;
import java.util.Collections;
import static org.elasticsearch.index.query.QueryBuilders.hasChildQuery; import static org.elasticsearch.index.query.QueryBuilders.hasChildQuery;
import static org.elasticsearch.index.query.QueryBuilders.hasParentQuery; import static org.elasticsearch.index.query.QueryBuilders.hasParentQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
@ -100,14 +102,14 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
.setRefresh(true) .setRefresh(true)
.get(); .get();
SearchResponse response = client().prepareSearch("test") SearchResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .prepareSearch("test")
.setQuery(randomBoolean() ? QueryBuilders.termQuery("field1", "value1") : QueryBuilders.matchAllQuery()) .setQuery(randomBoolean() ? QueryBuilders.termQuery("field1", "value1") : QueryBuilders.matchAllQuery())
.get(); .get();
assertHitCount(response, 1); assertHitCount(response, 1);
assertSearchHits(response, "1"); assertSearchHits(response, "1");
response = client().prepareSearch("test") response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .prepareSearch("test")
.setQuery(randomBoolean() ? QueryBuilders.termQuery("field2", "value2") : QueryBuilders.matchAllQuery()) .setQuery(randomBoolean() ? QueryBuilders.termQuery("field2", "value2") : QueryBuilders.matchAllQuery())
.get(); .get();
assertHitCount(response, 1); assertHitCount(response, 1);
@ -125,31 +127,31 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
.get(); .get();
Boolean realtime = randomFrom(true, false, null); 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) .setRealtime(realtime)
.setRefresh(true) .setRefresh(true)
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))
.get(); .get();
assertThat(response.isExists(), is(true)); assertThat(response.isExists(), is(true));
assertThat(response.getId(), equalTo("1")); 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) .setRealtime(realtime)
.setRefresh(true) .setRefresh(true)
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))
.get(); .get();
assertThat(response.isExists(), is(true)); assertThat(response.isExists(), is(true));
assertThat(response.getId(), equalTo("2")); 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) .setRealtime(realtime)
.setRefresh(true) .setRefresh(true)
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))
.get(); .get();
assertThat(response.isExists(), is(false)); 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) .setRealtime(realtime)
.setRefresh(true) .setRefresh(true)
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))
.get(); .get();
assertThat(response.isExists(), is(false)); assertThat(response.isExists(), is(false));
} }
@ -165,40 +167,40 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
.get(); .get();
Boolean realtime = randomFrom(true, false, null); 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") .add("test", "type1", "1")
.setRealtime(realtime) .setRealtime(realtime)
.setRefresh(true) .setRefresh(true)
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))
.get(); .get();
assertThat(response.getResponses()[0].isFailed(), is(false)); assertThat(response.getResponses()[0].isFailed(), is(false));
assertThat(response.getResponses()[0].getResponse().isExists(), is(true)); assertThat(response.getResponses()[0].getResponse().isExists(), is(true));
assertThat(response.getResponses()[0].getResponse().getId(), equalTo("1")); 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") .add("test", "type1", "2")
.setRealtime(realtime) .setRealtime(realtime)
.setRefresh(true) .setRefresh(true)
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))
.get(); .get();
assertThat(response.getResponses()[0].isFailed(), is(false)); assertThat(response.getResponses()[0].isFailed(), is(false));
assertThat(response.getResponses()[0].getResponse().isExists(), is(true)); assertThat(response.getResponses()[0].getResponse().isExists(), is(true));
assertThat(response.getResponses()[0].getResponse().getId(), equalTo("2")); 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") .add("test", "type1", "1")
.setRealtime(realtime) .setRealtime(realtime)
.setRefresh(true) .setRefresh(true)
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))
.get(); .get();
assertThat(response.getResponses()[0].isFailed(), is(false)); assertThat(response.getResponses()[0].isFailed(), is(false));
assertThat(response.getResponses()[0].getResponse().isExists(), 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") .add("test", "type1", "2")
.setRealtime(realtime) .setRealtime(realtime)
.setRefresh(true) .setRefresh(true)
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))
.get(); .get();
assertThat(response.getResponses()[0].isFailed(), is(false)); assertThat(response.getResponses()[0].isFailed(), is(false));
assertThat(response.getResponses()[0].getResponse().isExists(), is(false)); assertThat(response.getResponses()[0].getResponse().isExists(), is(false));
@ -216,29 +218,29 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
.get(); .get();
Boolean realtime = randomFrom(true, false, null); 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) .setRealtime(realtime)
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))
.get(); .get();
assertThat(response.isExists(), is(true)); assertThat(response.isExists(), is(true));
assertThat(response.getId(), is("1")); 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) .setRealtime(realtime)
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))
.get(); .get();
assertThat(response.isExists(), is(true)); assertThat(response.isExists(), is(true));
assertThat(response.getId(), is("2")); 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) .setRealtime(realtime)
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))
.get(); .get();
assertThat(response.isExists(), is(false)); 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) .setRealtime(realtime)
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))
.get(); .get();
assertThat(response.isExists(), is(false)); assertThat(response.isExists(), is(false));
} }
@ -255,32 +257,32 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
.get(); .get();
Boolean realtime = randomFrom(true, false, null); 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)) .add(new TermVectorsRequest("test", "type1", "1").realtime(realtime))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))
.get(); .get();
assertThat(response.getResponses().length, equalTo(1)); assertThat(response.getResponses().length, equalTo(1));
assertThat(response.getResponses()[0].getResponse().isExists(), is(true)); assertThat(response.getResponses()[0].getResponse().isExists(), is(true));
assertThat(response.getResponses()[0].getResponse().getId(), is("1")); 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)) .add(new TermVectorsRequest("test", "type1", "2").realtime(realtime))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))
.get(); .get();
assertThat(response.getResponses().length, equalTo(1)); assertThat(response.getResponses().length, equalTo(1));
assertThat(response.getResponses()[0].getResponse().isExists(), is(true)); assertThat(response.getResponses()[0].getResponse().isExists(), is(true));
assertThat(response.getResponses()[0].getResponse().getId(), is("2")); 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)) .add(new TermVectorsRequest("test", "type1", "1").realtime(realtime))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))
.get(); .get();
assertThat(response.getResponses().length, equalTo(1)); assertThat(response.getResponses().length, equalTo(1));
assertThat(response.getResponses()[0].getResponse().isExists(), is(false)); 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)) .add(new TermVectorsRequest("test", "type1", "2").realtime(realtime))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))
.get(); .get();
assertThat(response.getResponses().length, equalTo(1)); assertThat(response.getResponses().length, equalTo(1));
assertThat(response.getResponses()[0].getResponse().isExists(), is(false)); 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).getKeyAsString(), equalTo("value2"));
assertThat(termsAgg.getBuckets().get(0).getDocCount(), equalTo(1l)); 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"))) .addAggregation(AggregationBuilders.global("global").subAggregation(AggregationBuilders.terms("field2").field("field2")))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))
.get(); .get();
assertHitCount(response, 1); assertHitCount(response, 1);
assertSearchHits(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).getKeyAsString(), equalTo("value3"));
assertThat(termsAgg.getBuckets().get(0).getDocCount(), equalTo(1l)); 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") .setTypes("type1")
.addAggregation(AggregationBuilders.children("children").childType("type2") .addAggregation(AggregationBuilders.children("children").childType("type2")
.subAggregation(AggregationBuilders.terms("field3").field("field3"))) .subAggregation(AggregationBuilders.terms("field3").field("field3")))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))
.get(); .get();
assertHitCount(response, 1); assertHitCount(response, 1);
assertSearchHits(response, "1"); assertSearchHits(response, "1");
@ -392,27 +394,27 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
assertThat(searchResponse.getHits().getAt(1).id(), equalTo("c2")); 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: // 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())) .setQuery(hasChildQuery("child", matchAllQuery()))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))
.get(); .get();
assertHitCount(searchResponse, 0l); 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())) .setQuery(hasChildQuery("child", matchAllQuery()))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))
.get(); .get();
assertHitCount(searchResponse, 0l); 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())) .setQuery(hasParentQuery("parent", matchAllQuery()))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))
.get(); .get();
assertHitCount(searchResponse, 0l); 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())) .setQuery(hasParentQuery("parent", matchAllQuery()))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))
.get(); .get();
assertHitCount(searchResponse, 0l); assertHitCount(searchResponse, 0l);
} }
@ -427,30 +429,30 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
.get(); .get();
// Percolator without a query just evaluates all percolator queries that are loaded, so we have a match: // 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") .setDocumentType("type")
.setPercolateDoc(new PercolateSourceBuilder.DocBuilder().setDoc("{}")) .setPercolateDoc(new PercolateSourceBuilder.DocBuilder().setDoc("{}"))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))
.get(); .get();
assertThat(response.getCount(), equalTo(1l)); assertThat(response.getCount(), equalTo(1l));
assertThat(response.getMatches()[0].getId().string(), equalTo("1")); 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: // 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") .setDocumentType("type")
.setPercolateQuery(termQuery("field1", "value1")) .setPercolateQuery(termQuery("field1", "value1"))
.setPercolateDoc(new PercolateSourceBuilder.DocBuilder().setDoc("{}")) .setPercolateDoc(new PercolateSourceBuilder.DocBuilder().setDoc("{}"))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))
.get(); .get();
assertThat(response.getCount(), equalTo(1l)); assertThat(response.getCount(), equalTo(1l));
assertThat(response.getMatches()[0].getId().string(), equalTo("1")); 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: // 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") .setDocumentType("type")
.setPercolateQuery(termQuery("field1", "value1")) .setPercolateQuery(termQuery("field1", "value1"))
.setPercolateDoc(new PercolateSourceBuilder.DocBuilder().setDoc("{}")) .setPercolateDoc(new PercolateSourceBuilder.DocBuilder().setDoc("{}"))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))
.get(); .get();
assertThat(response.getCount(), equalTo(0l)); assertThat(response.getCount(), equalTo(0l));
@ -459,10 +461,10 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
ensureGreen("test"); ensureGreen("test");
// Ensure that the query loading that happens at startup has permissions to load the percolator queries: // 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") .setDocumentType("type")
.setPercolateDoc(new PercolateSourceBuilder.DocBuilder().setDoc("{}")) .setPercolateDoc(new PercolateSourceBuilder.DocBuilder().setDoc("{}"))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))
.get(); .get();
assertThat(response.getCount(), equalTo(1l)); assertThat(response.getCount(), equalTo(1l));
assertThat(response.getMatches()[0].getId().string(), equalTo("1")); assertThat(response.getMatches()[0].getId().string(), equalTo("1"));
@ -482,19 +484,19 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
int max = scaledRandomIntBetween(4, 32); int max = scaledRandomIntBetween(4, 32);
for (int i = 0; i < max; i++) { for (int i = 0; i < max; i++) {
Boolean requestCache = randomFrom(true, null); 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) .setSize(0)
.setQuery(termQuery("field1", "value1")) .setQuery(termQuery("field1", "value1"))
.setRequestCache(requestCache) .setRequestCache(requestCache)
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))
.get(); .get();
assertNoFailures(response); assertNoFailures(response);
assertHitCount(response, 1); assertHitCount(response, 1);
response = client().prepareSearch("test") response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)))
.prepareSearch("test")
.setSize(0) .setSize(0)
.setQuery(termQuery("field1", "value1")) .setQuery(termQuery("field1", "value1"))
.setRequestCache(requestCache) .setRequestCache(requestCache)
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))
.get(); .get();
assertNoFailures(response); assertNoFailures(response);
assertHitCount(response, 0); assertHitCount(response, 0);
@ -511,8 +513,8 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
// With document level security enabled the update is not allowed: // With document level security enabled the update is not allowed:
try { try {
client().prepareUpdate("test", "type", "1").setDoc("field1", "value2") client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .prepareUpdate("test", "type", "1").setDoc("field1", "value2")
.get(); .get();
fail("failed, because update request shouldn't be allowed if document level security is enabled"); fail("failed, because update request shouldn't be allowed if document level security is enabled");
} catch (ElasticsearchSecurityException e) { } catch (ElasticsearchSecurityException e) {
@ -528,8 +530,8 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
// With document level security enabled the update in bulk is not allowed: // With document level security enabled the update in bulk is not allowed:
try { try {
client().prepareBulk() client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .prepareBulk()
.add(new UpdateRequest("test", "type", "1").doc("field1", "value3")) .add(new UpdateRequest("test", "type", "1").doc("field1", "value3"))
.get(); .get();
fail("failed, because bulk request with updates shouldn't be allowed if field or document level security is enabled"); fail("failed, because bulk request with updates shouldn't be allowed if field or document level security is enabled");

View File

@ -16,6 +16,7 @@ import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.test.ShieldIntegTestCase; import org.elasticsearch.test.ShieldIntegTestCase;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -135,17 +136,17 @@ public class FieldLevelSecurityRandomTests extends ShieldIntegTestCase {
for (String allowedField : allowedFields) { for (String allowedField : allowedFields) {
logger.info("Checking allowed field [{}]", allowedField); 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")) .setQuery(matchQuery(allowedField, "value"))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))
.get(); .get();
assertHitCount(response, 1); assertHitCount(response, 1);
} }
for (String disallowedField : disAllowedFields) { for (String disallowedField : disAllowedFields) {
logger.info("Checking disallowed field [{}]", disallowedField); 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")) .setQuery(matchQuery(disallowedField, "value"))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))
.get(); .get();
assertHitCount(response, 0); assertHitCount(response, 0);
} }
@ -165,8 +166,8 @@ public class FieldLevelSecurityRandomTests extends ShieldIntegTestCase {
} }
indexRandom(true, requests); indexRandom(true, requests);
SearchResponse actual = client().prepareSearch("test") SearchResponse actual = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .prepareSearch("test")
.addSort("_uid", SortOrder.ASC) .addSort("_uid", SortOrder.ASC)
.setQuery(QueryBuilders.boolQuery() .setQuery(QueryBuilders.boolQuery()
.should(QueryBuilders.termQuery("field1", "value")) .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())); assertThat(actual.getHits().getAt(i).getId(), equalTo(expected.getHits().getAt(i).getId()));
} }
actual = client().prepareSearch("test") actual = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)) .prepareSearch("test")
.addSort("_uid", SortOrder.ASC) .addSort("_uid", SortOrder.ASC)
.setQuery(QueryBuilders.boolQuery() .setQuery(QueryBuilders.boolQuery()
.should(QueryBuilders.termQuery("field1", "value")) .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())); assertThat(actual.getHits().getAt(i).getId(), equalTo(expected.getHits().getAt(i).getId()));
} }
actual = client().prepareSearch("test") actual = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD)) .prepareSearch("test")
.addSort("_uid", SortOrder.ASC) .addSort("_uid", SortOrder.ASC)
.setQuery(QueryBuilders.boolQuery() .setQuery(QueryBuilders.boolQuery()
.should(QueryBuilders.termQuery("field1", "value")) .should(QueryBuilders.termQuery("field1", "value"))

View File

@ -29,6 +29,8 @@ import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.ShieldIntegTestCase; import org.elasticsearch.test.ShieldIntegTestCase;
import java.util.Collections;
import static org.elasticsearch.index.query.QueryBuilders.constantScoreQuery; import static org.elasticsearch.index.query.QueryBuilders.constantScoreQuery;
import static org.elasticsearch.index.query.QueryBuilders.hasChildQuery; import static org.elasticsearch.index.query.QueryBuilders.hasChildQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchQuery; import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
@ -127,63 +129,63 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
.get(); .get();
// user1 has access to field1, so the query should match with the document: // user1 has access to field1, so the query should match with the document:
SearchResponse response = client().prepareSearch("test") SearchResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .prepareSearch("test")
.setQuery(matchQuery("field1", "value1")) .setQuery(matchQuery("field1", "value1"))
.get(); .get();
assertHitCount(response, 1); assertHitCount(response, 1);
// user2 has no access to field1, so the query should not match with the document: // user2 has no access to field1, so the query should not match with the document:
response = client().prepareSearch("test") response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .prepareSearch("test")
.setQuery(matchQuery("field1", "value1")) .setQuery(matchQuery("field1", "value1"))
.get(); .get();
assertHitCount(response, 0); assertHitCount(response, 0);
// user3 has access to field1 and field2, so the query should match with the document: // user3 has access to field1 and field2, so the query should match with the document:
response = client().prepareSearch("test") response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)) .prepareSearch("test")
.setQuery(matchQuery("field1", "value1")) .setQuery(matchQuery("field1", "value1"))
.get(); .get();
assertHitCount(response, 1); assertHitCount(response, 1);
// user4 has access to no fields, so the query should not match with the document: // user4 has access to no fields, so the query should not match with the document:
response = client().prepareSearch("test") response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD)) .prepareSearch("test")
.setQuery(matchQuery("field1", "value1")) .setQuery(matchQuery("field1", "value1"))
.get(); .get();
assertHitCount(response, 0); assertHitCount(response, 0);
// user5 has no field level security configured, so the query should match with the document: // user5 has no field level security configured, so the query should match with the document:
response = client().prepareSearch("test") response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user5", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user5", USERS_PASSWD)) .prepareSearch("test")
.setQuery(matchQuery("field1", "value1")) .setQuery(matchQuery("field1", "value1"))
.get(); .get();
assertHitCount(response, 1); assertHitCount(response, 1);
// user1 has no access to field1, so the query should not match with the document: // user1 has no access to field1, so the query should not match with the document:
response = client().prepareSearch("test") response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .prepareSearch("test")
.setQuery(matchQuery("field2", "value2")) .setQuery(matchQuery("field2", "value2"))
.get(); .get();
assertHitCount(response, 0); assertHitCount(response, 0);
// user2 has access to field1, so the query should match with the document: // user2 has access to field1, so the query should match with the document:
response = client().prepareSearch("test") response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .prepareSearch("test")
.setQuery(matchQuery("field2", "value2")) .setQuery(matchQuery("field2", "value2"))
.get(); .get();
assertHitCount(response, 1); assertHitCount(response, 1);
// user3 has access to field1 and field2, so the query should match with the document: // user3 has access to field1 and field2, so the query should match with the document:
response = client().prepareSearch("test") response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)) .prepareSearch("test")
.setQuery(matchQuery("field2", "value2")) .setQuery(matchQuery("field2", "value2"))
.get(); .get();
assertHitCount(response, 1); assertHitCount(response, 1);
// user4 has access to no fields, so the query should not match with the document: // user4 has access to no fields, so the query should not match with the document:
response = client().prepareSearch("test") response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD)) .prepareSearch("test")
.setQuery(matchQuery("field2", "value2")) .setQuery(matchQuery("field2", "value2"))
.get(); .get();
assertHitCount(response, 0); assertHitCount(response, 0);
// user5 has no field level security configured, so the query should match with the document: // user5 has no field level security configured, so the query should match with the document:
response = client().prepareSearch("test") response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user5", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user5", USERS_PASSWD)) .prepareSearch("test")
.setQuery(matchQuery("field2", "value2")) .setQuery(matchQuery("field2", "value2"))
.get(); .get();
assertHitCount(response, 1); assertHitCount(response, 1);
@ -199,30 +201,30 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
Boolean realtime = randomFrom(true, false, null); Boolean realtime = randomFrom(true, false, null);
// user1 is granted access to field1 only: // 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) .setRealtime(realtime)
.setRefresh(true) .setRefresh(true)
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))
.get(); .get();
assertThat(response.isExists(), is(true)); assertThat(response.isExists(), is(true));
assertThat(response.getSource().size(), equalTo(1)); assertThat(response.getSource().size(), equalTo(1));
assertThat(response.getSource().get("field1").toString(), equalTo("value1")); assertThat(response.getSource().get("field1").toString(), equalTo("value1"));
// user2 is granted access to field2 only: // 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) .setRealtime(realtime)
.setRefresh(true) .setRefresh(true)
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))
.get(); .get();
assertThat(response.isExists(), is(true)); assertThat(response.isExists(), is(true));
assertThat(response.getSource().size(), equalTo(1)); assertThat(response.getSource().size(), equalTo(1));
assertThat(response.getSource().get("field2").toString(), equalTo("value2")); assertThat(response.getSource().get("field2").toString(), equalTo("value2"));
// user3 is granted access to field1 and field2: // 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) .setRealtime(realtime)
.setRefresh(true) .setRefresh(true)
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD))
.get(); .get();
assertThat(response.isExists(), is(true)); assertThat(response.isExists(), is(true));
assertThat(response.getSource().size(), equalTo(2)); assertThat(response.getSource().size(), equalTo(2));
@ -230,19 +232,19 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
assertThat(response.getSource().get("field2").toString(), equalTo("value2")); 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: // 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) .setRealtime(realtime)
.setRefresh(true) .setRefresh(true)
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD))
.get(); .get();
assertThat(response.isExists(), is(true)); assertThat(response.isExists(), is(true));
assertThat(response.getSource().size(), equalTo(0)); assertThat(response.getSource().size(), equalTo(0));
// user5 has no field level security configured, so all fields are returned: // 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) .setRealtime(realtime)
.setRefresh(true) .setRefresh(true)
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user5", USERS_PASSWD))
.get(); .get();
assertThat(response.isExists(), is(true)); assertThat(response.isExists(), is(true));
assertThat(response.getSource().size(), equalTo(2)); assertThat(response.getSource().size(), equalTo(2));
@ -259,11 +261,11 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
Boolean realtime = randomFrom(true, false, null); Boolean realtime = randomFrom(true, false, null);
// user1 is granted access to field1 only: // 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") .add("test", "type1", "1")
.setRealtime(realtime) .setRealtime(realtime)
.setRefresh(true) .setRefresh(true)
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))
.get(); .get();
assertThat(response.getResponses()[0].isFailed(), is(false)); assertThat(response.getResponses()[0].isFailed(), is(false));
assertThat(response.getResponses()[0].getResponse().isExists(), is(true)); 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")); assertThat(response.getResponses()[0].getResponse().getSource().get("field1").toString(), equalTo("value1"));
// user2 is granted access to field2 only: // 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") .add("test", "type1", "1")
.setRealtime(realtime) .setRealtime(realtime)
.setRefresh(true) .setRefresh(true)
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))
.get(); .get();
assertThat(response.getResponses()[0].isFailed(), is(false)); assertThat(response.getResponses()[0].isFailed(), is(false));
assertThat(response.getResponses()[0].getResponse().isExists(), is(true)); 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")); assertThat(response.getResponses()[0].getResponse().getSource().get("field2").toString(), equalTo("value2"));
// user3 is granted access to field1 and field2: // 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") .add("test", "type1", "1")
.setRealtime(realtime) .setRealtime(realtime)
.setRefresh(true) .setRefresh(true)
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD))
.get(); .get();
assertThat(response.getResponses()[0].isFailed(), is(false)); assertThat(response.getResponses()[0].isFailed(), is(false));
assertThat(response.getResponses()[0].getResponse().isExists(), is(true)); 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")); 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: // 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") .add("test", "type1", "1")
.setRealtime(realtime) .setRealtime(realtime)
.setRefresh(true) .setRefresh(true)
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD))
.get(); .get();
assertThat(response.getResponses()[0].isFailed(), is(false)); assertThat(response.getResponses()[0].isFailed(), is(false));
assertThat(response.getResponses()[0].getResponse().isExists(), is(true)); assertThat(response.getResponses()[0].getResponse().isExists(), is(true));
assertThat(response.getResponses()[0].getResponse().getSource().size(), equalTo(0)); assertThat(response.getResponses()[0].getResponse().getSource().size(), equalTo(0));
// user5 has no field level security configured, so all fields are returned: // 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") .add("test", "type1", "1")
.setRealtime(realtime) .setRealtime(realtime)
.setRefresh(true) .setRefresh(true)
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user5", USERS_PASSWD))
.get(); .get();
assertThat(response.getResponses()[0].isFailed(), is(false)); assertThat(response.getResponses()[0].isFailed(), is(false));
assertThat(response.getResponses()[0].getResponse().isExists(), is(true)); assertThat(response.getResponses()[0].getResponse().isExists(), is(true));
@ -329,41 +331,41 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
.get(); .get();
// user1 is granted access to field1 only: // 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") .setFields("field1", "field2")
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))
.get(); .get();
assertThat(response.getAllFieldStats().size(), equalTo(1)); assertThat(response.getAllFieldStats().size(), equalTo(1));
assertThat(response.getAllFieldStats().get("field1").getDocCount(), equalTo(1l)); assertThat(response.getAllFieldStats().get("field1").getDocCount(), equalTo(1l));
// user2 is granted access to field2 only: // 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") .setFields("field1", "field2")
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))
.get(); .get();
assertThat(response.getAllFieldStats().size(), equalTo(1)); assertThat(response.getAllFieldStats().size(), equalTo(1));
assertThat(response.getAllFieldStats().get("field2").getDocCount(), equalTo(1l)); assertThat(response.getAllFieldStats().get("field2").getDocCount(), equalTo(1l));
// user3 is granted access to field1 and field2: // 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") .setFields("field1", "field2")
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD))
.get(); .get();
assertThat(response.getAllFieldStats().size(), equalTo(2)); assertThat(response.getAllFieldStats().size(), equalTo(2));
assertThat(response.getAllFieldStats().get("field1").getDocCount(), equalTo(1l)); assertThat(response.getAllFieldStats().get("field1").getDocCount(), equalTo(1l));
assertThat(response.getAllFieldStats().get("field2").getDocCount(), equalTo(1l)); assertThat(response.getAllFieldStats().get("field2").getDocCount(), equalTo(1l));
// user4 is granted access to no fields: // 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") .setFields("field1", "field2")
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD))
.get(); .get();
assertThat(response.getAllFieldStats().size(), equalTo(0)); assertThat(response.getAllFieldStats().size(), equalTo(0));
// user5 has no field level security configured: // 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") .setFields("field1", "field2")
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user5", USERS_PASSWD))
.get(); .get();
assertThat(response.getAllFieldStats().size(), equalTo(2)); assertThat(response.getAllFieldStats().size(), equalTo(2));
assertThat(response.getAllFieldStats().get("field1").getDocCount(), equalTo(1l)); assertThat(response.getAllFieldStats().get("field1").getDocCount(), equalTo(1l));
@ -381,14 +383,14 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
int max = scaledRandomIntBetween(4, 32); int max = scaledRandomIntBetween(4, 32);
for (int i = 0; i < max; i++) { 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"))) .setQuery(constantScoreQuery(termQuery("field1", "value1")))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))
.get(); .get();
assertHitCount(response, 1); 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"))) .setQuery(constantScoreQuery(termQuery("field1", "value1")))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))
.get(); .get();
assertHitCount(response, 0); assertHitCount(response, 0);
} }
@ -406,19 +408,19 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
int max = scaledRandomIntBetween(4, 32); int max = scaledRandomIntBetween(4, 32);
for (int i = 0; i < max; i++) { for (int i = 0; i < max; i++) {
Boolean requestCache = randomFrom(true, null); 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) .setSize(0)
.setQuery(termQuery("field1", "value1")) .setQuery(termQuery("field1", "value1"))
.setRequestCache(requestCache) .setRequestCache(requestCache)
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))
.get(); .get();
assertNoFailures(response); assertNoFailures(response);
assertHitCount(response, 1); assertHitCount(response, 1);
response = client().prepareSearch("test") response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)))
.prepareSearch("test")
.setSize(0) .setSize(0)
.setQuery(termQuery("field1", "value1")) .setQuery(termQuery("field1", "value1"))
.setRequestCache(requestCache) .setRequestCache(requestCache)
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))
.get(); .get();
assertNoFailures(response); assertNoFailures(response);
assertHitCount(response, 0); assertHitCount(response, 0);
@ -434,46 +436,46 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
.get(); .get();
// user1 is granted access to field1 only: // 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("field1")
.addField("field2") .addField("field2")
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))
.get(); .get();
assertThat(response.getHits().getAt(0).fields().size(), equalTo(1)); assertThat(response.getHits().getAt(0).fields().size(), equalTo(1));
assertThat(response.getHits().getAt(0).fields().get("field1").<String>getValue(), equalTo("value1")); assertThat(response.getHits().getAt(0).fields().get("field1").<String>getValue(), equalTo("value1"));
// user2 is granted access to field2 only: // 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("field1")
.addField("field2") .addField("field2")
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))
.get(); .get();
assertThat(response.getHits().getAt(0).fields().size(), equalTo(1)); assertThat(response.getHits().getAt(0).fields().size(), equalTo(1));
assertThat(response.getHits().getAt(0).fields().get("field2").<String>getValue(), equalTo("value2")); assertThat(response.getHits().getAt(0).fields().get("field2").<String>getValue(), equalTo("value2"));
// user3 is granted access to field1 and field2: // 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("field1")
.addField("field2") .addField("field2")
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD))
.get(); .get();
assertThat(response.getHits().getAt(0).fields().size(), equalTo(2)); assertThat(response.getHits().getAt(0).fields().size(), equalTo(2));
assertThat(response.getHits().getAt(0).fields().get("field1").<String>getValue(), equalTo("value1")); assertThat(response.getHits().getAt(0).fields().get("field1").<String>getValue(), equalTo("value1"));
assertThat(response.getHits().getAt(0).fields().get("field2").<String>getValue(), equalTo("value2")); assertThat(response.getHits().getAt(0).fields().get("field2").<String>getValue(), equalTo("value2"));
// user4 is granted access to no fields: // 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("field1")
.addField("field2") .addField("field2")
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD))
.get(); .get();
assertThat(response.getHits().getAt(0).fields().size(), equalTo(0)); assertThat(response.getHits().getAt(0).fields().size(), equalTo(0));
// user5 has no field level security configured: // 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("field1")
.addField("field2") .addField("field2")
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user5", USERS_PASSWD))
.get(); .get();
assertThat(response.getHits().getAt(0).fields().size(), equalTo(2)); assertThat(response.getHits().getAt(0).fields().size(), equalTo(2));
assertThat(response.getHits().getAt(0).fields().get("field1").<String>getValue(), equalTo("value1")); assertThat(response.getHits().getAt(0).fields().get("field1").<String>getValue(), equalTo("value1"));
@ -489,36 +491,36 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
.get(); .get();
// user1 is granted access to field1 only: // 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)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .prepareSearch("test")
.get(); .get();
assertThat(response.getHits().getAt(0).sourceAsMap().size(), equalTo(1)); assertThat(response.getHits().getAt(0).sourceAsMap().size(), equalTo(1));
assertThat(response.getHits().getAt(0).sourceAsMap().get("field1").toString(), equalTo("value1")); assertThat(response.getHits().getAt(0).sourceAsMap().get("field1").toString(), equalTo("value1"));
// user2 is granted access to field2 only: // user2 is granted access to field2 only:
response = client().prepareSearch("test") response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .prepareSearch("test")
.get(); .get();
assertThat(response.getHits().getAt(0).sourceAsMap().size(), equalTo(1)); assertThat(response.getHits().getAt(0).sourceAsMap().size(), equalTo(1));
assertThat(response.getHits().getAt(0).sourceAsMap().get("field2").toString(), equalTo("value2")); assertThat(response.getHits().getAt(0).sourceAsMap().get("field2").toString(), equalTo("value2"));
// user3 is granted access to field1 and field2: // user3 is granted access to field1 and field2:
response = client().prepareSearch("test") response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)) .prepareSearch("test")
.get(); .get();
assertThat(response.getHits().getAt(0).sourceAsMap().size(), equalTo(2)); 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("field1").toString(), equalTo("value1"));
assertThat(response.getHits().getAt(0).sourceAsMap().get("field2").toString(), equalTo("value2")); assertThat(response.getHits().getAt(0).sourceAsMap().get("field2").toString(), equalTo("value2"));
// user4 is granted access to no fields: // user4 is granted access to no fields:
response = client().prepareSearch("test") response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD)) .prepareSearch("test")
.get(); .get();
assertThat(response.getHits().getAt(0).sourceAsMap().size(), equalTo(0)); assertThat(response.getHits().getAt(0).sourceAsMap().size(), equalTo(0));
// user5 has no field level security configured: // user5 has no field level security configured:
response = client().prepareSearch("test") response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user5", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user5", USERS_PASSWD)) .prepareSearch("test")
.get(); .get();
assertThat(response.getHits().getAt(0).sourceAsMap().size(), equalTo(2)); 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("field1").toString(), equalTo("value1"));
@ -535,29 +537,29 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
.get(); .get();
// user1 is granted to use field1, so it is included in the sort_values // user1 is granted to use field1, so it is included in the sort_values
SearchResponse response = client().prepareSearch("test") SearchResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .prepareSearch("test")
.addSort("field1", SortOrder.ASC) .addSort("field1", SortOrder.ASC)
.get(); .get();
assertThat((Long) response.getHits().getAt(0).sortValues()[0], equalTo(1l)); 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 // user2 is not granted to use field1, so the default missing sort value is included
response = client().prepareSearch("test") response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .prepareSearch("test")
.addSort("field1", SortOrder.ASC) .addSort("field1", SortOrder.ASC)
.get(); .get();
assertThat((Long) response.getHits().getAt(0).sortValues()[0], equalTo(Long.MAX_VALUE)); 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 // user1 is not granted to use field2, so the default missing sort value is included
response = client().prepareSearch("test") response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .prepareSearch("test")
.addSort("field2", SortOrder.ASC) .addSort("field2", SortOrder.ASC)
.get(); .get();
assertThat((Long) response.getHits().getAt(0).sortValues()[0], equalTo(Long.MAX_VALUE)); 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 // user2 is granted to use field2, so it is included in the sort_values
response = client().prepareSearch("test") response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .prepareSearch("test")
.addSort("field2", SortOrder.ASC) .addSort("field2", SortOrder.ASC)
.get(); .get();
assertThat((Long) response.getHits().getAt(0).sortValues()[0], equalTo(2l)); assertThat((Long) response.getHits().getAt(0).sortValues()[0], equalTo(2l));
@ -572,29 +574,29 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
.get(); .get();
// user1 is authorized to use field1, so buckets are include for a term agg on field1 // user1 is authorized to use field1, so buckets are include for a term agg on field1
SearchResponse response = client().prepareSearch("test") SearchResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .prepareSearch("test")
.addAggregation(AggregationBuilders.terms("_name").field("field1")) .addAggregation(AggregationBuilders.terms("_name").field("field1"))
.get(); .get();
assertThat(((Terms) response.getAggregations().get("_name")).getBucketByKey("value1").getDocCount(), equalTo(1l)); 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 // user2 is not authorized to use field1, so no buckets are include for a term agg on field1
response = client().prepareSearch("test") response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .prepareSearch("test")
.addAggregation(AggregationBuilders.terms("_name").field("field1")) .addAggregation(AggregationBuilders.terms("_name").field("field1"))
.get(); .get();
assertThat(((Terms) response.getAggregations().get("_name")).getBucketByKey("value1"), nullValue()); 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 // user1 is not authorized to use field2, so no buckets are include for a term agg on field2
response = client().prepareSearch("test") response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .prepareSearch("test")
.addAggregation(AggregationBuilders.terms("_name").field("field2")) .addAggregation(AggregationBuilders.terms("_name").field("field2"))
.get(); .get();
assertThat(((Terms) response.getAggregations().get("_name")).getBucketByKey("value2"), nullValue()); 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 // user2 is authorized to use field2, so buckets are include for a term agg on field2
response = client().prepareSearch("test") response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)) .prepareSearch("test")
.addAggregation(AggregationBuilders.terms("_name").field("field2")) .addAggregation(AggregationBuilders.terms("_name").field("field2"))
.get(); .get();
assertThat(((Terms) response.getAggregations().get("_name")).getBucketByKey("value2").getDocCount(), equalTo(1l)); assertThat(((Terms) response.getAggregations().get("_name")).getBucketByKey("value2").getDocCount(), equalTo(1l));
@ -609,24 +611,24 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
.get(); .get();
Boolean realtime = randomFrom(true, false, null); 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) .setRealtime(realtime)
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))
.get(); .get();
assertThat(response.isExists(), is(true)); assertThat(response.isExists(), is(true));
assertThat(response.getFields().size(), equalTo(1)); assertThat(response.getFields().size(), equalTo(1));
assertThat(response.getFields().terms("field1").size(), equalTo(1l)); 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) .setRealtime(realtime)
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))
.get(); .get();
assertThat(response.isExists(), is(true)); assertThat(response.isExists(), is(true));
assertThat(response.getFields().size(), equalTo(1)); assertThat(response.getFields().size(), equalTo(1));
assertThat(response.getFields().terms("field2").size(), equalTo(1l)); assertThat(response.getFields().terms("field2").size(), equalTo(1l));
response = client().prepareTermVectors("test", "type1", "1") response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)) .prepareTermVectors("test", "type1", "1")
.setRealtime(realtime) .setRealtime(realtime)
.get(); .get();
assertThat(response.isExists(), is(true)); 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("field1").size(), equalTo(1l));
assertThat(response.getFields().terms("field2").size(), equalTo(1l)); assertThat(response.getFields().terms("field2").size(), equalTo(1l));
response = client().prepareTermVectors("test", "type1", "1") response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD)) .prepareTermVectors("test", "type1", "1")
.setRealtime(realtime) .setRealtime(realtime)
.get(); .get();
assertThat(response.isExists(), is(true)); assertThat(response.isExists(), is(true));
@ -651,27 +653,27 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
.get(); .get();
Boolean realtime = randomFrom(true, false, null); 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)) .add(new TermVectorsRequest("test", "type1", "1").realtime(realtime))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))
.get(); .get();
assertThat(response.getResponses().length, equalTo(1)); assertThat(response.getResponses().length, equalTo(1));
assertThat(response.getResponses()[0].getResponse().isExists(), is(true)); assertThat(response.getResponses()[0].getResponse().isExists(), is(true));
assertThat(response.getResponses()[0].getResponse().getFields().size(), equalTo(1)); assertThat(response.getResponses()[0].getResponse().getFields().size(), equalTo(1));
assertThat(response.getResponses()[0].getResponse().getFields().terms("field1").size(), equalTo(1l)); 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)) .add(new TermVectorsRequest("test", "type1", "1").realtime(realtime))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))
.get(); .get();
assertThat(response.getResponses().length, equalTo(1)); assertThat(response.getResponses().length, equalTo(1));
assertThat(response.getResponses()[0].getResponse().isExists(), is(true)); assertThat(response.getResponses()[0].getResponse().isExists(), is(true));
assertThat(response.getResponses()[0].getResponse().getFields().size(), equalTo(1)); assertThat(response.getResponses()[0].getResponse().getFields().size(), equalTo(1));
assertThat(response.getResponses()[0].getResponse().getFields().terms("field2").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("user3", USERS_PASSWD)))
.prepareMultiTermVectors()
.add(new TermVectorsRequest("test", "type1", "1").realtime(realtime)) .add(new TermVectorsRequest("test", "type1", "1").realtime(realtime))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD))
.get(); .get();
assertThat(response.getResponses().length, equalTo(1)); assertThat(response.getResponses().length, equalTo(1));
assertThat(response.getResponses()[0].getResponse().isExists(), is(true)); 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("field1").size(), equalTo(1l));
assertThat(response.getResponses()[0].getResponse().getFields().terms("field2").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)) .add(new TermVectorsRequest("test", "type1", "1").realtime(realtime))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD))
.get(); .get();
assertThat(response.getResponses().length, equalTo(1)); assertThat(response.getResponses().length, equalTo(1));
assertThat(response.getResponses()[0].getResponse().isExists(), is(true)); assertThat(response.getResponses()[0].getResponse().isExists(), is(true));
@ -698,20 +700,20 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
.get(); .get();
// Percolator without a query just evaluates all percolator queries that are loaded, so we have a match: // 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") .setDocumentType("type")
.setPercolateDoc(new PercolateSourceBuilder.DocBuilder().setDoc("{}")) .setPercolateDoc(new PercolateSourceBuilder.DocBuilder().setDoc("{}"))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))
.get(); .get();
assertThat(response.getCount(), equalTo(1l)); assertThat(response.getCount(), equalTo(1l));
assertThat(response.getMatches()[0].getId().string(), equalTo("1")); 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: // 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") .setDocumentType("type")
.setPercolateQuery(termQuery("field1", "value1")) .setPercolateQuery(termQuery("field1", "value1"))
.setPercolateDoc(new PercolateSourceBuilder.DocBuilder().setDoc("{}")) .setPercolateDoc(new PercolateSourceBuilder.DocBuilder().setDoc("{}"))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))
.get(); .get();
assertThat(response.getCount(), equalTo(0l)); assertThat(response.getCount(), equalTo(0l));
@ -720,10 +722,10 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
ensureGreen("test"); ensureGreen("test");
// Ensure that the query loading that happens at startup has permissions to load the percolator queries: // 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") .setDocumentType("type")
.setPercolateDoc(new PercolateSourceBuilder.DocBuilder().setDoc("{}")) .setPercolateDoc(new PercolateSourceBuilder.DocBuilder().setDoc("{}"))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))
.get(); .get();
assertThat(response.getCount(), equalTo(1l)); assertThat(response.getCount(), equalTo(1l));
assertThat(response.getMatches()[0].getId().string(), equalTo("1")); 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(); client().prepareIndex("test", "child", "c2").setSource("field1", "yellow").setParent("p1").get();
refresh(); 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"))) .setQuery(hasChildQuery("child", termQuery("field1", "yellow")))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))
.get(); .get();
assertHitCount(searchResponse, 1l); assertHitCount(searchResponse, 1l);
assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); assertThat(searchResponse.getHits().totalHits(), equalTo(1l));
assertThat(searchResponse.getHits().getAt(0).id(), equalTo("p1")); 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"))) .setQuery(hasChildQuery("child", termQuery("field1", "yellow")))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))
.get(); .get();
assertHitCount(searchResponse, 0l); assertHitCount(searchResponse, 0l);
} }
@ -767,8 +769,8 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
// With field level security enabled the update is not allowed: // With field level security enabled the update is not allowed:
try { try {
client().prepareUpdate("test", "type", "1").setDoc("field2", "value2") client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .prepareUpdate("test", "type", "1").setDoc("field2", "value2")
.get(); .get();
fail("failed, because update request shouldn't be allowed if field level security is enabled"); fail("failed, because update request shouldn't be allowed if field level security is enabled");
} catch (ElasticsearchSecurityException e) { } catch (ElasticsearchSecurityException e) {
@ -784,8 +786,8 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
// With field level security enabled the update in bulk is not allowed: // With field level security enabled the update in bulk is not allowed:
try { try {
client().prepareBulk() client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .prepareBulk()
.add(new UpdateRequest("test", "type", "1").doc("field2", "value3")) .add(new UpdateRequest("test", "type", "1").doc("field2", "value3"))
.get(); .get();
fail("failed, because bulk request with updates shouldn't be allowed if field level security is enabled"); 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(); .get();
// user6 has access to all fields, so the query should match with the document: // user6 has access to all fields, so the query should match with the document:
SearchResponse response = client().prepareSearch("test") SearchResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user6", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user6", USERS_PASSWD)) .prepareSearch("test")
.setQuery(matchQuery("field1", "value1")) .setQuery(matchQuery("field1", "value1"))
.get(); .get();
assertHitCount(response, 1); 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("field1").toString(), equalTo("value1"));
assertThat(response.getHits().getAt(0).sourceAsMap().get("field2").toString(), equalTo("value2")); assertThat(response.getHits().getAt(0).sourceAsMap().get("field2").toString(), equalTo("value2"));
response = client().prepareSearch("test") response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user6", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user6", USERS_PASSWD)) .prepareSearch("test")
.setQuery(matchQuery("field2", "value2")) .setQuery(matchQuery("field2", "value2"))
.get(); .get();
assertHitCount(response, 1); assertHitCount(response, 1);

View File

@ -13,6 +13,8 @@ import org.elasticsearch.shield.authc.support.Hasher;
import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.test.ShieldIntegTestCase; 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.BASIC_AUTH_HEADER;
import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
@ -72,20 +74,20 @@ public class IndicesPermissionsWithAliasesWildcardsAndRegexsTests extends Shield
.setRefresh(true) .setRefresh(true)
.get(); .get();
GetResponse getResponse = client().prepareGet("test", "type1", "1") GetResponse getResponse = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .prepareGet("test", "type1", "1")
.get(); .get();
assertThat(getResponse.getSource().size(), equalTo(1)); assertThat(getResponse.getSource().size(), equalTo(1));
assertThat((String) getResponse.getSource().get("field1"), equalTo("value1")); assertThat((String) getResponse.getSource().get("field1"), equalTo("value1"));
getResponse = client().prepareGet("my_alias", "type1", "1") getResponse = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .prepareGet("my_alias", "type1", "1")
.get(); .get();
assertThat(getResponse.getSource().size(), equalTo(1)); assertThat(getResponse.getSource().size(), equalTo(1));
assertThat((String) getResponse.getSource().get("field2"), equalTo("value2")); assertThat((String) getResponse.getSource().get("field2"), equalTo("value2"));
getResponse = client().prepareGet("an_alias", "type1", "1") getResponse = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)) .prepareGet("an_alias", "type1", "1")
.get(); .get();
assertThat(getResponse.getSource().size(), equalTo(1)); assertThat(getResponse.getSource().size(), equalTo(1));
assertThat((String) getResponse.getSource().get("field3"), equalTo("value3")); assertThat((String) getResponse.getSource().get("field3"), equalTo("value3"));

View File

@ -14,7 +14,6 @@ import org.elasticsearch.action.admin.cluster.stats.ClusterStatsResponse;
import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse; import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse;
import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.elasticsearch.client.support.Headers;
import org.elasticsearch.client.transport.NoNodeAvailableException; import org.elasticsearch.client.transport.NoNodeAvailableException;
import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.component.AbstractComponent; 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.inject.Module;
import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.license.core.License.OperationMode; import org.elasticsearch.license.core.License.OperationMode;
import org.elasticsearch.license.plugin.LicensePlugin; import org.elasticsearch.license.plugin.LicensePlugin;
import org.elasticsearch.license.plugin.core.LicenseState; import org.elasticsearch.license.plugin.core.LicenseState;
@ -203,7 +203,7 @@ public class LicensingTests extends ShieldIntegTestCase {
.put(internalCluster().transportClient().settings()); .put(internalCluster().transportClient().settings());
// remove user info // remove user info
builder.remove("shield.user"); builder.remove("shield.user");
builder.remove(Headers.PREFIX + "." + UsernamePasswordToken.BASIC_AUTH_HEADER); builder.remove(ThreadContext.PREFIX + "." + UsernamePasswordToken.BASIC_AUTH_HEADER);
// basic has no auth // basic has no auth
try (TransportClient client = TransportClient.builder().settings(builder).addPlugin(XPackPlugin.class).build()) { try (TransportClient client = TransportClient.builder().settings(builder).addPlugin(XPackPlugin.class).build()) {

View File

@ -13,21 +13,23 @@ import org.elasticsearch.client.Client;
import org.elasticsearch.rest.RestStatus; import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.shield.authc.support.Hasher; import org.elasticsearch.shield.authc.support.Hasher;
import org.elasticsearch.shield.authc.support.SecuredString; 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.ShieldIntegTestCase;
import org.elasticsearch.test.ShieldSettingsSource; import org.elasticsearch.test.ShieldSettingsSource;
import java.util.Collections;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.index.query.QueryBuilders.indicesQuery; import static org.elasticsearch.index.query.QueryBuilders.indicesQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; 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.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.assertHitCount;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
public class MultipleIndicesPermissionsTests extends ShieldIntegTestCase { 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 @Override
protected String configRoles() { protected String configRoles() {
@ -154,8 +156,8 @@ public class MultipleIndicesPermissionsTests extends ShieldIntegTestCase {
Client client = internalCluster().transportClient(); Client client = internalCluster().transportClient();
SearchResponse response = client.prepareSearch("a") SearchResponse response = client.filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user_a", PASSWD)))
.putHeader(BASIC_AUTH_HEADER, userHeader("user_a", "passwd")) .prepareSearch("a")
.get(); .get();
assertNoFailures(response); assertNoFailures(response);
assertHitCount(response, 1); assertHitCount(response, 1);
@ -164,16 +166,16 @@ public class MultipleIndicesPermissionsTests extends ShieldIntegTestCase {
new String[] { "_all"} : randomBoolean() ? new String[] { "_all"} : randomBoolean() ?
new String[] { "*" } : new String[] { "*" } :
new String[] {}; new String[] {};
response = client.prepareSearch(indices) response = client.filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user_a", PASSWD)))
.putHeader(BASIC_AUTH_HEADER, userHeader("user_a", "passwd")) .prepareSearch(indices)
.get(); .get();
assertNoFailures(response); assertNoFailures(response);
assertHitCount(response, 1); assertHitCount(response, 1);
try { try {
indices = randomBoolean() ? new String[] { "a", "b" } : new String[] { "b", "a" }; indices = randomBoolean() ? new String[] { "a", "b" } : new String[] { "b", "a" };
client.prepareSearch(indices) client.filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user_a", PASSWD)))
.putHeader(BASIC_AUTH_HEADER, userHeader("user_a", "passwd")) .prepareSearch(indices)
.get(); .get();
fail("expected an authorization excpetion when trying to search on multiple indices where there are no search permissions on one/some of them"); 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) { } catch (ElasticsearchSecurityException e) {
@ -181,15 +183,15 @@ public class MultipleIndicesPermissionsTests extends ShieldIntegTestCase {
assertThat(e.status(), is(RestStatus.FORBIDDEN)); assertThat(e.status(), is(RestStatus.FORBIDDEN));
} }
response = client.prepareSearch("b") response = client.filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user_ab", PASSWD)))
.putHeader(BASIC_AUTH_HEADER, userHeader("user_ab", "passwd")) .prepareSearch("b")
.get(); .get();
assertNoFailures(response); assertNoFailures(response);
assertHitCount(response, 1); assertHitCount(response, 1);
indices = randomBoolean() ? new String[] { "a", "b" } : new String[] { "b", "a" }; indices = randomBoolean() ? new String[] { "a", "b" } : new String[] { "b", "a" };
response = client.prepareSearch(indices) response = client.filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user_ab", PASSWD)))
.putHeader(BASIC_AUTH_HEADER, userHeader("user_ab", "passwd")) .prepareSearch(indices)
.get(); .get();
assertNoFailures(response); assertNoFailures(response);
assertHitCount(response, 2); assertHitCount(response, 2);
@ -198,14 +200,10 @@ public class MultipleIndicesPermissionsTests extends ShieldIntegTestCase {
new String[] { "_all"} : randomBoolean() ? new String[] { "_all"} : randomBoolean() ?
new String[] { "*" } : new String[] { "*" } :
new String[] {}; new String[] {};
response = client.prepareSearch(indices) response = client.filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user_ab", PASSWD)))
.putHeader(BASIC_AUTH_HEADER, userHeader("user_ab", "passwd")) .prepareSearch(indices)
.get(); .get();
assertNoFailures(response); assertNoFailures(response);
assertHitCount(response, 2); assertHitCount(response, 2);
} }
private static String userHeader(String username, String password) {
return UsernamePasswordToken.basicAuthHeaderValue(username, SecuredStringTests.build(password));
}
} }

View File

@ -17,6 +17,7 @@ import org.elasticsearch.shield.authc.support.SecuredStringTests;
import org.elasticsearch.shield.authc.support.UsernamePasswordToken; import org.elasticsearch.shield.authc.support.UsernamePasswordToken;
import org.elasticsearch.test.ShieldIntegTestCase; import org.elasticsearch.test.ShieldIntegTestCase;
import java.util.Collections;
import java.util.List; import java.util.List;
import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue; 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 // 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_*") .setTemplate("test_*")
.putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, basicAuthHeaderValue(transportClientUsername(), transportClientPassword()))
.get(); .get();
assertAcked(putResponse); assertAcked(putResponse);
@ -106,9 +107,9 @@ public class PermissionPrecedenceTests extends ShieldIntegTestCase {
// now lets try with "user" // now lets try with "user"
try { try {
client.admin().indices().preparePutTemplate("template1") client.filterWithHeader(Collections.singletonMap(UsernamePasswordToken.BASIC_AUTH_HEADER, basicAuthHeaderValue("user", transportClientPassword())))
.admin().indices().preparePutTemplate("template1")
.setTemplate("test_*") .setTemplate("test_*")
.putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, basicAuthHeaderValue("user", transportClientPassword()))
.get(); .get();
fail("expected an authorization exception as template APIs should require cluster ALL permission"); fail("expected an authorization exception as template APIs should require cluster ALL permission");
} catch (ElasticsearchSecurityException e) { } catch (ElasticsearchSecurityException e) {
@ -117,8 +118,8 @@ public class PermissionPrecedenceTests extends ShieldIntegTestCase {
} }
try { try {
client.admin().indices().prepareGetTemplates("template1") client.filterWithHeader(Collections.singletonMap(UsernamePasswordToken.BASIC_AUTH_HEADER, basicAuthHeaderValue("user", SecuredStringTests.build("test123"))))
.putHeader("Authorization", basicAuthHeaderValue("user", SecuredStringTests.build("test123"))) .admin().indices().prepareGetTemplates("template1")
.get(); .get();
fail("expected an authorization exception as template APIs should require cluster ALL permission"); fail("expected an authorization exception as template APIs should require cluster ALL permission");
} catch (ElasticsearchSecurityException e) { } catch (ElasticsearchSecurityException e) {

View File

@ -19,6 +19,8 @@ import org.elasticsearch.shield.authc.support.SecuredStringTests;
import org.elasticsearch.shield.authc.support.UsernamePasswordToken; import org.elasticsearch.shield.authc.support.UsernamePasswordToken;
import org.elasticsearch.test.ShieldIntegTestCase; import org.elasticsearch.test.ShieldIntegTestCase;
import java.util.Collections;
import static org.elasticsearch.client.Requests.searchRequest; import static org.elasticsearch.client.Requests.searchRequest;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.test.ShieldTestsUtils.assertAuthorizationException; import static org.elasticsearch.test.ShieldTestsUtils.assertAuthorizationException;
@ -77,21 +79,21 @@ public class SearchGetAndSuggestPermissionsTests extends ShieldIntegTestCase {
Client client = internalCluster().transportClient(); Client client = internalCluster().transportClient();
SuggestResponse suggestResponse = client.prepareSuggest("a") SuggestResponse suggestResponse = client.filterWithHeader(Collections.singletonMap(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("suggest_user", "passwd")))
.putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("suggest_user", "passwd")) .prepareSuggest("a")
.addSuggestion(SuggestBuilders.termSuggestion("name").field("name").text("val")).get(); .addSuggestion(SuggestBuilders.termSuggestion("name").field("name").text("val")).get();
assertNoFailures(suggestResponse); assertNoFailures(suggestResponse);
assertThat(suggestResponse.getSuggest().size(), is(1)); assertThat(suggestResponse.getSuggest().size(), is(1));
suggestResponse = client.prepareSuggest("a") suggestResponse = client.filterWithHeader(Collections.singletonMap(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("search_user", "passwd")))
.putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("search_user", "passwd")) .prepareSuggest("a")
.addSuggestion(SuggestBuilders.termSuggestion("name").field("name").text("val")).get(); .addSuggestion(SuggestBuilders.termSuggestion("name").field("name").text("val")).get();
assertNoFailures(suggestResponse); assertNoFailures(suggestResponse);
assertThat(suggestResponse.getSuggest().size(), is(1)); assertThat(suggestResponse.getSuggest().size(), is(1));
try { try {
client.prepareSearch("a") client.filterWithHeader(Collections.singletonMap(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("suggest_user", "passwd")))
.putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("suggest_user", "passwd")) .prepareSearch("a")
.get(); .get();
fail("a user with only a suggest privilege cannot execute search"); fail("a user with only a suggest privilege cannot execute search");
} catch (ElasticsearchSecurityException e) { } catch (ElasticsearchSecurityException e) {
@ -115,8 +117,8 @@ public class SearchGetAndSuggestPermissionsTests extends ShieldIntegTestCase {
Client client = internalCluster().transportClient(); Client client = internalCluster().transportClient();
try { try {
client.prepareGet("a", "type", indexResponse.getId()) client.filterWithHeader(Collections.singletonMap(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("search_user", "passwd")))
.putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("search_user", "passwd")) .prepareGet("a", "type", indexResponse.getId())
.get(); .get();
fail("a user with only search privilege should not be authorized for a get request"); fail("a user with only search privilege should not be authorized for a get request");
} catch (ElasticsearchSecurityException e) { } catch (ElasticsearchSecurityException e) {
@ -140,16 +142,16 @@ public class SearchGetAndSuggestPermissionsTests extends ShieldIntegTestCase {
Client client = internalCluster().transportClient(); Client client = internalCluster().transportClient();
MultiGetResponse response = client.prepareMultiGet().add("a", "type", indexResponse.getId()) MultiGetResponse response = client.filterWithHeader(Collections.singletonMap(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("get_user", "passwd")))
.putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("get_user", "passwd")) .prepareMultiGet().add("a", "type", indexResponse.getId())
.get(); .get();
assertNotNull(response); assertNotNull(response);
assertThat(response.getResponses().length, is(1)); assertThat(response.getResponses().length, is(1));
assertThat(response.getResponses()[0].getId(), equalTo(indexResponse.getId())); assertThat(response.getResponses()[0].getId(), equalTo(indexResponse.getId()));
try { try {
client.prepareMultiGet().add("a", "type", indexResponse.getId()) client.filterWithHeader(Collections.singletonMap(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("search_user", "passwd")))
.putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("search_user", "passwd")) .prepareMultiGet().add("a", "type", indexResponse.getId())
.get(); .get();
fail("a user with only a search privilege should not be able to execute the mget API"); fail("a user with only a search privilege should not be able to execute the mget API");
} catch (ElasticsearchSecurityException e) { } catch (ElasticsearchSecurityException e) {
@ -173,8 +175,8 @@ public class SearchGetAndSuggestPermissionsTests extends ShieldIntegTestCase {
Client client = internalCluster().transportClient(); Client client = internalCluster().transportClient();
MultiSearchResponse response = client.prepareMultiSearch().add(searchRequest("a").types("type")) MultiSearchResponse response = client.filterWithHeader(Collections.singletonMap(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("search_user", "passwd")))
.putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, userHeader("search_user", "passwd")) .prepareMultiSearch().add(searchRequest("a").types("type"))
.get(); .get();
assertNotNull(response); assertNotNull(response);
assertThat(response.getResponses().length, is(1)); assertThat(response.getResponses().length, is(1));

View File

@ -19,8 +19,11 @@ import org.junit.After;
import org.junit.Before; import org.junit.Before;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; 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.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertThrows; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertThrows;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
@ -85,9 +88,11 @@ public class ShieldClearScrollTests extends ShieldIntegTestCase {
public void testThatClearingAllScrollIdsWorks() throws Exception { public void testThatClearingAllScrollIdsWorks() throws Exception {
String shieldUser = "allowed_user:change_me"; String shieldUser = "allowed_user:change_me";
String basicAuth = basicAuthHeaderValue("allowed_user", new SecuredString("change_me".toCharArray())); String basicAuth = basicAuthHeaderValue("allowed_user", new SecuredString("change_me".toCharArray()));
ClearScrollResponse clearScrollResponse = internalCluster().transportClient().prepareClearScroll() Map<String, String> headers = new HashMap<>();
.putHeader("shield.user", shieldUser) headers.put("shield.user", shieldUser);
.putHeader("Authorization", basicAuth) headers.put(BASIC_AUTH_HEADER, basicAuth);
ClearScrollResponse clearScrollResponse = internalCluster().transportClient().filterWithHeader(headers)
.prepareClearScroll()
.addScrollId("_all").get(); .addScrollId("_all").get();
assertThat(clearScrollResponse.isSucceeded(), is(true)); assertThat(clearScrollResponse.isSucceeded(), is(true));
@ -97,10 +102,11 @@ public class ShieldClearScrollTests extends ShieldIntegTestCase {
public void testThatClearingAllScrollIdsRequirePermissions() throws Exception { public void testThatClearingAllScrollIdsRequirePermissions() throws Exception {
String shieldUser = "denied_user:change_me"; String shieldUser = "denied_user:change_me";
String basicAuth = basicAuthHeaderValue("denied_user", new SecuredString("change_me".toCharArray())); String basicAuth = basicAuthHeaderValue("denied_user", new SecuredString("change_me".toCharArray()));
Map<String, String> headers = new HashMap<>();
assertThrows(internalCluster().transportClient().prepareClearScroll() headers.put("shield.user", shieldUser);
.putHeader("shield.user", shieldUser) headers.put(BASIC_AUTH_HEADER, basicAuth);
.putHeader("Authorization", basicAuth) assertThrows(internalCluster().transportClient().filterWithHeader(headers)
.prepareClearScroll()
.addScrollId("_all"), ElasticsearchSecurityException.class, "action [cluster:admin/indices/scroll/clear_all] is unauthorized for user [denied_user]"); .addScrollId("_all"), ElasticsearchSecurityException.class, "action [cluster:admin/indices/scroll/clear_all] is unauthorized for user [denied_user]");
// deletion of scroll ids should work // deletion of scroll ids should work

View File

@ -9,6 +9,7 @@ import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.ElasticsearchSecurityException; import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.logging.ESLoggerFactory; import org.elasticsearch.common.logging.ESLoggerFactory;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.shield.authc.activedirectory.ActiveDirectoryRealm; import org.elasticsearch.shield.authc.activedirectory.ActiveDirectoryRealm;
@ -24,6 +25,7 @@ import org.junit.BeforeClass;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Collections;
import static org.elasticsearch.common.settings.Settings.settingsBuilder; import static org.elasticsearch.common.settings.Settings.settingsBuilder;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; 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 { 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() setSource(jsonBuilder()
.startObject() .startObject()
.field("name", "value") .field("name", "value")
.endObject()) .endObject())
.putHeader(BASIC_AUTH_HEADER, userHeader(user, PASSWORD))
.execute().actionGet(); .execute().actionGet();
assertThat("user " + user + " should have write access to index " + index, indexResponse.isCreated(), is(true)); assertThat("user " + user + " should have write access to index " + index, indexResponse.isCreated(), is(true));
refresh(); refresh();
GetResponse getResponse = client().prepareGet(index, "type", indexResponse.getId()) GetResponse getResponse = client.prepareGet(index, "type", indexResponse.getId())
.putHeader(BASIC_AUTH_HEADER, userHeader(user, PASSWORD))
.get(); .get();
assertThat("user " + user + " should have read access to index " + index, getResponse.getId(), equalTo(indexResponse.getId())); 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 { protected void assertAccessDenied(String user, String index) throws IOException {
try { try {
client().prepareIndex(index, "type"). client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, userHeader(user, PASSWORD)))
.prepareIndex(index, "type").
setSource(jsonBuilder() setSource(jsonBuilder()
.startObject() .startObject()
.field("name", "value") .field("name", "value")
.endObject()) .endObject())
.putHeader(BASIC_AUTH_HEADER, userHeader(user, PASSWORD))
.execute().actionGet(); .execute().actionGet();
fail("Write access to index " + index + " should not be allowed for user " + user); fail("Write access to index " + index + " should not be allowed for user " + user);
} catch (ElasticsearchSecurityException e) { } catch (ElasticsearchSecurityException e) {

View File

@ -11,6 +11,7 @@ import org.elasticsearch.action.ActionRequest;
import org.elasticsearch.action.search.SearchScrollRequest; import org.elasticsearch.action.search.SearchScrollRequest;
import org.elasticsearch.action.support.ActionFilterChain; import org.elasticsearch.action.support.ActionFilterChain;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.shield.User; import org.elasticsearch.shield.User;
import org.elasticsearch.shield.action.interceptor.RequestInterceptor; import org.elasticsearch.shield.action.interceptor.RequestInterceptor;
import org.elasticsearch.shield.audit.AuditTrail; 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.shield.license.ShieldLicenseState;
import org.elasticsearch.tasks.Task; import org.elasticsearch.tasks.Task;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.threadpool.ThreadPool;
import org.junit.Before; import org.junit.Before;
import java.util.HashSet; import java.util.HashSet;
@ -56,7 +58,9 @@ public class ShieldActionFilterTests extends ESTestCase {
shieldLicenseState = mock(ShieldLicenseState.class); shieldLicenseState = mock(ShieldLicenseState.class);
when(shieldLicenseState.securityEnabled()).thenReturn(true); when(shieldLicenseState.securityEnabled()).thenReturn(true);
when(shieldLicenseState.statsAndHealthEnabled()).thenReturn(true); when(shieldLicenseState.statsAndHealthEnabled()).thenReturn(true);
filter = new ShieldActionFilter(Settings.EMPTY, authcService, authzService, cryptoService, auditTrail, shieldLicenseState, new ShieldActionMapper(), new HashSet<RequestInterceptor>()); 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<RequestInterceptor>(), threadPool);
} }
public void testApply() throws Exception { public void testApply() throws Exception {

View File

@ -29,6 +29,7 @@ import org.junit.After;
import org.junit.Before; import org.junit.Before;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue; 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(); client().prepareIndex("idx", "doc", "1").setSource("body", "foo").setRefresh(true).get();
String token = basicAuthHeaderValue("joe", new SecuredString("s3krit".toCharArray())); 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); assertEquals(searchResp.getHits().getTotalHits(), 1L);
} }
@ -223,7 +224,7 @@ public class ESNativeTests extends ShieldIntegTestCase {
// Index a document with the default test user // Index a document with the default test user
client().prepareIndex("idx", "doc", "1").setSource("body", "foo").setRefresh(true).get(); client().prepareIndex("idx", "doc", "1").setSource("body", "foo").setRefresh(true).get();
String token = basicAuthHeaderValue("joe", new SecuredString("s3krit".toCharArray())); 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); assertEquals(searchResp.getHits().getTotalHits(), 1L);
@ -234,7 +235,7 @@ public class ESNativeTests extends ShieldIntegTestCase {
.get(); .get();
try { 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!"); fail("authentication with old credentials after an update to the user should fail!");
} catch (ElasticsearchSecurityException e) { } catch (ElasticsearchSecurityException e) {
// expected // expected
@ -242,7 +243,7 @@ public class ESNativeTests extends ShieldIntegTestCase {
} }
token = basicAuthHeaderValue("joe", new SecuredString("s3krit2".toCharArray())); 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); assertEquals(searchResp.getHits().getTotalHits(), 1L);
} }
@ -267,14 +268,14 @@ public class ESNativeTests extends ShieldIntegTestCase {
// Index a document with the default test user // Index a document with the default test user
client().prepareIndex("idx", "doc", "1").setSource("body", "foo").setRefresh(true).get(); client().prepareIndex("idx", "doc", "1").setSource("body", "foo").setRefresh(true).get();
String token = basicAuthHeaderValue("joe", new SecuredString("s3krit".toCharArray())); 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); assertEquals(searchResp.getHits().getTotalHits(), 1L);
DeleteUserResponse response = c.prepareDeleteUser().user("joe").get(); DeleteUserResponse response = c.prepareDeleteUser().user("joe").get();
assertThat(response.found(), is(true)); assertThat(response.found(), is(true));
try { 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!"); fail("authentication with a deleted user should fail!");
} catch (ElasticsearchSecurityException e) { } catch (ElasticsearchSecurityException e) {
// expected // expected
@ -304,7 +305,7 @@ public class ESNativeTests extends ShieldIntegTestCase {
if (authenticate) { if (authenticate) {
final String token = basicAuthHeaderValue("joe", new SecuredString("s3krit".toCharArray())); 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()); assertFalse(response.isTimedOut());
c.prepareAddRole() c.prepareAddRole()
.name("test_role") .name("test_role")
@ -313,7 +314,7 @@ public class ESNativeTests extends ShieldIntegTestCase {
new String[]{"body", "title"}, new BytesArray("{\"match_all\": {}}")) new String[]{"body", "title"}, new BytesArray("{\"match_all\": {}}"))
.get(); .get();
try { 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!"); fail("user should not be able to execute any cluster actions!");
} catch (ElasticsearchSecurityException e) { } catch (ElasticsearchSecurityException e) {
assertThat(e.status(), is(RestStatus.FORBIDDEN)); assertThat(e.status(), is(RestStatus.FORBIDDEN));
@ -356,11 +357,11 @@ public class ESNativeTests extends ShieldIntegTestCase {
ensureGreen(ShieldTemplateService.SHIELD_ADMIN_INDEX_NAME); ensureGreen(ShieldTemplateService.SHIELD_ADMIN_INDEX_NAME);
final String token = basicAuthHeaderValue("joe", new SecuredString("s3krit".toCharArray())); 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()); assertFalse(response.isTimedOut());
c.prepareDeleteRole().role("test_role").get(); c.prepareDeleteRole().role("test_role").get();
try { 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!"); fail("user should not be able to execute any actions!");
} catch (ElasticsearchSecurityException e) { } catch (ElasticsearchSecurityException e) {
assertThat(e.status(), is(RestStatus.FORBIDDEN)); assertThat(e.status(), is(RestStatus.FORBIDDEN));

View File

@ -194,7 +194,7 @@ public class IndexAuditTrailTests extends ShieldIntegTestCase {
} }
settings = builder.build(); 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(); settings = Settings.builder().put(settings).put("path.home", createTempDir()).build();

View File

@ -24,7 +24,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import static org.elasticsearch.test.InternalTestCluster.clusterName; import static org.elasticsearch.test.InternalTestCluster.clusterName;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
@ -107,7 +106,8 @@ public class RemoteIndexAuditTrailStartingTests extends ShieldIntegTestCase {
return builder.build(); 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); remoteCluster.beforeTest(getRandom(), 0.5);
} }

View File

@ -17,6 +17,7 @@ import org.elasticsearch.common.transport.DummyTransportAddress;
import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.transport.LocalTransportAddress; import org.elasticsearch.common.transport.LocalTransportAddress;
import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.shield.User; import org.elasticsearch.shield.User;
import org.elasticsearch.shield.audit.logfile.CapturingLogger.Level; import org.elasticsearch.shield.audit.logfile.CapturingLogger.Level;
@ -102,6 +103,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
private String prefix; private String prefix;
private Settings settings; private Settings settings;
private Transport transport; private Transport transport;
private ThreadContext threadContext;
@Before @Before
public void init() throws Exception { public void init() throws Exception {
@ -118,10 +120,11 @@ public class LoggingAuditTrailTests extends ESTestCase {
public void testAnonymousAccessDeniedTransport() throws Exception { public void testAnonymousAccessDeniedTransport() throws Exception {
for (Level level : Level.values()) { for (Level level : Level.values()) {
threadContext = new ThreadContext(Settings.EMPTY);
CapturingLogger logger = new CapturingLogger(level); CapturingLogger logger = new CapturingLogger(level);
LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger).start(); LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger, threadContext).start();
TransportMessage message = randomBoolean() ? new MockMessage() : new MockIndicesRequest(); TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext);
String origins = LoggingAuditTrail.originAttributes(message, transport); String origins = LoggingAuditTrail.originAttributes(message, transport, threadContext);
auditTrail.anonymousAccessDenied("_action", message); auditTrail.anonymousAccessDenied("_action", message);
switch (level) { switch (level) {
case ERROR: case ERROR:
@ -154,8 +157,9 @@ public class LoggingAuditTrailTests extends ESTestCase {
String expectedMessage = prepareRestContent(request); String expectedMessage = prepareRestContent(request);
for (Level level : Level.values()) { for (Level level : Level.values()) {
threadContext = new ThreadContext(Settings.EMPTY);
CapturingLogger logger = new CapturingLogger(level); 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); auditTrail.anonymousAccessDenied(request);
switch (level) { switch (level) {
case ERROR: case ERROR:
@ -174,10 +178,11 @@ public class LoggingAuditTrailTests extends ESTestCase {
public void testAuthenticationFailed() throws Exception { public void testAuthenticationFailed() throws Exception {
for (Level level : Level.values()) { for (Level level : Level.values()) {
threadContext = new ThreadContext(Settings.EMPTY);
CapturingLogger logger = new CapturingLogger(level); CapturingLogger logger = new CapturingLogger(level);
LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger).start(); LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger, threadContext).start();
TransportMessage message = randomBoolean() ? new MockMessage() : new MockIndicesRequest(); TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext);
String origins = LoggingAuditTrail.originAttributes(message, transport);; String origins = LoggingAuditTrail.originAttributes(message, transport, threadContext);;
auditTrail.authenticationFailed(new MockToken(), "_action", message); auditTrail.authenticationFailed(new MockToken(), "_action", message);
switch (level) { switch (level) {
case ERROR: case ERROR:
@ -202,10 +207,11 @@ public class LoggingAuditTrailTests extends ESTestCase {
public void testAuthenticationFailedNoToken() throws Exception { public void testAuthenticationFailedNoToken() throws Exception {
for (Level level : Level.values()) { for (Level level : Level.values()) {
threadContext = new ThreadContext(Settings.EMPTY);
CapturingLogger logger = new CapturingLogger(level); CapturingLogger logger = new CapturingLogger(level);
LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger).start(); LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger, threadContext).start();
TransportMessage message = randomBoolean() ? new MockMessage() : new MockIndicesRequest(); TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext);
String origins = LoggingAuditTrail.originAttributes(message, transport);; String origins = LoggingAuditTrail.originAttributes(message, transport, threadContext);;
auditTrail.authenticationFailed("_action", message); auditTrail.authenticationFailed("_action", message);
switch (level) { switch (level) {
case ERROR: case ERROR:
@ -230,13 +236,14 @@ public class LoggingAuditTrailTests extends ESTestCase {
public void testAuthenticationFailedRest() throws Exception { public void testAuthenticationFailedRest() throws Exception {
for (Level level : Level.values()) { for (Level level : Level.values()) {
threadContext = new ThreadContext(Settings.EMPTY);
RestRequest request = mock(RestRequest.class); RestRequest request = mock(RestRequest.class);
InetAddress address = forge("_hostname", randomBoolean() ? "127.0.0.1" : "::1"); InetAddress address = forge("_hostname", randomBoolean() ? "127.0.0.1" : "::1");
when(request.getRemoteAddress()).thenReturn(new InetSocketAddress(address, 9200)); when(request.getRemoteAddress()).thenReturn(new InetSocketAddress(address, 9200));
when(request.uri()).thenReturn("_uri"); when(request.uri()).thenReturn("_uri");
String expectedMessage = prepareRestContent(request); String expectedMessage = prepareRestContent(request);
CapturingLogger logger = new CapturingLogger(level); 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); auditTrail.authenticationFailed(new MockToken(), request);
switch (level) { switch (level) {
case ERROR: case ERROR:
@ -253,13 +260,14 @@ public class LoggingAuditTrailTests extends ESTestCase {
public void testAuthenticationFailedRestNoToken() throws Exception { public void testAuthenticationFailedRestNoToken() throws Exception {
for (Level level : Level.values()) { for (Level level : Level.values()) {
threadContext = new ThreadContext(Settings.EMPTY);
RestRequest request = mock(RestRequest.class); RestRequest request = mock(RestRequest.class);
InetAddress address = forge("_hostname", randomBoolean() ? "127.0.0.1" : "::1"); InetAddress address = forge("_hostname", randomBoolean() ? "127.0.0.1" : "::1");
when(request.getRemoteAddress()).thenReturn(new InetSocketAddress(address, 9200)); when(request.getRemoteAddress()).thenReturn(new InetSocketAddress(address, 9200));
when(request.uri()).thenReturn("_uri"); when(request.uri()).thenReturn("_uri");
String expectedMessage = prepareRestContent(request); String expectedMessage = prepareRestContent(request);
CapturingLogger logger = new CapturingLogger(level); 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); auditTrail.authenticationFailed(request);
switch (level) { switch (level) {
case ERROR: case ERROR:
@ -276,10 +284,11 @@ public class LoggingAuditTrailTests extends ESTestCase {
public void testAuthenticationFailedRealm() throws Exception { public void testAuthenticationFailedRealm() throws Exception {
for (Level level : Level.values()) { for (Level level : Level.values()) {
threadContext = new ThreadContext(Settings.EMPTY);
CapturingLogger logger = new CapturingLogger(level); CapturingLogger logger = new CapturingLogger(level);
LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger).start(); LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger, threadContext).start();
TransportMessage message = randomBoolean() ? new MockMessage() : new MockIndicesRequest(); TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext);
String origins = LoggingAuditTrail.originAttributes(message, transport);; String origins = LoggingAuditTrail.originAttributes(message, transport, threadContext);;
auditTrail.authenticationFailed("_realm", new MockToken(), "_action", message); auditTrail.authenticationFailed("_realm", new MockToken(), "_action", message);
switch (level) { switch (level) {
case ERROR: case ERROR:
@ -300,13 +309,14 @@ public class LoggingAuditTrailTests extends ESTestCase {
public void testAuthenticationFailedRealmRest() throws Exception { public void testAuthenticationFailedRealmRest() throws Exception {
for (Level level : Level.values()) { for (Level level : Level.values()) {
threadContext = new ThreadContext(Settings.EMPTY);
RestRequest request = mock(RestRequest.class); RestRequest request = mock(RestRequest.class);
InetAddress address = forge("_hostname", randomBoolean() ? "127.0.0.1" : "::1"); InetAddress address = forge("_hostname", randomBoolean() ? "127.0.0.1" : "::1");
when(request.getRemoteAddress()).thenReturn(new InetSocketAddress(address, 9200)); when(request.getRemoteAddress()).thenReturn(new InetSocketAddress(address, 9200));
when(request.uri()).thenReturn("_uri"); when(request.uri()).thenReturn("_uri");
String expectedMessage = prepareRestContent(request); String expectedMessage = prepareRestContent(request);
CapturingLogger logger = new CapturingLogger(level); 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); auditTrail.authenticationFailed("_realm", new MockToken(), request);
switch (level) { switch (level) {
case ERROR: case ERROR:
@ -323,10 +333,11 @@ public class LoggingAuditTrailTests extends ESTestCase {
public void testAccessGranted() throws Exception { public void testAccessGranted() throws Exception {
for (Level level : Level.values()) { for (Level level : Level.values()) {
threadContext = new ThreadContext(Settings.EMPTY);
CapturingLogger logger = new CapturingLogger(level); CapturingLogger logger = new CapturingLogger(level);
LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger).start(); LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger, threadContext).start();
TransportMessage message = randomBoolean() ? new MockMessage() : new MockIndicesRequest(); TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext);
String origins = LoggingAuditTrail.originAttributes(message, transport); String origins = LoggingAuditTrail.originAttributes(message, transport, threadContext);
boolean runAs = randomBoolean(); boolean runAs = randomBoolean();
User user; User user;
if (runAs) { if (runAs) {
@ -362,10 +373,11 @@ public class LoggingAuditTrailTests extends ESTestCase {
public void testAccessGrantedInternalSystemAction() throws Exception { public void testAccessGrantedInternalSystemAction() throws Exception {
for (Level level : Level.values()) { for (Level level : Level.values()) {
threadContext = new ThreadContext(Settings.EMPTY);
CapturingLogger logger = new CapturingLogger(level); CapturingLogger logger = new CapturingLogger(level);
LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger).start(); LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger, threadContext).start();
TransportMessage message = randomBoolean() ? new MockMessage() : new MockIndicesRequest(); TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext);
String origins = LoggingAuditTrail.originAttributes(message, transport); String origins = LoggingAuditTrail.originAttributes(message, transport, threadContext);
auditTrail.accessGranted(User.SYSTEM, "internal:_action", message); auditTrail.accessGranted(User.SYSTEM, "internal:_action", message);
switch (level) { switch (level) {
case ERROR: case ERROR:
@ -386,10 +398,11 @@ public class LoggingAuditTrailTests extends ESTestCase {
public void testAccessGrantedInternalSystemActionNonSystemUser() throws Exception { public void testAccessGrantedInternalSystemActionNonSystemUser() throws Exception {
for (Level level : Level.values()) { for (Level level : Level.values()) {
threadContext = new ThreadContext(Settings.EMPTY);
CapturingLogger logger = new CapturingLogger(level); CapturingLogger logger = new CapturingLogger(level);
LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger).start(); LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger, threadContext).start();
TransportMessage message = randomBoolean() ? new MockMessage() : new MockIndicesRequest(); TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext);
String origins = LoggingAuditTrail.originAttributes(message, transport); String origins = LoggingAuditTrail.originAttributes(message, transport, threadContext);
boolean runAs = randomBoolean(); boolean runAs = randomBoolean();
User user; User user;
if (runAs) { if (runAs) {
@ -425,10 +438,11 @@ public class LoggingAuditTrailTests extends ESTestCase {
public void testAccessDenied() throws Exception { public void testAccessDenied() throws Exception {
for (Level level : Level.values()) { for (Level level : Level.values()) {
threadContext = new ThreadContext(Settings.EMPTY);
CapturingLogger logger = new CapturingLogger(level); CapturingLogger logger = new CapturingLogger(level);
LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger).start(); LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger, threadContext).start();
TransportMessage message = randomBoolean() ? new MockMessage() : new MockIndicesRequest(); TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext);
String origins = LoggingAuditTrail.originAttributes(message, transport); String origins = LoggingAuditTrail.originAttributes(message, transport, threadContext);
boolean runAs = randomBoolean(); boolean runAs = randomBoolean();
User user; User user;
if (runAs) { if (runAs) {
@ -462,11 +476,12 @@ public class LoggingAuditTrailTests extends ESTestCase {
public void testTamperedRequest() throws Exception { public void testTamperedRequest() throws Exception {
String action = "_action"; String action = "_action";
TransportMessage message = randomBoolean() ? new MockMessage() : new MockIndicesRequest();
String origins = LoggingAuditTrail.originAttributes(message, transport);
for (Level level : Level.values()) { 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); 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); auditTrail.tamperedRequest(action, message);
switch (level) { switch (level) {
case ERROR: case ERROR:
@ -491,8 +506,6 @@ public class LoggingAuditTrailTests extends ESTestCase {
public void testTamperedRequestWithUser() throws Exception { public void testTamperedRequestWithUser() throws Exception {
String action = "_action"; String action = "_action";
TransportMessage message = randomBoolean() ? new MockMessage() : new MockIndicesRequest();
String origins = LoggingAuditTrail.originAttributes(message, transport);
final boolean runAs = randomBoolean(); final boolean runAs = randomBoolean();
User user; User user;
if (runAs) { if (runAs) {
@ -502,8 +515,11 @@ public class LoggingAuditTrailTests extends ESTestCase {
} }
String userInfo = runAs ? "principal=[running as], run_by_principal=[_username]" : "principal=[_username]"; String userInfo = runAs ? "principal=[running as], run_by_principal=[_username]" : "principal=[_username]";
for (Level level : Level.values()) { 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); 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); auditTrail.tamperedRequest(user, action, message);
switch (level) { switch (level) {
case ERROR: case ERROR:
@ -528,8 +544,9 @@ public class LoggingAuditTrailTests extends ESTestCase {
public void testConnectionDenied() throws Exception { public void testConnectionDenied() throws Exception {
for (Level level : Level.values()) { for (Level level : Level.values()) {
threadContext = new ThreadContext(Settings.EMPTY);
CapturingLogger logger = new CapturingLogger(level); 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(); InetAddress inetAddress = InetAddress.getLoopbackAddress();
ShieldIpFilterRule rule = new ShieldIpFilterRule(false, "_all"); ShieldIpFilterRule rule = new ShieldIpFilterRule(false, "_all");
auditTrail.connectionDenied(inetAddress, "default", rule); auditTrail.connectionDenied(inetAddress, "default", rule);
@ -548,8 +565,9 @@ public class LoggingAuditTrailTests extends ESTestCase {
public void testConnectionGranted() throws Exception { public void testConnectionGranted() throws Exception {
for (Level level : Level.values()) { for (Level level : Level.values()) {
threadContext = new ThreadContext(Settings.EMPTY);
CapturingLogger logger = new CapturingLogger(level); 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(); InetAddress inetAddress = InetAddress.getLoopbackAddress();
ShieldIpFilterRule rule = IPFilter.DEFAULT_PROFILE_ACCEPT_ALL; ShieldIpFilterRule rule = IPFilter.DEFAULT_PROFILE_ACCEPT_ALL;
auditTrail.connectionGranted(inetAddress, "default", rule); auditTrail.connectionGranted(inetAddress, "default", rule);
@ -570,10 +588,11 @@ public class LoggingAuditTrailTests extends ESTestCase {
public void testRunAsGranted() throws Exception { public void testRunAsGranted() throws Exception {
for (Level level : Level.values()) { for (Level level : Level.values()) {
threadContext = new ThreadContext(Settings.EMPTY);
CapturingLogger logger = new CapturingLogger(level); CapturingLogger logger = new CapturingLogger(level);
LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger).start(); LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger, threadContext).start();
TransportMessage message = new MockMessage(); TransportMessage message = new MockMessage(threadContext);
String origins = LoggingAuditTrail.originAttributes(message, transport); String origins = LoggingAuditTrail.originAttributes(message, transport, threadContext);
User user = new User("_username", new String[]{"r1"}, new User("running as", new String[] {"r2"})); User user = new User("_username", new String[]{"r1"}, new User("running as", new String[] {"r2"}));
auditTrail.runAsGranted(user, "_action", message); auditTrail.runAsGranted(user, "_action", message);
switch (level) { switch (level) {
@ -593,10 +612,11 @@ public class LoggingAuditTrailTests extends ESTestCase {
public void testRunAsDenied() throws Exception { public void testRunAsDenied() throws Exception {
for (Level level : Level.values()) { for (Level level : Level.values()) {
threadContext = new ThreadContext(Settings.EMPTY);
CapturingLogger logger = new CapturingLogger(level); CapturingLogger logger = new CapturingLogger(level);
LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger).start(); LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, transport, logger, threadContext).start();
TransportMessage message = new MockMessage(); TransportMessage message = new MockMessage(threadContext);
String origins = LoggingAuditTrail.originAttributes(message, transport); String origins = LoggingAuditTrail.originAttributes(message, transport, threadContext);
User user = new User("_username", new String[]{"r1"}, new User("running as", new String[] {"r2"})); User user = new User("_username", new String[]{"r1"}, new User("running as", new String[] {"r2"}));
auditTrail.runAsDenied(user, "_action", message); auditTrail.runAsDenied(user, "_action", message);
switch (level) { switch (level) {
@ -615,9 +635,10 @@ public class LoggingAuditTrailTests extends ESTestCase {
} }
public void testOriginAttributes() throws Exception { public void testOriginAttributes() throws Exception {
MockMessage message = new MockMessage(); threadContext = new ThreadContext(Settings.EMPTY);
String text = LoggingAuditTrail.originAttributes(message, transport);; MockMessage message = new MockMessage(threadContext);
InetSocketAddress restAddress = RemoteHostHeader.restRemoteAddress(message); String text = LoggingAuditTrail.originAttributes(message, transport, threadContext);;
InetSocketAddress restAddress = RemoteHostHeader.restRemoteAddress(threadContext);
if (restAddress != null) { if (restAddress != null) {
assertThat(text, equalTo("origin_type=[rest], origin_address=[" + NetworkAddress.formatAddress(restAddress.getAddress()) + "]")); assertThat(text, equalTo("origin_type=[rest], origin_address=[" + NetworkAddress.formatAddress(restAddress.getAddress()) + "]"));
return; return;
@ -662,7 +683,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
private static class MockMessage extends TransportMessage<MockMessage> { private static class MockMessage extends TransportMessage<MockMessage> {
private MockMessage() throws IOException { private MockMessage(ThreadContext threadContext) throws IOException {
if (randomBoolean()) { if (randomBoolean()) {
if (randomBoolean()) { if (randomBoolean()) {
remoteAddress(new LocalTransportAddress("local_host")); remoteAddress(new LocalTransportAddress("local_host"));
@ -671,19 +692,19 @@ public class LoggingAuditTrailTests extends ESTestCase {
} }
} }
if (randomBoolean()) { 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<MockIndicesRequest> implements IndicesRequest { private static class MockIndicesRequest extends TransportMessage<MockIndicesRequest> implements IndicesRequest {
private MockIndicesRequest() throws IOException { private MockIndicesRequest(ThreadContext threadContext) throws IOException {
if (randomBoolean()) { if (randomBoolean()) {
remoteAddress(new LocalTransportAddress("_host")); remoteAddress(new LocalTransportAddress("_host"));
} }
if (randomBoolean()) { 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));
} }
} }

View File

@ -10,6 +10,7 @@ import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.Environment; import org.elasticsearch.env.Environment;
import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.shield.ShieldSettingsFilter; import org.elasticsearch.shield.ShieldSettingsFilter;
@ -21,6 +22,7 @@ import org.elasticsearch.shield.crypto.CryptoService;
import org.elasticsearch.shield.license.ShieldLicenseState; import org.elasticsearch.shield.license.ShieldLicenseState;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.rest.FakeRestRequest; import org.elasticsearch.test.rest.FakeRestRequest;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportMessage; import org.elasticsearch.transport.TransportMessage;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
@ -68,6 +70,8 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
AuthenticationToken token; AuthenticationToken token;
CryptoService cryptoService; CryptoService cryptoService;
AnonymousService anonymousService; AnonymousService anonymousService;
ThreadPool threadPool;
ThreadContext threadContext;
@Before @Before
public void init() throws Exception { public void init() throws Exception {
@ -95,13 +99,16 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
auditTrail = mock(AuditTrail.class); auditTrail = mock(AuditTrail.class);
anonymousService = mock(AnonymousService.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") @SuppressWarnings("unchecked")
public void testTokenFirstMissingSecondFound() throws Exception { public void testTokenFirstMissingSecondFound() throws Exception {
when(firstRealm.token(message)).thenReturn(null); when(firstRealm.token(threadContext)).thenReturn(null);
when(secondRealm.token(message)).thenReturn(token); when(secondRealm.token(threadContext)).thenReturn(token);
AuthenticationToken result = service.token("_action", message); AuthenticationToken result = service.token("_action", message);
assertThat(result, notNullValue()); assertThat(result, notNullValue());
@ -113,19 +120,19 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
AuthenticationToken token = service.token("_action", message); AuthenticationToken token = service.token("_action", message);
assertThat(token, nullValue()); assertThat(token, nullValue());
verifyNoMoreInteractions(auditTrail); verifyNoMoreInteractions(auditTrail);
assertThat(message.getContext().get(InternalAuthenticationService.TOKEN_KEY), nullValue()); assertThat(threadContext.getTransient(InternalAuthenticationService.TOKEN_KEY), nullValue());
} }
public void testTokenCached() throws Exception { public void testTokenCached() throws Exception {
message.putInContext(InternalAuthenticationService.TOKEN_KEY, token); threadContext.putTransient(InternalAuthenticationService.TOKEN_KEY, token);
AuthenticationToken result = service.token("_action", message); AuthenticationToken result = service.token("_action", message);
assertThat(result, notNullValue()); assertThat(result, notNullValue());
assertThat(result, is(token)); assertThat(result, is(token));
verifyZeroInteractions(auditTrail); verifyZeroInteractions(auditTrail);
verifyZeroInteractions(firstRealm); verifyZeroInteractions(firstRealm);
verifyZeroInteractions(secondRealm); verifyZeroInteractions(secondRealm);
assertThat(message.getContext().get(InternalAuthenticationService.TOKEN_KEY), notNullValue()); assertThat(threadContext.getTransient(InternalAuthenticationService.TOKEN_KEY), notNullValue());
assertThat(message.getContext().get(InternalAuthenticationService.TOKEN_KEY), is((Object) token)); assertThat(threadContext.getTransient(InternalAuthenticationService.TOKEN_KEY), is((Object) token));
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -145,9 +152,10 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
assertThat(result, notNullValue()); assertThat(result, notNullValue());
assertThat(result, is(user)); assertThat(result, is(user));
verify(auditTrail).authenticationFailed("esusers", token, "_action", message); verify(auditTrail).authenticationFailed("esusers", token, "_action", message);
assertThat(message.getContext().get(InternalAuthenticationService.USER_KEY), notNullValue()); User user1 = threadContext.getTransient(InternalAuthenticationService.USER_KEY);
assertThat(message.getContext().get(InternalAuthenticationService.USER_KEY), sameInstance((Object) user)); assertThat(user1, notNullValue());
assertThat(message.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_encoded_user")); assertThat(user1, sameInstance(user));
assertThat(threadContext.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_encoded_user"));
} }
public void testAuthenticateFirstNotSupportingSecondSucceeds() throws Exception { public void testAuthenticateFirstNotSupportingSecondSucceeds() throws Exception {
@ -166,14 +174,15 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
assertThat(result, is(user)); assertThat(result, is(user));
verifyZeroInteractions(auditTrail); verifyZeroInteractions(auditTrail);
verify(firstRealm, never()).authenticate(token); verify(firstRealm, never()).authenticate(token);
assertThat(message.getContext().get(InternalAuthenticationService.USER_KEY), notNullValue()); User user1 = threadContext.getTransient(InternalAuthenticationService.USER_KEY);
assertThat(message.getContext().get(InternalAuthenticationService.USER_KEY), is((Object) user)); assertThat(user1, notNullValue());
assertThat(message.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_encoded_user")); assertThat(user1, is((Object) user));
assertThat(threadContext.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_encoded_user"));
} }
public void testAuthenticateCached() throws Exception { public void testAuthenticateCached() throws Exception {
User user = new User("_username", "r1"); 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); User result = service.authenticate("_action", message, null);
assertThat(result, notNullValue()); assertThat(result, notNullValue());
assertThat(result, is(user)); assertThat(result, is(user));
@ -181,12 +190,13 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
verifyZeroInteractions(firstRealm); verifyZeroInteractions(firstRealm);
verifyZeroInteractions(secondRealm); verifyZeroInteractions(secondRealm);
verifyZeroInteractions(cryptoService); verifyZeroInteractions(cryptoService);
assertThat(message.getContext().get(InternalAuthenticationService.USER_KEY), notNullValue()); User user1 = threadContext.getTransient(InternalAuthenticationService.USER_KEY);
assertThat(message.getContext().get(InternalAuthenticationService.USER_KEY), is((Object) user)); assertThat(user1, notNullValue());
assertThat(user1, is(user));
} }
public void testAuthenticateNonExistentRestRequestUserThrowsAuthenticationException() throws Exception { 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 { try {
service.authenticate(restRequest); service.authenticate(restRequest);
fail("Authentication was successful but should not"); fail("Authentication was successful but should not");
@ -197,17 +207,17 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
public void testTokenRestExists() throws Exception { public void testTokenRestExists() throws Exception {
AuthenticationToken token = mock(AuthenticationToken.class); AuthenticationToken token = mock(AuthenticationToken.class);
when(firstRealm.token(restRequest)).thenReturn(null); when(firstRealm.token(threadContext)).thenReturn(null);
when(secondRealm.token(restRequest)).thenReturn(token); when(secondRealm.token(threadContext)).thenReturn(token);
AuthenticationToken foundToken = service.token(restRequest); AuthenticationToken foundToken = service.token();
assertThat(foundToken, is(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 { public void testTokenRestMissing() throws Exception {
when(firstRealm.token(restRequest)).thenReturn(null); when(firstRealm.token(threadContext)).thenReturn(null);
when(secondRealm.token(restRequest)).thenReturn(null); when(secondRealm.token(threadContext)).thenReturn(null);
AuthenticationToken token = service.token(restRequest); AuthenticationToken token = service.token();
assertThat(token, nullValue()); assertThat(token, nullValue());
} }
@ -224,7 +234,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
public void testUserHeader() throws Exception { public void testUserHeader() throws Exception {
User user = new User("_username", "r1"); 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.supports(token)).thenReturn(true);
when(firstRealm.authenticate(token)).thenReturn(user); when(firstRealm.authenticate(token)).thenReturn(user);
when(cryptoService.sign(InternalAuthenticationService.encodeUser(user, null))).thenReturn("_signed_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); User result = service.authenticate("_action", message, null);
assertThat(result, notNullValue()); assertThat(result, notNullValue());
assertThat(result, is(user)); assertThat(result, is(user));
String userStr = (String) message.getHeader(InternalAuthenticationService.USER_KEY); String userStr = threadContext.getHeader(InternalAuthenticationService.USER_KEY);
assertThat(userStr, notNullValue()); assertThat(userStr, notNullValue());
assertThat(userStr, equalTo("_signed_user")); assertThat(userStr, equalTo("_signed_user"));
} }
public void testAuthenticateTransportAnonymous() throws Exception { public void testAuthenticateTransportAnonymous() throws Exception {
when(firstRealm.token(message)).thenReturn(null); when(firstRealm.token(threadContext)).thenReturn(null);
when(secondRealm.token(message)).thenReturn(null); when(secondRealm.token(threadContext)).thenReturn(null);
try { try {
service.authenticate("_action", message, null); service.authenticate("_action", message, null);
fail("expected an authentication exception when trying to authenticate an anonymous message"); 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 { public void testAuthenticateRestAnonymous() throws Exception {
when(firstRealm.token(restRequest)).thenReturn(null); when(firstRealm.token(threadContext)).thenReturn(null);
when(secondRealm.token(restRequest)).thenReturn(null); when(secondRealm.token(threadContext)).thenReturn(null);
try { try {
service.authenticate(restRequest); service.authenticate(restRequest);
fail("expected an authentication exception when trying to authenticate an anonymous message"); 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 { public void testAuthenticateTransportFallback() throws Exception {
when(firstRealm.token(message)).thenReturn(null); when(firstRealm.token(threadContext)).thenReturn(null);
when(secondRealm.token(message)).thenReturn(null); when(secondRealm.token(threadContext)).thenReturn(null);
User user1 = new User("username", "r1", "r2"); User user1 = new User("username", "r1", "r2");
when(cryptoService.sign(InternalAuthenticationService.encodeUser(user1, null))).thenReturn("_signed_user"); when(cryptoService.sign(InternalAuthenticationService.encodeUser(user1, null))).thenReturn("_signed_user");
User user2 = service.authenticate("_action", message, user1); User user2 = service.authenticate("_action", message, user1);
assertThat(user1, sameInstance(user2)); assertThat(user1, sameInstance(user2));
assertThat(message.getFromContext(InternalAuthenticationService.USER_KEY), sameInstance((Object) user2)); User user3 = threadContext.getTransient(InternalAuthenticationService.USER_KEY);
assertThat(message.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_signed_user")); assertThat(user3, sameInstance(user2));
assertThat(threadContext.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_signed_user"));
} }
public void testAuthenticateTransportSuccessNoFallback() throws Exception { public void testAuthenticateTransportSuccessNoFallback() throws Exception {
User user1 = new User("username", "r1", "r2"); 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.supports(token)).thenReturn(true);
when(firstRealm.authenticate(token)).thenReturn(user1); when(firstRealm.authenticate(token)).thenReturn(user1);
when(cryptoService.sign(InternalAuthenticationService.encodeUser(user1, null))).thenReturn("_signed_user"); when(cryptoService.sign(InternalAuthenticationService.encodeUser(user1, null))).thenReturn("_signed_user");
User user2 = service.authenticate("_action", message, null); User user2 = service.authenticate("_action", message, null);
assertThat(user1, sameInstance(user2)); assertThat(user1, sameInstance(user2));
assertThat(message.getFromContext(InternalAuthenticationService.USER_KEY), sameInstance((Object) user2)); User user3 = threadContext.getTransient(InternalAuthenticationService.USER_KEY);
assertThat(message.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_signed_user")); assertThat(user3, sameInstance(user2));
assertThat(threadContext.getHeader(InternalAuthenticationService.USER_KEY), equalTo("_signed_user"));
} }
public void testAuthenticateTransportSuccessWithFallback() throws Exception { public void testAuthenticateTransportSuccessWithFallback() throws Exception {
User user1 = new User("username", "r1", "r2"); 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.supports(token)).thenReturn(true);
when(firstRealm.authenticate(token)).thenReturn(user1); when(firstRealm.authenticate(token)).thenReturn(user1);
when(cryptoService.sign(InternalAuthenticationService.encodeUser(user1, null))).thenReturn("_signed_user"); when(cryptoService.sign(InternalAuthenticationService.encodeUser(user1, null))).thenReturn("_signed_user");
User user2 = service.authenticate("_action", message, User.SYSTEM); User user2 = service.authenticate("_action", message, User.SYSTEM);
assertThat(user1, sameInstance(user2)); assertThat(user1, sameInstance(user2));
assertThat(message.getFromContext(InternalAuthenticationService.USER_KEY), sameInstance((Object) user2)); User user3 = threadContext.getTransient(InternalAuthenticationService.USER_KEY);
assertThat(message.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_signed_user")); assertThat(user3, sameInstance((Object) user2));
assertThat(threadContext.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_signed_user"));
} }
public void testAuthenticateRestSuccess() throws Exception { public void testAuthenticateRestSuccess() throws Exception {
User user1 = new User("username", "r1", "r2"); 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.supports(token)).thenReturn(true);
when(firstRealm.authenticate(token)).thenReturn(user1); when(firstRealm.authenticate(token)).thenReturn(user1);
User user2 = service.authenticate(restRequest); User user2 = service.authenticate(restRequest);
assertThat(user1, sameInstance(user2)); 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 { public void testAutheticateTransportContextAndHeader() throws Exception {
User user1 = new User("username", "r1", "r2"); 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.supports(token)).thenReturn(true);
when(firstRealm.authenticate(token)).thenReturn(user1); when(firstRealm.authenticate(token)).thenReturn(user1);
when(cryptoService.sign(InternalAuthenticationService.encodeUser(user1, null))).thenReturn("_signed_user"); when(cryptoService.sign(InternalAuthenticationService.encodeUser(user1, null))).thenReturn("_signed_user");
User user2 = service.authenticate("_action", message, User.SYSTEM); User user2 = service.authenticate("_action", message, User.SYSTEM);
assertThat(user1, sameInstance(user2)); assertThat(user1, sameInstance(user2));
assertThat(message.getFromContext(InternalAuthenticationService.USER_KEY), sameInstance((Object) user2)); User user3 = threadContext.getTransient(InternalAuthenticationService.USER_KEY);
assertThat(message.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_signed_user")); assertThat(user3, sameInstance(user2));
assertThat(threadContext.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_signed_user"));
reset(firstRealm); reset(firstRealm);
// checking authentication from the context // checking authentication from the context
InternalMessage message1 = new InternalMessage(); 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); User user = service.authenticate("_action", message1, User.SYSTEM);
assertThat(user, sameInstance(user1)); assertThat(user, sameInstance(user1));
verifyZeroInteractions(firstRealm); verifyZeroInteractions(firstRealm);
@ -331,35 +350,46 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
// checking authentication from the user header // 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)); when(cryptoService.unsignAndVerify("_signed_user")).thenReturn(InternalAuthenticationService.encodeUser(user1, null));
BytesStreamOutput output = new BytesStreamOutput(); BytesStreamOutput output = new BytesStreamOutput();
message1.writeTo(output); threadContext1.writeTo(output);
StreamInput input = StreamInput.wrap(output.bytes()); StreamInput input = StreamInput.wrap(output.bytes());
InternalMessage message2 = new InternalMessage(); threadContext1 = new ThreadContext(Settings.EMPTY);
message2.readFrom(input); threadContext1.readHeaders(input);
user = service.authenticate("_action", message2, User.SYSTEM);
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)); assertThat(user, equalTo(user1));
verifyZeroInteractions(firstRealm); verifyZeroInteractions(firstRealm);
} }
public void testAutheticateTransportContextAndHeaderNoSigning() throws Exception { public void testAutheticateTransportContextAndHeaderNoSigning() throws Exception {
Settings settings = Settings.builder().put(InternalAuthenticationService.SETTING_SIGN_USER_HEADER, false).build(); 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"); User user1 = new User("username", "r1", "r2");
when(firstRealm.supports(token)).thenReturn(true); when(firstRealm.supports(token)).thenReturn(true);
when(firstRealm.token(message)).thenReturn(token); when(firstRealm.token(threadContext)).thenReturn(token);
when(firstRealm.authenticate(token)).thenReturn(user1); when(firstRealm.authenticate(token)).thenReturn(user1);
User user2 = service.authenticate("_action", message, User.SYSTEM); User user2 = service.authenticate("_action", message, User.SYSTEM);
assertThat(user1, sameInstance(user2)); assertThat(user1, sameInstance(user2));
assertThat(message.getFromContext(InternalAuthenticationService.USER_KEY), sameInstance((Object) user2)); User user3 = threadContext.getTransient(InternalAuthenticationService.USER_KEY);
assertThat(message.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) InternalAuthenticationService.encodeUser(user1, null))); assertThat(user3, sameInstance(user2));
assertThat(threadContext.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) InternalAuthenticationService.encodeUser(user1, null)));
reset(firstRealm); reset(firstRealm);
// checking authentication from the context // checking authentication from the context
InternalMessage message1 = new InternalMessage(); 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); User user = service.authenticate("_action", message1, User.SYSTEM);
assertThat(user, sameInstance(user1)); assertThat(user, sameInstance(user1));
verifyZeroInteractions(firstRealm); verifyZeroInteractions(firstRealm);
@ -367,13 +397,18 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
// checking authentication from the user header // 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(); BytesStreamOutput output = new BytesStreamOutput();
message1.writeTo(output); threadContext1.writeTo(output);
StreamInput input = StreamInput.wrap(output.bytes()); StreamInput input = StreamInput.wrap(output.bytes());
InternalMessage message2 = new InternalMessage(); threadContext1 = new ThreadContext(Settings.EMPTY);
message2.readFrom(input); threadContext1.readHeaders(input);
user = service.authenticate("_action", message2, User.SYSTEM);
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)); assertThat(user, equalTo(user1));
verifyZeroInteractions(firstRealm); verifyZeroInteractions(firstRealm);
@ -382,7 +417,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
public void testAuthenticateTamperedUser() throws Exception { public void testAuthenticateTamperedUser() throws Exception {
InternalMessage message = new InternalMessage(); 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())); when(cryptoService.unsignAndVerify("_signed_user")).thenThrow(randomFrom(new RuntimeException(), new IllegalArgumentException(), new IllegalStateException()));
try { try {
@ -394,32 +429,30 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
} }
} }
public void testAttachIfMissingMissing() throws Exception { public void testAttachIfMissing() throws Exception {
User user = new User("username", "r1", "r2"); User user;
assertThat(message.getFromContext(InternalAuthenticationService.USER_KEY), nullValue()); if (randomBoolean()) {
assertThat(message.getHeader(InternalAuthenticationService.USER_KEY), nullValue()); 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"); when(cryptoService.sign(InternalAuthenticationService.encodeUser(user, null))).thenReturn("_signed_user");
service.attachUserHeaderIfMissing(message, user); service.attachUserHeaderIfMissing(user);
assertThat(message.getFromContext(InternalAuthenticationService.USER_KEY), sameInstance((Object) user)); User user1 = threadContext.getTransient(InternalAuthenticationService.USER_KEY);
assertThat(message.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_signed_user")); assertThat(user1, sameInstance((Object) user));
assertThat(threadContext.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"));
} }
public void testAttachIfMissingExists() throws Exception { public void testAttachIfMissingExists() throws Exception {
User user = new User("username", "r1", "r2"); User user = new User("username", "r1", "r2");
message.putInContext(InternalAuthenticationService.USER_KEY, user); threadContext.putTransient(InternalAuthenticationService.USER_KEY, user);
message.putHeader(InternalAuthenticationService.USER_KEY, "_signed_user"); threadContext.putHeader(InternalAuthenticationService.USER_KEY, "_signed_user");
service.attachUserHeaderIfMissing(message, new User("username2", "r3", "r4")); service.attachUserHeaderIfMissing(new User("username2", "r3", "r4"));
assertThat(message.getFromContext(InternalAuthenticationService.USER_KEY), sameInstance((Object) user)); User user1 = threadContext.getTransient(InternalAuthenticationService.USER_KEY);
assertThat(message.getHeader(InternalAuthenticationService.USER_KEY), equalTo((Object) "_signed_user")); assertThat(user1, sameInstance(user));
assertThat(threadContext.getHeader(InternalAuthenticationService.USER_KEY), equalTo("_signed_user"));
} }
public void testAnonymousUserRest() throws Exception { public void testAnonymousUserRest() throws Exception {
@ -431,13 +464,14 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
} }
Settings settings = builder.build(); Settings settings = builder.build();
AnonymousService holder = new AnonymousService(settings); 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(); RestRequest request = new FakeRestRequest();
User user = service.authenticate(request); User user = service.authenticate(request);
assertThat(request.getFromContext(InternalAuthenticationService.USER_KEY), notNullValue()); User user1 = threadContext.getTransient(InternalAuthenticationService.USER_KEY);
assertThat(request.getFromContext(InternalAuthenticationService.USER_KEY), sameInstance((Object) user)); assertThat(user1, notNullValue());
assertThat(user1, sameInstance((Object) user));
assertThat(user, notNullValue()); assertThat(user, notNullValue());
assertThat(user.principal(), equalTo(username)); assertThat(user.principal(), equalTo(username));
assertThat(user.roles(), arrayContainingInAnyOrder("r1", "r2", "r3")); assertThat(user.roles(), arrayContainingInAnyOrder("r1", "r2", "r3"));
@ -447,7 +481,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
Settings settings = Settings.builder() Settings settings = Settings.builder()
.putArray("shield.authc.anonymous.roles", "r1", "r2", "r3") .putArray("shield.authc.anonymous.roles", "r1", "r2", "r3")
.build(); .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(); InternalMessage message = new InternalMessage();
@ -461,7 +495,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
Settings settings = Settings.builder() Settings settings = Settings.builder()
.putArray("shield.authc.anonymous.roles", "r1", "r2", "r3") .putArray("shield.authc.anonymous.roles", "r1", "r2", "r3")
.build(); .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(); InternalMessage message = new InternalMessage();
@ -471,7 +505,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
} }
public void testRealmTokenThrowingException() throws Exception { 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 { try {
service.authenticate("_action", message, null); service.authenticate("_action", message, null);
fail("exception should bubble out"); fail("exception should bubble out");
@ -482,7 +516,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
} }
public void testRealmTokenThrowingExceptionRest() throws Exception { 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 { try {
service.authenticate(restRequest); service.authenticate(restRequest);
fail("exception should bubble out"); fail("exception should bubble out");
@ -494,7 +528,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
public void testRealmSupportsMethodThrowingException() throws Exception { public void testRealmSupportsMethodThrowingException() throws Exception {
AuthenticationToken token = mock(AuthenticationToken.class); 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")); when(secondRealm.supports(token)).thenThrow(authenticationError("realm doesn't like supports"));
try { try {
service.authenticate("_action", message, null); service.authenticate("_action", message, null);
@ -507,7 +541,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
public void testRealmSupportsMethodThrowingExceptionRest() throws Exception { public void testRealmSupportsMethodThrowingExceptionRest() throws Exception {
AuthenticationToken token = mock(AuthenticationToken.class); 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")); when(secondRealm.supports(token)).thenThrow(authenticationError("realm doesn't like supports"));
try { try {
service.authenticate(restRequest); service.authenticate(restRequest);
@ -520,7 +554,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
public void testRealmAuthenticateThrowingException() throws Exception { public void testRealmAuthenticateThrowingException() throws Exception {
AuthenticationToken token = mock(AuthenticationToken.class); 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.supports(token)).thenReturn(true);
when(secondRealm.authenticate(token)).thenThrow(authenticationError("realm doesn't like authenticate")); when(secondRealm.authenticate(token)).thenThrow(authenticationError("realm doesn't like authenticate"));
try { try {
@ -534,7 +568,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
public void testRealmAuthenticateThrowingExceptionRest() throws Exception { public void testRealmAuthenticateThrowingExceptionRest() throws Exception {
AuthenticationToken token = mock(AuthenticationToken.class); 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.supports(token)).thenReturn(true);
when(secondRealm.authenticate(token)).thenThrow(authenticationError("realm doesn't like authenticate")); when(secondRealm.authenticate(token)).thenThrow(authenticationError("realm doesn't like authenticate"));
try { try {
@ -548,8 +582,8 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
public void testRealmLookupThrowingException() throws Exception { public void testRealmLookupThrowingException() throws Exception {
AuthenticationToken token = mock(AuthenticationToken.class); AuthenticationToken token = mock(AuthenticationToken.class);
message.putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, "run_as"); threadContext.putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, "run_as");
when(secondRealm.token(message)).thenReturn(token); when(secondRealm.token(threadContext)).thenReturn(token);
when(secondRealm.supports(token)).thenReturn(true); when(secondRealm.supports(token)).thenReturn(true);
when(secondRealm.authenticate(token)).thenReturn(new User("lookup user", new String[]{"user"})); 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")); 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 { public void testRealmLookupThrowingExceptionRest() throws Exception {
AuthenticationToken token = mock(AuthenticationToken.class); AuthenticationToken token = mock(AuthenticationToken.class);
restRequest = new FakeRestRequest(Collections.singletonMap(InternalAuthenticationService.RUN_AS_USER_HEADER, "run_as"), Collections.<String, String>emptyMap()); restRequest = new FakeRestRequest(Collections.singletonMap(InternalAuthenticationService.RUN_AS_USER_HEADER, "run_as"));
when(secondRealm.token(restRequest)).thenReturn(token); when(secondRealm.token(threadContext)).thenReturn(token);
when(secondRealm.supports(token)).thenReturn(true); when(secondRealm.supports(token)).thenReturn(true);
when(secondRealm.authenticate(token)).thenReturn(new User("lookup user", new String[]{"user"})); 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")); 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 { public void testRunAsLookupSameRealm() throws Exception {
AuthenticationToken token = mock(AuthenticationToken.class); AuthenticationToken token = mock(AuthenticationToken.class);
message.putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, "run_as"); threadContext.putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, "run_as");
when(secondRealm.token(message)).thenReturn(token); when(secondRealm.token(threadContext)).thenReturn(token);
when(secondRealm.supports(token)).thenReturn(true); when(secondRealm.supports(token)).thenReturn(true);
when(secondRealm.authenticate(token)).thenReturn(new User("lookup user", new String[]{"user"})); 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"})); 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.roles(), arrayContaining("user"));
assertThat(authenticated.runAs().principal(), is("looked up user")); assertThat(authenticated.runAs().principal(), is("looked up user"));
assertThat(authenticated.runAs().roles(), arrayContaining("some role")); 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 { public void testRunAsLookupSameRealmRest() throws Exception {
AuthenticationToken token = mock(AuthenticationToken.class); AuthenticationToken token = mock(AuthenticationToken.class);
restRequest = new FakeRestRequest(Collections.singletonMap(InternalAuthenticationService.RUN_AS_USER_HEADER, "run_as"), Collections.<String, String>emptyMap()); restRequest = new FakeRestRequest(Collections.singletonMap(InternalAuthenticationService.RUN_AS_USER_HEADER, "run_as"));
when(secondRealm.token(restRequest)).thenReturn(token); when(secondRealm.token(threadContext)).thenReturn(token);
when(secondRealm.supports(token)).thenReturn(true); when(secondRealm.supports(token)).thenReturn(true);
when(secondRealm.authenticate(token)).thenReturn(new User("lookup user", new String[]{"user"})); 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"})); 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.roles(), arrayContaining("user"));
assertThat(authenticated.runAs().principal(), is("looked up user")); assertThat(authenticated.runAs().principal(), is("looked up user"));
assertThat(authenticated.runAs().roles(), arrayContaining("some role")); 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 { public void testRunAsLookupDifferentRealm() throws Exception {
AuthenticationToken token = mock(AuthenticationToken.class); AuthenticationToken token = mock(AuthenticationToken.class);
message.putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, "run_as"); threadContext.putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, "run_as");
when(secondRealm.token(message)).thenReturn(token); when(secondRealm.token(threadContext)).thenReturn(token);
when(secondRealm.supports(token)).thenReturn(true); when(secondRealm.supports(token)).thenReturn(true);
when(secondRealm.authenticate(token)).thenReturn(new User("lookup user", new String[]{"user"})); when(secondRealm.authenticate(token)).thenReturn(new User("lookup user", new String[]{"user"}));
when(firstRealm.userLookupSupported()).thenReturn(true); when(firstRealm.userLookupSupported()).thenReturn(true);
@ -640,13 +676,14 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
assertThat(authenticated.roles(), arrayContaining("user")); assertThat(authenticated.roles(), arrayContaining("user"));
assertThat(authenticated.runAs().principal(), is("looked up user")); assertThat(authenticated.runAs().principal(), is("looked up user"));
assertThat(authenticated.runAs().roles(), arrayContaining("some role")); 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 { public void testRunAsLookupDifferentRealmRest() throws Exception {
AuthenticationToken token = mock(AuthenticationToken.class); AuthenticationToken token = mock(AuthenticationToken.class);
restRequest = new FakeRestRequest(Collections.singletonMap(InternalAuthenticationService.RUN_AS_USER_HEADER, "run_as"), Collections.<String, String>emptyMap()); restRequest = new FakeRestRequest(Collections.singletonMap(InternalAuthenticationService.RUN_AS_USER_HEADER, "run_as"));
when(secondRealm.token(restRequest)).thenReturn(token); when(secondRealm.token(threadContext)).thenReturn(token);
when(secondRealm.supports(token)).thenReturn(true); when(secondRealm.supports(token)).thenReturn(true);
when(secondRealm.authenticate(token)).thenReturn(new User("lookup user", new String[]{"user"})); 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"})); 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.roles(), arrayContaining("user"));
assertThat(authenticated.runAs().principal(), is("looked up user")); assertThat(authenticated.runAs().principal(), is("looked up user"));
assertThat(authenticated.runAs().roles(), arrayContaining("some role")); 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 { public void testRunAsWithEmptyRunAsUsernameRest() throws Exception {
AuthenticationToken token = mock(AuthenticationToken.class); AuthenticationToken token = mock(AuthenticationToken.class);
restRequest = new FakeRestRequest(Collections.singletonMap(InternalAuthenticationService.RUN_AS_USER_HEADER, ""), Collections.<String, String>emptyMap()); restRequest = new FakeRestRequest(Collections.singletonMap(InternalAuthenticationService.RUN_AS_USER_HEADER, ""));
when(secondRealm.token(restRequest)).thenReturn(token); when(secondRealm.token(threadContext)).thenReturn(token);
when(secondRealm.supports(token)).thenReturn(true); when(secondRealm.supports(token)).thenReturn(true);
when(secondRealm.authenticate(token)).thenReturn(new User("lookup user", new String[]{"user"})); when(secondRealm.authenticate(token)).thenReturn(new User("lookup user", new String[]{"user"}));
when(secondRealm.userLookupSupported()).thenReturn(true); when(secondRealm.userLookupSupported()).thenReturn(true);
@ -682,8 +720,8 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
public void testRunAsWithEmptyRunAsUsername() throws Exception { public void testRunAsWithEmptyRunAsUsername() throws Exception {
AuthenticationToken token = mock(AuthenticationToken.class); AuthenticationToken token = mock(AuthenticationToken.class);
message.putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, ""); threadContext.putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, "");
when(secondRealm.token(message)).thenReturn(token); when(secondRealm.token(threadContext)).thenReturn(token);
when(secondRealm.supports(token)).thenReturn(true); when(secondRealm.supports(token)).thenReturn(true);
when(secondRealm.authenticate(token)).thenReturn(new User("lookup user", new String[]{"user"})); when(secondRealm.authenticate(token)).thenReturn(new User("lookup user", new String[]{"user"}));
when(secondRealm.userLookupSupported()).thenReturn(true); when(secondRealm.userLookupSupported()).thenReturn(true);

View File

@ -6,15 +6,14 @@
package org.elasticsearch.shield.authc; package org.elasticsearch.shield.authc;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.Environment; import org.elasticsearch.env.Environment;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.shield.ShieldSettingsFilter; import org.elasticsearch.shield.ShieldSettingsFilter;
import org.elasticsearch.shield.User; import org.elasticsearch.shield.User;
import org.elasticsearch.shield.authc.esusers.ESUsersRealm; import org.elasticsearch.shield.authc.esusers.ESUsersRealm;
import org.elasticsearch.shield.authc.ldap.LdapRealm; import org.elasticsearch.shield.authc.ldap.LdapRealm;
import org.elasticsearch.shield.license.ShieldLicenseState; import org.elasticsearch.shield.license.ShieldLicenseState;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.transport.TransportMessage;
import org.junit.Before; import org.junit.Before;
import java.util.ArrayList; import java.util.ArrayList;
@ -236,12 +235,7 @@ public class RealmsTests extends ESTestCase {
} }
@Override @Override
public AuthenticationToken token(RestRequest request) { public AuthenticationToken token(ThreadContext threadContext) {
return null;
}
@Override
public AuthenticationToken token(TransportMessage message) {
return null; return null;
} }

View File

@ -22,6 +22,10 @@ import org.elasticsearch.test.ShieldSettingsSource;
import org.elasticsearch.test.rest.client.http.HttpResponse; import org.elasticsearch.test.rest.client.http.HttpResponse;
import org.elasticsearch.xpack.XPackPlugin; 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.containsString;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
@ -86,17 +90,19 @@ public class RunAsIntegTests extends ShieldIntegTestCase {
// let's run as without authorization // let's run as without authorization
try { 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"); fail("run as should be unauthorized for the transport client user");
} catch (ElasticsearchSecurityException e) { } catch (ElasticsearchSecurityException e) {
assertThat(e.getMessage(), containsString("unauthorized")); assertThat(e.getMessage(), containsString("unauthorized"));
assertThat(e.getMessage(), containsString("run as")); assertThat(e.getMessage(), containsString("run as"));
} }
Map<String, String> 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 // lets set the user
ClusterHealthResponse response = client.admin().cluster().prepareHealth() ClusterHealthResponse response = client.filterWithHeader(headers).admin().cluster().prepareHealth().get();
.putHeader("Authorization", UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER, new SecuredString(ShieldSettingsSource.DEFAULT_PASSWORD.toCharArray())))
.putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, ShieldSettingsSource.DEFAULT_USER_NAME).get();
assertThat(response.isTimedOut(), is(false)); assertThat(response.isTimedOut(), is(false));
} }
} }
@ -134,9 +140,11 @@ public class RunAsIntegTests extends ShieldIntegTestCase {
}); });
try { try {
client.admin().cluster().prepareHealth() Map<String, String> headers = new HashMap<>();
.putHeader("Authorization", UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER, new SecuredString(ShieldSettingsSource.DEFAULT_PASSWORD.toCharArray()))) headers.put("Authorization", UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER, new SecuredString(ShieldSettingsSource.DEFAULT_PASSWORD.toCharArray())));
.putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, "").get(); 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"); fail("run as header should not be allowed to be empty");
} catch (ElasticsearchSecurityException e) { } catch (ElasticsearchSecurityException e) {
assertThat(e.getMessage(), containsString("unable to authenticate")); assertThat(e.getMessage(), containsString("unable to authenticate"));
@ -161,9 +169,11 @@ public class RunAsIntegTests extends ShieldIntegTestCase {
}); });
try { try {
client.admin().cluster().prepareHealth() Map<String, String> headers = new HashMap<>();
.putHeader("Authorization", UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER, new SecuredString(ShieldSettingsSource.DEFAULT_PASSWORD.toCharArray()))) headers.put("Authorization", UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER, new SecuredString(ShieldSettingsSource.DEFAULT_PASSWORD.toCharArray())));
.putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, "idontexist").get(); 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"); fail("run as header should not accept non-existent users");
} catch (ElasticsearchSecurityException e) { } catch (ElasticsearchSecurityException e) {
assertThat(e.getMessage(), containsString("unauthorized")); assertThat(e.getMessage(), containsString("unauthorized"));

View File

@ -13,8 +13,8 @@ import org.elasticsearch.client.AdminClient;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.elasticsearch.client.ClusterAdminClient; import org.elasticsearch.client.ClusterAdminClient;
import org.elasticsearch.client.IndicesAdminClient; import org.elasticsearch.client.IndicesAdminClient;
import org.elasticsearch.client.support.Headers;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.RestChannel; import org.elasticsearch.rest.RestChannel;
import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestController;
@ -118,10 +118,10 @@ public class ESUsersRealmTests extends ESTestCase {
when(userRolesStore.roles("user1")).thenReturn(new String[]{"role1", "role2"}); when(userRolesStore.roles("user1")).thenReturn(new String[]{"role1", "role2"});
ESUsersRealm realm = new ESUsersRealm(config, userPasswdStore, userRolesStore); ESUsersRealm realm = new ESUsersRealm(config, userPasswdStore, userRolesStore);
TransportRequest request = new TransportRequest() {}; ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
UsernamePasswordToken.putTokenHeader(request, new UsernamePasswordToken("user1", SecuredStringTests.build("test123"))); UsernamePasswordToken.putTokenHeader(threadContext, new UsernamePasswordToken("user1", SecuredStringTests.build("test123")));
UsernamePasswordToken token = realm.token(request); UsernamePasswordToken token = realm.token(threadContext);
assertThat(token, notNullValue()); assertThat(token, notNullValue());
assertThat(token.principal(), equalTo("user1")); assertThat(token.principal(), equalTo("user1"));
assertThat(token.credentials(), notNullValue()); assertThat(token.credentials(), notNullValue());
@ -178,39 +178,6 @@ public class ESUsersRealmTests extends ESTestCase {
assertThat(user5, sameInstance(user6)); 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<ActionRequest, ?, ?> 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 { static class UserPasswdStore extends FileUserPasswdStore {
public UserPasswdStore(RealmConfig config) { public UserPasswdStore(RealmConfig config) {
super(config, mock(ResourceWatcherService.class)); super(config, mock(ResourceWatcherService.class));

View File

@ -6,7 +6,7 @@
package org.elasticsearch.shield.authc.pki; package org.elasticsearch.shield.authc.pki;
import org.elasticsearch.common.settings.Settings; 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.User;
import org.elasticsearch.shield.authc.RealmConfig; import org.elasticsearch.shield.authc.RealmConfig;
import org.elasticsearch.shield.authc.support.DnRoleMapper; 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.authc.support.UsernamePasswordToken;
import org.elasticsearch.shield.support.NoOpLogger; import org.elasticsearch.shield.support.NoOpLogger;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.rest.FakeRestRequest;
import org.elasticsearch.transport.TransportMessage; import org.elasticsearch.transport.TransportMessage;
import org.junit.Before; import org.junit.Before;
@ -53,25 +52,13 @@ public class PkiRealmTests extends ESTestCase {
assertThat(realm.supports(new X509AuthenticationToken(new X509Certificate[0], "", "")), is(true)); 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")); X509Certificate certificate = readCert(getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.cert"));
RestRequest restRequest = new FakeRestRequest(); ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
restRequest.putInContext(PkiRealm.PKI_CERT_HEADER_NAME, new X509Certificate[] { certificate }); threadContext.putTransient(PkiRealm.PKI_CERT_HEADER_NAME, new X509Certificate[] { certificate });
PkiRealm realm = new PkiRealm(new RealmConfig("", Settings.EMPTY, globalSettings), mock(DnRoleMapper.class)); PkiRealm realm = new PkiRealm(new RealmConfig("", Settings.EMPTY, globalSettings), mock(DnRoleMapper.class));
X509AuthenticationToken token = realm.token(restRequest); 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"));
}
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);
assertThat(token, is(notNullValue())); assertThat(token, is(notNullValue()));
assertThat(token.dn(), is("CN=Elasticsearch Test Node, OU=elasticsearch, O=org")); assertThat(token.dn(), is("CN=Elasticsearch Test Node, OU=elasticsearch, O=org"));
assertThat(token.principal(), is("Elasticsearch Test Node")); assertThat(token.principal(), is("Elasticsearch Test Node"));
@ -96,10 +83,10 @@ public class PkiRealmTests extends ESTestCase {
DnRoleMapper roleMapper = mock(DnRoleMapper.class); DnRoleMapper roleMapper = mock(DnRoleMapper.class);
PkiRealm realm = new PkiRealm(new RealmConfig("", Settings.builder().put("username_pattern", "OU=(.*?),").build(), globalSettings), roleMapper); PkiRealm realm = new PkiRealm(new RealmConfig("", Settings.builder().put("username_pattern", "OU=(.*?),").build(), globalSettings), roleMapper);
when(roleMapper.resolveRoles(anyString(), anyList())).thenReturn(Collections.<String>emptySet()); when(roleMapper.resolveRoles(anyString(), anyList())).thenReturn(Collections.<String>emptySet());
FakeRestRequest restRequest = new FakeRestRequest(); ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
restRequest.putInContext(PkiRealm.PKI_CERT_HEADER_NAME, new X509Certificate[] { certificate }); 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); User user = realm.authenticate(token);
assertThat(user, is(notNullValue())); assertThat(user, is(notNullValue()));
assertThat(user.principal(), is("elasticsearch")); assertThat(user.principal(), is("elasticsearch"));
@ -117,10 +104,10 @@ public class PkiRealmTests extends ESTestCase {
PkiRealm realm = new PkiRealm(new RealmConfig("", settings, globalSettings), roleMapper); PkiRealm realm = new PkiRealm(new RealmConfig("", settings, globalSettings), roleMapper);
when(roleMapper.resolveRoles(anyString(), anyList())).thenReturn(Collections.<String>emptySet()); when(roleMapper.resolveRoles(anyString(), anyList())).thenReturn(Collections.<String>emptySet());
FakeRestRequest restRequest = new FakeRestRequest(); ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
restRequest.putInContext(PkiRealm.PKI_CERT_HEADER_NAME, new X509Certificate[] { certificate }); 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); User user = realm.authenticate(token);
assertThat(user, is(notNullValue())); assertThat(user, is(notNullValue()));
assertThat(user.principal(), is("Elasticsearch Test Node")); 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); PkiRealm realm = new PkiRealm(new RealmConfig("", settings, globalSettings), roleMapper);
when(roleMapper.resolveRoles(anyString(), anyList())).thenReturn(Collections.<String>emptySet()); when(roleMapper.resolveRoles(anyString(), anyList())).thenReturn(Collections.<String>emptySet());
FakeRestRequest restRequest = new FakeRestRequest(); ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
restRequest.putInContext(PkiRealm.PKI_CERT_HEADER_NAME, new X509Certificate[] { certificate }); 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); User user = realm.authenticate(token);
assertThat(user, is(nullValue())); assertThat(user, is(nullValue()));
} }

View File

@ -7,9 +7,10 @@ package org.elasticsearch.shield.authc.support;
import org.elasticsearch.ElasticsearchSecurityException; import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.common.Base64; 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.rest.RestRequest;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.transport.TransportRequest;
import org.junit.Rule; import org.junit.Rule;
import org.junit.rules.ExpectedException; import org.junit.rules.ExpectedException;
@ -31,9 +32,9 @@ public class UsernamePasswordTokenTests extends ESTestCase {
public ExpectedException thrown = ExpectedException.none(); public ExpectedException thrown = ExpectedException.none();
public void testPutToken() throws Exception { public void testPutToken() throws Exception {
TransportRequest request = new TransportRequest() {}; ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
UsernamePasswordToken.putTokenHeader(request, new UsernamePasswordToken("user1", SecuredStringTests.build("test123"))); UsernamePasswordToken.putTokenHeader(threadContext, new UsernamePasswordToken("user1", SecuredStringTests.build("test123")));
String header = request.getHeader(UsernamePasswordToken.BASIC_AUTH_HEADER); String header = threadContext.getHeader(UsernamePasswordToken.BASIC_AUTH_HEADER);
assertThat(header, notNullValue()); assertThat(header, notNullValue());
assertTrue(header.startsWith("Basic ")); assertTrue(header.startsWith("Basic "));
String token = header.substring("Basic ".length()); String token = header.substring("Basic ".length());
@ -47,10 +48,10 @@ public class UsernamePasswordTokenTests extends ESTestCase {
} }
public void testExtractToken() throws Exception { 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)); String header = "Basic " + Base64.encodeBytes("user1:test123".getBytes(StandardCharsets.UTF_8));
request.putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, header); threadContext.putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, header);
UsernamePasswordToken token = UsernamePasswordToken.extractToken(request, null); UsernamePasswordToken token = UsernamePasswordToken.extractToken(threadContext, null);
assertThat(token, notNullValue()); assertThat(token, notNullValue());
assertThat(token.principal(), equalTo("user1")); assertThat(token.principal(), equalTo("user1"));
assertThat(new String(token.credentials().internalChars()), equalTo("test123")); assertThat(new String(token.credentials().internalChars()), equalTo("test123"));
@ -59,10 +60,10 @@ public class UsernamePasswordTokenTests extends ESTestCase {
public void testExtractTokenInvalid() throws Exception { public void testExtractTokenInvalid() throws Exception {
String[] invalidValues = { "Basic", "Basic ", "Basic f" }; String[] invalidValues = { "Basic", "Basic ", "Basic f" };
for (String value : invalidValues) { for (String value : invalidValues) {
TransportRequest request = new TransportRequest() {}; ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
request.putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, value); threadContext.putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, value);
try { try {
UsernamePasswordToken.extractToken(request, null); UsernamePasswordToken.extractToken(threadContext, null);
fail("Expected an authentication exception for invalid basic auth token [" + value + "]"); fail("Expected an authentication exception for invalid basic auth token [" + value + "]");
} catch (ElasticsearchSecurityException e) { } catch (ElasticsearchSecurityException e) {
// expected // expected
@ -72,11 +73,11 @@ public class UsernamePasswordTokenTests extends ESTestCase {
} }
public void testThatAuthenticationExceptionContainsResponseHeaders() { public void testThatAuthenticationExceptionContainsResponseHeaders() {
TransportRequest request = new TransportRequest() {}; ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
String header = "BasicBroken"; String header = "BasicBroken";
request.putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, header); threadContext.putHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, header);
try { try {
UsernamePasswordToken.extractToken(request, null); UsernamePasswordToken.extractToken(threadContext, null);
fail("Expected exception but did not happen"); fail("Expected exception but did not happen");
} catch (ElasticsearchSecurityException e) { } catch (ElasticsearchSecurityException e) {
assertAuthenticationException(e); assertAuthenticationException(e);

View File

@ -10,6 +10,8 @@ import org.elasticsearch.shield.authc.support.Hasher;
import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.test.ShieldIntegTestCase; 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.BASIC_AUTH_HEADER;
import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
import static org.elasticsearch.test.ShieldTestsUtils.assertAuthorizationException; import static org.elasticsearch.test.ShieldTestsUtils.assertAuthorizationException;
@ -51,21 +53,21 @@ public class AnalyzeTests extends ShieldIntegTestCase {
ensureGreen(); ensureGreen();
//ok: user has permissions for analyze on test_* //ok: user has permissions for analyze on test_*
client().admin().indices().prepareAnalyze("this is my text").setIndex("test_1").setAnalyzer("standard") client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("analyze_indices", new SecuredString("test123".toCharArray()))))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("analyze_indices", new SecuredString("test123".toCharArray()))).get(); .admin().indices().prepareAnalyze("this is my text").setIndex("test_1").setAnalyzer("standard").get();
try { try {
//fails: user doesn't have permissions for analyze on index non_authorized //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") client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("analyze_indices", new SecuredString("test123".toCharArray()))))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("analyze_indices", new SecuredString("test123".toCharArray()))).get(); .admin().indices().prepareAnalyze("this is my text").setIndex("non_authorized").setAnalyzer("standard").get();
} catch(ElasticsearchSecurityException e) { } catch(ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:admin/analyze] is unauthorized for user [analyze_indices]")); assertAuthorizationException(e, containsString("action [indices:admin/analyze] is unauthorized for user [analyze_indices]"));
} }
try { try {
//fails: user doesn't have permissions for cluster level analyze //fails: user doesn't have permissions for cluster level analyze
client().admin().indices().prepareAnalyze("this is my text").setAnalyzer("standard") client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("analyze_indices", new SecuredString("test123".toCharArray()))))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("analyze_indices", new SecuredString("test123".toCharArray()))).get(); .admin().indices().prepareAnalyze("this is my text").setAnalyzer("standard").get();
} catch(ElasticsearchSecurityException e) { } catch(ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [cluster:admin/analyze] is unauthorized for user [analyze_indices]")); assertAuthorizationException(e, containsString("action [cluster:admin/analyze] is unauthorized for user [analyze_indices]"));
} }
@ -76,13 +78,13 @@ public class AnalyzeTests extends ShieldIntegTestCase {
try { try {
//fails: user doesn't have permissions for analyze on index test_1 //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") client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("analyze_cluster", new SecuredString("test123".toCharArray()))))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("analyze_cluster", new SecuredString("test123".toCharArray()))).get(); .admin().indices().prepareAnalyze("this is my text").setIndex("test_1").setAnalyzer("standard").get();
} catch(ElasticsearchSecurityException e) { } catch(ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:admin/analyze] is unauthorized for user [analyze_cluster]")); assertAuthorizationException(e, containsString("action [indices:admin/analyze] is unauthorized for user [analyze_cluster]"));
} }
client().admin().indices().prepareAnalyze("this is my text").setAnalyzer("standard") client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("analyze_cluster", new SecuredString("test123".toCharArray()))))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("analyze_cluster", new SecuredString("test123".toCharArray()))).get(); .admin().indices().prepareAnalyze("this is my text").setAnalyzer("standard").get();
} }
} }

View File

@ -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.GetAliasesRequestBuilder;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesResponse; import org.elasticsearch.action.admin.indices.alias.get.GetAliasesResponse;
import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.client.Client;
import org.elasticsearch.index.IndexNotFoundException; import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.shield.authc.support.Hasher; import org.elasticsearch.shield.authc.support.Hasher;
import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.test.ShieldIntegTestCase; import org.elasticsearch.test.ShieldIntegTestCase;
import org.junit.Before; 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.BASIC_AUTH_HEADER;
import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
import static org.elasticsearch.test.ShieldTestsUtils.assertAuthorizationException; import static org.elasticsearch.test.ShieldTestsUtils.assertAuthorizationException;
@ -85,20 +89,18 @@ public class IndexAliasesTests extends ShieldIntegTestCase {
public void testCreateIndexThenAliasesCreateOnlyPermission() { public void testCreateIndexThenAliasesCreateOnlyPermission() {
//user has create permission only: allows to create indices, manage_aliases is required to add/remove aliases //user has create permission only: allows to create indices, manage_aliases is required to add/remove aliases
assertAcked(client().admin().indices().prepareCreate("test_1") Map<String, String> headers = Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray())));
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray())))); assertAcked(client().filterWithHeader(headers).admin().indices().prepareCreate("test_1").get());
try { try {
client().admin().indices().prepareAliases().addAlias("test_1", "test_alias") client().filterWithHeader(headers).admin().indices().prepareAliases().addAlias("test_1", "test_alias").get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray()))).get();
fail("add alias should have failed due to missing manage_aliases privileges"); fail("add alias should have failed due to missing manage_aliases privileges");
} catch(ElasticsearchSecurityException e) { } catch(ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:admin/aliases] is unauthorized for user [create_only]")); assertAuthorizationException(e, containsString("action [indices:admin/aliases] is unauthorized for user [create_only]"));
} }
try { try {
client().admin().indices().prepareAliases().addAlias("test_*", "test_alias") client().filterWithHeader(headers).admin().indices().prepareAliases().addAlias("test_*", "test_alias").get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray()))).get();
fail("add alias should have failed due to missing manage_aliases privileges"); fail("add alias should have failed due to missing manage_aliases privileges");
} catch(IndexNotFoundException e) { } catch(IndexNotFoundException e) {
assertThat(e.toString(), containsString("[test_*]")); assertThat(e.toString(), containsString("[test_*]"));
@ -107,9 +109,9 @@ public class IndexAliasesTests extends ShieldIntegTestCase {
public void testCreateIndexAndAliasesCreateOnlyPermission() { 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 //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<String, String> headers = Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray())));
try { try {
client().admin().indices().prepareCreate("test_1").addAlias(new Alias("test_2")) client().filterWithHeader(headers).admin().indices().prepareCreate("test_1").addAlias(new Alias("test_2")).get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray()))).get();
fail("create index should have failed due to missing manage_aliases privileges"); fail("create index should have failed due to missing manage_aliases privileges");
} catch(ElasticsearchSecurityException e) { } catch(ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:admin/aliases] is unauthorized for user [create_only]")); 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() { public void testDeleteAliasesCreateOnlyPermission() {
//user has create permission only: allows to create indices, manage_aliases is required to add/remove aliases //user has create permission only: allows to create indices, manage_aliases is required to add/remove aliases
Map<String, String> headers = Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray())));
try { try {
client().admin().indices().prepareAliases().removeAlias("test_1", "alias_1") client().filterWithHeader(headers).admin().indices().prepareAliases().removeAlias("test_1", "alias_1").get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray()))).get();
fail("remove alias should have failed due to missing manage_aliases privileges"); fail("remove alias should have failed due to missing manage_aliases privileges");
} catch(ElasticsearchSecurityException e) { } catch(ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:admin/aliases] is unauthorized for user [create_only]")); assertAuthorizationException(e, containsString("action [indices:admin/aliases] is unauthorized for user [create_only]"));
} }
try { try {
client().admin().indices().prepareAliases().removeAlias("test_1", "alias_*") client().filterWithHeader(headers).admin().indices().prepareAliases().removeAlias("test_1", "alias_*").get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray()))).get();
fail("remove alias should have failed due to missing manage_aliases privileges"); fail("remove alias should have failed due to missing manage_aliases privileges");
} catch(IndexNotFoundException e) { } catch(IndexNotFoundException e) {
assertThat(e.toString(), containsString("[alias_*")); assertThat(e.toString(), containsString("[alias_*"));
} }
try { try {
client().admin().indices().prepareAliases().removeAlias("test_1", "_all") client().filterWithHeader(headers).admin().indices().prepareAliases().removeAlias("test_1", "_all").get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray()))).get();
fail("remove alias should have failed due to missing manage_aliases privileges"); fail("remove alias should have failed due to missing manage_aliases privileges");
} catch(IndexNotFoundException e) { } catch(IndexNotFoundException e) {
assertThat(e.toString(), containsString("[_all]")); assertThat(e.toString(), containsString("[_all]"));
@ -145,41 +145,37 @@ public class IndexAliasesTests extends ShieldIntegTestCase {
public void testGetAliasesCreateOnlyPermission() { public void testGetAliasesCreateOnlyPermission() {
//user has create permission only: allows to create indices, manage_aliases is required to retrieve aliases though //user has create permission only: allows to create indices, manage_aliases is required to retrieve aliases though
Map<String, String> headers = Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray())));
try { try {
client().admin().indices().prepareGetAliases("test_1").setIndices("test_1").setIndicesOptions(IndicesOptions.lenientExpandOpen()) client().filterWithHeader(headers).admin().indices().prepareGetAliases("test_1").setIndices("test_1").setIndicesOptions(IndicesOptions.lenientExpandOpen()).get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray()))).get();
fail("get alias should have failed due to missing manage_aliases privileges"); fail("get alias should have failed due to missing manage_aliases privileges");
} catch(ElasticsearchSecurityException e) { } catch(ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:admin/aliases/get] is unauthorized for user [create_only]")); assertAuthorizationException(e, containsString("action [indices:admin/aliases/get] is unauthorized for user [create_only]"));
} }
try { try {
client().admin().indices().prepareGetAliases("_all").setIndices("test_1").setIndicesOptions(IndicesOptions.lenientExpandOpen()) client().filterWithHeader(headers).admin().indices().prepareGetAliases("_all").setIndices("test_1").setIndicesOptions(IndicesOptions.lenientExpandOpen()).get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray()))).get();
fail("get alias should have failed due to missing manage_aliases privileges"); fail("get alias should have failed due to missing manage_aliases privileges");
} catch(IndexNotFoundException e) { } catch(IndexNotFoundException e) {
assertThat(e.toString(), containsString("[_all]")); assertThat(e.toString(), containsString("[_all]"));
} }
try { try {
client().admin().indices().prepareGetAliases().setIndices("test_1").setIndicesOptions(IndicesOptions.lenientExpandOpen()) client().filterWithHeader(headers).admin().indices().prepareGetAliases().setIndices("test_1").setIndicesOptions(IndicesOptions.lenientExpandOpen()).get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray()))).get();
fail("get alias should have failed due to missing manage_aliases privileges"); fail("get alias should have failed due to missing manage_aliases privileges");
} catch(IndexNotFoundException e) { } catch(IndexNotFoundException e) {
assertThat(e.toString(), containsString("[_all]")); assertThat(e.toString(), containsString("[_all]"));
} }
try { try {
client().admin().indices().prepareGetAliases("test_alias").setIndices("test_*").setIndicesOptions(IndicesOptions.lenientExpandOpen()) client().filterWithHeader(headers).admin().indices().prepareGetAliases("test_alias").setIndices("test_*").setIndicesOptions(IndicesOptions.lenientExpandOpen()).get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray()))).get();
fail("get alias should have failed due to missing manage_aliases privileges"); fail("get alias should have failed due to missing manage_aliases privileges");
} catch(IndexNotFoundException e) { } catch(IndexNotFoundException e) {
assertThat(e.toString(), containsString("[test_*]")); assertThat(e.toString(), containsString("[test_*]"));
} }
try { try {
client().admin().indices().prepareGetAliases() client().filterWithHeader(headers).admin().indices().prepareGetAliases().get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_only", new SecuredString("test123".toCharArray()))).get();
fail("get alias should have failed due to missing manage_aliases privileges"); fail("get alias should have failed due to missing manage_aliases privileges");
} catch(IndexNotFoundException e) { } catch(IndexNotFoundException e) {
assertThat(e.toString(), containsString("[_all]")); assertThat(e.toString(), containsString("[_all]"));
@ -188,21 +184,19 @@ public class IndexAliasesTests extends ShieldIntegTestCase {
public void testCreateIndexThenAliasesCreateAndAliasesPermission() { 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 //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") Map<String, String> headers = Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray())));
.putHeader(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_* //ok: user has manage_aliases on test_*
assertAcked(client().admin().indices().prepareAliases().addAlias("test_1", "test_alias") assertAcked(client().filterWithHeader(headers).admin().indices().prepareAliases().addAlias("test_1", "test_alias").get());
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))));
//ok: user has manage_aliases on test_* //ok: user has manage_aliases on test_*
assertAcked(client().admin().indices().prepareAliases().addAlias("test_*", "test_alias_2") assertAcked(client().filterWithHeader(headers).admin().indices().prepareAliases().addAlias("test_*", "test_alias_2").get());
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))));
try { try {
//fails: user doesn't have manage_aliases on alias_1 //fails: user doesn't have manage_aliases on alias_1
client().admin().indices().prepareAliases().addAlias("test_1", "alias_1").addAlias("test_1", "test_alias") client().filterWithHeader(headers).admin().indices().prepareAliases().addAlias("test_1", "alias_1").addAlias("test_1", "test_alias").get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))).get();
fail("add alias should have failed due to missing manage_aliases privileges on alias_1"); fail("add alias should have failed due to missing manage_aliases privileges on alias_1");
} catch(ElasticsearchSecurityException e) { } catch(ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:admin/aliases] is unauthorized for user [create_test_aliases_test]")); 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() { 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 //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_* //ok: user has manage_aliases on test_*
assertAcked(client().admin().indices().prepareCreate("test_1").addAlias(new Alias("test_alias")) Map<String, String> headers = Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray())));
.putHeader(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 { try {
//fails: user doesn't have manage_aliases on alias_1 //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")) client().filterWithHeader(headers).admin().indices().prepareCreate("test_2").addAlias(new Alias("test_alias")).addAlias(new Alias("alias_2")).get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))).get();
fail("create index should have failed due to missing manage_aliases privileges on alias_2"); fail("create index should have failed due to missing manage_aliases privileges on alias_2");
} catch(ElasticsearchSecurityException e) { } catch(ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:admin/aliases] is unauthorized for user [create_test_aliases_test]")); 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() { 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 //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_* //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")) Map<String, String> headers = Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray())));
.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())))); 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_* //ok: user has manage_aliases on test_*
assertAcked(client().admin().indices().prepareAliases().removeAlias("test_1", "test_alias_1") assertAcked(client().filterWithHeader(headers).admin().indices().prepareAliases().removeAlias("test_1", "test_alias_1").get());
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))));
//ok: user has manage_aliases on test_* //ok: user has manage_aliases on test_*
assertAcked(client().admin().indices().prepareAliases().removeAlias("test_*", "test_alias_2") assertAcked(client().filterWithHeader(headers).admin().indices().prepareAliases().removeAlias("test_*", "test_alias_2").get());
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))));
//ok: user has manage_aliases on test_* //ok: user has manage_aliases on test_*
assertAcked(client().admin().indices().prepareAliases().removeAlias("test_1", "test_alias_*") assertAcked(client().filterWithHeader(headers).admin().indices().prepareAliases().removeAlias("test_1", "test_alias_*").get());
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))));
try { try {
//fails: all aliases have been deleted, no existing aliases match test_alias_* //fails: all aliases have been deleted, no existing aliases match test_alias_*
client().admin().indices().prepareAliases().removeAlias("test_1", "test_alias_*") client().filterWithHeader(headers).admin().indices().prepareAliases().removeAlias("test_1", "test_alias_*").get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))).get();
fail("remove alias should have failed due to no existing matching aliases to expand test_alias_* to"); fail("remove alias should have failed due to no existing matching aliases to expand test_alias_* to");
} catch(IndexNotFoundException e) { } catch(IndexNotFoundException e) {
assertThat(e.toString(), containsString("[test_alias_*]")); assertThat(e.toString(), containsString("[test_alias_*]"));
@ -252,8 +242,7 @@ public class IndexAliasesTests extends ShieldIntegTestCase {
try { try {
//fails: all aliases have been deleted, no existing aliases match _all //fails: all aliases have been deleted, no existing aliases match _all
client().admin().indices().prepareAliases().removeAlias("test_1", "_all") client().filterWithHeader(headers).admin().indices().prepareAliases().removeAlias("test_1", "_all").get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))).get();
fail("remove alias should have failed due to no existing matching aliases to expand _all to"); fail("remove alias should have failed due to no existing matching aliases to expand _all to");
} catch(IndexNotFoundException e) { } catch(IndexNotFoundException e) {
assertThat(e.toString(), containsString("[_all]")); assertThat(e.toString(), containsString("[_all]"));
@ -261,8 +250,7 @@ public class IndexAliasesTests extends ShieldIntegTestCase {
try { try {
//fails: user doesn't have manage_aliases on alias_1 //fails: user doesn't have manage_aliases on alias_1
client().admin().indices().prepareAliases().removeAlias("test_1", "alias_1") client().filterWithHeader(headers).admin().indices().prepareAliases().removeAlias("test_1", "alias_1").get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))).get();
fail("remove alias should have failed due to missing manage_aliases privileges on alias_1"); fail("remove alias should have failed due to missing manage_aliases privileges on alias_1");
} catch(ElasticsearchSecurityException e) { } catch(ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:admin/aliases] is unauthorized for user [create_test_aliases_test]")); 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 { try {
//fails: user doesn't have manage_aliases on alias_1 //fails: user doesn't have manage_aliases on alias_1
client().admin().indices().prepareAliases().removeAlias("test_1", new String[]{"_all", "alias_1"}) client().filterWithHeader(headers).admin().indices().prepareAliases().removeAlias("test_1", new String[]{"_all", "alias_1"}).get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))).get();
fail("remove alias should have failed due to missing manage_aliases privileges on alias_1"); fail("remove alias should have failed due to missing manage_aliases privileges on alias_1");
} catch(ElasticsearchSecurityException e) { } catch(ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:admin/aliases] is unauthorized for user [create_test_aliases_test]")); 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() { public void testGetAliasesCreateAndAliasesPermission() {
//user has create and manage_aliases permission on test_*. manage_aliases is required to retrieve aliases on both aliases and indices //user has create and manage_aliases permission on test_*. manage_aliases is required to retrieve aliases on both aliases and indices
Map<String, String> headers = Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray())));
assertAcked(client().admin().indices().prepareCreate("test_1").addAlias(new Alias("test_alias")) final Client client = client().filterWithHeader(headers);
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray())))); assertAcked(client.admin().indices().prepareCreate("test_1").addAlias(new Alias("test_alias")).get());
//ok: user has manage_aliases on test_* //ok: user has manage_aliases on test_*
assertAliases(client().admin().indices().prepareGetAliases().setAliases("test_alias").setIndices("test_1") assertAliases(client.admin().indices().prepareGetAliases().setAliases("test_alias").setIndices("test_1"),
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))),
"test_1", "test_alias"); "test_1", "test_alias");
//ok: user has manage_aliases on test_*, test_* gets resolved to test_1 //ok: user has manage_aliases on test_*, test_* gets resolved to test_1
assertAliases(client().admin().indices().prepareGetAliases().setAliases("test_alias").setIndices("test_*") assertAliases(client.admin().indices().prepareGetAliases().setAliases("test_alias").setIndices("test_*"),
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))),
"test_1", "test_alias"); "test_1", "test_alias");
//ok: user has manage_aliases on test_*, empty indices gets resolved to _all indices (thus test_1) //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") assertAliases(client.admin().indices().prepareGetAliases().setAliases("test_alias"),
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))),
"test_1", "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) //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") assertAliases(client.admin().indices().prepareGetAliases().setAliases("_all").setIndices("test_1"),
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))),
"test_1", "test_alias"); "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) //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") assertAliases(client.admin().indices().prepareGetAliases().setIndices("test_1"),
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))),
"test_1", "test_alias"); "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) //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") assertAliases(client.admin().indices().prepareGetAliases().setAliases("test_*").setIndices("test_1"),
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))),
"test_1", "test_alias"); "test_1", "test_alias");
//ok: user has manage_aliases on test_*, _all aliases gets resolved to test_alias and _all indices becomes test_1 //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") assertAliases(client.admin().indices().prepareGetAliases().setAliases("_all").setIndices("_all"),
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))),
"test_1", "test_alias"); "test_1", "test_alias");
//ok: user has manage_aliases on test_*, empty aliases gets resolved to test_alias and empty indices becomes test_1 //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() assertAliases(client.admin().indices().prepareGetAliases(),
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))),
"test_1", "test_alias"); "test_1", "test_alias");
try { 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 //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") client.admin().indices().prepareGetAliases().setAliases("_all", "alias_1").get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))).get();
fail("get alias should have failed due to missing manage_aliases privileges on alias_1"); fail("get alias should have failed due to missing manage_aliases privileges on alias_1");
} catch(ElasticsearchSecurityException e) { } catch(ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:admin/aliases/get] is unauthorized for user [create_test_aliases_test]")); 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 { try {
//fails: user doesn't have manage_aliases on alias_1 //fails: user doesn't have manage_aliases on alias_1
client().admin().indices().prepareGetAliases().setAliases("alias_1") client.admin().indices().prepareGetAliases().setAliases("alias_1").get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test", new SecuredString("test123".toCharArray()))).get();
fail("get alias should have failed due to missing manage_aliases privileges on alias_1"); fail("get alias should have failed due to missing manage_aliases privileges on alias_1");
} catch(ElasticsearchSecurityException e) { } catch(ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:admin/aliases/get] is unauthorized for user [create_test_aliases_test]")); 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() { public void testCreateIndexThenAliasesCreateAndAliasesPermission2() {
Map<String, String> 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 //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") assertAcked(client.admin().indices().prepareCreate("test_1"));
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))));
try { try {
//fails: user doesn't have manage aliases on test_1 //fails: user doesn't have manage aliases on test_1
client().admin().indices().prepareAliases().addAlias("test_1", "test_alias") client.admin().indices().prepareAliases().addAlias("test_1", "test_alias").get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))).get();
fail("add alias should have failed due to missing manage_aliases privileges on test_alias and test_1"); fail("add alias should have failed due to missing manage_aliases privileges on test_alias and test_1");
} catch(ElasticsearchSecurityException e) { } catch(ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:admin/aliases] is unauthorized for user [create_test_aliases_alias]")); 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 { try {
//fails: user doesn't have manage aliases on test_1 //fails: user doesn't have manage aliases on test_1
client().admin().indices().prepareAliases().addAlias("test_1", "alias_1") client.admin().indices().prepareAliases().addAlias("test_1", "alias_1").get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))).get();
fail("add alias should have failed due to missing manage_aliases privileges on test_1"); fail("add alias should have failed due to missing manage_aliases privileges on test_1");
} catch(ElasticsearchSecurityException e) { } catch(ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:admin/aliases] is unauthorized for user [create_test_aliases_alias]")); 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 { try {
//fails: user doesn't have manage aliases on test_*, no matching indices to replace wildcards //fails: user doesn't have manage aliases on test_*, no matching indices to replace wildcards
client().admin().indices().prepareAliases().addAlias("test_*", "alias_1") client.admin().indices().prepareAliases().addAlias("test_*", "alias_1").get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))).get();
fail("add alias should have failed due to missing manage_aliases privileges on test_1"); fail("add alias should have failed due to missing manage_aliases privileges on test_1");
} catch(IndexNotFoundException e) { } catch(IndexNotFoundException e) {
assertThat(e.toString(), containsString("[test_*]")); assertThat(e.toString(), containsString("[test_*]"));
@ -377,11 +353,13 @@ public class IndexAliasesTests extends ShieldIntegTestCase {
} }
public void testCreateIndexAndAliasesCreateAndAliasesPermission2() { public void testCreateIndexAndAliasesCreateAndAliasesPermission2() {
Map<String, String> 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 //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 { try {
//fails: user doesn't have manage_aliases on test_1, create index is rejected as a whole //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")) client.admin().indices().prepareCreate("test_1").addAlias(new Alias("test_alias")).get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))).get();
fail("create index should have failed due to missing manage_aliases privileges on test_1 and test_alias"); fail("create index should have failed due to missing manage_aliases privileges on test_1 and test_alias");
} catch(ElasticsearchSecurityException e) { } catch(ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:admin/aliases] is unauthorized for user [create_test_aliases_alias]")); 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 { try {
//fails: user doesn't have manage_aliases on test_*, create index is rejected as a whole //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")) client.admin().indices().prepareCreate("test_1").addAlias(new Alias("test_alias")).addAlias(new Alias("alias_1")).get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))).get();
fail("create index should have failed due to missing manage_aliases privileges on test_1 and test_alias"); fail("create index should have failed due to missing manage_aliases privileges on test_1 and test_alias");
} catch(ElasticsearchSecurityException e) { } catch(ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:admin/aliases] is unauthorized for user [create_test_aliases_alias]")); 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() { public void testDeleteAliasesCreateAndAliasesPermission2() {
Map<String, String> 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 //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 { try {
//fails: user doesn't have manage_aliases on test_1 //fails: user doesn't have manage_aliases on test_1
client().admin().indices().prepareAliases().removeAlias("test_1", "test_alias") client.admin().indices().prepareAliases().removeAlias("test_1", "test_alias").get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))).get();
fail("remove alias should have failed due to missing manage_aliases privileges on test_alias and test_1"); fail("remove alias should have failed due to missing manage_aliases privileges on test_alias and test_1");
} catch(ElasticsearchSecurityException e) { } catch(ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:admin/aliases] is unauthorized for user [create_test_aliases_alias]")); 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 { try {
//fails: user doesn't have manage_aliases on test_1 //fails: user doesn't have manage_aliases on test_1
client().admin().indices().prepareAliases().removeAlias("test_1", "alias_1") client.admin().indices().prepareAliases().removeAlias("test_1", "alias_1").get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))).get();
fail("remove alias should have failed due to missing manage_aliases privileges on test_1"); fail("remove alias should have failed due to missing manage_aliases privileges on test_1");
} catch(ElasticsearchSecurityException e) { } catch(ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:admin/aliases] is unauthorized for user [create_test_aliases_alias]")); 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 { try {
//fails: user doesn't have manage_aliases on test_*, wildcards can't get replaced //fails: user doesn't have manage_aliases on test_*, wildcards can't get replaced
client().admin().indices().prepareAliases().removeAlias("test_*", "alias_1") client.admin().indices().prepareAliases().removeAlias("test_*", "alias_1").get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))).get();
fail("remove alias should have failed due to missing manage_aliases privileges on test_*"); fail("remove alias should have failed due to missing manage_aliases privileges on test_*");
} catch(IndexNotFoundException e) { } catch(IndexNotFoundException e) {
assertThat(e.toString(), containsString("[test_*]")); assertThat(e.toString(), containsString("[test_*]"));
@ -428,14 +405,15 @@ public class IndexAliasesTests extends ShieldIntegTestCase {
} }
public void testGetAliasesCreateAndAliasesPermission2() { public void testGetAliasesCreateAndAliasesPermission2() {
Map<String, String> 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 //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") assertAcked(client.admin().indices().prepareCreate("test_1"));
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))));
try { try {
//fails: user doesn't have manage aliases on test_1, nor test_alias //fails: user doesn't have manage aliases on test_1, nor test_alias
client().admin().indices().prepareGetAliases().setAliases("test_alias").setIndices("test_1") client.admin().indices().prepareGetAliases().setAliases("test_alias").setIndices("test_1").get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))).get();
fail("get alias should have failed due to missing manage_aliases privileges on test_alias and test_1"); fail("get alias should have failed due to missing manage_aliases privileges on test_alias and test_1");
} catch(ElasticsearchSecurityException e) { } catch(ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:admin/aliases/get] is unauthorized for user [create_test_aliases_alias]")); 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 { try {
//fails: user doesn't have manage aliases on test_*, no matching indices to replace wildcards //fails: user doesn't have manage aliases on test_*, no matching indices to replace wildcards
client().admin().indices().prepareGetAliases().setIndices("test_*").setAliases("test_alias") client.admin().indices().prepareGetAliases().setIndices("test_*").setAliases("test_alias").get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))).get();
fail("get alias should have failed due to missing manage_aliases privileges on test_*"); fail("get alias should have failed due to missing manage_aliases privileges on test_*");
} catch(IndexNotFoundException e) { } catch(IndexNotFoundException e) {
assertThat(e.toString(), containsString("[test_*]")); assertThat(e.toString(), containsString("[test_*]"));
@ -452,8 +429,7 @@ public class IndexAliasesTests extends ShieldIntegTestCase {
try { try {
//fails: no existing indices to replace empty indices (thus _all) //fails: no existing indices to replace empty indices (thus _all)
client().admin().indices().prepareGetAliases().setAliases("test_alias") client.admin().indices().prepareGetAliases().setAliases("test_alias").get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))).get();
fail("get alias should have failed due to missing manage_aliases privileges on any index"); fail("get alias should have failed due to missing manage_aliases privileges on any index");
} catch(IndexNotFoundException e) { } catch(IndexNotFoundException e) {
assertThat(e.toString(), containsString("[_all]")); assertThat(e.toString(), containsString("[_all]"));
@ -461,8 +437,7 @@ public class IndexAliasesTests extends ShieldIntegTestCase {
try { try {
//fails: no existing aliases to replace wildcards //fails: no existing aliases to replace wildcards
client().admin().indices().prepareGetAliases().setIndices("test_1").setAliases("test_*") client.admin().indices().prepareGetAliases().setIndices("test_1").setAliases("test_*").get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))).get();
fail("get alias should have failed due to missing manage_aliases privileges on test_1"); fail("get alias should have failed due to missing manage_aliases privileges on test_1");
} catch(IndexNotFoundException e) { } catch(IndexNotFoundException e) {
assertThat(e.toString(), containsString("[test_*]")); assertThat(e.toString(), containsString("[test_*]"));
@ -470,8 +445,7 @@ public class IndexAliasesTests extends ShieldIntegTestCase {
try { try {
//fails: no existing aliases to replace _all //fails: no existing aliases to replace _all
client().admin().indices().prepareGetAliases().setIndices("test_1").setAliases("_all") client.admin().indices().prepareGetAliases().setIndices("test_1").setAliases("_all").get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))).get();
fail("get alias should have failed due to missing manage_aliases privileges on test_1"); fail("get alias should have failed due to missing manage_aliases privileges on test_1");
} catch(IndexNotFoundException e) { } catch(IndexNotFoundException e) {
assertThat(e.toString(), containsString("[_all]")); assertThat(e.toString(), containsString("[_all]"));
@ -479,8 +453,7 @@ public class IndexAliasesTests extends ShieldIntegTestCase {
try { try {
//fails: no existing aliases to replace empty aliases //fails: no existing aliases to replace empty aliases
client().admin().indices().prepareGetAliases().setIndices("test_1") client.admin().indices().prepareGetAliases().setIndices("test_1").get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))).get();
fail("get alias should have failed due to missing manage_aliases privileges on test_1"); fail("get alias should have failed due to missing manage_aliases privileges on test_1");
} catch(IndexNotFoundException e) { } catch(IndexNotFoundException e) {
assertThat(e.toString(), containsString("[_all]")); assertThat(e.toString(), containsString("[_all]"));
@ -488,8 +461,7 @@ public class IndexAliasesTests extends ShieldIntegTestCase {
try { try {
//fails: no existing aliases to replace empty aliases //fails: no existing aliases to replace empty aliases
client().admin().indices().prepareGetAliases() client.admin().indices().prepareGetAliases().get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_alias", new SecuredString("test123".toCharArray()))).get();
fail("get alias should have failed due to missing manage_aliases privileges on test_1"); fail("get alias should have failed due to missing manage_aliases privileges on test_1");
} catch(IndexNotFoundException e) { } catch(IndexNotFoundException e) {
assertThat(e.toString(), containsString("[_all]")); assertThat(e.toString(), containsString("[_all]"));
@ -497,55 +469,52 @@ public class IndexAliasesTests extends ShieldIntegTestCase {
} }
public void testCreateIndexThenAliasesCreateAndAliasesPermission3() { public void testCreateIndexThenAliasesCreateAndAliasesPermission3() {
Map<String, String> 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. //user has create permission on test_* and manage_aliases permission on test_*,alias_*. All good.
assertAcked(client().admin().indices().prepareCreate("test_1") 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().prepareAliases().addAlias("test_1", "test_alias") 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", "alias_1") 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_*", "alias_2") assertAcked(client.admin().indices().prepareAliases().addAlias("test_*", "alias_2"));
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))));
} }
public void testCreateIndexAndAliasesCreateAndAliasesPermission3() { public void testCreateIndexAndAliasesCreateAndAliasesPermission3() {
//user has create permission on test_* and manage_aliases permission on test_*,alias_*. All good. Map<String, String> headers = Collections.singletonMap(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")) final Client client = client().filterWithHeader(headers);
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))));
assertAcked(client().admin().indices().prepareCreate("test_2").addAlias(new Alias("test_alias_2")).addAlias(new Alias("alias_2")) //user has create permission on test_* and manage_aliases permission on test_*,alias_*. All good.
.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")));
assertAcked(client.admin().indices().prepareCreate("test_2").addAlias(new Alias("test_alias_2")).addAlias(new Alias("alias_2")));
} }
public void testDeleteAliasesCreateAndAliasesPermission3() { public void testDeleteAliasesCreateAndAliasesPermission3() {
Map<String, String> 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. //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")) 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")) .addAlias(new Alias("alias_2")).addAlias(new Alias("alias_3")));
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))));
try { try {
//fails: user doesn't have manage_aliases privilege on non_authorized //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") client.admin().indices().prepareAliases().removeAlias("test_1", "non_authorized").removeAlias("test_1", "test_alias").get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))).get();
fail("remove alias should have failed due to missing manage_aliases privileges on non_authorized"); fail("remove alias should have failed due to missing manage_aliases privileges on non_authorized");
} catch(ElasticsearchSecurityException e) { } catch(ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:admin/aliases] is unauthorized for user [create_test_aliases_test_alias]")); 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") 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_*", "_all"));
try { try {
//fails: all aliases have been deleted, _all can't be resolved to any existing authorized aliases //fails: all aliases have been deleted, _all can't be resolved to any existing authorized aliases
client().admin().indices().prepareAliases().removeAlias("test_1", "_all") client.admin().indices().prepareAliases().removeAlias("test_1", "_all").get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))).get();
fail("remove alias should have failed due to no existing aliases matching _all"); fail("remove alias should have failed due to no existing aliases matching _all");
} catch(IndexNotFoundException e) { } catch(IndexNotFoundException e) {
assertThat(e.toString(), containsString("[_all]")); assertThat(e.toString(), containsString("[_all]"));
@ -553,51 +522,43 @@ public class IndexAliasesTests extends ShieldIntegTestCase {
} }
public void testGetAliasesCreateAndAliasesPermission3() { public void testGetAliasesCreateAndAliasesPermission3() {
Map<String, String> 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. //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")) 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()))));
assertAliases(client().admin().indices().prepareGetAliases().setAliases("test_alias").setIndices("test_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()))),
"test_1", "test_alias"); "test_1", "test_alias");
assertAliases(client().admin().indices().prepareGetAliases().setAliases("alias_1").setIndices("test_1") 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()))),
"test_1", "alias_1"); "test_1", "alias_1");
assertAliases(client().admin().indices().prepareGetAliases().setAliases("alias_1").setIndices("test_*") assertAliases(client.admin().indices().prepareGetAliases().setAliases("alias_1").setIndices("test_*"),
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))),
"test_1", "alias_1"); "test_1", "alias_1");
assertAliases(client().admin().indices().prepareGetAliases().setAliases("test_*").setIndices("test_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()))),
"test_1", "test_alias"); "test_1", "test_alias");
assertAliases(client().admin().indices().prepareGetAliases().setAliases("_all").setIndices("test_1") assertAliases(client.admin().indices().prepareGetAliases().setAliases("_all").setIndices("test_1"),
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))),
"test_1", "alias_1", "test_alias"); "test_1", "alias_1", "test_alias");
assertAliases(client().admin().indices().prepareGetAliases().setAliases("_all") assertAliases(client.admin().indices().prepareGetAliases().setAliases("_all"),
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))),
"test_1", "alias_1", "test_alias"); "test_1", "alias_1", "test_alias");
assertAliases(client().admin().indices().prepareGetAliases().setIndices("test_1") assertAliases(client.admin().indices().prepareGetAliases().setIndices("test_1"),
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))),
"test_1", "alias_1", "test_alias"); "test_1", "alias_1", "test_alias");
assertAliases(client().admin().indices().prepareGetAliases() assertAliases(client.admin().indices().prepareGetAliases(), "test_1", "alias_1", "test_alias");
.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().setAliases("alias_*").setIndices("test_*") assertAliases(client.admin().indices().prepareGetAliases().setAliases("alias_*").setIndices("test_*"),
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))),
"test_1", "alias_1"); "test_1", "alias_1");
} }
public void testCreateIndexAliasesOnlyPermission() { public void testCreateIndexAliasesOnlyPermission() {
try { try {
client().admin().indices().prepareCreate("test_1") client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("aliases_only", new SecuredString("test123".toCharArray()))))
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("aliases_only", new SecuredString("test123".toCharArray()))).get(); .admin().indices().prepareCreate("test_1").get();
fail("Expected ElasticsearchSecurityException"); fail("Expected ElasticsearchSecurityException");
} catch (ElasticsearchSecurityException e) { } catch (ElasticsearchSecurityException e) {
assertThat(e.getMessage(), is("action [indices:admin/create] is unauthorized for user [aliases_only]")); 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() { public void testGetAliasesAliasesOnlyPermission() {
Map<String, String> 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_* //user has manage_aliases only permissions on both alias_* and test_*
//ok: manage_aliases on both test_* and alias_* //ok: manage_aliases on both test_* and alias_*
GetAliasesResponse getAliasesResponse = client().admin().indices().prepareGetAliases("alias_1").addIndices("test_1").setIndicesOptions(IndicesOptions.lenientExpandOpen()) GetAliasesResponse getAliasesResponse = client.admin().indices().prepareGetAliases("alias_1").addIndices("test_1").setIndicesOptions(IndicesOptions.lenientExpandOpen()).get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("aliases_only", new SecuredString("test123".toCharArray()))).get();
assertThat(getAliasesResponse.getAliases().isEmpty(), is(true)); assertThat(getAliasesResponse.getAliases().isEmpty(), is(true));
try { try {
//fails: no manage_aliases privilege on non_authorized alias //fails: no manage_aliases privilege on non_authorized alias
client().admin().indices().prepareGetAliases("non_authorized").addIndices("test_1").setIndicesOptions(IndicesOptions.lenientExpandOpen()) client.admin().indices().prepareGetAliases("non_authorized").addIndices("test_1").setIndicesOptions(IndicesOptions.lenientExpandOpen()).get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("aliases_only", new SecuredString("test123".toCharArray()))).get();
} catch(ElasticsearchSecurityException e) { } catch(ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:admin/aliases/get] is unauthorized for user [aliases_only]")); assertAuthorizationException(e, containsString("action [indices:admin/aliases/get] is unauthorized for user [aliases_only]"));
} }
try { try {
//fails: no manage_aliases privilege on non_authorized index //fails: no manage_aliases privilege on non_authorized index
client().admin().indices().prepareGetAliases("alias_1").addIndices("non_authorized").setIndicesOptions(IndicesOptions.lenientExpandOpen()) client.admin().indices().prepareGetAliases("alias_1").addIndices("non_authorized").setIndicesOptions(IndicesOptions.lenientExpandOpen()).get();
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("aliases_only", new SecuredString("test123".toCharArray()))).get();
} catch(ElasticsearchSecurityException e) { } catch(ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:admin/aliases/get] is unauthorized for user [aliases_only]")); assertAuthorizationException(e, containsString("action [indices:admin/aliases/get] is unauthorized for user [aliases_only]"));
} }

View File

@ -23,6 +23,7 @@ import org.elasticsearch.cluster.metadata.AliasMetaData;
import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.search.action.SearchServiceTransportAction; import org.elasticsearch.search.action.SearchServiceTransportAction;
import org.elasticsearch.shield.User; import org.elasticsearch.shield.User;
import org.elasticsearch.shield.audit.AuditTrail; 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.privilege.IndexPrivilege;
import org.elasticsearch.shield.authz.store.RolesStore; import org.elasticsearch.shield.authz.store.RolesStore;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportRequest; import org.elasticsearch.transport.TransportRequest;
import org.junit.Before; import org.junit.Before;
@ -56,6 +58,8 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
private RolesStore rolesStore; private RolesStore rolesStore;
private ClusterService clusterService; private ClusterService clusterService;
private InternalAuthorizationService internalAuthorizationService; private InternalAuthorizationService internalAuthorizationService;
private ThreadContext threadContext;
private ThreadPool threadPool;
@Before @Before
public void setup() { public void setup() {
@ -63,7 +67,12 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
clusterService = mock(ClusterService.class); clusterService = mock(ClusterService.class);
auditTrail = mock(AuditTrail.class); auditTrail = mock(AuditTrail.class);
AnonymousService anonymousService = new AnonymousService(Settings.EMPTY); 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() { public void testActionsSystemUserIsAuthorized() {
@ -297,7 +306,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
TransportRequest request = new IndicesExistsRequest("b"); TransportRequest request = new IndicesExistsRequest("b");
ClusterState state = mock(ClusterState.class); ClusterState state = mock(ClusterState.class);
AnonymousService anonymousService = new AnonymousService(Settings.builder().put("shield.authc.anonymous.roles", "a_all").build()); 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(rolesStore.role("a_all")).thenReturn(Role.builder("a_all").add(IndexPrivilege.ALL, "a").build());
when(clusterService.state()).thenReturn(state); when(clusterService.state()).thenReturn(state);
@ -322,7 +331,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
.put("shield.authc.anonymous.roles", "a_all") .put("shield.authc.anonymous.roles", "a_all")
.put(AnonymousService.SETTING_AUTHORIZATION_EXCEPTION_ENABLED, false) .put(AnonymousService.SETTING_AUTHORIZATION_EXCEPTION_ENABLED, false)
.build()); .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(rolesStore.role("a_all")).thenReturn(Role.builder("a_all").add(IndexPrivilege.ALL, "a").build());
when(clusterService.state()).thenReturn(state); when(clusterService.state()).thenReturn(state);

View File

@ -24,6 +24,7 @@ import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.lucene.index.ElasticsearchDirectoryReader; import org.elasticsearch.common.lucene.index.ElasticsearchDirectoryReader;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.index.Index; import org.elasticsearch.index.Index;
import org.elasticsearch.index.IndexSettings; import org.elasticsearch.index.IndexSettings;
import org.elasticsearch.index.cache.bitset.BitsetFilterCache; 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.shield.license.ShieldLicenseState;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.IndexSettingsModule; import org.elasticsearch.test.IndexSettingsModule;
import org.elasticsearch.transport.TransportRequest;
import org.mockito.invocation.InvocationOnMock; import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer; import org.mockito.stubbing.Answer;
@ -65,10 +65,8 @@ public class ShieldIndexSearcherWrapperIntegrationTests extends ESTestCase {
} }
}); });
TransportRequest request = new TransportRequest.Empty(); ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
RequestContext.setCurrent(new RequestContext(request));
IndicesAccessControl.IndexAccessControl indexAccessControl = new IndicesAccessControl.IndexAccessControl(true, null, singleton(new BytesArray("{}"))); 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); IndexSettings indexSettings = IndexSettingsModule.newIndexSettings(shardId.index(), Settings.EMPTY);
QueryShardContext queryShardContext = mock(QueryShardContext.class); QueryShardContext queryShardContext = mock(QueryShardContext.class);
IndexSettings settings = IndexSettingsModule.newIndexSettings(new Index("_index"), Settings.EMPTY); IndexSettings settings = IndexSettingsModule.newIndexSettings(new Index("_index"), Settings.EMPTY);
@ -85,12 +83,17 @@ public class ShieldIndexSearcherWrapperIntegrationTests extends ESTestCase {
}); });
ShieldLicenseState licenseState = mock(ShieldLicenseState.class); ShieldLicenseState licenseState = mock(ShieldLicenseState.class);
when(licenseState.documentAndFieldLevelSecurityEnabled()).thenReturn(true); 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 @Override
protected QueryShardContext copyQueryShardContext(QueryShardContext context) { protected QueryShardContext copyQueryShardContext(QueryShardContext context) {
return queryShardContext; return queryShardContext;
} }
@Override
protected IndicesAccessControl getIndicesAccessControl() {
return new IndicesAccessControl(true, singletonMap("_index", indexAccessControl));
}
}; };
Directory directory = newDirectory(); Directory directory = newDirectory();

View File

@ -30,6 +30,7 @@ import org.apache.lucene.util.SparseFixedBitSet;
import org.elasticsearch.common.compress.CompressedXContent; import org.elasticsearch.common.compress.CompressedXContent;
import org.elasticsearch.common.lucene.index.ElasticsearchDirectoryReader; import org.elasticsearch.common.lucene.index.ElasticsearchDirectoryReader;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.Index; import org.elasticsearch.index.Index;
import org.elasticsearch.index.IndexSettings; import org.elasticsearch.index.IndexSettings;
@ -43,11 +44,9 @@ import org.elasticsearch.index.similarity.SimilarityService;
import org.elasticsearch.indices.IndicesModule; import org.elasticsearch.indices.IndicesModule;
import org.elasticsearch.indices.IndicesWarmer; import org.elasticsearch.indices.IndicesWarmer;
import org.elasticsearch.search.aggregations.LeafBucketCollector; import org.elasticsearch.search.aggregations.LeafBucketCollector;
import org.elasticsearch.shield.authz.InternalAuthorizationService;
import org.elasticsearch.shield.license.ShieldLicenseState; import org.elasticsearch.shield.license.ShieldLicenseState;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.IndexSettingsModule; import org.elasticsearch.test.IndexSettingsModule;
import org.elasticsearch.transport.TransportRequest;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
@ -68,16 +67,17 @@ import static org.mockito.Mockito.when;
public class ShieldIndexSearcherWrapperUnitTests extends ESTestCase { public class ShieldIndexSearcherWrapperUnitTests extends ESTestCase {
private TransportRequest request; private ThreadContext threadContext;
private MapperService mapperService; private MapperService mapperService;
private ShieldIndexSearcherWrapper shieldIndexSearcherWrapper; private ShieldIndexSearcherWrapper shieldIndexSearcherWrapper;
private ElasticsearchDirectoryReader esIn; private ElasticsearchDirectoryReader esIn;
private ShieldLicenseState licenseState; private ShieldLicenseState licenseState;
private IndexSettings indexSettings;
@Before @Before
public void before() throws Exception { public void before() throws Exception {
Index index = new Index("_index"); 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(), AnalysisService analysisService = new AnalysisService(indexSettings, Collections.emptyMap(), Collections.emptyMap(),
Collections.emptyMap(), Collections.emptyMap()); Collections.emptyMap(), Collections.emptyMap());
SimilarityService similarityService = new SimilarityService(indexSettings, Collections.emptyMap()); SimilarityService similarityService = new SimilarityService(indexSettings, Collections.emptyMap());
@ -86,13 +86,10 @@ public class ShieldIndexSearcherWrapperUnitTests extends ESTestCase {
ShardId shardId = new ShardId(index, 0); ShardId shardId = new ShardId(index, 0);
licenseState = mock(ShieldLicenseState.class); licenseState = mock(ShieldLicenseState.class);
when(licenseState.documentAndFieldLevelSecurityEnabled()).thenReturn(true); when(licenseState.documentAndFieldLevelSecurityEnabled()).thenReturn(true);
shieldIndexSearcherWrapper = new ShieldIndexSearcherWrapper(indexSettings, null, mapperService, null, licenseState); threadContext = new ThreadContext(Settings.EMPTY);
IndexShard indexShard = mock(IndexShard.class); IndexShard indexShard = mock(IndexShard.class);
when(indexShard.shardId()).thenReturn(shardId); when(indexShard.shardId()).thenReturn(shardId);
request = new TransportRequest.Empty();
RequestContext.setCurrent(new RequestContext(request));
Directory directory = new RAMDirectory(); Directory directory = new RAMDirectory();
IndexWriter writer = new IndexWriter(directory, newIndexWriterConfig()); IndexWriter writer = new IndexWriter(directory, newIndexWriterConfig());
writer.close(); writer.close();
@ -106,16 +103,6 @@ public class ShieldIndexSearcherWrapperUnitTests extends ESTestCase {
esIn.close(); 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 { public void testDefaultMetaFields() throws Exception {
XContentBuilder mappingSource = jsonBuilder().startObject().startObject("type") XContentBuilder mappingSource = jsonBuilder().startObject().startObject("type")
.startObject("properties") .startObject("properties")
@ -123,8 +110,13 @@ public class ShieldIndexSearcherWrapperUnitTests extends ESTestCase {
.endObject().endObject(); .endObject().endObject();
mapperService.merge("type", new CompressedXContent(mappingSource.string()), MapperService.MergeReason.MAPPING_UPDATE, false); mapperService.merge("type", new CompressedXContent(mappingSource.string()), MapperService.MergeReason.MAPPING_UPDATE, false);
IndicesAccessControl.IndexAccessControl indexAccessControl = new IndicesAccessControl.IndexAccessControl(true, emptySet(), null); shieldIndexSearcherWrapper = new ShieldIndexSearcherWrapper(indexSettings, null, mapperService, null, threadContext, licenseState) {
request.putInContext(InternalAuthorizationService.INDICES_PERMISSIONS_KEY, new IndicesAccessControl(true, singletonMap("_index", indexAccessControl))); @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); FieldSubsetReader.FieldSubsetDirectoryReader result = (FieldSubsetReader.FieldSubsetDirectoryReader) shieldIndexSearcherWrapper.wrap(esIn);
assertThat(result.getFieldNames().size(), equalTo(11)); assertThat(result.getFieldNames().size(), equalTo(11));
@ -144,12 +136,14 @@ public class ShieldIndexSearcherWrapperUnitTests extends ESTestCase {
public void testWrapReaderWhenFeatureDisabled() throws Exception { public void testWrapReaderWhenFeatureDisabled() throws Exception {
when(licenseState.documentAndFieldLevelSecurityEnabled()).thenReturn(false); when(licenseState.documentAndFieldLevelSecurityEnabled()).thenReturn(false);
shieldIndexSearcherWrapper = new ShieldIndexSearcherWrapper(indexSettings, null, mapperService, null, threadContext, licenseState);
DirectoryReader reader = shieldIndexSearcherWrapper.wrap(esIn); DirectoryReader reader = shieldIndexSearcherWrapper.wrap(esIn);
assertThat(reader, sameInstance(esIn)); assertThat(reader, sameInstance(esIn));
} }
public void testWrapSearcherWhenFeatureDisabled() throws Exception { public void testWrapSearcherWhenFeatureDisabled() throws Exception {
ShardId shardId = new ShardId("_index", 0); ShardId shardId = new ShardId("_index", 0);
shieldIndexSearcherWrapper = new ShieldIndexSearcherWrapper(indexSettings, null, mapperService, null, threadContext, licenseState);
IndexSearcher indexSearcher = new IndexSearcher(esIn); IndexSearcher indexSearcher = new IndexSearcher(esIn);
IndexSearcher result = shieldIndexSearcherWrapper.wrap(indexSearcher); IndexSearcher result = shieldIndexSearcherWrapper.wrap(indexSearcher);
assertThat(result, sameInstance(indexSearcher)); assertThat(result, sameInstance(indexSearcher));
@ -262,6 +256,7 @@ public class ShieldIndexSearcherWrapperUnitTests extends ESTestCase {
}); });
DirectoryReader directoryReader = DocumentSubsetReader.wrap(esIn, bitsetFilterCache, new MatchAllDocsQuery()); DirectoryReader directoryReader = DocumentSubsetReader.wrap(esIn, bitsetFilterCache, new MatchAllDocsQuery());
IndexSearcher indexSearcher = new IndexSearcher(directoryReader); IndexSearcher indexSearcher = new IndexSearcher(directoryReader);
shieldIndexSearcherWrapper = new ShieldIndexSearcherWrapper(indexSettings, null, mapperService, null, threadContext, licenseState);
IndexSearcher result = shieldIndexSearcherWrapper.wrap(indexSearcher); IndexSearcher result = shieldIndexSearcherWrapper.wrap(indexSearcher);
assertThat(result, not(sameInstance(indexSearcher))); assertThat(result, not(sameInstance(indexSearcher)));
assertThat(result.getSimilarity(true), sameInstance(indexSearcher.getSimilarity(true))); assertThat(result.getSimilarity(true), sameInstance(indexSearcher.getSimilarity(true)));
@ -269,6 +264,7 @@ public class ShieldIndexSearcherWrapperUnitTests extends ESTestCase {
} }
public void testIntersectScorerAndRoleBits() throws Exception { public void testIntersectScorerAndRoleBits() throws Exception {
shieldIndexSearcherWrapper = new ShieldIndexSearcherWrapper(indexSettings, null, mapperService, null, threadContext, licenseState);
final Directory directory = newDirectory(); final Directory directory = newDirectory();
IndexWriter iw = new IndexWriter( IndexWriter iw = new IndexWriter(
directory, directory,
@ -356,8 +352,13 @@ public class ShieldIndexSearcherWrapperUnitTests extends ESTestCase {
} }
private void assertResolvedFields(String expression, String... expectedFields) { private void assertResolvedFields(String expression, String... expectedFields) {
IndicesAccessControl.IndexAccessControl indexAccessControl = new IndicesAccessControl.IndexAccessControl(true, singleton(expression), null); shieldIndexSearcherWrapper = new ShieldIndexSearcherWrapper(indexSettings, null, mapperService, null, threadContext, licenseState) {
request.putInContext(InternalAuthorizationService.INDICES_PERMISSIONS_KEY, new IndicesAccessControl(true, singletonMap("_index", indexAccessControl))); @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); FieldSubsetReader.FieldSubsetDirectoryReader result = (FieldSubsetReader.FieldSubsetDirectoryReader) shieldIndexSearcherWrapper.wrap(esIn);
assertThat(result.getFieldNames().size() - shieldIndexSearcherWrapper.getAllowedMetaFields().size(), equalTo(expectedFields.length)); assertThat(result.getFieldNames().size() - shieldIndexSearcherWrapper.getAllowedMetaFields().size(), equalTo(expectedFields.length));
for (String expectedField : expectedFields) { for (String expectedField : expectedFields) {

View File

@ -7,6 +7,7 @@ package org.elasticsearch.shield.rest;
import org.elasticsearch.ElasticsearchSecurityException; import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.rest.RestChannel; import org.elasticsearch.rest.RestChannel;
import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestFilterChain; import org.elasticsearch.rest.RestFilterChain;
@ -15,6 +16,7 @@ import org.elasticsearch.shield.User;
import org.elasticsearch.shield.authc.AuthenticationService; import org.elasticsearch.shield.authc.AuthenticationService;
import org.elasticsearch.shield.license.ShieldLicenseState; import org.elasticsearch.shield.license.ShieldLicenseState;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.threadpool.ThreadPool;
import org.junit.Before; import org.junit.Before;
import static org.elasticsearch.shield.support.Exceptions.authenticationError; import static org.elasticsearch.shield.support.Exceptions.authenticationError;
@ -42,7 +44,9 @@ public class ShieldRestFilterTests extends ESTestCase {
chain = mock(RestFilterChain.class); chain = mock(RestFilterChain.class);
licenseState = mock(ShieldLicenseState.class); licenseState = mock(ShieldLicenseState.class);
when(licenseState.securityEnabled()).thenReturn(true); 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); verify(restController).registerFilter(filter);
} }

View File

@ -30,6 +30,6 @@ public class ClientTransportFilterTests extends ESTestCase {
public void testOutbound() throws Exception { public void testOutbound() throws Exception {
TransportRequest request = mock(TransportRequest.class); TransportRequest request = mock(TransportRequest.class);
filter.outbound("_action", request); filter.outbound("_action", request);
verify(authcService).attachUserHeaderIfMissing(request, User.SYSTEM); verify(authcService).attachUserHeaderIfMissing(User.SYSTEM);
} }
} }

View File

@ -6,6 +6,8 @@
package org.elasticsearch.shield.transport; package org.elasticsearch.shield.transport;
import org.elasticsearch.ElasticsearchSecurityException; 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.User;
import org.elasticsearch.shield.action.ShieldActionMapper; import org.elasticsearch.shield.action.ShieldActionMapper;
import org.elasticsearch.shield.authc.AuthenticationService; import org.elasticsearch.shield.authc.AuthenticationService;
@ -40,7 +42,7 @@ public class ServerTransportFilterTests extends ESTestCase {
authzService = mock(AuthorizationService.class); authzService = mock(AuthorizationService.class);
channel = mock(NettyTransportChannel.class); channel = mock(NettyTransportChannel.class);
when(channel.getProfileName()).thenReturn(NettyTransport.DEFAULT_PROFILE); 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 { public void testInbound() throws Exception {

View File

@ -16,6 +16,7 @@ import org.elasticsearch.shield.ssl.ServerSSLService;
import org.elasticsearch.shield.transport.SSLClientAuth; import org.elasticsearch.shield.transport.SSLClientAuth;
import org.elasticsearch.shield.transport.filter.IPFilter; import org.elasticsearch.shield.transport.filter.IPFilter;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.threadpool.ThreadPool;
import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.handler.ssl.SslHandler; import org.jboss.netty.handler.ssl.SslHandler;
import org.junit.Before; import org.junit.Before;
@ -45,7 +46,7 @@ public class ShieldNettyHttpServerTransportTests extends ESTestCase {
public void testDefaultClientAuth() throws Exception { public void testDefaultClientAuth() throws Exception {
Settings settings = Settings.builder().put(ShieldNettyHttpServerTransport.HTTP_SSL_SETTING, true).build(); 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); NettyHttpMockUtil.setOpenChannelsHandlerToMock(transport);
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory(); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory();
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(false)); assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(false));
@ -57,7 +58,7 @@ public class ShieldNettyHttpServerTransportTests extends ESTestCase {
Settings settings = Settings.builder() Settings settings = Settings.builder()
.put(ShieldNettyHttpServerTransport.HTTP_SSL_SETTING, true) .put(ShieldNettyHttpServerTransport.HTTP_SSL_SETTING, true)
.put(ShieldNettyHttpServerTransport.HTTP_CLIENT_AUTH_SETTING, value).build(); .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); NettyHttpMockUtil.setOpenChannelsHandlerToMock(transport);
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory(); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory();
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(false)); assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(false));
@ -69,7 +70,7 @@ public class ShieldNettyHttpServerTransportTests extends ESTestCase {
Settings settings = Settings.builder() Settings settings = Settings.builder()
.put(ShieldNettyHttpServerTransport.HTTP_SSL_SETTING, true) .put(ShieldNettyHttpServerTransport.HTTP_SSL_SETTING, true)
.put(ShieldNettyHttpServerTransport.HTTP_CLIENT_AUTH_SETTING, value).build(); .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); NettyHttpMockUtil.setOpenChannelsHandlerToMock(transport);
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory(); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory();
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(true)); assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(true));
@ -81,7 +82,7 @@ public class ShieldNettyHttpServerTransportTests extends ESTestCase {
Settings settings = Settings.builder() Settings settings = Settings.builder()
.put(ShieldNettyHttpServerTransport.HTTP_SSL_SETTING, true) .put(ShieldNettyHttpServerTransport.HTTP_SSL_SETTING, true)
.put(ShieldNettyHttpServerTransport.HTTP_CLIENT_AUTH_SETTING, value).build(); .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); NettyHttpMockUtil.setOpenChannelsHandlerToMock(transport);
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory(); ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory();
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(false)); assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(false));

View File

@ -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.NodeInfo;
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse; import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.cluster.health.ClusterHealthStatus; import org.elasticsearch.cluster.health.ClusterHealthStatus;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.shield.authc.support.SecuredString;
@ -26,10 +26,14 @@ import org.junit.rules.ExternalResource;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors; 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.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoTimeout;
import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.is;
@ -303,4 +307,10 @@ public abstract class ShieldIntegTestCase extends ESIntegTestCase {
assertNoTimeout(clusterHealthResponse); assertNoTimeout(clusterHealthResponse);
assertThat(clusterHealthResponse.getStatus(), is(ClusterHealthStatus.GREEN)); assertThat(clusterHealthResponse.getStatus(), is(ClusterHealthStatus.GREEN));
} }
@Override
protected Function<Client,Client> getClientWrapper() {
Map<String, String> headers = Collections.singletonMap("Authorization", basicAuthHeaderValue(nodeClientUsername(), nodeClientPassword()));
return client -> (client instanceof NodeClient) ? client.filterWithHeader(headers) : client;
}
} }

View File

@ -6,9 +6,9 @@
package org.elasticsearch.test; package org.elasticsearch.test;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.client.support.Headers;
import org.elasticsearch.common.io.PathUtils; import org.elasticsearch.common.io.PathUtils;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.index.IndexModule; import org.elasticsearch.index.IndexModule;
import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.shield.ShieldPlugin; 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.esnative.ESNativeRealm;
import org.elasticsearch.shield.authc.support.Hasher; import org.elasticsearch.shield.authc.support.Hasher;
import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.shield.authc.support.UsernamePasswordToken;
import org.elasticsearch.shield.crypto.InternalCryptoService; import org.elasticsearch.shield.crypto.InternalCryptoService;
import org.elasticsearch.shield.test.ShieldTestUtils; import org.elasticsearch.shield.test.ShieldTestUtils;
import org.elasticsearch.shield.transport.netty.ShieldNettyHttpServerTransport; 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.type", ESNativeRealm.TYPE)
.put("shield.authc.realms.index.order", "1") .put("shield.authc.realms.index.order", "1")
.put("shield.authz.store.files.roles", writeFile(folder, "roles.yml", configRoles())) .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. // validation in ShieldPlugin fail.
.put(IndexModule.INDEX_QUERY_CACHE_TYPE_SETTING.getKey(), ShieldPlugin.OPT_OUT_QUERY_CACHE) .put(IndexModule.INDEX_QUERY_CACHE_TYPE_SETTING.getKey(), ShieldPlugin.OPT_OUT_QUERY_CACHE)
.put(getNodeSSLSettings()); .put(getNodeSSLSettings());
setUser(builder, nodeClientUsername(), nodeClientPassword());
return builder.build(); return builder.build();
} }
@ -148,7 +145,11 @@ public class ShieldSettingsSource extends ClusterDiscoveryConfiguration.UnicastZ
public Settings transportClientSettings() { public Settings transportClientSettings() {
Settings.Builder builder = settingsBuilder().put(super.transportClientSettings()) Settings.Builder builder = settingsBuilder().put(super.transportClientSettings())
.put(getClientSSLSettings()); .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(); return builder.build();
} }
@ -198,14 +199,6 @@ public class ShieldSettingsSource extends ClusterDiscoveryConfiguration.UnicastZ
return XPackPlugin.class; 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() { private static byte[] generateKey() {
try { try {
return InternalCryptoService.generateKey(); return InternalCryptoService.generateKey();

View File

@ -15,8 +15,8 @@ import org.apache.http.client.methods.HttpPut;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.BasicHttpClientConnectionManager; import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
import org.elasticsearch.client.support.Headers;
import org.elasticsearch.common.settings.Settings; 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.SecuredString;
import org.elasticsearch.test.rest.ESRestTestCase; import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.test.rest.RestTestCandidate; import org.elasticsearch.test.rest.RestTestCandidate;
@ -67,7 +67,7 @@ public abstract class XPackRestTestCase extends ESRestTestCase {
protected Settings restClientSettings() { protected Settings restClientSettings() {
String token = basicAuthHeaderValue("test_user", new SecuredString("changeme".toCharArray())); String token = basicAuthHeaderValue("test_user", new SecuredString("changeme".toCharArray()));
return Settings.builder() return Settings.builder()
.put(Headers.PREFIX + ".Authorization", token) .put(ThreadContext.PREFIX + ".Authorization", token)
.build(); .build();
} }
} }

View File

@ -8,7 +8,6 @@ package org.elasticsearch.watcher.client;
import org.elasticsearch.action.ActionFuture; import org.elasticsearch.action.ActionFuture;
import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionListener;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.elasticsearch.client.ElasticsearchClient;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.watcher.transport.actions.ack.AckWatchAction; import org.elasticsearch.watcher.transport.actions.ack.AckWatchAction;
import org.elasticsearch.watcher.transport.actions.ack.AckWatchRequest; 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.WatcherStatsRequestBuilder;
import org.elasticsearch.watcher.transport.actions.stats.WatcherStatsResponse; import org.elasticsearch.watcher.transport.actions.stats.WatcherStatsResponse;
import java.util.Map;
/** /**
*/ */
public class WatcherClient { public class WatcherClient {
private final ElasticsearchClient client; private final Client client;
@Inject @Inject
public WatcherClient(Client client) { public WatcherClient(Client client) {
@ -323,4 +324,7 @@ public class WatcherClient {
return client.execute(ExecuteWatchAction.INSTANCE, request); return client.execute(ExecuteWatchAction.INSTANCE, request);
} }
public WatcherClient filterWithHeader(Map<String, String> headers) {
return new WatcherClient(client.filterWithHeader(headers));
}
} }

View File

@ -149,7 +149,8 @@ public class ExecutionService extends AbstractComponent {
} }
public List<QueuedWatch> queuedWatches() { public List<QueuedWatch> queuedWatches() {
List<Runnable> snapshot = new ArrayList<>(executor.queue()); List<Runnable> snapshot = new ArrayList<>();
executor.tasks().forEach(t -> snapshot.add(t));
if (snapshot.isEmpty()) { if (snapshot.isEmpty()) {
return Collections.emptyList(); return Collections.emptyList();
} }

View File

@ -14,6 +14,9 @@ import org.elasticsearch.watcher.WatcherPlugin;
import org.elasticsearch.watcher.support.ThreadPoolSettingsBuilder; import org.elasticsearch.watcher.support.ThreadPoolSettingsBuilder;
import java.util.concurrent.BlockingQueue; 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(); return executor().getQueue();
} }
@Override
public Stream<Runnable> tasks() {
return executor().getTasks();
}
@Override @Override
public long largestPoolSize() { public long largestPoolSize() {
return executor().getLargestPoolSize(); return executor().getLargestPoolSize();

Some files were not shown because too many files have changed in this diff Show More