diff --git a/src/main/java/org/elasticsearch/shield/authz/Privilege.java b/src/main/java/org/elasticsearch/shield/authz/Privilege.java
index 7e85130199e..e107865030b 100644
--- a/src/main/java/org/elasticsearch/shield/authz/Privilege.java
+++ b/src/main/java/org/elasticsearch/shield/authz/Privilege.java
@@ -10,6 +10,7 @@ import org.apache.lucene.util.automaton.Automaton;
import org.apache.lucene.util.automaton.Operations;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.ElasticsearchIllegalArgumentException;
+import org.elasticsearch.action.admin.indices.create.CreateIndexAction;
import org.elasticsearch.action.get.GetAction;
import org.elasticsearch.action.search.SearchAction;
import org.elasticsearch.common.Strings;
@@ -107,8 +108,8 @@ public abstract class Privilege
> {
public static final Index NONE = new Index(Name.NONE, Automata.makeEmpty());
public static final Index ALL = new Index(Name.ALL, "indices:*");
public static final Index MANAGE = new Index("manage", "indices:monitor/*", "indices:admin/*");
- public static final Index CREATE_INDEX = new Index("create_index", "indices:admin/create");
- public static final Index MANAGE_ALIASES = new Index("manage_aliases", "indices:admin/aliases");
+ public static final Index CREATE_INDEX = new Index("create_index", CreateIndexAction.NAME);
+ public static final Index MANAGE_ALIASES = new Index("manage_aliases", "indices:admin/aliases*");
public static final Index MONITOR = new Index("monitor", "indices:monitor/*");
public static final Index DATA_ACCESS = new Index("data_access", "indices:data/*");
public static final Index CRUD = new Index("crud", "indices:data/write/*", "indices:data/read/*");
diff --git a/src/main/java/org/elasticsearch/shield/authz/indicesresolver/DefaultIndicesResolver.java b/src/main/java/org/elasticsearch/shield/authz/indicesresolver/DefaultIndicesResolver.java
index 73534f967d0..b39aa3db52a 100644
--- a/src/main/java/org/elasticsearch/shield/authz/indicesresolver/DefaultIndicesResolver.java
+++ b/src/main/java/org/elasticsearch/shield/authz/indicesresolver/DefaultIndicesResolver.java
@@ -8,11 +8,14 @@ package org.elasticsearch.shield.authz.indicesresolver;
import org.elasticsearch.action.CompositeIndicesRequest;
import org.elasticsearch.action.IndicesRequest;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
+import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.cluster.metadata.AliasAction;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MetaData;
-import org.elasticsearch.common.collect.*;
+import org.elasticsearch.common.collect.ImmutableList;
+import org.elasticsearch.common.collect.Lists;
+import org.elasticsearch.common.collect.Sets;
import org.elasticsearch.common.hppc.ObjectLookupContainer;
import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.index.Index;
@@ -68,84 +71,110 @@ public class DefaultIndicesResolver implements IndicesResolver
ImmutableList authorizedIndices = authzService.authorizedIndicesAndAliases(user, action);
List indices = replaceWildcardsWithAuthorizedIndices(indicesRequest.indices(), indicesRequest.indicesOptions(), metaData, authorizedIndices);
((IndicesRequest.Replaceable) indicesRequest).indices(indices.toArray(new String[indices.size()]));
- return Sets.newHashSet(indices);
+ } else {
+ assert indicesRequest instanceof IndicesAliasesRequest || !containsWildcards(indicesRequest) :
+ "IndicesAliasesRequest is the only external request known to support wildcards that doesn't support replacing its indices";
+
+ //NOTE: shard level requests do support wildcards (as they hold the original indices options) but don't support replacing their indices.
+ //That is fine though because they never contain wildcards, as they get replaced as part of the authorization of their
+ //corresponding parent request on the coordinating node. Hence wildcards don't need to get replaced nor exploded for shard level requests.
}
-
- assert indicesRequest instanceof IndicesAliasesRequest || !containsWildcards(indicesRequest) :
- "IndicesAliasesRequest is the only external request known to support wildcards that doesn't support replacing its indices";
-
- //NOTE: shard level requests do support wildcards (as they hold the original indices options) but don't support replacing their indices.
- //That is fine though because they never contain wildcards, as they get replaced as part of the authorization of their
- //corresponding parent request on the coordinating node. Hence wildcards don't need to get replaced nor exploded for shard level requests.
}
if (indicesRequest instanceof IndicesAliasesRequest) {
//special treatment for IndicesAliasesRequest since we need to extract indices from indices() as well as aliases()
//Also, we need to replace wildcards in both with authorized indices and/or aliases (IndicesAliasesRequest doesn't implement Replaceable)
- IndicesAliasesRequest request = (IndicesAliasesRequest) indicesRequest;
+ return resolveIndicesAliasesRequest(user, action, (IndicesAliasesRequest) indicesRequest, metaData);
+ }
- ImmutableList authorizedIndices = authzService.authorizedIndicesAndAliases(user, action);
- Set finalIndices = Sets.newHashSet();
-
- List authorizedAliases = null;
-
- for (IndicesAliasesRequest.AliasActions aliasActions : request.getAliasActions()) {
- //replace indices with authorized ones if needed
- if (indicesRequest.indicesOptions().expandWildcardsOpen() || indicesRequest.indicesOptions().expandWildcardsClosed()) {
- //Note: the indices that the alias operation maps to might end up containing aliases, since authorized indices can also be aliases.
- //This is fine as es core resolves them to concrete indices anyway before executing the actual operation.
- //Also es core already allows to specify aliases among indices, they will just be resolved (alias to alias is not supported).
- //e.g. index: foo* gets resolved in core to anything that matches the expression, aliases included, hence their corresponding indices.
- List indices = replaceWildcardsWithAuthorizedIndices(aliasActions.indices(), indicesRequest.indicesOptions(), metaData, authorizedIndices);
- aliasActions.indices(indices.toArray(new String[indices.size()]));
- }
- Collections.addAll(finalIndices, aliasActions.indices());
-
- //replace aliases with authorized ones if needed
- if (aliasActions.actionType() == AliasAction.Type.REMOVE) {
- //lazily initialize a list of all the authorized aliases (filtering concrete indices out)
- if (authorizedAliases == null) {
- authorizedAliases = Lists.newArrayList();
- ObjectLookupContainer existingAliases = metaData.aliases().keys();
- for (String authorizedIndex : authorizedIndices) {
- if (existingAliases.contains(authorizedIndex)) {
- authorizedAliases.add(authorizedIndex);
- }
- }
- }
-
- List finalAliases = Lists.newArrayList();
- for (String aliasPattern : aliasActions.aliases()) {
- if (aliasPattern.equals(MetaData.ALL)) {
- finalAliases.addAll(authorizedAliases);
- } else if (Regex.isSimpleMatchPattern(aliasPattern)) {
- for (String authorizedAlias : authorizedAliases) {
- if (Regex.simpleMatch(aliasPattern, authorizedAlias)) {
- finalAliases.add(authorizedAlias);
- }
- }
- } else {
- finalAliases.add(aliasPattern);
- }
- }
-
- //throw exception if the wildcards expansion to authorized aliases resulted in no indices.
- // This is important as we always need to replace wildcards for security reason,
- //to make sure that the operation is executed on the aliases that we authorized it to execute on.
- //If we can't replace because we got an empty set, we can only throw exception.
- if (finalAliases.isEmpty()) {
- throw new IndexMissingException(new Index(Arrays.toString(aliasActions.aliases())));
- }
- aliasActions.aliases(finalAliases.toArray(new String[finalAliases.size()]));
- }
- Collections.addAll(finalIndices, aliasActions.aliases());
- }
- return finalIndices;
+ if (indicesRequest instanceof GetAliasesRequest) {
+ //special treatment for GetAliasesRequest since we need to replace wildcards among the specified aliases.
+ //GetAliasesRequest implements IndicesRequest.Replaceable, hence its indices have already been properly replaced.
+ return resolveGetAliasesRequest(user, action, (GetAliasesRequest) indicesRequest, metaData);
}
return Sets.newHashSet(indicesRequest.indices());
}
+ private Set resolveGetAliasesRequest(User user, String action, GetAliasesRequest request, MetaData metaData) {
+ ImmutableList authorizedIndices = authzService.authorizedIndicesAndAliases(user, action);
+ List aliases = replaceWildcardsWithAuthorizedAliases(request.aliases(), loadAuthorizedAliases(authorizedIndices, metaData));
+ request.aliases(aliases.toArray(new String[aliases.size()]));
+ Set indices = Sets.newHashSet(request.indices());
+ indices.addAll(aliases);
+ return indices;
+ }
+
+ private Set resolveIndicesAliasesRequest(User user, String action, IndicesAliasesRequest request, MetaData metaData) {
+ ImmutableList authorizedIndices = authzService.authorizedIndicesAndAliases(user, action);
+ Set finalIndices = Sets.newHashSet();
+
+ List authorizedAliases = null;
+
+ for (IndicesAliasesRequest.AliasActions aliasActions : request.getAliasActions()) {
+ //replace indices with authorized ones if needed
+ if (request.indicesOptions().expandWildcardsOpen() || request.indicesOptions().expandWildcardsClosed()) {
+ //Note: the indices that the alias operation maps to might end up containing aliases, since authorized indices can also be aliases.
+ //This is fine as es core resolves them to concrete indices anyway before executing the actual operation.
+ //Also es core already allows to specify aliases among indices, they will just be resolved (alias to alias is not supported).
+ //e.g. index: foo* gets resolved in core to anything that matches the expression, aliases included, hence their corresponding indices.
+ List indices = replaceWildcardsWithAuthorizedIndices(aliasActions.indices(), request.indicesOptions(), metaData, authorizedIndices);
+ aliasActions.indices(indices.toArray(new String[indices.size()]));
+ }
+ Collections.addAll(finalIndices, aliasActions.indices());
+
+ //replace aliases with authorized ones if needed
+ if (aliasActions.actionType() == AliasAction.Type.REMOVE) {
+ //lazily initialize a list of all the authorized aliases (filtering concrete indices out)
+ if (authorizedAliases == null) {
+ authorizedAliases = loadAuthorizedAliases(authorizedIndices, metaData);
+ }
+
+ List aliases = replaceWildcardsWithAuthorizedAliases(aliasActions.aliases(), authorizedAliases);
+ aliasActions.aliases(aliases.toArray(new String[aliases.size()]));
+ }
+ Collections.addAll(finalIndices, aliasActions.aliases());
+ }
+ return finalIndices;
+ }
+
+ private List loadAuthorizedAliases(List authorizedIndices, MetaData metaData) {
+ List authorizedAliases = Lists.newArrayList();
+ ObjectLookupContainer existingAliases = metaData.aliases().keys();
+ for (String authorizedIndex : authorizedIndices) {
+ if (existingAliases.contains(authorizedIndex)) {
+ authorizedAliases.add(authorizedIndex);
+ }
+ }
+ return authorizedAliases;
+ }
+
+ private List replaceWildcardsWithAuthorizedAliases(String[] aliases, List authorizedAliases) {
+ List finalAliases = Lists.newArrayList();
+ for (String aliasPattern : aliases) {
+ if (aliasPattern.equals(MetaData.ALL)) {
+ finalAliases.addAll(authorizedAliases);
+ } else if (Regex.isSimpleMatchPattern(aliasPattern)) {
+ for (String authorizedAlias : authorizedAliases) {
+ if (Regex.simpleMatch(aliasPattern, authorizedAlias)) {
+ finalAliases.add(authorizedAlias);
+ }
+ }
+ } else {
+ finalAliases.add(aliasPattern);
+ }
+ }
+
+ //throw exception if the wildcards expansion to authorized aliases resulted in no indices.
+ // This is important as we always need to replace wildcards for security reason,
+ //to make sure that the operation is executed on the aliases that we authorized it to execute on.
+ //If we can't replace because we got an empty set, we can only throw exception.
+ if (finalAliases.isEmpty()) {
+ throw new IndexMissingException(new Index(Arrays.toString(aliases)));
+ }
+ return finalAliases;
+ }
+
private boolean containsWildcards(IndicesRequest indicesRequest) {
if (MetaData.isAllIndices(indicesRequest.indices())) {
return true;
diff --git a/src/test/java/org/elasticsearch/shield/authz/IndexAliasesTests.java b/src/test/java/org/elasticsearch/shield/authz/IndexAliasesTests.java
index 2e3a1fc2800..31d96eea542 100644
--- a/src/test/java/org/elasticsearch/shield/authz/IndexAliasesTests.java
+++ b/src/test/java/org/elasticsearch/shield/authz/IndexAliasesTests.java
@@ -6,9 +6,13 @@
package org.elasticsearch.shield.authz;
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.indices.IndexMissingException;
import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.test.ShieldIntegrationTest;
+import org.junit.Before;
import org.junit.Test;
import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.BASIC_AUTH_HEADER;
@@ -17,6 +21,8 @@ import static org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
@ClusterScope(scope = Scope.SUITE)
public class IndexAliasesTests extends ShieldIntegrationTest {
@@ -68,6 +74,14 @@ public class IndexAliasesTests extends ShieldIntegrationTest {
" 'alias_*,test_*': manage_aliases\n";
}
+ @Before
+ public void createBogusIndex() {
+ if (randomBoolean()) {
+ //randomly create an index with two aliases from user admin, to make sure it doesn't affect any of the test results
+ assertAcked(client().admin().indices().prepareCreate("index1").addAlias(new Alias("alias1")).addAlias(new Alias("alias2")));
+ }
+ }
+
@Test
public void testCreateIndexThenAliasesCreateOnlyPermission() {
//user has create permission only: allows to create indices, manage_aliases is required to add/remove aliases
@@ -131,6 +145,34 @@ public class IndexAliasesTests extends ShieldIntegrationTest {
}
}
+ @Test
+ public void testGetAliasesCreateOnlyPermission() {
+ //user has create permission only: allows to create indices, manage_aliases is required to retrieve aliases though
+ 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();
+ fail("get alias should have failed due to missing manage_aliases privileges");
+ } catch(AuthorizationException e) {
+ assertThat(e.getMessage(), 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();
+ fail("get alias should have failed due to missing manage_aliases privileges");
+ } catch(IndexMissingException e) {
+ assertThat(e.getMessage(), 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();
+ fail("get alias should have failed due to missing manage_aliases privileges");
+ } catch(IndexMissingException e) {
+ assertThat(e.getMessage(), containsString("[test_*]"));
+ }
+ }
+
@Test
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
@@ -217,6 +259,53 @@ public class IndexAliasesTests extends ShieldIntegrationTest {
}
}
+ @Test
+ 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()))));
+
+ //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()))),
+ "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()))),
+ "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()))),
+ "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()))),
+ "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()))),
+ "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()))),
+ "test_1", "test_alias");
+
+ 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();
+ fail("get alias should have failed due to missing manage_aliases privileges on alias_1");
+ } catch(AuthorizationException e) {
+ assertThat(e.getMessage(), containsString("action [indices:admin/aliases/get] is unauthorized for user [create_test_aliases_test]"));
+ }
+ }
+
@Test
public void testCreateIndexThenAliasesCreateAndAliasesPermission2() {
//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
@@ -304,6 +393,58 @@ public class IndexAliasesTests extends ShieldIntegrationTest {
}
}
+ @Test
+ public void testGetAliasesCreateAndAliasesPermission2() {
+ //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()))));
+
+ 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();
+ fail("get alias should have failed due to missing manage_aliases privileges on test_alias and test_1");
+ } catch(AuthorizationException e) {
+ assertThat(e.getMessage(), containsString("action [indices:admin/aliases/get] is unauthorized for user [create_test_aliases_alias]"));
+ }
+
+ 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();
+ fail("get alias should have failed due to missing manage_aliases privileges on test_*");
+ } catch(IndexMissingException e) {
+ assertThat(e.getMessage(), containsString("[test_*]"));
+ }
+
+ 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();
+ fail("get alias should have failed due to missing manage_aliases privileges on any index");
+ } catch(IndexMissingException e) {
+ assertThat(e.getMessage(), containsString("[_all]"));
+ }
+
+ 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();
+ fail("get alias should have failed due to missing manage_aliases privileges on test_1");
+ } catch(IndexMissingException e) {
+ assertThat(e.getMessage(), containsString("[test_*]"));
+ }
+
+ 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();
+ fail("get alias should have failed due to missing manage_aliases privileges on test_1");
+ } catch(IndexMissingException e) {
+ assertThat(e.getMessage(), containsString("[_all]"));
+ }
+ }
+
@Test
public void testCreateIndexThenAliasesCreateAndAliasesPermission3() {
//user has create permission on test_* and manage_aliases permission on test_*,alias_*. All good.
@@ -363,9 +504,79 @@ public class IndexAliasesTests extends ShieldIntegrationTest {
}
}
+ @Test
+ public void testGetAliasesCreateAndAliasesPermission3() {
+ //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()))));
+
+ assertAliases(client().admin().indices().prepareGetAliases().setAliases("test_alias").setIndices("test_1")
+ .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))),
+ "test_1", "test_alias");
+
+ assertAliases(client().admin().indices().prepareGetAliases().setAliases("alias_1").setIndices("test_1")
+ .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))),
+ "test_1", "alias_1");
+
+ assertAliases(client().admin().indices().prepareGetAliases().setAliases("alias_1").setIndices("test_*")
+ .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))),
+ "test_1", "alias_1");
+
+ assertAliases(client().admin().indices().prepareGetAliases().setAliases("test_*").setIndices("test_1")
+ .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))),
+ "test_1", "test_alias");
+
+ assertAliases(client().admin().indices().prepareGetAliases().setAliases("_all").setIndices("test_1")
+ .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))),
+ "test_1", "alias_1", "test_alias");
+
+ assertAliases(client().admin().indices().prepareGetAliases().setAliases("_all")
+ .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))),
+ "test_1", "alias_1", "test_alias");
+
+ assertAliases(client().admin().indices().prepareGetAliases().setAliases("alias_*").setIndices("test_*")
+ .putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("create_test_aliases_test_alias", new SecuredString("test123".toCharArray()))),
+ "test_1", "alias_1");
+ }
+
@Test(expected = AuthorizationException.class)
public void testCreateIndexAliasesOnlyPermission() {
client().admin().indices().prepareCreate("test_1")
.putHeader(BASIC_AUTH_HEADER, basicAuthHeaderValue("aliases_only", new SecuredString("test123".toCharArray()))).get();
}
+
+ @Test
+ public void testGetAliasesAliasesOnlyPermission() {
+ //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();
+ 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();
+ } catch(AuthorizationException e) {
+ assertThat(e.getMessage(), 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();
+ } catch(AuthorizationException e) {
+ assertThat(e.getMessage(), containsString("action [indices:admin/aliases/get] is unauthorized for user [aliases_only]"));
+ }
+ }
+
+ private static void assertAliases(GetAliasesRequestBuilder getAliasesRequestBuilder, String index, String... aliases) {
+ GetAliasesResponse getAliasesResponse = getAliasesRequestBuilder.get();
+ assertThat(getAliasesResponse.getAliases().size(), equalTo(1));
+ assertThat(getAliasesResponse.getAliases().get(index).size(), equalTo(aliases.length));
+ for (int i = 0; i < aliases.length; i++) {
+ assertThat(getAliasesResponse.getAliases().get(index).get(i).alias(), equalTo(aliases[i]));
+ }
+ }
}
diff --git a/src/test/java/org/elasticsearch/shield/authz/indicesresolver/DefaultIndicesResolverTests.java b/src/test/java/org/elasticsearch/shield/authz/indicesresolver/DefaultIndicesResolverTests.java
index 9413b8cc207..9128ca274d2 100644
--- a/src/test/java/org/elasticsearch/shield/authz/indicesresolver/DefaultIndicesResolverTests.java
+++ b/src/test/java/org/elasticsearch/shield/authz/indicesresolver/DefaultIndicesResolverTests.java
@@ -7,6 +7,8 @@ package org.elasticsearch.shield.authz.indicesresolver;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesAction;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
+import org.elasticsearch.action.admin.indices.alias.get.GetAliasesAction;
+import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexAction;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.deletebyquery.DeleteByQueryAction;
@@ -67,10 +69,12 @@ public class DefaultIndicesResolverTests extends ElasticsearchTestCase {
when(authzService.authorizedIndicesAndAliases(user, MultiSearchAction.NAME)).thenReturn(ImmutableList.copyOf(authorizedIndices));
when(authzService.authorizedIndicesAndAliases(user, MultiGetAction.NAME)).thenReturn(ImmutableList.copyOf(authorizedIndices));
when(authzService.authorizedIndicesAndAliases(user, IndicesAliasesAction.NAME)).thenReturn(ImmutableList.copyOf(authorizedIndices));
+ when(authzService.authorizedIndicesAndAliases(user, GetAliasesAction.NAME)).thenReturn(ImmutableList.copyOf(authorizedIndices));
when(authzService.authorizedIndicesAndAliases(user, DeleteIndexAction.NAME)).thenReturn(ImmutableList.copyOf(authorizedIndices));
when(authzService.authorizedIndicesAndAliases(user, DeleteByQueryAction.NAME)).thenReturn(ImmutableList.copyOf(authorizedIndices));
userNoIndices = new User.Simple("test", "test");
when(authzService.authorizedIndicesAndAliases(userNoIndices, IndicesAliasesAction.NAME)).thenReturn(ImmutableList.of());
+ when(authzService.authorizedIndicesAndAliases(userNoIndices, GetAliasesAction.NAME)).thenReturn(ImmutableList.of());
when(authzService.authorizedIndicesAndAliases(userNoIndices, SearchAction.NAME)).thenReturn(ImmutableList.of());
when(authzService.authorizedIndicesAndAliases(userNoIndices, MultiSearchAction.NAME)).thenReturn(ImmutableList.of());
@@ -431,6 +435,157 @@ public class DefaultIndicesResolverTests extends ElasticsearchTestCase {
assertThat(request.getAliasActions().get(1).aliases(), arrayContaining("foofoobar"));
}
+ @Test
+ public void testResolveGetAliasesRequest() {
+ GetAliasesRequest request = new GetAliasesRequest("alias1").indices("foo", "foofoo");
+ Set indices = defaultIndicesResolver.resolve(user, GetAliasesAction.NAME, request, metaData);
+ //the union of all indices and aliases gets returned
+ String[] expectedIndices = new String[]{"alias1", "foo", "foofoo"};
+ assertThat(indices.size(), equalTo(expectedIndices.length));
+ assertThat(indices, hasItems(expectedIndices));
+ assertThat(request.indices(), arrayContaining("foo", "foofoo"));
+ assertThat(request.aliases(), arrayContaining("alias1"));
+ }
+
+ @Test
+ public void testResolveGetAliasesRequestMissingIndex() {
+ GetAliasesRequest request = new GetAliasesRequest();
+ request.indices("missing");
+ request.aliases("alias2");
+ Set indices = defaultIndicesResolver.resolve(user, GetAliasesAction.NAME, request, metaData);
+ //the union of all indices and aliases gets returned, missing is not an existing index/alias but that doesn't make any difference
+ String[] expectedIndices = new String[]{"alias2", "missing"};
+ assertThat(indices.size(), equalTo(expectedIndices.length));
+ assertThat(indices, hasItems(expectedIndices));
+ assertThat(request.indices(), arrayContaining("missing"));
+ assertThat(request.aliases(), arrayContaining("alias2"));
+ }
+
+ @Test
+ public void testResolveWildcardsGetAliasesRequest() {
+ GetAliasesRequest request = new GetAliasesRequest();
+ request.aliases("alias1");
+ request.indices("foo*");
+ Set indices = defaultIndicesResolver.resolve(user, GetAliasesAction.NAME, request, metaData);
+ //the union of all resolved indices and aliases gets returned, based on indices and aliases that user is authorized for
+ String[] expectedIndices = new String[]{"alias1", "foofoo", "foofoobar"};
+ assertThat(indices.size(), equalTo(expectedIndices.length));
+ assertThat(indices, hasItems(expectedIndices));
+ //wildcards get replaced on each single action
+ assertThat(request.indices(), arrayContaining("foofoobar", "foofoo"));
+ assertThat(request.aliases(), arrayContaining("alias1"));
+ }
+
+ @Test(expected = IndexMissingException.class)
+ public void testResolveWildcardsGetAliasesRequestNoMatchingIndices() {
+ GetAliasesRequest request = new GetAliasesRequest();
+ request.aliases("alias3");
+ request.indices("non_matching_*");
+ //indices get resolved to no indices, request gets rejected
+ defaultIndicesResolver.resolve(user, GetAliasesAction.NAME, request, metaData);
+ }
+
+ @Test
+ public void testResolveAllGetAliasesRequest() {
+ GetAliasesRequest request = new GetAliasesRequest();
+ //even if not set, empty means _all
+ if (randomBoolean()) {
+ request.indices("_all");
+ }
+ request.aliases("alias1");
+ Set indices = defaultIndicesResolver.resolve(user, GetAliasesAction.NAME, request, metaData);
+ //the union of all resolved indices and aliases gets returned
+ String[] expectedIndices = new String[]{"bar", "foofoobar", "foofoo", "alias1"};
+ assertThat(indices.size(), equalTo(expectedIndices.length));
+ assertThat(indices, hasItems(expectedIndices));
+ String[] replacedIndices = new String[]{"bar", "foofoobar", "foofoo"};
+ //_all gets replaced with all indices that user is authorized for
+ assertThat(request.indices(), arrayContaining(replacedIndices));
+ assertThat(request.aliases(), arrayContaining("alias1"));
+ }
+
+ @Test
+ public void testResolveAllGetAliasesRequestExpandWildcardsClosed() {
+ GetAliasesRequest request = new GetAliasesRequest();
+ //set indices options to have wildcards resolved to open and closed indices (default is open only)
+ request.indicesOptions(IndicesOptions.fromOptions(true, false, true, true));
+ //even if not set, empty means _all
+ if (randomBoolean()) {
+ request.indices("_all");
+ }
+ request.aliases("alias1");
+ Set indices = defaultIndicesResolver.resolve(user, GetAliasesAction.NAME, request, metaData);
+ //the union of all resolved indices and aliases gets returned
+ String[] expectedIndices = new String[]{"bar", "bar-closed", "foofoobar", "foofoo", "foofoo-closed", "alias1"};
+ assertThat(indices.size(), equalTo(expectedIndices.length));
+ assertThat(indices, hasItems(expectedIndices));
+ String[] replacedIndices = new String[]{"bar", "bar-closed", "foofoobar", "foofoo", "foofoo-closed"};
+ //_all gets replaced with all indices that user is authorized for
+ assertThat(request.indices(), arrayContaining(replacedIndices));
+ assertThat(request.aliases(), arrayContaining("alias1"));
+ }
+
+ @Test(expected = IndexMissingException.class)
+ public void testResolveAllGetAliasesRequestNoAuthorizedIndices() {
+ GetAliasesRequest request = new GetAliasesRequest();
+ request.aliases("alias1");
+ request.indices("_all");
+ //current user is not authorized for any index, _all resolves to no indices, the request fails
+ defaultIndicesResolver.resolve(userNoIndices, GetAliasesAction.NAME, request, metaData);
+ }
+
+ @Test(expected = IndexMissingException.class)
+ public void testResolveWildcardsGetAliasesRequestNoAuthorizedIndices() {
+ GetAliasesRequest request = new GetAliasesRequest();
+ request.aliases("alias1");
+ request.indices("foo*");
+ //current user is not authorized for any index, foo* resolves to no indices, the request fails
+ defaultIndicesResolver.resolve(userNoIndices, GetAliasesAction.NAME, request, metaData);
+ }
+
+ @Test
+ public void testResolveAllAliasesGetAliasesRequest() {
+ GetAliasesRequest request = new GetAliasesRequest();
+ request.aliases("_all");
+ if (randomBoolean()) {
+ request.indices("_all");
+ }
+ Set indices = defaultIndicesResolver.resolve(user, GetAliasesAction.NAME, request, metaData);
+ //the union of all resolved indices and aliases gets returned
+ String[] expectedIndices = new String[]{"bar", "foofoobar", "foofoo"};
+ assertThat(indices.size(), equalTo(expectedIndices.length));
+ assertThat(indices, hasItems(expectedIndices));
+ //_all gets replaced with all indices that user is authorized for
+ assertThat(request.indices(), arrayContaining(expectedIndices));
+ assertThat(request.aliases(), arrayContaining("foofoobar"));
+ }
+
+ @Test
+ public void testResolveAliasesWildcardsGetAliasesRequest() {
+ GetAliasesRequest request = new GetAliasesRequest();
+ request.indices("*bar");
+ request.aliases("foo*");
+ Set indices = defaultIndicesResolver.resolve(user, GetAliasesAction.NAME, request, metaData);
+ //union of all resolved indices and aliases gets returned, based on what user is authorized for
+ //note that the index side will end up containing matching aliases too, which is fine, as es core would do
+ //the same and resolve those aliases to their corresponding concrete indices (which we let core do)
+ String[] expectedIndices = new String[]{"bar", "foofoobar"};
+ assertThat(indices.size(), equalTo(expectedIndices.length));
+ assertThat(indices, hasItems(expectedIndices));
+ //alias foofoobar on both sides, that's fine, es core would do the same, same as above
+ assertThat(request.indices(), arrayContaining("bar", "foofoobar"));
+ assertThat(request.aliases(), arrayContaining("foofoobar"));
+ }
+
+ @Test(expected = IndexMissingException.class)
+ public void testResolveAliasesWildcardsGetAliasesRequestNoAuthorizedIndices() {
+ GetAliasesRequest request = new GetAliasesRequest();
+ //no authorized aliases match bar*, hence the request fails
+ request.aliases("bar*");
+ request.indices("*bar");
+ defaultIndicesResolver.resolve(user, GetAliasesAction.NAME, request, metaData);
+ }
+
//msearch is a CompositeIndicesRequest whose items (SearchRequests) implement IndicesRequest.Replaceable, wildcards will get replaced
@Test
public void testResolveMultiSearchNoWildcards() {