mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-02-09 14:35:04 +00:00
Indices resolution: special treatment for get aliases request
GetAliasesRequest is the Java api request class behind the get alias and alias exists api. It allows for replacing its indices, as it implements IndicesRequest.Replaceable, but its authorization is only based on the indices specified on the request, the aliases are ignored. This commit makes sure that the aliases are taken into account. Also get aliases is now part of the manage_aliases privilege and wildcards expression within aliases are replaced too with matching aliases that the current user is authorized for. Closes elastic/elasticsearch#558 Closes elastic/elasticsearch#595 Original commit: elastic/x-pack-elasticsearch@b40b4cccc6
This commit is contained in:
parent
3bf687e726
commit
9fed91b795
@ -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<P extends Privilege<P>> {
|
||||
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/*");
|
||||
|
@ -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<TransportRequest>
|
||||
ImmutableList<String> authorizedIndices = authzService.authorizedIndicesAndAliases(user, action);
|
||||
List<String> 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<String> authorizedIndices = authzService.authorizedIndicesAndAliases(user, action);
|
||||
Set<String> finalIndices = Sets.newHashSet();
|
||||
|
||||
List<String> 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<String> 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<String> existingAliases = metaData.aliases().keys();
|
||||
for (String authorizedIndex : authorizedIndices) {
|
||||
if (existingAliases.contains(authorizedIndex)) {
|
||||
authorizedAliases.add(authorizedIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<String> 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<String> resolveGetAliasesRequest(User user, String action, GetAliasesRequest request, MetaData metaData) {
|
||||
ImmutableList<String> authorizedIndices = authzService.authorizedIndicesAndAliases(user, action);
|
||||
List<String> aliases = replaceWildcardsWithAuthorizedAliases(request.aliases(), loadAuthorizedAliases(authorizedIndices, metaData));
|
||||
request.aliases(aliases.toArray(new String[aliases.size()]));
|
||||
Set<String> indices = Sets.newHashSet(request.indices());
|
||||
indices.addAll(aliases);
|
||||
return indices;
|
||||
}
|
||||
|
||||
private Set<String> resolveIndicesAliasesRequest(User user, String action, IndicesAliasesRequest request, MetaData metaData) {
|
||||
ImmutableList<String> authorizedIndices = authzService.authorizedIndicesAndAliases(user, action);
|
||||
Set<String> finalIndices = Sets.newHashSet();
|
||||
|
||||
List<String> 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<String> 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<String> aliases = replaceWildcardsWithAuthorizedAliases(aliasActions.aliases(), authorizedAliases);
|
||||
aliasActions.aliases(aliases.toArray(new String[aliases.size()]));
|
||||
}
|
||||
Collections.addAll(finalIndices, aliasActions.aliases());
|
||||
}
|
||||
return finalIndices;
|
||||
}
|
||||
|
||||
private List<String> loadAuthorizedAliases(List<String> authorizedIndices, MetaData metaData) {
|
||||
List<String> authorizedAliases = Lists.newArrayList();
|
||||
ObjectLookupContainer<String> existingAliases = metaData.aliases().keys();
|
||||
for (String authorizedIndex : authorizedIndices) {
|
||||
if (existingAliases.contains(authorizedIndex)) {
|
||||
authorizedAliases.add(authorizedIndex);
|
||||
}
|
||||
}
|
||||
return authorizedAliases;
|
||||
}
|
||||
|
||||
private List<String> replaceWildcardsWithAuthorizedAliases(String[] aliases, List<String> authorizedAliases) {
|
||||
List<String> 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;
|
||||
|
@ -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]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.<String>of());
|
||||
when(authzService.authorizedIndicesAndAliases(userNoIndices, GetAliasesAction.NAME)).thenReturn(ImmutableList.<String>of());
|
||||
when(authzService.authorizedIndicesAndAliases(userNoIndices, SearchAction.NAME)).thenReturn(ImmutableList.<String>of());
|
||||
when(authzService.authorizedIndicesAndAliases(userNoIndices, MultiSearchAction.NAME)).thenReturn(ImmutableList.<String>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<String> 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<String> 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<String> 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<String> 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<String> 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<String> 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<String> 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() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user