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

View File

@ -90,7 +90,8 @@ public class ShieldTransportClientIT extends ESIntegTestCase {
// this checks that the transport client is really running in a limited state
ClusterHealthResponse response;
if (useTransportUser) {
response = client.admin().cluster().prepareHealth().putHeader("Authorization", basicAuthHeaderValue("test_user", new SecuredString("changeme".toCharArray()))).get();
response = client.filterWithHeader(Collections.singletonMap("Authorization", basicAuthHeaderValue("test_user", new SecuredString("changeme".toCharArray()))))
.admin().cluster().prepareHealth().get();
} else {
response = client.admin().cluster().prepareHealth().get();
}

View File

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

View File

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

View File

@ -5,13 +5,17 @@
*/
package org.elasticsearch.example.realm;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.shield.authc.Realm;
import org.elasticsearch.shield.authc.RealmConfig;
public class CustomRealmFactory extends Realm.Factory<CustomRealm> {
public CustomRealmFactory() {
@Inject
public CustomRealmFactory(RestController controller) {
super(CustomRealm.TYPE, false);
controller.registerRelevantHeaders(CustomRealm.USER_HEADER, CustomRealm.PW_HEADER);
}
@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.node.info.NodeInfo;
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
import org.elasticsearch.client.support.Headers;
import org.elasticsearch.client.transport.NoNodeAvailableException;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.rest.client.http.HttpResponse;
@ -30,8 +30,8 @@ public class CustomRealmIT extends ESIntegTestCase {
@Override
protected Settings externalClusterClientSettings() {
return Settings.builder()
.put(Headers.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER)
.put(Headers.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW)
.put(ThreadContext.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER)
.put(ThreadContext.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW)
.build();
}
@ -64,8 +64,8 @@ public class CustomRealmIT extends ESIntegTestCase {
Settings settings = Settings.builder()
.put("cluster.name", clusterName)
.put(Headers.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER)
.put(Headers.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW)
.put(ThreadContext.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER)
.put(ThreadContext.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW)
.build();
try (TransportClient client = TransportClient.builder().settings(settings).addPlugin(XPackPlugin.class).build()) {
client.addTransportAddress(publishAddress);
@ -83,8 +83,8 @@ public class CustomRealmIT extends ESIntegTestCase {
Settings settings = Settings.builder()
.put("cluster.name", clusterName)
.put(Headers.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER + randomAsciiOfLength(1))
.put(Headers.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW)
.put(ThreadContext.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER + randomAsciiOfLength(1))
.put(ThreadContext.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW)
.build();
try (TransportClient client = TransportClient.builder().addPlugin(XPackPlugin.class).settings(settings).build()) {
client.addTransportAddress(publishAddress);

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

@ -13,6 +13,7 @@ import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.FilterClient;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.util.concurrent.ThreadContext;
/**
*
@ -30,7 +31,9 @@ public class SecuredClient extends FilterClient {
@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) {
this.shieldIntegration.bindInternalMarvelUser(request);
try (ThreadContext.StoredContext ctx = threadPool().getThreadContext().stashContext()) {
this.shieldIntegration.bindInternalMarvelUser();
super.doExecute(action, request, listener);
}
}
}

View File

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

View File

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

View File

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

View File

@ -16,6 +16,7 @@ import org.elasticsearch.action.support.ActionFilterChain;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.license.plugin.core.LicenseUtils;
import org.elasticsearch.shield.ShieldPlugin;
import org.elasticsearch.shield.User;
@ -26,7 +27,10 @@ import org.elasticsearch.shield.authz.AuthorizationService;
import org.elasticsearch.shield.authz.privilege.HealthAndStatsPrivilege;
import org.elasticsearch.shield.crypto.CryptoService;
import org.elasticsearch.shield.license.ShieldLicenseState;
import org.elasticsearch.shield.support.AutomatonPredicate;
import org.elasticsearch.shield.support.Automatons;
import org.elasticsearch.tasks.Task;
import org.elasticsearch.threadpool.ThreadPool;
import java.io.IOException;
import java.util.ArrayList;
@ -42,6 +46,8 @@ import static org.elasticsearch.shield.support.Exceptions.authorizationError;
public class ShieldActionFilter extends AbstractComponent implements ActionFilter {
private static final Predicate<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 AuthorizationService authzService;
@ -50,10 +56,12 @@ public class ShieldActionFilter extends AbstractComponent implements ActionFilte
private final ShieldActionMapper actionMapper;
private final Set<RequestInterceptor> requestInterceptors;
private final ShieldLicenseState licenseState;
private final ThreadContext threadContext;
@Inject
public ShieldActionFilter(Settings settings, AuthenticationService authcService, AuthorizationService authzService, CryptoService cryptoService,
AuditTrail auditTrail, ShieldLicenseState licenseState, ShieldActionMapper actionMapper, Set<RequestInterceptor> requestInterceptors) {
AuditTrail auditTrail, ShieldLicenseState licenseState, ShieldActionMapper actionMapper, Set<RequestInterceptor> requestInterceptors,
ThreadPool threadPool) {
super(settings);
this.authcService = authcService;
this.authzService = authzService;
@ -62,6 +70,7 @@ public class ShieldActionFilter extends AbstractComponent implements ActionFilte
this.actionMapper = actionMapper;
this.licenseState = licenseState;
this.requestInterceptors = requestInterceptors;
this.threadContext = threadPool.getThreadContext();
}
@Override
@ -78,8 +87,56 @@ public class ShieldActionFilter extends AbstractComponent implements ActionFilte
throw LicenseUtils.newComplianceException(ShieldPlugin.NAME);
}
try {
try (ThreadContext.StoredContext original = threadContext.newStoredContext()) {
if (licenseState.securityEnabled()) {
// FIXME yet another hack. Needed to work around something like
/*
FailedNodeException[total failure in fetching]; nested: ElasticsearchSecurityException[action [internal:gateway/local/started_shards] is unauthorized for user [test_user]];
at org.elasticsearch.gateway.AsyncShardFetch$1.onFailure(AsyncShardFetch.java:284)
at org.elasticsearch.action.support.TransportAction$1.onFailure(TransportAction.java:84)
at org.elasticsearch.shield.action.ShieldActionFilter.apply(ShieldActionFilter.java:121)
at org.elasticsearch.action.support.TransportAction$RequestFilterChain.proceed(TransportAction.java:133)
at org.elasticsearch.action.support.TransportAction.execute(TransportAction.java:107)
at org.elasticsearch.action.support.TransportAction.execute(TransportAction.java:74)
at org.elasticsearch.gateway.TransportNodesListGatewayStartedShards.list(TransportNodesListGatewayStartedShards.java:78)
at org.elasticsearch.gateway.AsyncShardFetch.asyncFetch(AsyncShardFetch.java:274)
at org.elasticsearch.gateway.AsyncShardFetch.fetchData(AsyncShardFetch.java:124)
at org.elasticsearch.gateway.GatewayAllocator$InternalPrimaryShardAllocator.fetchData(GatewayAllocator.java:156)
at org.elasticsearch.gateway.PrimaryShardAllocator.allocateUnassigned(PrimaryShardAllocator.java:83)
at org.elasticsearch.gateway.GatewayAllocator.allocateUnassigned(GatewayAllocator.java:120)
at org.elasticsearch.cluster.routing.allocation.allocator.ShardsAllocators.allocateUnassigned(ShardsAllocators.java:72)
at org.elasticsearch.cluster.routing.allocation.AllocationService.reroute(AllocationService.java:309)
at org.elasticsearch.cluster.routing.allocation.AllocationService.reroute(AllocationService.java:273)
at org.elasticsearch.cluster.routing.allocation.AllocationService.reroute(AllocationService.java:259)
at org.elasticsearch.cluster.routing.RoutingService$2.execute(RoutingService.java:158)
at org.elasticsearch.cluster.ClusterStateUpdateTask.execute(ClusterStateUpdateTask.java:45)
at org.elasticsearch.cluster.service.InternalClusterService.runTasksForExecutor(InternalClusterService.java:447)
at org.elasticsearch.cluster.service.InternalClusterService$UpdateTask.run(InternalClusterService.java:757)
at org.elasticsearch.common.util.concurrent.EsThreadPoolExecutor$FilterRunnable.run(EsThreadPoolExecutor.java:211)
at org.elasticsearch.common.util.concurrent.PrioritizedEsThreadPoolExecutor$TieBreakingPrioritizedRunnable.runAndClean(PrioritizedEsThreadPoolExecutor.java:237)
at org.elasticsearch.common.util.concurrent.PrioritizedEsThreadPoolExecutor$TieBreakingPrioritizedRunnable.run(PrioritizedEsThreadPoolExecutor.java:200)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
*/
if (INTERNAL_PREDICATE.test(action)) {
try (ThreadContext.StoredContext ctx = threadContext.stashContext()) {
String shieldAction = actionMapper.action(action, request);
User user = authcService.authenticate(shieldAction, request, User.SYSTEM);
authzService.authorize(user, shieldAction, request);
request = unsign(user, shieldAction, request);
for (RequestInterceptor interceptor : requestInterceptors) {
if (interceptor.supports(request)) {
interceptor.intercept(request, user);
}
}
chain.proceed(task, action, request, new SigningListener(this, listener));
return;
}
}
/**
here we fallback on the system user. Internal system requests are requests that are triggered by
the system itself (e.g. pings, update mappings, share relocation, etc...) and were not originated

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -15,6 +15,7 @@ import org.elasticsearch.common.network.NetworkAddress;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.shield.User;
import org.elasticsearch.shield.admin.ShieldInternalUserHolder;
@ -24,6 +25,7 @@ import org.elasticsearch.shield.authz.privilege.Privilege;
import org.elasticsearch.shield.authz.privilege.SystemPrivilege;
import org.elasticsearch.shield.rest.RemoteHostHeader;
import org.elasticsearch.shield.transport.filter.ShieldIpFilterRule;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.Transport;
import org.elasticsearch.transport.TransportMessage;
@ -44,6 +46,7 @@ public class LoggingAuditTrail extends AbstractLifecycleComponent<LoggingAuditTr
private final ESLogger logger;
private final Transport transport;
private final ThreadContext threadContext;
private String prefix;
@ -53,19 +56,20 @@ public class LoggingAuditTrail extends AbstractLifecycleComponent<LoggingAuditTr
}
@Inject
public LoggingAuditTrail(Settings settings, Transport transport) {
this(settings, transport, Loggers.getLogger(LoggingAuditTrail.class));
public LoggingAuditTrail(Settings settings, Transport transport, ThreadPool threadPool) {
this(settings, transport, Loggers.getLogger(LoggingAuditTrail.class), threadPool.getThreadContext());
}
LoggingAuditTrail(Settings settings, Transport transport, ESLogger logger) {
this("", settings, transport, logger);
LoggingAuditTrail(Settings settings, Transport transport, ESLogger logger, ThreadContext threadContext) {
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);
this.logger = logger;
this.prefix = prefix;
this.transport = transport;
this.threadContext = threadContext;
}
@ -96,15 +100,15 @@ public class LoggingAuditTrail extends AbstractLifecycleComponent<LoggingAuditTr
String indices = indicesString(message);
if (indices != null) {
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 {
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 {
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 {
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);
if (indices != null) {
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 {
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 {
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 {
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);
if (indices != null) {
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 {
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 {
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 {
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()) {
String indices = indicesString(message);
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 {
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 (logger.isTraceEnabled()) {
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 {
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;
@ -209,15 +213,15 @@ public class LoggingAuditTrail extends AbstractLifecycleComponent<LoggingAuditTr
if (indices != null) {
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 {
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 {
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 {
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);
if (indices != null) {
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 {
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 {
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 {
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);
if (indices != null) {
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 {
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 {
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 {
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);
if (indices != null) {
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 {
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 {
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 {
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
public void runAsGranted(User user, String action, TransportMessage<?> message) {
if (logger.isDebugEnabled()) {
logger.debug("{}[transport] [run_as_granted]\t{}, principal=[{}], run_as_principal=[{}], action=[{}], request=[{}]", prefix, originAttributes(message, transport), user.principal(), user.runAs().principal(), action, message.getClass().getSimpleName());
logger.debug("{}[transport] [run_as_granted]\t{}, principal=[{}], run_as_principal=[{}], action=[{}], request=[{}]", prefix, originAttributes(message, transport, threadContext), user.principal(), user.runAs().principal(), action, message.getClass().getSimpleName());
} else {
logger.info("{}[transport] [run_as_granted]\t{}, principal=[{}], run_as_principal=[{}], action=[{}]", prefix, originAttributes(message, transport), user.principal(), user.runAs().principal(), action);
logger.info("{}[transport] [run_as_granted]\t{}, principal=[{}], run_as_principal=[{}], action=[{}]", prefix, originAttributes(message, transport, threadContext), user.principal(), user.runAs().principal(), action);
}
}
@Override
public void runAsDenied(User user, String action, TransportMessage<?> message) {
if (logger.isDebugEnabled()) {
logger.debug("{}[transport] [run_as_denied]\t{}, principal=[{}], run_as_principal=[{}], action=[{}], request=[{}]", prefix, originAttributes(message, transport), user.principal(), user.runAs().principal(), action, message.getClass().getSimpleName());
logger.debug("{}[transport] [run_as_denied]\t{}, principal=[{}], run_as_principal=[{}], action=[{}], request=[{}]", prefix, originAttributes(message, transport, threadContext), user.principal(), user.runAs().principal(), action, message.getClass().getSimpleName());
} else {
logger.info("{}[transport] [run_as_denied]\t{}, principal=[{}], run_as_principal=[{}], action=[{}]", prefix, originAttributes(message, transport), user.principal(), user.runAs().principal(), action);
logger.info("{}[transport] [run_as_denied]\t{}, principal=[{}], run_as_principal=[{}], action=[{}]", prefix, originAttributes(message, transport, threadContext), user.principal(), user.runAs().principal(), action);
}
}
@ -317,11 +321,11 @@ public class LoggingAuditTrail extends AbstractLifecycleComponent<LoggingAuditTr
return "origin_address=[" + formattedAddress + "]";
}
static String originAttributes(TransportMessage message, Transport transport) {
static String originAttributes(TransportMessage message, Transport transport, ThreadContext threadContext) {
StringBuilder builder = new StringBuilder();
// first checking if the message originated in a rest call
InetSocketAddress restAddress = RemoteHostHeader.restRemoteAddress(message);
InetSocketAddress restAddress = RemoteHostHeader.restRemoteAddress(threadContext);
if (restAddress != null) {
builder.append("origin_type=[rest], origin_address=[").append(NetworkAddress.formatAddress(restAddress.getAddress())).append("]");
return builder.toString();

View File

@ -6,7 +6,6 @@
package org.elasticsearch.shield.authc;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.common.ContextAndHeaderHolder;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.shield.User;
import org.elasticsearch.transport.TransportMessage;
@ -27,8 +26,9 @@ public interface AuthenticationService {
* @return The authenticated user
* @throws ElasticsearchSecurityException If no user was associated with the request or if the associated
* 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.
@ -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
* 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
*/
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.common.Base64;
import org.elasticsearch.common.ContextAndHeaderHolder;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.component.AbstractComponent;
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.logging.ESLogger;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.shield.User;
import org.elasticsearch.shield.audit.AuditTrail;
import org.elasticsearch.shield.crypto.CryptoService;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportMessage;
import java.io.IOException;
@ -44,32 +45,35 @@ public class InternalAuthenticationService extends AbstractComponent implements
private final CryptoService cryptoService;
private final AnonymousService anonymousService;
private final AuthenticationFailureHandler failureHandler;
private final ThreadContext threadContext;
private final boolean signUserHeader;
private final boolean runAsEnabled;
@Inject
public InternalAuthenticationService(Settings settings, Realms realms, AuditTrail auditTrail, CryptoService cryptoService,
AnonymousService anonymousService, AuthenticationFailureHandler failureHandler) {
AnonymousService anonymousService, AuthenticationFailureHandler failureHandler,
ThreadPool threadPool) {
super(settings);
this.realms = realms;
this.auditTrail = auditTrail;
this.cryptoService = cryptoService;
this.anonymousService = anonymousService;
this.failureHandler = failureHandler;
this.threadContext = threadPool.getThreadContext();
this.signUserHeader = settings.getAsBoolean(SETTING_SIGN_USER_HEADER, true);
this.runAsEnabled = settings.getAsBoolean(SETTING_RUN_AS_ENABLED, true);
}
@Override
public User authenticate(RestRequest request) throws ElasticsearchSecurityException {
User user = getUserFromContext(request);
public User authenticate(RestRequest request) throws IOException, ElasticsearchSecurityException {
User user = getUserFromContext();
if (user != null) {
return user;
}
AuthenticationToken token;
try {
token = token(request);
token = token();
} catch (Exception e) {
if (logger.isDebugEnabled()) {
logger.debug("failed to extract token from request", e);
@ -84,7 +88,7 @@ public class InternalAuthenticationService extends AbstractComponent implements
if (anonymousService.enabled()) {
// 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
request.putInContext(USER_KEY, anonymousService.anonymousUser());
putUserInContext(anonymousService.anonymousUser());
return anonymousService.anonymousUser();
}
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
// transport request - without it, the transport will assume system user
request.putInContext(USER_KEY, user);
putUserInContext(user);
return user;
}
@Override
public User authenticate(String action, TransportMessage message, User fallbackUser) throws IOException {
User user = getUserFromContext(message);
User user = getUserFromContext();
if (user != null) {
return user;
}
String header = message.getHeader(USER_KEY);
String header = threadContext.getHeader(USER_KEY);
if (header != null) {
if (signUserHeader) {
try {
@ -168,36 +172,46 @@ public class InternalAuthenticationService extends AbstractComponent implements
}
if (user == null) {
user = authenticateWithRealms(action, message, fallbackUser);
header = signUserHeader ? cryptoService.sign(encodeUser(user, logger)) : encodeUser(user, logger);
message.putHeader(USER_KEY, header);
setUserHeader(user);
}
message.putInContext(USER_KEY, user);
putUserInContext(user);
return user;
}
@Override
public void attachUserHeaderIfMissing(ContextAndHeaderHolder message, User user) throws IOException {
if (message.hasHeader(USER_KEY)) {
public void attachUserHeaderIfMissing(User user) throws IOException {
if (threadContext.getHeader(USER_KEY) != null) {
return;
}
User userFromContext = message.getFromContext(USER_KEY);
if (userFromContext != null) {
String userHeader = signUserHeader ? cryptoService.sign(encodeUser(userFromContext, logger)) : encodeUser(userFromContext, logger);
message.putHeader(USER_KEY, userHeader);
User transientUser = threadContext.getTransient(USER_KEY);
if (transientUser != null) {
setUserHeader(transientUser);
return;
}
message.putInContext(USER_KEY, user);
setUser(user);
}
void setUserHeader(User user) throws IOException {
String userHeader = signUserHeader ? cryptoService.sign(encodeUser(user, logger)) : encodeUser(user, logger);
message.putHeader(USER_KEY, userHeader);
threadContext.putHeader(USER_KEY, userHeader);
}
User getUserFromContext(ContextAndHeaderHolder message) {
User user = message.getFromContext(USER_KEY);
if (user != null) {
return user;
void setUser(User user) throws IOException {
putUserInContext(user);
setUserHeader(user);
}
return null;
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() + "]");
}
threadContext.putTransient(USER_KEY, user);
}
User getUserFromContext() {
return threadContext.getTransient(USER_KEY);
}
static User decodeUser(String text) {
@ -283,7 +297,7 @@ public class InternalAuthenticationService extends AbstractComponent implements
}
if (runAsEnabled) {
String runAsUsername = message.getHeader(RUN_AS_USER_HEADER);
String runAsUsername = threadContext.getHeader(RUN_AS_USER_HEADER);
if (runAsUsername != null) {
if (runAsUsername.isEmpty()) {
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) {
AuthenticationToken token = realm.token(request);
AuthenticationToken token = realm.token(threadContext);
if (token != null) {
request.putInContext(TOKEN_KEY, token);
threadContext.putTransient(TOKEN_KEY, token);
return token;
}
}
@ -372,19 +387,19 @@ public class InternalAuthenticationService extends AbstractComponent implements
@SuppressWarnings("unchecked")
AuthenticationToken token(String action, TransportMessage<?> message) {
AuthenticationToken token = message.getFromContext(TOKEN_KEY);
AuthenticationToken token = threadContext.getTransient(TOKEN_KEY);
if (token != null) {
return token;
}
for (Realm realm : realms) {
token = realm.token(message);
token = realm.token(threadContext);
if (token != null) {
if (logger.isTraceEnabled()) {
logger.trace("realm [{}] resolved authentication token [{}] from transport request with action [{}]", realm, token.principal(), action);
}
message.putInContext(TOKEN_KEY, token);
threadContext.putTransient(TOKEN_KEY, token);
return token;
}
}

View File

@ -6,10 +6,9 @@
package org.elasticsearch.shield.authc;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.shield.ShieldSettingsFilter;
import org.elasticsearch.shield.User;
import org.elasticsearch.transport.TransportMessage;
/**
* An authentication mechanism to which the default authentication {@link org.elasticsearch.shield.authc.AuthenticationService service}
@ -60,22 +59,13 @@ public abstract class Realm<T extends AuthenticationToken> implements Comparable
public abstract boolean supports(AuthenticationToken token);
/**
* Attempts to extract an authentication token from the given rest request. If an appropriate token
* Attempts to extract an authentication token from the given context. If an appropriate token
* is found it's returned, otherwise {@code null} is returned.
*
* @param request The rest request
* @param context The context that will provide information about the incoming request
* @return The authentication token or {@code null} if not found
*/
public abstract T token(RestRequest request);
/**
* Attempts to extract an authentication token from the given transport message. If an appropriate token
* is found it's returned, otherwise {@code null} is returned.
*
* @param message The transport message
* @return The authentication token or {@code null} if not found
*/
public abstract T token(TransportMessage<?> message);
public abstract T token(ThreadContext context);
/**
* Authenticates the given token. A successful authentication will return the User associated

View File

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

View File

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

View File

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

View File

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

View File

@ -5,6 +5,7 @@
*/
package org.elasticsearch.shield.authc.ldap.support;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.shield.User;
import org.elasticsearch.shield.authc.RealmConfig;
import org.elasticsearch.shield.authc.support.CachingUsernamePasswordRealm;
@ -92,8 +93,8 @@ public abstract class AbstractLdapRealm extends CachingUsernamePasswordRealm {
public static abstract class Factory<R extends AbstractLdapRealm> extends UsernamePasswordRealm.Factory<R> {
public Factory(String type) {
super(type, false);
public Factory(String type, RestController restController) {
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.logging.ESLogger;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.Environment;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.shield.ShieldSettingsFilter;
import org.elasticsearch.shield.User;
import org.elasticsearch.shield.authc.AuthenticationToken;
@ -20,7 +20,6 @@ import org.elasticsearch.shield.authc.support.DnRoleMapper;
import org.elasticsearch.shield.transport.SSLClientAuth;
import org.elasticsearch.shield.transport.netty.ShieldNettyHttpServerTransport;
import org.elasticsearch.shield.transport.netty.ShieldNettyTransport;
import org.elasticsearch.transport.TransportMessage;
import org.elasticsearch.watcher.ResourceWatcherService;
import javax.net.ssl.TrustManager;
@ -66,13 +65,8 @@ public class PkiRealm extends Realm<X509AuthenticationToken> {
}
@Override
public X509AuthenticationToken token(RestRequest request) {
return token(request.getFromContext(PKI_CERT_HEADER_NAME), principalPattern, logger);
}
@Override
public X509AuthenticationToken token(TransportMessage<?> message) {
return token(message.getFromContext(PKI_CERT_HEADER_NAME), principalPattern, logger);
public X509AuthenticationToken token(ThreadContext context) {
return token(context.getTransient(PKI_CERT_HEADER_NAME), principalPattern, logger);
}
@Override

View File

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

View File

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

View File

@ -19,6 +19,7 @@ import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.search.action.SearchServiceTransportAction;
import org.elasticsearch.shield.User;
@ -35,6 +36,7 @@ import org.elasticsearch.shield.authz.permission.RunAsPermission;
import org.elasticsearch.shield.authz.privilege.ClusterPrivilege;
import org.elasticsearch.shield.authz.privilege.IndexPrivilege;
import org.elasticsearch.shield.authz.store.RolesStore;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportRequest;
import java.util.ArrayList;
@ -59,10 +61,12 @@ public class InternalAuthorizationService extends AbstractComponent implements A
private final IndicesAndAliasesResolver[] indicesAndAliasesResolvers;
private final AnonymousService anonymousService;
private final AuthenticationFailureHandler authcFailureHandler;
private final ThreadContext threadContext;
@Inject
public InternalAuthorizationService(Settings settings, RolesStore rolesStore, ClusterService clusterService,
AuditTrail auditTrail, AnonymousService anonymousService, AuthenticationFailureHandler authcFailureHandler) {
AuditTrail auditTrail, AnonymousService anonymousService,
AuthenticationFailureHandler authcFailureHandler, ThreadPool threadPool) {
super(settings);
this.rolesStore = rolesStore;
this.clusterService = clusterService;
@ -72,6 +76,7 @@ public class InternalAuthorizationService extends AbstractComponent implements A
};
this.anonymousService = anonymousService;
this.authcFailureHandler = authcFailureHandler;
this.threadContext = threadPool.getThreadContext();
}
@Override
@ -106,7 +111,7 @@ public class InternalAuthorizationService extends AbstractComponent implements A
// first we need to check if the user is the system. If it is, we'll just authorize the system access
if (user.isSystem()) {
if (SystemRole.INSTANCE.check(action)) {
request.putInContext(INDICES_PERMISSIONS_KEY, IndicesAccessControl.ALLOW_ALL);
setIndicesAccessControl(IndicesAccessControl.ALLOW_ALL);
grant(user, action, request);
return;
}
@ -149,7 +154,7 @@ public class InternalAuthorizationService extends AbstractComponent implements A
if (ClusterPrivilege.ACTION_MATCHER.test(action)) {
ClusterPermission cluster = permission.cluster();
if (cluster != null && cluster.check(action)) {
request.putInContext(INDICES_PERMISSIONS_KEY, IndicesAccessControl.ALLOW_ALL);
setIndicesAccessControl(IndicesAccessControl.ALLOW_ALL);
grant(user, action, request);
return;
}
@ -191,7 +196,7 @@ public class InternalAuthorizationService extends AbstractComponent implements A
if (!indicesAccessControl.isGranted()) {
throw denial(user, action, request);
} else {
request.putInContext(INDICES_PERMISSIONS_KEY, indicesAccessControl);
setIndicesAccessControl(indicesAccessControl);
}
//if we are creating an index we need to authorize potential aliases created at the same time
@ -215,6 +220,12 @@ public class InternalAuthorizationService extends AbstractComponent implements A
grant(user, action, request);
}
private void setIndicesAccessControl(IndicesAccessControl accessControl) {
if (threadContext.getTransient(INDICES_PERMISSIONS_KEY) == null) {
threadContext.putTransient(INDICES_PERMISSIONS_KEY, accessControl);
}
}
private GlobalPermission permission(String[] roleNames) {
if (roleNames.length == 0) {
return GlobalPermission.NONE;

View File

@ -45,7 +45,7 @@ public final class OptOutQueryCache extends AbstractIndexComponent implements Qu
if (context == null) {
throw new IllegalStateException("opting out of the query cache. current request can't be found");
}
final IndicesAccessControl indicesAccessControl = context.getRequest().getFromContext(InternalAuthorizationService.INDICES_PERMISSIONS_KEY);
IndicesAccessControl indicesAccessControl = context.getThreadContext().getTransient(InternalAuthorizationService.INDICES_PERMISSIONS_KEY);
if (indicesAccessControl == null) {
logger.debug("opting out of the query cache. current request doesn't hold indices permissions");
return weight;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -38,7 +38,7 @@ public class BulkUpdateTests extends ShieldIntegTestCase {
public void testThatBulkUpdateDoesNotLoseFields() {
assertThat(client().prepareIndex("index1", "type").setSource("{\"test\": \"test\"}").setId("1").get().isCreated(), is(true));
GetResponse getResponse = internalCluster().transportClient().prepareGet("index1", "type", "1").setFields("test").get();
assertThat((String) getResponse.getField("test").getValue(), equalTo("test"));
assertThat(getResponse.getField("test").getValue(), equalTo("test"));
if (randomBoolean()) {
flushAndRefresh();

View File

@ -140,11 +140,11 @@ public class ClearRealmsCacheTests extends ShieldIntegTestCase {
public abstract void executeRequest() throws Exception;
static void executeTransportRequest(ClearRealmCacheRequest request) throws Exception {
ShieldClient client = new ShieldClient(client());
ShieldClient shieldClient = new ShieldClient(client());
final CountDownLatch latch = new CountDownLatch(1);
final AtomicReference<Throwable> error = new AtomicReference<>();
client.clearRealmCache(request, new ActionListener<ClearRealmCacheResponse>() {
shieldClient.clearRealmCache(request, new ActionListener<ClearRealmCacheResponse>() {
@Override
public void onResponse(ClearRealmCacheResponse response) {
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.test.ShieldIntegTestCase;
import java.util.Collections;
import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.BASIC_AUTH_HEADER;
import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
@ -88,16 +90,16 @@ public class DocumentAndFieldLevelSecurityTests extends ShieldIntegTestCase {
.setRefresh(true)
.get();
SearchResponse response = client().prepareSearch("test")
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))
SearchResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)))
.prepareSearch("test")
.get();
assertHitCount(response, 1);
assertSearchHits(response, "1");
assertThat(response.getHits().getAt(0).getSource().size(), equalTo(1));
assertThat(response.getHits().getAt(0).getSource().get("field1").toString(), equalTo("value1"));
response = client().prepareSearch("test")
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)))
.prepareSearch("test")
.get();
assertHitCount(response, 1);
assertSearchHits(response, "2");
@ -120,15 +122,15 @@ public class DocumentAndFieldLevelSecurityTests extends ShieldIntegTestCase {
// Both users have the same role query, but user3 has access to field2 and not field1, which should result in zero hits:
int max = scaledRandomIntBetween(4, 32);
for (int i = 0; i < max; i++) {
SearchResponse response = client().prepareSearch("test")
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD))
SearchResponse response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)))
.prepareSearch("test")
.get();
assertHitCount(response, 1);
assertThat(response.getHits().getAt(0).getId(), equalTo("1"));
assertThat(response.getHits().getAt(0).sourceAsMap().size(), equalTo(1));
assertThat(response.getHits().getAt(0).sourceAsMap().get("field1"), equalTo("value1"));
response = client().prepareSearch("test")
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD))
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)))
.prepareSearch("test")
.get();
assertHitCount(response, 1);
assertThat(response.getHits().getAt(0).getId(), equalTo("2"));
@ -137,8 +139,8 @@ public class DocumentAndFieldLevelSecurityTests extends ShieldIntegTestCase {
// this is a bit weird the document level permission (all docs with field2:value2) don't match with the field level permissions (field1),
// this results in document 2 being returned but no fields are visible:
response = client().prepareSearch("test")
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD))
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)))
.prepareSearch("test")
.get();
assertHitCount(response, 1);
assertThat(response.getHits().getAt(0).getId(), equalTo("2"));

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -194,7 +194,7 @@ public class IndexAuditTrailTests extends ShieldIntegTestCase {
}
settings = builder.build();
doThrow(new IllegalStateException("indexing user should not be attached when sending remotely")).when(authService).attachUserHeaderIfMissing(any(TransportMessage.class), eq(user.user()));
doThrow(new IllegalStateException("indexing user should not be attached when sending remotely")).when(authService).attachUserHeaderIfMissing(eq(user.user()));
}
settings = Settings.builder().put(settings).put("path.home", createTempDir()).build();

View File

@ -24,7 +24,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import static org.elasticsearch.test.InternalTestCluster.clusterName;
import static org.hamcrest.Matchers.is;
@ -107,7 +106,8 @@ public class RemoteIndexAuditTrailStartingTests extends ShieldIntegTestCase {
return builder.build();
}
};
remoteCluster = new InternalTestCluster("network", randomLong(), createTempDir(), numNodes, numNodes, cluster2Name, cluster2SettingsSource, 0, false, SECOND_CLUSTER_NODE_PREFIX, getMockPlugins(), Function.identity());
remoteCluster = new InternalTestCluster("network", randomLong(), createTempDir(), numNodes, numNodes, cluster2Name,
cluster2SettingsSource, 0, false, SECOND_CLUSTER_NODE_PREFIX, getMockPlugins(), getClientWrapper());
remoteCluster.beforeTest(getRandom(), 0.5);
}

View File

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

View File

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

View File

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

View File

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

View File

@ -13,8 +13,8 @@ import org.elasticsearch.client.AdminClient;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.ClusterAdminClient;
import org.elasticsearch.client.IndicesAdminClient;
import org.elasticsearch.client.support.Headers;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.RestChannel;
import org.elasticsearch.rest.RestController;
@ -118,10 +118,10 @@ public class ESUsersRealmTests extends ESTestCase {
when(userRolesStore.roles("user1")).thenReturn(new String[]{"role1", "role2"});
ESUsersRealm realm = new ESUsersRealm(config, userPasswdStore, userRolesStore);
TransportRequest request = new TransportRequest() {};
UsernamePasswordToken.putTokenHeader(request, new UsernamePasswordToken("user1", SecuredStringTests.build("test123")));
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
UsernamePasswordToken.putTokenHeader(threadContext, new UsernamePasswordToken("user1", SecuredStringTests.build("test123")));
UsernamePasswordToken token = realm.token(request);
UsernamePasswordToken token = realm.token(threadContext);
assertThat(token, notNullValue());
assertThat(token.principal(), equalTo("user1"));
assertThat(token.credentials(), notNullValue());
@ -178,39 +178,6 @@ public class ESUsersRealmTests extends ESTestCase {
assertThat(user5, sameInstance(user6));
}
@SuppressWarnings("unchecked")
public void testAuthorizationHeaderIsNotCopied() throws Exception {
RestController restController = mock(RestController.class);
RealmConfig config = new RealmConfig("esusers-test", Settings.EMPTY, globalSettings);
new ESUsersRealm(config, new UserPasswdStore(config), new UserRolesStore(config));
when(restController.relevantHeaders()).thenReturn(emptySet());
when(client.admin()).thenReturn(adminClient);
when(client.settings()).thenReturn(Settings.EMPTY);
when(client.headers()).thenReturn(Headers.EMPTY);
when(adminClient.cluster()).thenReturn(mock(ClusterAdminClient.class));
when(adminClient.indices()).thenReturn(mock(IndicesAdminClient.class));
final ActionRequest request = new ActionRequest() {
@Override
public ActionRequestValidationException validate() {
return null;
}
};
RestRequest restRequest = mock(RestRequest.class);
final Action<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 {
public UserPasswdStore(RealmConfig config) {
super(config, mock(ResourceWatcherService.class));

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -6,6 +6,8 @@
package org.elasticsearch.shield.transport;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.shield.User;
import org.elasticsearch.shield.action.ShieldActionMapper;
import org.elasticsearch.shield.authc.AuthenticationService;
@ -40,7 +42,7 @@ public class ServerTransportFilterTests extends ESTestCase {
authzService = mock(AuthorizationService.class);
channel = mock(NettyTransportChannel.class);
when(channel.getProfileName()).thenReturn(NettyTransport.DEFAULT_PROFILE);
filter = new ServerTransportFilter.NodeProfile(authcService, authzService, new ShieldActionMapper(), false);
filter = new ServerTransportFilter.NodeProfile(authcService, authzService, new ShieldActionMapper(), new ThreadContext(Settings.EMPTY), false);
}
public void testInbound() throws Exception {

View File

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

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.NodesInfoResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.cluster.health.ClusterHealthStatus;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.shield.authc.support.SecuredString;
@ -26,10 +26,14 @@ import org.junit.rules.ExternalResource;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoTimeout;
import static org.hamcrest.CoreMatchers.is;
@ -303,4 +307,10 @@ public abstract class ShieldIntegTestCase extends ESIntegTestCase {
assertNoTimeout(clusterHealthResponse);
assertThat(clusterHealthResponse.getStatus(), is(ClusterHealthStatus.GREEN));
}
@Override
protected Function<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;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.client.support.Headers;
import org.elasticsearch.common.io.PathUtils;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.index.IndexModule;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.shield.ShieldPlugin;
@ -16,7 +16,6 @@ import org.elasticsearch.shield.authc.esusers.ESUsersRealm;
import org.elasticsearch.shield.authc.esnative.ESNativeRealm;
import org.elasticsearch.shield.authc.support.Hasher;
import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.shield.authc.support.UsernamePasswordToken;
import org.elasticsearch.shield.crypto.InternalCryptoService;
import org.elasticsearch.shield.test.ShieldTestUtils;
import org.elasticsearch.shield.transport.netty.ShieldNettyHttpServerTransport;
@ -134,13 +133,11 @@ public class ShieldSettingsSource extends ClusterDiscoveryConfiguration.UnicastZ
.put("shield.authc.realms.index.type", ESNativeRealm.TYPE)
.put("shield.authc.realms.index.order", "1")
.put("shield.authz.store.files.roles", writeFile(folder, "roles.yml", configRoles()))
// Test framework sometimes randomily selects the 'index' or 'none' cache and that makes the
// Test framework sometimes randomly selects the 'index' or 'none' cache and that makes the
// validation in ShieldPlugin fail.
.put(IndexModule.INDEX_QUERY_CACHE_TYPE_SETTING.getKey(), ShieldPlugin.OPT_OUT_QUERY_CACHE)
.put(getNodeSSLSettings());
setUser(builder, nodeClientUsername(), nodeClientPassword());
return builder.build();
}
@ -148,7 +145,11 @@ public class ShieldSettingsSource extends ClusterDiscoveryConfiguration.UnicastZ
public Settings transportClientSettings() {
Settings.Builder builder = settingsBuilder().put(super.transportClientSettings())
.put(getClientSSLSettings());
setUser(builder, transportClientUsername(), transportClientPassword());
if (randomBoolean()) {
builder.put("shield.user", transportClientUsername() + ":" + new String(transportClientPassword().internalChars()));
} else {
builder.put(ThreadContext.PREFIX + ".Authorization", basicAuthHeaderValue(transportClientUsername(), transportClientPassword()));
}
return builder.build();
}
@ -198,14 +199,6 @@ public class ShieldSettingsSource extends ClusterDiscoveryConfiguration.UnicastZ
return XPackPlugin.class;
}
private void setUser(Settings.Builder builder, String username, SecuredString password) {
if (randomBoolean()) {
builder.put(Headers.PREFIX + "." + UsernamePasswordToken.BASIC_AUTH_HEADER, basicAuthHeaderValue(username, password));
} else {
builder.put("shield.user", username + ":" + new String(password.internalChars()));
}
}
private static byte[] generateKey() {
try {
return InternalCryptoService.generateKey();

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

View File

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

View File

@ -149,7 +149,8 @@ public class ExecutionService extends AbstractComponent {
}
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()) {
return Collections.emptyList();
}

View File

@ -14,6 +14,9 @@ import org.elasticsearch.watcher.WatcherPlugin;
import org.elasticsearch.watcher.support.ThreadPoolSettingsBuilder;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.stream.Stream;
/**
*
@ -48,6 +51,11 @@ public class InternalWatchExecutor implements WatchExecutor {
return executor().getQueue();
}
@Override
public Stream<Runnable> tasks() {
return executor().getTasks();
}
@Override
public long largestPoolSize() {
return executor().getLargestPoolSize();

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