From dd99bef666dd02714c09f5c56bea49395a34c680 Mon Sep 17 00:00:00 2001 From: Albert Zaharovits Date: Tue, 14 Jul 2020 21:45:02 +0300 Subject: [PATCH] Disallow mapping updates for doc ingestion privileges (#58784) The `create_doc`, `create`, `write` and `index` privileges do not grant the PutMapping action anymore. Apart from the `write` privilege, the other three privileges also do NOT grant (auto) updating the mapping when ingesting a document with unmapped fields, according to the templates. In order to maintain the BWC in the 7.x releases, the above privileges will still grant the Put and AutoPutMapping actions, but only when the "index" entity is an alias or a concrete index, but not a data stream or a backing index of a data stream. --- .../authz/permission/IndicesPermission.java | 171 +++-- .../authz/permission/LimitedRole.java | 4 +- .../core/security/authz/permission/Role.java | 2 +- .../authz/privilege/IndexPrivilege.java | 11 +- .../authz/permission/LimitedRoleTests.java | 36 +- .../authz/store/ReservedRolesStoreTests.java | 593 ++++++++++-------- .../plugin/ml/qa/ml-with-security/roles.yml | 2 +- .../xpack/security/authz/RBACEngine.java | 12 +- .../AbstractPrivilegeTestCase.java | 7 +- .../integration/IndexPrivilegeTests.java | 43 +- .../xpack/security/authz/RBACEngineTests.java | 37 ++ .../accesscontrol/IndicesPermissionTests.java | 100 ++- .../authz/permission/PermissionTests.java | 51 +- .../authz/store/CompositeRolesStoreTests.java | 47 +- .../security/user/AsyncSearchUserTests.java | 27 +- .../xpack/security/user/XPackUserTests.java | 37 +- .../test/security/authz/15_auto_create.yml | 6 +- .../test/security/authz/50_data_streams.yml | 113 +++- .../test/20_small_users_one_index.yml | 6 +- 19 files changed, 897 insertions(+), 408 deletions(-) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/permission/IndicesPermission.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/permission/IndicesPermission.java index bbc664f50f8c6..31d217d143333 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/permission/IndicesPermission.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/permission/IndicesPermission.java @@ -10,11 +10,14 @@ import org.apache.lucene.util.automaton.Operations; import org.apache.lucene.util.automaton.TooComplexToDeterminizeException; import org.elasticsearch.ElasticsearchSecurityException; +import org.elasticsearch.action.admin.indices.mapping.put.AutoPutMappingAction; +import org.elasticsearch.action.admin.indices.mapping.put.PutMappingAction; import org.elasticsearch.cluster.metadata.IndexAbstraction; import org.elasticsearch.cluster.metadata.IndexMetadata; import org.elasticsearch.common.Nullable; import org.elasticsearch.common.Strings; import org.elasticsearch.common.bytes.BytesReference; +import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.common.regex.Regex; import org.elasticsearch.xpack.core.security.authz.accesscontrol.IndicesAccessControl; import org.elasticsearch.xpack.core.security.authz.privilege.IndexPrivilege; @@ -32,7 +35,6 @@ import java.util.Objects; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; import java.util.function.Predicate; import static java.util.Collections.unmodifiableMap; @@ -44,9 +46,13 @@ */ public final class IndicesPermission { + private static final DeprecationLogger deprecationLogger = DeprecationLogger.getLogger(IndicesPermission.class); + public static final IndicesPermission NONE = new IndicesPermission(); - private final ConcurrentMap> allowedIndicesMatchersForAction = new ConcurrentHashMap<>(); + private static final Set PRIVILEGE_NAME_SET_BWC_ALLOW_MAPPING_UPDATE = Set.of("create", "create_doc", "index", "write"); + + private final Map> allowedIndicesMatchersForAction = new ConcurrentHashMap<>(); private final Group[] groups; @@ -54,6 +60,24 @@ public IndicesPermission(Group... groups) { this.groups = groups; } + private static Predicate indexMatcher(Collection ordinaryIndices, Collection restrictedIndices) { + Predicate namePredicate; + if (ordinaryIndices.isEmpty()) { + namePredicate = indexMatcher(restrictedIndices); + } else { + namePredicate = indexMatcher(ordinaryIndices) + .and(index -> false == RestrictedIndicesNames.isRestricted(index)); + if (restrictedIndices.isEmpty() == false) { + namePredicate = indexMatcher(restrictedIndices).or(namePredicate); + } + } + return namePredicate; + } + + /** + * Given a collection of index names and patterns, this constructs a {@code Predicate} that tests + * {@code true} for the names in the collection as well as for any names matching the patterns in the collection. + */ public static Predicate indexMatcher(Collection indices) { Set exactMatch = new HashSet<>(); List nonExactMatch = new ArrayList<>(); @@ -105,7 +129,7 @@ public Group[] groups() { * @return A predicate that will match all the indices that this permission * has the privilege for executing the given action on. */ - public Predicate allowedIndicesMatcher(String action) { + public Predicate allowedIndicesMatcher(String action) { return allowedIndicesMatchersForAction.computeIfAbsent(action, a -> Group.buildIndexMatcherPredicateForAction(a, groups)); } @@ -116,8 +140,9 @@ public Predicate allowedIndicesMatcher(String action) { * checked on the coordinating node), and properly authorized later at the shard level checking their indices as well. */ public boolean check(String action) { + final boolean isMappingUpdateAction = isMappingUpdateAction(action); for (Group group : groups) { - if (group.check(action)) { + if (group.checkAction(action) || (isMappingUpdateAction && containsPrivilegeThatGrantsMappingUpdatesForBwc(group))) { return true; } } @@ -202,43 +227,84 @@ public Map authorize(String act Map roleQueriesByIndex = new HashMap<>(); Map grantedBuilder = new HashMap<>(); + final boolean isMappingUpdateAction = isMappingUpdateAction(action); + for (String indexOrAlias : requestedIndicesOrAliases) { - boolean granted = false; - Set concreteIndices = new HashSet<>(); - IndexAbstraction indexAbstraction = lookup.get(indexOrAlias); + final boolean isBackingIndex; + final boolean isDataStream; + final Set concreteIndices = new HashSet<>(); + final IndexAbstraction indexAbstraction = lookup.get(indexOrAlias); if (indexAbstraction != null) { for (IndexMetadata indexMetadata : indexAbstraction.getIndices()) { concreteIndices.add(indexMetadata.getIndex().getName()); } + isBackingIndex = indexAbstraction.getType() == IndexAbstraction.Type.CONCRETE_INDEX && + indexAbstraction.getParentDataStream() != null; + isDataStream = indexAbstraction.getType() == IndexAbstraction.Type.DATA_STREAM; + } else { + isBackingIndex = isDataStream = false; } + // true if ANY group covers the given index AND the given action + boolean granted = false; + // true if ANY group, which contains certain ingest privileges, covers the given index AND the action is a mapping update for + // an index or an alias (but not for a data stream) + boolean bwcGrantMappingUpdate = false; + final List bwcDeprecationLogActions = new ArrayList<>(); + for (Group group : groups) { - // check for privilege granted directly on the requested index/alias - if (group.check(action, indexOrAlias) || - // check for privilege granted on parent data stream if a backing index - (indexAbstraction != null && indexAbstraction.getType() == IndexAbstraction.Type.CONCRETE_INDEX && - indexAbstraction.getParentDataStream() != null && - group.check(action, indexAbstraction.getParentDataStream().getName()))) { - granted = true; - for (String index : concreteIndices) { - Set fieldPermissions = fieldPermissionsByIndex.computeIfAbsent(index, (k) -> new HashSet<>()); - fieldPermissionsByIndex.put(indexOrAlias, fieldPermissions); - fieldPermissions.add(group.getFieldPermissions()); - DocumentLevelPermissions permissions = - roleQueriesByIndex.computeIfAbsent(index, (k) -> new DocumentLevelPermissions()); - roleQueriesByIndex.putIfAbsent(indexOrAlias, permissions); - if (group.hasQuery()) { - permissions.addAll(group.getQuery()); - } else { - // if more than one permission matches for a concrete index here and if - // a single permission doesn't have a role query then DLS will not be - // applied even when other permissions do have a role query - permissions.setAllowAll(true); + // the group covers the given index OR the given index is a backing index and the group covers the parent data stream + final boolean indexCheck = group.checkIndex(indexOrAlias) || + (isBackingIndex && group.checkIndex(indexAbstraction.getParentDataStream().getName())); + if (indexCheck) { + boolean actionCheck = group.checkAction(action); + granted = granted || actionCheck; + // mapping updates are allowed for certain privileges on indices and aliases (but not on data streams), + // outside of the privilege definition + boolean bwcMappingActionCheck = isMappingUpdateAction && false == isDataStream && false == isBackingIndex && + containsPrivilegeThatGrantsMappingUpdatesForBwc(group); + bwcGrantMappingUpdate = bwcGrantMappingUpdate || bwcMappingActionCheck; + if (actionCheck || bwcMappingActionCheck) { + // propagate DLS and FLS permissions over the concrete indices + for (String index : concreteIndices) { + Set fieldPermissions = fieldPermissionsByIndex.computeIfAbsent(index, (k) -> new HashSet<>()); + fieldPermissionsByIndex.put(indexOrAlias, fieldPermissions); + fieldPermissions.add(group.getFieldPermissions()); + DocumentLevelPermissions permissions = + roleQueriesByIndex.computeIfAbsent(index, (k) -> new DocumentLevelPermissions()); + roleQueriesByIndex.putIfAbsent(indexOrAlias, permissions); + if (group.hasQuery()) { + permissions.addAll(group.getQuery()); + } else { + // if more than one permission matches for a concrete index here and if + // a single permission doesn't have a role query then DLS will not be + // applied even when other permissions do have a role query + permissions.setAllowAll(true); + } + } + if (false == actionCheck) { + for (String privilegeName : group.privilege.name()) { + if (PRIVILEGE_NAME_SET_BWC_ALLOW_MAPPING_UPDATE.contains(privilegeName)) { + bwcDeprecationLogActions.add(() -> { + deprecationLogger.deprecate("[" + indexOrAlias + "] mapping update for ingest privilege [" + + privilegeName + "]", "the index privilege [" + privilegeName + "] allowed the update " + + "mapping action [" + action + "] on index [" + indexOrAlias + "], this privilege " + + "will not permit mapping updates in the next major release - users who require access " + + "to update mappings must be granted explicit privileges"); + }); + } + } } } } } + if (false == granted && bwcGrantMappingUpdate) { + // the action is granted only due to the deprecated behaviour of certain privileges + granted = true; + bwcDeprecationLogActions.forEach(deprecationLogAction -> deprecationLogAction.run()); + } + if (concreteIndices.isEmpty()) { grantedBuilder.put(indexOrAlias, granted); } else { @@ -281,6 +347,14 @@ private boolean isConcreteRestrictedIndex(String indexPattern) { return RestrictedIndicesNames.isRestricted(indexPattern); } + private static boolean isMappingUpdateAction(String action) { + return action.equals(PutMappingAction.NAME) || action.equals(AutoPutMappingAction.NAME); + } + + private static boolean containsPrivilegeThatGrantsMappingUpdatesForBwc(Group group) { + return group.privilege().name().stream().anyMatch(PRIVILEGE_NAME_SET_BWC_ALLOW_MAPPING_UPDATE::contains); + } + public static class Group { private final IndexPrivilege privilege; private final Predicate actionMatcher; @@ -322,14 +396,13 @@ public FieldPermissions getFieldPermissions() { return fieldPermissions; } - private boolean check(String action) { + private boolean checkAction(String action) { return actionMatcher.test(action); } - private boolean check(String action, String index) { + private boolean checkIndex(String index) { assert index != null; - return check(action) && indexNameMatcher.test(index) - && (allowRestrictedIndices || (false == RestrictedIndicesNames.isRestricted(index))); + return indexNameMatcher.test(index) && (allowRestrictedIndices || (false == RestrictedIndicesNames.isRestricted(index))); } boolean hasQuery() { @@ -349,9 +422,12 @@ public static Automaton buildIndexMatcherAutomaton(boolean allowRestrictedIndice } } - private static Predicate buildIndexMatcherPredicateForAction(String action, Group... groups) { + private static Predicate buildIndexMatcherPredicateForAction(String action, Group... groups) { final Set ordinaryIndices = new HashSet<>(); final Set restrictedIndices = new HashSet<>(); + final Set grantMappingUpdatesOnIndices = new HashSet<>(); + final Set grantMappingUpdatesOnRestrictedIndices = new HashSet<>(); + final boolean isMappingUpdateAction = isMappingUpdateAction(action); for (final Group group : groups) { if (group.actionMatcher.test(action)) { if (group.allowRestrictedIndices) { @@ -359,20 +435,25 @@ private static Predicate buildIndexMatcherPredicateForAction(String acti } else { ordinaryIndices.addAll(Arrays.asList(group.indices())); } + } else if (isMappingUpdateAction && containsPrivilegeThatGrantsMappingUpdatesForBwc(group)) { + // special BWC case for certain privileges: allow put mapping on indices and aliases (but not on data streams), even if + // the privilege definition does not currently allow it + if (group.allowRestrictedIndices) { + grantMappingUpdatesOnRestrictedIndices.addAll(Arrays.asList(group.indices())); + } else { + grantMappingUpdatesOnIndices.addAll(Arrays.asList(group.indices())); + } } } - final Predicate predicate; - if (restrictedIndices.isEmpty()) { - predicate = indexMatcher(ordinaryIndices) - .and(index -> false == RestrictedIndicesNames.isRestricted(index)); - } else if (ordinaryIndices.isEmpty()) { - predicate = indexMatcher(restrictedIndices); - } else { - predicate = indexMatcher(restrictedIndices) - .or(indexMatcher(ordinaryIndices) - .and(index -> false == RestrictedIndicesNames.isRestricted(index))); - } - return predicate; + final Predicate namePredicate = indexMatcher(ordinaryIndices, restrictedIndices); + final Predicate bwcSpecialCaseNamePredicate = indexMatcher(grantMappingUpdatesOnIndices, + grantMappingUpdatesOnRestrictedIndices); + return indexAbstraction -> { + return namePredicate.test(indexAbstraction.getName()) || + (indexAbstraction.getType() != IndexAbstraction.Type.DATA_STREAM && + (indexAbstraction.getParentDataStream() == null) && + bwcSpecialCaseNamePredicate.test(indexAbstraction.getName())); + }; } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/permission/LimitedRole.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/permission/LimitedRole.java index 6e1b58dba6a28..129cdc655f637 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/permission/LimitedRole.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/permission/LimitedRole.java @@ -72,8 +72,8 @@ public IndicesAccessControl authorize(String action, Set requestedIndice * action on. */ @Override - public Predicate allowedIndicesMatcher(String action) { - Predicate predicate = super.indices().allowedIndicesMatcher(action); + public Predicate allowedIndicesMatcher(String action) { + Predicate predicate = super.indices().allowedIndicesMatcher(action); predicate = predicate.and(limitedBy.indices().allowedIndicesMatcher(action)); return predicate; } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/permission/Role.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/permission/Role.java index fe84f4fbe1c48..2a6e851810e08 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/permission/Role.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/permission/Role.java @@ -83,7 +83,7 @@ public static Builder builder(RoleDescriptor rd, FieldPermissionsCache fieldPerm * @return A predicate that will match all the indices that this role * has the privilege for executing the given action on. */ - public Predicate allowedIndicesMatcher(String action) { + public Predicate allowedIndicesMatcher(String action) { return indices.allowedIndicesMatcher(action); } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/IndexPrivilege.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/IndexPrivilege.java index e95bda670f23f..f98bba6dedfec 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/IndexPrivilege.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/IndexPrivilege.java @@ -21,7 +21,6 @@ import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsAction; import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsAction; import org.elasticsearch.action.admin.indices.mapping.put.AutoPutMappingAction; -import org.elasticsearch.action.admin.indices.mapping.put.PutMappingAction; import org.elasticsearch.action.admin.indices.settings.get.GetSettingsAction; import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryAction; import org.elasticsearch.common.Strings; @@ -51,15 +50,13 @@ public final class IndexPrivilege extends Privilege { private static final Automaton READ_AUTOMATON = patterns("indices:data/read/*"); private static final Automaton READ_CROSS_CLUSTER_AUTOMATON = patterns("internal:transport/proxy/indices:data/read/*", ClusterSearchShardsAction.NAME); - private static final Automaton CREATE_AUTOMATON = patterns("indices:data/write/index*", "indices:data/write/bulk*", - PutMappingAction.NAME, AutoPutMappingAction.NAME); + private static final Automaton CREATE_AUTOMATON = patterns("indices:data/write/index*", "indices:data/write/bulk*"); private static final Automaton CREATE_DOC_AUTOMATON = patterns("indices:data/write/index", "indices:data/write/index[*", - "indices:data/write/index:op_type/create", "indices:data/write/bulk*", PutMappingAction.NAME, AutoPutMappingAction.NAME); + "indices:data/write/index:op_type/create", "indices:data/write/bulk*"); private static final Automaton INDEX_AUTOMATON = patterns("indices:data/write/index*", "indices:data/write/bulk*", - "indices:data/write/update*", PutMappingAction.NAME, AutoPutMappingAction.NAME); + "indices:data/write/update*"); private static final Automaton DELETE_AUTOMATON = patterns("indices:data/write/delete*", "indices:data/write/bulk*"); - private static final Automaton WRITE_AUTOMATON = patterns("indices:data/write/*", PutMappingAction.NAME, - AutoPutMappingAction.NAME); + private static final Automaton WRITE_AUTOMATON = patterns("indices:data/write/*", AutoPutMappingAction.NAME); private static final Automaton MONITOR_AUTOMATON = patterns("indices:monitor/*"); private static final Automaton MANAGE_AUTOMATON = unionAndMinimize(Arrays.asList(MONITOR_AUTOMATON, patterns("indices:admin/*"))); diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/permission/LimitedRoleTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/permission/LimitedRoleTests.java index 57cc0938632e3..5497d92e5bbe1 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/permission/LimitedRoleTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/permission/LimitedRoleTests.java @@ -13,6 +13,7 @@ import org.elasticsearch.action.bulk.BulkAction; import org.elasticsearch.action.search.SearchAction; import org.elasticsearch.cluster.metadata.AliasMetadata; +import org.elasticsearch.cluster.metadata.IndexAbstraction; import org.elasticsearch.cluster.metadata.IndexMetadata; import org.elasticsearch.cluster.metadata.Metadata; import org.elasticsearch.common.collect.MapBuilder; @@ -40,6 +41,7 @@ import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class LimitedRoleTests extends ESTestCase { List applicationPrivilegeDescriptors; @@ -181,27 +183,27 @@ public void testCheckIndicesAction() { public void testAllowedIndicesMatcher() { Role fromRole = Role.builder("a-role").add(IndexPrivilege.READ, "ind-1*").build(); - assertThat(fromRole.allowedIndicesMatcher(SearchAction.NAME).test("ind-1"), is(true)); - assertThat(fromRole.allowedIndicesMatcher(SearchAction.NAME).test("ind-11"), is(true)); - assertThat(fromRole.allowedIndicesMatcher(SearchAction.NAME).test("ind-2"), is(false)); + assertThat(fromRole.allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction("ind-1")), is(true)); + assertThat(fromRole.allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction("ind-11")), is(true)); + assertThat(fromRole.allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction("ind-2")), is(false)); { Role limitedByRole = Role.builder("limited-role").add(IndexPrivilege.READ, "ind-1", "ind-2").build(); - assertThat(limitedByRole.allowedIndicesMatcher(SearchAction.NAME).test("ind-1"), is(true)); - assertThat(limitedByRole.allowedIndicesMatcher(SearchAction.NAME).test("ind-11"), is(false)); - assertThat(limitedByRole.allowedIndicesMatcher(SearchAction.NAME).test("ind-2"), is(true)); + assertThat(limitedByRole.allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction("ind-1")), is(true)); + assertThat(limitedByRole.allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction("ind-11")), is(false)); + assertThat(limitedByRole.allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction("ind-2")), is(true)); Role role = LimitedRole.createLimitedRole(fromRole, limitedByRole); - assertThat(role.allowedIndicesMatcher(SearchAction.NAME).test("ind-1"), is(true)); - assertThat(role.allowedIndicesMatcher(SearchAction.NAME).test("ind-11"), is(false)); - assertThat(role.allowedIndicesMatcher(SearchAction.NAME).test("ind-2"), is(false)); + assertThat(role.allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction("ind-1")), is(true)); + assertThat(role.allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction("ind-11")), is(false)); + assertThat(role.allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction("ind-2")), is(false)); } { Role limitedByRole = Role.builder("limited-role").add(IndexPrivilege.READ, "ind-*").build(); - assertThat(limitedByRole.allowedIndicesMatcher(SearchAction.NAME).test("ind-1"), is(true)); - assertThat(limitedByRole.allowedIndicesMatcher(SearchAction.NAME).test("ind-2"), is(true)); + assertThat(limitedByRole.allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction("ind-1")), is(true)); + assertThat(limitedByRole.allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction("ind-2")), is(true)); Role role = LimitedRole.createLimitedRole(fromRole, limitedByRole); - assertThat(role.allowedIndicesMatcher(SearchAction.NAME).test("ind-1"), is(true)); - assertThat(role.allowedIndicesMatcher(SearchAction.NAME).test("ind-2"), is(false)); + assertThat(role.allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction("ind-1")), is(true)); + assertThat(role.allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction("ind-2")), is(false)); } } @@ -441,6 +443,14 @@ private void verifyResourcesPrivileges(ResourcePrivilegesMap resourcePrivileges, assertThat(resourcePrivileges, equalTo(expectedAppPrivsByResource)); } + private IndexAbstraction mockIndexAbstraction(String name) { + IndexAbstraction mock = mock(IndexAbstraction.class); + when(mock.getName()).thenReturn(name); + when(mock.getType()).thenReturn(randomFrom(IndexAbstraction.Type.CONCRETE_INDEX, + IndexAbstraction.Type.ALIAS, IndexAbstraction.Type.DATA_STREAM)); + return mock; + } + private ApplicationPrivilege defineApplicationPrivilege(String app, String name, String... actions) { applicationPrivilegeDescriptors .add(new ApplicationPrivilegeDescriptor(app, name, Sets.newHashSet(actions), Collections.emptyMap())); diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/store/ReservedRolesStoreTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/store/ReservedRolesStoreTests.java index c56d91abb03ec..3de4f9418ecd2 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/store/ReservedRolesStoreTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/store/ReservedRolesStoreTests.java @@ -189,6 +189,7 @@ import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; /** * Unit tests for the {@link ReservedRolesStore} @@ -262,21 +263,26 @@ public void testSnapshotUserRole() { assertThat(snapshotUserRole.cluster().check(WatcherServiceAction.NAME, request, authentication), is(false)); assertThat(snapshotUserRole.cluster().check(DelegatePkiAuthenticationAction.NAME, request, authentication), is(false)); - assertThat(snapshotUserRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(randomAlphaOfLengthBetween(8, 24)), is(false)); - assertThat(snapshotUserRole.indices().allowedIndicesMatcher("indices:foo").test(randomAlphaOfLengthBetween(8, 24)), is(false)); - assertThat(snapshotUserRole.indices().allowedIndicesMatcher(GetAction.NAME).test(randomAlphaOfLengthBetween(8, 24)), is(false)); - assertThat(snapshotUserRole.indices().allowedIndicesMatcher(GetAction.NAME).test(randomAlphaOfLengthBetween(8, 24)), is(false)); + assertThat(snapshotUserRole.indices().allowedIndicesMatcher(IndexAction.NAME).test( + mockIndexAbstraction(randomAlphaOfLengthBetween(8, 24))), is(false)); + assertThat(snapshotUserRole.indices().allowedIndicesMatcher("indices:foo").test( + mockIndexAbstraction(randomAlphaOfLengthBetween(8, 24))), is(false)); + assertThat(snapshotUserRole.indices().allowedIndicesMatcher(GetAction.NAME).test( + mockIndexAbstraction(randomAlphaOfLengthBetween(8, 24))), is(false)); + assertThat(snapshotUserRole.indices().allowedIndicesMatcher(GetAction.NAME).test( + mockIndexAbstraction(randomAlphaOfLengthBetween(8, 24))), is(false)); - assertThat(snapshotUserRole.indices().allowedIndicesMatcher(GetIndexAction.NAME) - .test(randomAlphaOfLengthBetween(8, 24)), is(true)); + assertThat(snapshotUserRole.indices().allowedIndicesMatcher(GetIndexAction.NAME).test( + mockIndexAbstraction(randomAlphaOfLengthBetween(8, 24))), is(true)); for (String index : RestrictedIndicesNames.RESTRICTED_NAMES) { // This test might cease to be true if we ever have non-security restricted names // but that depends on how users are supposed to perform snapshots of those new indices. - assertThat(snapshotUserRole.indices().allowedIndicesMatcher(GetIndexAction.NAME).test(index), is(true)); + assertThat(snapshotUserRole.indices().allowedIndicesMatcher(GetIndexAction.NAME).test( + mockIndexAbstraction(index)), is(true)); } assertThat(snapshotUserRole.indices().allowedIndicesMatcher(GetIndexAction.NAME).test( - RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)), is(true)); + mockIndexAbstraction(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2))), is(true)); assertNoAccessAllowed(snapshotUserRole, RestrictedIndicesNames.RESTRICTED_NAMES); assertNoAccessAllowed(snapshotUserRole, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)); @@ -302,11 +308,11 @@ public void testIngestAdminRole() { assertThat(ingestAdminRole.cluster().check(MonitoringBulkAction.NAME, request, authentication), is(false)); assertThat(ingestAdminRole.cluster().check(DelegatePkiAuthenticationAction.NAME, request, authentication), is(false)); - assertThat(ingestAdminRole.indices().allowedIndicesMatcher(IndexAction.NAME).test("foo"), is(false)); - assertThat(ingestAdminRole.indices().allowedIndicesMatcher("indices:foo").test(randomAlphaOfLengthBetween(8, 24)), - is(false)); - assertThat(ingestAdminRole.indices().allowedIndicesMatcher(GetAction.NAME).test(randomAlphaOfLengthBetween(8, 24)), - is(false)); + assertThat(ingestAdminRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction("foo")), is(false)); + assertThat(ingestAdminRole.indices().allowedIndicesMatcher("indices:foo").test( + mockIndexAbstraction(randomAlphaOfLengthBetween(8, 24))), is(false)); + assertThat(ingestAdminRole.indices().allowedIndicesMatcher(GetAction.NAME).test( + mockIndexAbstraction(randomAlphaOfLengthBetween(8, 24))), is(false)); assertNoAccessAllowed(ingestAdminRole, RestrictedIndicesNames.RESTRICTED_NAMES); assertNoAccessAllowed(ingestAdminRole, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)); @@ -378,9 +384,10 @@ public void testKibanaSystemRole() { assertThat(kibanaRole.runAs().check(randomAlphaOfLengthBetween(1, 12)), is(false)); assertThat(kibanaRole.cluster().check(DelegatePkiAuthenticationAction.NAME, request, authentication), is(true)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(IndexAction.NAME).test("foo"), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(".reporting"), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher("indices:foo").test(randomAlphaOfLengthBetween(8, 24)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction("foo")), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction(".reporting")), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher("indices:foo").test(mockIndexAbstraction(randomAlphaOfLengthBetween(8, 24))), + is(false)); Arrays.asList( ".kibana", @@ -390,34 +397,34 @@ public void testKibanaSystemRole() { ".apm-custom-link" ).forEach((index) -> { logger.info("index name [{}]", index); - assertThat(kibanaRole.indices().allowedIndicesMatcher("indices:foo").test(index), is(true)); - assertThat(kibanaRole.indices().allowedIndicesMatcher("indices:bar").test(index), is(true)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(index), is(true)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(index), is(true)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(index), is(true)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(DeleteAction.NAME).test(index), is(true)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME).test(index), is(true)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(index), is(true)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(MultiSearchAction.NAME).test(index), is(true)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(GetAction.NAME).test(index), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher("indices:foo").test(mockIndexAbstraction(index)), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher("indices:bar").test(mockIndexAbstraction(index)), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(DeleteAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(MultiSearchAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(GetAction.NAME).test(mockIndexAbstraction(index)), is(true)); // inherits from 'all' - assertThat(kibanaRole.indices().allowedIndicesMatcher(READ_CROSS_CLUSTER_NAME).test(index), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(READ_CROSS_CLUSTER_NAME).test(mockIndexAbstraction(index)), is(true)); }); // read-only index access, including cross cluster Arrays.asList(".monitoring-" + randomAlphaOfLength(randomIntBetween(0, 13))).forEach((index) -> { logger.info("index name [{}]", index); - assertThat(kibanaRole.indices().allowedIndicesMatcher("indices:foo").test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher("indices:bar").test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(DeleteAction.NAME).test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME).test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(index), is(true)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(MultiSearchAction.NAME).test(index), is(true)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(GetAction.NAME).test(index), is(true)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(READ_CROSS_CLUSTER_NAME).test(index), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher("indices:foo").test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher("indices:bar").test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(DeleteAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(MultiSearchAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(GetAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(READ_CROSS_CLUSTER_NAME).test(mockIndexAbstraction(index)), is(true)); }); // read-only index access, excluding cross cluster @@ -427,67 +434,67 @@ public void testKibanaSystemRole() { ".ml-stats-" + randomAlphaOfLength(randomIntBetween(0, 13)) ).forEach((index) -> { logger.trace("index name [{}]", index); - assertThat(kibanaRole.indices().allowedIndicesMatcher("indices:foo").test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher("indices:bar").test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(DeleteAction.NAME).test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME).test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(index), is(true)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(MultiSearchAction.NAME).test(index), is(true)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(GetAction.NAME).test(index), is(true)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(READ_CROSS_CLUSTER_NAME).test(index), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher("indices:foo").test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher("indices:bar").test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(DeleteAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(MultiSearchAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(GetAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(READ_CROSS_CLUSTER_NAME).test(mockIndexAbstraction(index)), is(false)); }); // read-only indices for APM telemetry Arrays.asList("apm-*").forEach((index) -> { - assertThat(kibanaRole.indices().allowedIndicesMatcher("indices:foo").test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher("indices:bar").test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(GetIndexAction.NAME).test(index), is(true)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(DeleteAction.NAME).test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME).test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(index), is(true)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(MultiSearchAction.NAME).test(index), is(true)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(GetAction.NAME).test(index), is(true)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(READ_CROSS_CLUSTER_NAME).test(index), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher("indices:foo").test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher("indices:bar").test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(GetIndexAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(DeleteAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(MultiSearchAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(GetAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(READ_CROSS_CLUSTER_NAME).test(mockIndexAbstraction(index)), is(true)); }); // Data telemetry reads mappings, metadata and stats of indices Arrays.asList(randomAlphaOfLengthBetween(8, 24), "packetbeat-*", "logs-*").forEach((index) -> { logger.info("index name [{}]", index); - assertThat(kibanaRole.indices().allowedIndicesMatcher(GetIndexAction.NAME).test(index), is(true)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(GetMappingsAction.NAME).test(index), is(true)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(IndicesStatsAction.NAME).test(index), is(true)); - assertThat(kibanaRole.indices().allowedIndicesMatcher("indices:foo").test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher("indices:bar").test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(DeleteAction.NAME).test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME).test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(MultiSearchAction.NAME).test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(GetAction.NAME).test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(READ_CROSS_CLUSTER_NAME).test(index), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(GetIndexAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(GetMappingsAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(IndicesStatsAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher("indices:foo").test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher("indices:bar").test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(DeleteAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(MultiSearchAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(GetAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(READ_CROSS_CLUSTER_NAME).test(mockIndexAbstraction(index)), is(false)); }); // Beats management index final String index = ".management-beats"; - assertThat(kibanaRole.indices().allowedIndicesMatcher("indices:foo").test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher("indices:bar").test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(index), is(true)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(index), is(true)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(DeleteAction.NAME).test(index), is(true)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME).test(index), is(false)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(index), is(true)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(MultiSearchAction.NAME).test(index), is(true)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(GetAction.NAME).test(index), is(true)); - assertThat(kibanaRole.indices().allowedIndicesMatcher(READ_CROSS_CLUSTER_NAME).test(index), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher("indices:foo").test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher("indices:bar").test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(DeleteAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(MultiSearchAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(GetAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(kibanaRole.indices().allowedIndicesMatcher(READ_CROSS_CLUSTER_NAME).test(mockIndexAbstraction(index)), is(false)); assertNoAccessAllowed(kibanaRole, RestrictedIndicesNames.RESTRICTED_NAMES); assertNoAccessAllowed(kibanaRole, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)); @@ -516,11 +523,10 @@ public void testKibanaAdminRole() { assertThat(kibanaAdminRole.runAs().check(randomAlphaOfLengthBetween(1, 12)), is(false)); - assertThat(kibanaAdminRole.indices().allowedIndicesMatcher(IndexAction.NAME).test("foo"), is(false)); - assertThat(kibanaAdminRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(".reporting"), is(false)); - assertThat( - kibanaAdminRole.indices().allowedIndicesMatcher("indices:foo").test(randomAlphaOfLengthBetween(8, 24)), - is(false)); + assertThat(kibanaAdminRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction("foo")), is(false)); + assertThat(kibanaAdminRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction(".reporting")), is(false)); + assertThat(kibanaAdminRole.indices().allowedIndicesMatcher("indices:foo").test( + mockIndexAbstraction(randomAlphaOfLengthBetween(8, 24))), is(false)); final String randomApplication = "kibana-" + randomAlphaOfLengthBetween(8, 24); assertThat(kibanaAdminRole.application().grants(new ApplicationPrivilege(randomApplication, "app-random", "all"), @@ -562,10 +568,10 @@ public void testKibanaUserRole() { assertThat(kibanaUserRole.runAs().check(randomAlphaOfLengthBetween(1, 12)), is(false)); - assertThat(kibanaUserRole.indices().allowedIndicesMatcher(IndexAction.NAME).test("foo"), is(false)); - assertThat(kibanaUserRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(".reporting"), is(false)); + assertThat(kibanaUserRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction("foo")), is(false)); + assertThat(kibanaUserRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction(".reporting")), is(false)); assertThat(kibanaUserRole.indices().allowedIndicesMatcher("indices:foo") - .test(randomAlphaOfLengthBetween(8, 24)), is(false)); + .test(mockIndexAbstraction(randomAlphaOfLengthBetween(8, 24))), is(false)); final String randomApplication = "kibana-" + randomAlphaOfLengthBetween(8, 24); assertThat(kibanaUserRole.application().grants(new ApplicationPrivilege(randomApplication, "app-random", "all"), "*"), is(false)); @@ -605,26 +611,32 @@ public void testMonitoringUserRole() { assertThat(monitoringUserRole.runAs().check(randomAlphaOfLengthBetween(1, 12)), is(false)); - assertThat(monitoringUserRole.indices().allowedIndicesMatcher(SearchAction.NAME).test("foo"), is(false)); - assertThat(monitoringUserRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(".reporting"), is(false)); - assertThat(monitoringUserRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(".kibana"), is(false)); - assertThat(monitoringUserRole.indices().allowedIndicesMatcher("indices:foo").test(randomAlphaOfLengthBetween(8, 24)), - is(false)); - assertThat(monitoringUserRole.indices().allowedIndicesMatcher(READ_CROSS_CLUSTER_NAME).test("foo"), is(false)); - assertThat(monitoringUserRole.indices().allowedIndicesMatcher(READ_CROSS_CLUSTER_NAME).test(".reporting"), is(false)); - assertThat(monitoringUserRole.indices().allowedIndicesMatcher(READ_CROSS_CLUSTER_NAME).test(".kibana"), is(false)); + assertThat(monitoringUserRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction("foo")), is(false)); + assertThat(monitoringUserRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction(".reporting")), + is(false)); + assertThat(monitoringUserRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction(".kibana")), + is(false)); + assertThat(monitoringUserRole.indices().allowedIndicesMatcher("indices:foo").test( + mockIndexAbstraction(randomAlphaOfLengthBetween(8, 24))), is(false)); + assertThat(monitoringUserRole.indices().allowedIndicesMatcher(READ_CROSS_CLUSTER_NAME).test(mockIndexAbstraction("foo")), + is(false)); + assertThat(monitoringUserRole.indices().allowedIndicesMatcher(READ_CROSS_CLUSTER_NAME).test(mockIndexAbstraction(".reporting")), + is(false)); + assertThat(monitoringUserRole.indices().allowedIndicesMatcher(READ_CROSS_CLUSTER_NAME).test(mockIndexAbstraction(".kibana")), + is(false)); final String index = ".monitoring-" + randomAlphaOfLength(randomIntBetween(0, 13)); - assertThat(monitoringUserRole.indices().allowedIndicesMatcher("indices:foo").test(index), is(false)); - assertThat(monitoringUserRole.indices().allowedIndicesMatcher("indices:bar").test(index), is(false)); - assertThat(monitoringUserRole.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(index), is(false)); - assertThat(monitoringUserRole.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(index), is(false)); - assertThat(monitoringUserRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(index), is(false)); - assertThat(monitoringUserRole.indices().allowedIndicesMatcher(DeleteAction.NAME).test(index), is(false)); - assertThat(monitoringUserRole.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME).test(index), is(false)); - assertThat(monitoringUserRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(index), is(true)); - assertThat(monitoringUserRole.indices().allowedIndicesMatcher(GetAction.NAME).test(index), is(true)); - assertThat(monitoringUserRole.indices().allowedIndicesMatcher(READ_CROSS_CLUSTER_NAME).test(index), is(true)); + assertThat(monitoringUserRole.indices().allowedIndicesMatcher("indices:foo").test(mockIndexAbstraction(index)), is(false)); + assertThat(monitoringUserRole.indices().allowedIndicesMatcher("indices:bar").test(mockIndexAbstraction(index)), is(false)); + assertThat(monitoringUserRole.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(monitoringUserRole.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(monitoringUserRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(monitoringUserRole.indices().allowedIndicesMatcher(DeleteAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(monitoringUserRole.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME) + .test(mockIndexAbstraction(index)), is(false)); + assertThat(monitoringUserRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(monitoringUserRole.indices().allowedIndicesMatcher(GetAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(monitoringUserRole.indices().allowedIndicesMatcher(READ_CROSS_CLUSTER_NAME).test(mockIndexAbstraction(index)), is(true)); assertNoAccessAllowed(monitoringUserRole, RestrictedIndicesNames.RESTRICTED_NAMES); assertNoAccessAllowed(monitoringUserRole, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)); @@ -675,34 +687,56 @@ public void testRemoteMonitoringAgentRole() { assertThat(remoteMonitoringAgentRole.runAs().check(randomAlphaOfLengthBetween(1, 12)), is(false)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(SearchAction.NAME).test("foo"), is(false)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(".reporting"), is(false)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(".kibana"), is(false)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction("foo")), + is(false)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction(".reporting")), + is(false)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction(".kibana")), + is(false)); assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher("indices:foo") - .test(randomAlphaOfLengthBetween(8, 24)), is(false)); + .test(mockIndexAbstraction(randomAlphaOfLengthBetween(8, 24))), is(false)); final String monitoringIndex = ".monitoring-" + randomAlphaOfLength(randomIntBetween(0, 13)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher("indices:foo").test(monitoringIndex), is(true)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher("indices:bar").test(monitoringIndex), is(true)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(monitoringIndex), is(true)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(monitoringIndex), is(true)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(monitoringIndex), is(true)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(DeleteAction.NAME).test(monitoringIndex), is(true)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME).test(monitoringIndex), is(true)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(monitoringIndex), is(true)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(GetAction.NAME).test(monitoringIndex), is(true)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(GetIndexAction.NAME).test(monitoringIndex), is(true)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher("indices:foo").test(mockIndexAbstraction(monitoringIndex)), + is(true)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher("indices:bar").test(mockIndexAbstraction(monitoringIndex)), + is(true)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(DeleteIndexAction.NAME) + .test(mockIndexAbstraction(monitoringIndex)), is(true)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(CreateIndexAction.NAME) + .test(mockIndexAbstraction(monitoringIndex)), is(true)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(IndexAction.NAME) + .test(mockIndexAbstraction(monitoringIndex)), is(true)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(DeleteAction.NAME) + .test(mockIndexAbstraction(monitoringIndex)), is(true)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME) + .test(mockIndexAbstraction(monitoringIndex)), is(true)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(SearchAction.NAME) + .test(mockIndexAbstraction(monitoringIndex)), is(true)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(GetAction.NAME) + .test(mockIndexAbstraction(monitoringIndex)), is(true)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(GetIndexAction.NAME) + .test(mockIndexAbstraction(monitoringIndex)), is(true)); final String metricbeatIndex = "metricbeat-" + randomAlphaOfLength(randomIntBetween(0, 13)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher("indices:foo").test(metricbeatIndex), is(false)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher("indices:bar").test(metricbeatIndex), is(false)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(metricbeatIndex), is(false)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(metricbeatIndex), is(true)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(metricbeatIndex), is(true)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(DeleteAction.NAME).test(metricbeatIndex), is(false)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME).test(metricbeatIndex), is(false)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(metricbeatIndex), is(false)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(GetAction.NAME).test(metricbeatIndex), is(false)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher("indices:foo") + .test(mockIndexAbstraction(metricbeatIndex)), is(false)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher("indices:bar") + .test(mockIndexAbstraction(metricbeatIndex)), is(false)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(DeleteIndexAction.NAME) + .test(mockIndexAbstraction(metricbeatIndex)), is(false)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(CreateIndexAction.NAME) + .test(mockIndexAbstraction(metricbeatIndex)), is(true)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(IndexAction.NAME) + .test(mockIndexAbstraction(metricbeatIndex)), is(true)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(DeleteAction.NAME) + .test(mockIndexAbstraction(metricbeatIndex)), is(false)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME) + .test(mockIndexAbstraction(metricbeatIndex)), is(false)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(SearchAction.NAME) + .test(mockIndexAbstraction(metricbeatIndex)), is(false)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(GetAction.NAME) + .test(mockIndexAbstraction(metricbeatIndex)), is(false)); assertNoAccessAllowed(remoteMonitoringAgentRole, RestrictedIndicesNames.RESTRICTED_NAMES); assertNoAccessAllowed(remoteMonitoringAgentRole, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)); @@ -730,74 +764,89 @@ public void testRemoteMonitoringCollectorRole() { assertThat(remoteMonitoringAgentRole.runAs().check(randomAlphaOfLengthBetween(1, 12)), is(false)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(RecoveryAction.NAME).test("foo"), is(true)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(SearchAction.NAME).test("foo"), is(false)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(".reporting"), is(false)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(".kibana"), is(true)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(GetAction.NAME).test(".kibana"), is(true)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(RecoveryAction.NAME) + .test(mockIndexAbstraction("foo")), is(true)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(SearchAction.NAME) + .test(mockIndexAbstraction("foo")), is(false)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(SearchAction.NAME) + .test(mockIndexAbstraction(".reporting")), is(false)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(SearchAction.NAME) + .test(mockIndexAbstraction(".kibana")), is(true)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(GetAction.NAME) + .test(mockIndexAbstraction(".kibana")), is(true)); assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher("indices:foo") - .test(randomAlphaOfLengthBetween(8, 24)), is(false)); + .test(mockIndexAbstraction(randomAlphaOfLengthBetween(8, 24))), is(false)); Arrays.asList( ".monitoring-" + randomAlphaOfLength(randomIntBetween(0, 13)), "metricbeat-" + randomAlphaOfLength(randomIntBetween(0, 13)) ).forEach((index) -> { logger.info("index name [{}]", index); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher("indices:foo").test(index), is(false)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher("indices:bar").test(index), is(false)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(index), is(false)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(index), is(false)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(index), is(false)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(DeleteAction.NAME).test(index), is(false)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME).test(index), is(false)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(index), is(false)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(GetAction.NAME).test(index), is(false)); - assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(GetIndexAction.NAME).test(index), is(false)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher("indices:foo") + .test(mockIndexAbstraction(index)), is(false)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher("indices:bar") + .test(mockIndexAbstraction(index)), is(false)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(DeleteIndexAction.NAME) + .test(mockIndexAbstraction(index)), is(false)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(CreateIndexAction.NAME) + .test(mockIndexAbstraction(index)), is(false)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(IndexAction.NAME) + .test(mockIndexAbstraction(index)), is(false)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(DeleteAction.NAME) + .test(mockIndexAbstraction(index)), is(false)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME) + .test(mockIndexAbstraction(index)), is(false)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(SearchAction.NAME) + .test(mockIndexAbstraction(index)), is(false)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(GetAction.NAME) + .test(mockIndexAbstraction(index)), is(false)); + assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(GetIndexAction.NAME) + .test(mockIndexAbstraction(index)), is(false)); }); // These tests might need to change if we add new non-security restricted indices that the monitoring user isn't supposed to see // (but ideally, the monitoring user should see all indices). assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(GetSettingsAction.NAME) - .test(randomFrom(RestrictedIndicesNames.RESTRICTED_NAMES)), is(true)); + .test(mockIndexAbstraction(randomFrom(RestrictedIndicesNames.RESTRICTED_NAMES))), is(true)); assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(GetSettingsAction.NAME) - .test(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)), is(true)); + .test(mockIndexAbstraction(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2))), is(true)); assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(IndicesShardStoresAction.NAME) - .test(randomFrom(RestrictedIndicesNames.RESTRICTED_NAMES)), is(true)); + .test(mockIndexAbstraction(randomFrom(RestrictedIndicesNames.RESTRICTED_NAMES))), is(true)); assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(IndicesShardStoresAction.NAME) - .test(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)), is(true)); + .test(mockIndexAbstraction(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2))), is(true)); assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(UpgradeStatusAction.NAME) - .test(randomFrom(RestrictedIndicesNames.RESTRICTED_NAMES)), is(true)); + .test(mockIndexAbstraction(randomFrom(RestrictedIndicesNames.RESTRICTED_NAMES))), is(true)); assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(UpgradeStatusAction.NAME) - .test(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)), is(true)); + .test(mockIndexAbstraction(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2))), is(true)); assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(RecoveryAction.NAME) - .test(randomFrom(RestrictedIndicesNames.RESTRICTED_NAMES)), is(true)); + .test(mockIndexAbstraction(randomFrom(RestrictedIndicesNames.RESTRICTED_NAMES))), is(true)); assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(RecoveryAction.NAME) - .test(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)), is(true)); + .test(mockIndexAbstraction(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2))), is(true)); assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(IndicesStatsAction.NAME) - .test(randomFrom(RestrictedIndicesNames.RESTRICTED_NAMES)), is(true)); + .test(mockIndexAbstraction(randomFrom(RestrictedIndicesNames.RESTRICTED_NAMES))), is(true)); assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(IndicesStatsAction.NAME) - .test(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)), is(true)); + .test(mockIndexAbstraction(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2))), is(true)); assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(IndicesSegmentsAction.NAME) - .test(randomFrom(RestrictedIndicesNames.RESTRICTED_NAMES)), is(true)); + .test(mockIndexAbstraction(randomFrom(RestrictedIndicesNames.RESTRICTED_NAMES))), is(true)); assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(IndicesSegmentsAction.NAME) - .test(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)), is(true)); + .test(mockIndexAbstraction(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2))), is(true)); assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(SearchAction.NAME) - .test(randomFrom(RestrictedIndicesNames.RESTRICTED_NAMES)), is(false)); + .test(mockIndexAbstraction(randomFrom(RestrictedIndicesNames.RESTRICTED_NAMES))), is(false)); assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(SearchAction.NAME) - .test(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)), is(false)); + .test(mockIndexAbstraction(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2))), is(false)); assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(GetAction.NAME) - .test(randomFrom(RestrictedIndicesNames.RESTRICTED_NAMES)), is(false)); + .test(mockIndexAbstraction(randomFrom(RestrictedIndicesNames.RESTRICTED_NAMES))), is(false)); assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(GetAction.NAME) - .test(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)), is(false)); + .test(mockIndexAbstraction(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2))), is(false)); assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(DeleteAction.NAME) - .test(randomFrom(RestrictedIndicesNames.RESTRICTED_NAMES)), is(false)); + .test(mockIndexAbstraction(randomFrom(RestrictedIndicesNames.RESTRICTED_NAMES))), is(false)); assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(DeleteAction.NAME) - .test(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)), is(false)); + .test(mockIndexAbstraction(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2))), is(false)); assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(IndexAction.NAME) - .test(randomFrom(RestrictedIndicesNames.RESTRICTED_NAMES)), is(false)); + .test(mockIndexAbstraction(randomFrom(RestrictedIndicesNames.RESTRICTED_NAMES))), is(false)); assertThat(remoteMonitoringAgentRole.indices().allowedIndicesMatcher(IndexAction.NAME) - .test(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)), is(false)); + .test(mockIndexAbstraction(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2))), is(false)); assertMonitoringOnRestrictedIndices(remoteMonitoringAgentRole); @@ -851,24 +900,27 @@ public void testReportingUserRole() { assertThat(reportingUserRole.runAs().check(randomAlphaOfLengthBetween(1, 12)), is(false)); - assertThat(reportingUserRole.indices().allowedIndicesMatcher(SearchAction.NAME).test("foo"), is(false)); - assertThat(reportingUserRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(".reporting"), is(false)); - assertThat(reportingUserRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(".kibana"), is(false)); - assertThat(reportingUserRole.indices().allowedIndicesMatcher("indices:foo").test(randomAlphaOfLengthBetween(8, 24)), - is(false)); + assertThat(reportingUserRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction("foo")), is(false)); + assertThat(reportingUserRole.indices().allowedIndicesMatcher(SearchAction.NAME) + .test(mockIndexAbstraction(".reporting")), is(false)); + assertThat(reportingUserRole.indices().allowedIndicesMatcher(SearchAction.NAME) + .test(mockIndexAbstraction(".kibana")), is(false)); + assertThat(reportingUserRole.indices().allowedIndicesMatcher("indices:foo") + .test(mockIndexAbstraction(randomAlphaOfLengthBetween(8, 24))), is(false)); final String index = ".reporting-" + randomAlphaOfLength(randomIntBetween(0, 13)); - assertThat(reportingUserRole.indices().allowedIndicesMatcher("indices:foo").test(index), is(false)); - assertThat(reportingUserRole.indices().allowedIndicesMatcher("indices:bar").test(index), is(false)); - assertThat(reportingUserRole.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(index), is(false)); - assertThat(reportingUserRole.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(index), is(false)); - assertThat(reportingUserRole.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME).test(index), is(false)); - assertThat(reportingUserRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(index), is(false)); - assertThat(reportingUserRole.indices().allowedIndicesMatcher(GetAction.NAME).test(index), is(false)); - assertThat(reportingUserRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(index), is(false)); - assertThat(reportingUserRole.indices().allowedIndicesMatcher(UpdateAction.NAME).test(index), is(false)); - assertThat(reportingUserRole.indices().allowedIndicesMatcher(DeleteAction.NAME).test(index), is(false)); - assertThat(reportingUserRole.indices().allowedIndicesMatcher(BulkAction.NAME).test(index), is(false)); + assertThat(reportingUserRole.indices().allowedIndicesMatcher("indices:foo").test(mockIndexAbstraction(index)), is(false)); + assertThat(reportingUserRole.indices().allowedIndicesMatcher("indices:bar").test(mockIndexAbstraction(index)), is(false)); + assertThat(reportingUserRole.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(reportingUserRole.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(reportingUserRole.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME) + .test(mockIndexAbstraction(index)), is(false)); + assertThat(reportingUserRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(reportingUserRole.indices().allowedIndicesMatcher(GetAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(reportingUserRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(reportingUserRole.indices().allowedIndicesMatcher(UpdateAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(reportingUserRole.indices().allowedIndicesMatcher(DeleteAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(reportingUserRole.indices().allowedIndicesMatcher(BulkAction.NAME).test(mockIndexAbstraction(index)), is(false)); assertNoAccessAllowed(reportingUserRole, RestrictedIndicesNames.RESTRICTED_NAMES); assertNoAccessAllowed(reportingUserRole, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)); @@ -979,9 +1031,9 @@ public void testSuperuserRole() { assertThat(superuserRole.runAs().check(randomAlphaOfLengthBetween(1, 30)), is(true)); assertThat(superuserRole.indices().allowedIndicesMatcher(randomFrom(IndexAction.NAME, DeleteIndexAction.NAME, SearchAction.NAME)) - .test(RestrictedIndicesNames.SECURITY_MAIN_ALIAS), is(true)); + .test(mockIndexAbstraction(RestrictedIndicesNames.SECURITY_MAIN_ALIAS)), is(true)); assertThat(superuserRole.indices().allowedIndicesMatcher(randomFrom(IndexAction.NAME, DeleteIndexAction.NAME, SearchAction.NAME)) - .test(internalSecurityIndex), is(true)); + .test(mockIndexAbstraction(internalSecurityIndex)), is(true)); } public void testLogstashSystemRole() { @@ -1004,10 +1056,11 @@ public void testLogstashSystemRole() { assertThat(logstashSystemRole.runAs().check(randomAlphaOfLengthBetween(1, 30)), is(false)); - assertThat(logstashSystemRole.indices().allowedIndicesMatcher(IndexAction.NAME).test("foo"), is(false)); - assertThat(logstashSystemRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(".reporting"), is(false)); - assertThat(logstashSystemRole.indices().allowedIndicesMatcher("indices:foo").test(randomAlphaOfLengthBetween(8, 24)), - is(false)); + assertThat(logstashSystemRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction("foo")), is(false)); + assertThat(logstashSystemRole.indices().allowedIndicesMatcher(IndexAction.NAME) + .test(mockIndexAbstraction(".reporting")), is(false)); + assertThat(logstashSystemRole.indices().allowedIndicesMatcher("indices:foo") + .test(mockIndexAbstraction(randomAlphaOfLengthBetween(8, 24))), is(false)); assertNoAccessAllowed(logstashSystemRole, RestrictedIndicesNames.RESTRICTED_NAMES); assertNoAccessAllowed(logstashSystemRole, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)); @@ -1034,21 +1087,21 @@ public void testBeatsAdminRole() { assertThat(beatsAdminRole.runAs().check(randomAlphaOfLengthBetween(1, 30)), is(false)); - assertThat(beatsAdminRole.indices().allowedIndicesMatcher("indices:foo").test(randomAlphaOfLengthBetween(8, 24)), - is(false)); + assertThat(beatsAdminRole.indices().allowedIndicesMatcher("indices:foo") + .test(mockIndexAbstraction(randomAlphaOfLengthBetween(8, 24))), is(false)); final String index = ".management-beats"; logger.info("index name [{}]", index); - assertThat(beatsAdminRole.indices().allowedIndicesMatcher("indices:foo").test(index), is(true)); - assertThat(beatsAdminRole.indices().allowedIndicesMatcher("indices:bar").test(index), is(true)); - assertThat(beatsAdminRole.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(index), is(true)); - assertThat(beatsAdminRole.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(index), is(true)); - assertThat(beatsAdminRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(index), is(true)); - assertThat(beatsAdminRole.indices().allowedIndicesMatcher(DeleteAction.NAME).test(index), is(true)); - assertThat(beatsAdminRole.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME).test(index), is(true)); - assertThat(beatsAdminRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(index), is(true)); - assertThat(beatsAdminRole.indices().allowedIndicesMatcher(MultiSearchAction.NAME).test(index), is(true)); - assertThat(beatsAdminRole.indices().allowedIndicesMatcher(GetAction.NAME).test(index), is(true)); + assertThat(beatsAdminRole.indices().allowedIndicesMatcher("indices:foo").test(mockIndexAbstraction(index)), is(true)); + assertThat(beatsAdminRole.indices().allowedIndicesMatcher("indices:bar").test(mockIndexAbstraction(index)), is(true)); + assertThat(beatsAdminRole.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(beatsAdminRole.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(beatsAdminRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(beatsAdminRole.indices().allowedIndicesMatcher(DeleteAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(beatsAdminRole.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(beatsAdminRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(beatsAdminRole.indices().allowedIndicesMatcher(MultiSearchAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(beatsAdminRole.indices().allowedIndicesMatcher(GetAction.NAME).test(mockIndexAbstraction(index)), is(true)); assertNoAccessAllowed(beatsAdminRole, RestrictedIndicesNames.RESTRICTED_NAMES); assertNoAccessAllowed(beatsAdminRole, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)); @@ -1077,14 +1130,14 @@ public void testBeatsSystemRole() { final String index = ".monitoring-beats-" + randomIntBetween(0, 5);; logger.info("beats monitoring index name [{}]", index); - assertThat(beatsSystemRole.indices().allowedIndicesMatcher(IndexAction.NAME).test("foo"), is(false)); - assertThat(beatsSystemRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(".reporting"), is(false)); - assertThat(beatsSystemRole.indices().allowedIndicesMatcher("indices:foo").test(randomAlphaOfLengthBetween(8, 24)), - is(false)); - assertThat(beatsSystemRole.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(index), is(true)); - assertThat(beatsSystemRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(index), is(true)); - assertThat(beatsSystemRole.indices().allowedIndicesMatcher(DeleteAction.NAME).test(index), is(false)); - assertThat(beatsSystemRole.indices().allowedIndicesMatcher(BulkAction.NAME).test(index), is(true)); + assertThat(beatsSystemRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction("foo")), is(false)); + assertThat(beatsSystemRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction(".reporting")), is(false)); + assertThat(beatsSystemRole.indices().allowedIndicesMatcher("indices:foo") + .test(mockIndexAbstraction(randomAlphaOfLengthBetween(8, 24))), is(false)); + assertThat(beatsSystemRole.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(beatsSystemRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(beatsSystemRole.indices().allowedIndicesMatcher(DeleteAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(beatsSystemRole.indices().allowedIndicesMatcher(BulkAction.NAME).test(mockIndexAbstraction(index)), is(true)); assertNoAccessAllowed(beatsSystemRole, RestrictedIndicesNames.RESTRICTED_NAMES); assertNoAccessAllowed(beatsSystemRole, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)); @@ -1110,22 +1163,24 @@ public void testAPMSystemRole() { assertThat(APMSystemRole.runAs().check(randomAlphaOfLengthBetween(1, 30)), is(false)); - assertThat(APMSystemRole.indices().allowedIndicesMatcher(IndexAction.NAME).test("foo"), is(false)); - assertThat(APMSystemRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(".reporting"), is(false)); - assertThat(APMSystemRole.indices().allowedIndicesMatcher("indices:foo").test(randomAlphaOfLengthBetween(8, 24)), - is(false)); + assertThat(APMSystemRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction("foo")), is(false)); + assertThat(APMSystemRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction(".reporting")), is(false)); + assertThat(APMSystemRole.indices().allowedIndicesMatcher("indices:foo") + .test(mockIndexAbstraction(randomAlphaOfLengthBetween(8, 24))), is(false)); final String index = ".monitoring-beats-" + randomIntBetween(10, 15); logger.info("APM beats monitoring index name [{}]", index); - assertThat(APMSystemRole.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(index), is(true)); - assertThat(APMSystemRole.indices().allowedIndicesMatcher("indices:data/write/index:op_type/create").test(index), is(true)); - assertThat(APMSystemRole.indices().allowedIndicesMatcher(DeleteAction.NAME).test(index), is(false)); - assertThat(APMSystemRole.indices().allowedIndicesMatcher(BulkAction.NAME).test(index), is(true)); + assertThat(APMSystemRole.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(APMSystemRole.indices().allowedIndicesMatcher("indices:data/write/index:op_type/create") + .test(mockIndexAbstraction(index)), is(true)); + assertThat(APMSystemRole.indices().allowedIndicesMatcher(DeleteAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(APMSystemRole.indices().allowedIndicesMatcher(BulkAction.NAME).test(mockIndexAbstraction(index)), is(true)); - assertThat(APMSystemRole.indices().allowedIndicesMatcher("indices:data/write/index:op_type/index").test(index), is(false)); + assertThat(APMSystemRole.indices().allowedIndicesMatcher("indices:data/write/index:op_type/index") + .test(mockIndexAbstraction(index)), is(false)); assertThat(APMSystemRole.indices().allowedIndicesMatcher( - "indices:data/write/index:op_type/" + randomAlphaOfLengthBetween(3,5)).test(index), is(false)); + "indices:data/write/index:op_type/" + randomAlphaOfLengthBetween(3,5)).test(mockIndexAbstraction(index)), is(false)); assertNoAccessAllowed(APMSystemRole, RestrictedIndicesNames.RESTRICTED_NAMES); assertNoAccessAllowed(APMSystemRole, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)); @@ -1484,7 +1539,7 @@ public void testWatcherAdminRole() { assertThat(role.runAs().check(randomAlphaOfLengthBetween(1, 30)), is(false)); - assertThat(role.indices().allowedIndicesMatcher(IndexAction.NAME).test("foo"), is(false)); + assertThat(role.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction("foo")), is(false)); ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC); String historyIndex = HistoryStoreField.getHistoryIndexNameForTime(now); @@ -1517,8 +1572,9 @@ public void testWatcherUserRole() { assertThat(role.runAs().check(randomAlphaOfLengthBetween(1, 30)), is(false)); - assertThat(role.indices().allowedIndicesMatcher(IndexAction.NAME).test("foo"), is(false)); - assertThat(role.indices().allowedIndicesMatcher(IndexAction.NAME).test(TriggeredWatchStoreField.INDEX_NAME), is(false)); + assertThat(role.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction("foo")), is(false)); + assertThat(role.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction(TriggeredWatchStoreField.INDEX_NAME)), + is(false)); ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC); String historyIndex = HistoryStoreField.getHistoryIndexNameForTime(now); @@ -1531,25 +1587,25 @@ public void testWatcherUserRole() { } private void assertReadWriteDocsButNotDeleteIndexAllowed(Role role, String index) { - assertThat(role.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(index), is(false)); - assertThat(role.indices().allowedIndicesMatcher(SearchAction.NAME).test(index), is(true)); - assertThat(role.indices().allowedIndicesMatcher(GetAction.NAME).test(index), is(true)); - assertThat(role.indices().allowedIndicesMatcher(IndexAction.NAME).test(index), is(true)); - assertThat(role.indices().allowedIndicesMatcher(UpdateAction.NAME).test(index), is(true)); - assertThat(role.indices().allowedIndicesMatcher(DeleteAction.NAME).test(index), is(true)); - assertThat(role.indices().allowedIndicesMatcher(BulkAction.NAME).test(index), is(true)); + assertThat(role.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(role.indices().allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(role.indices().allowedIndicesMatcher(GetAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(role.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(role.indices().allowedIndicesMatcher(UpdateAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(role.indices().allowedIndicesMatcher(DeleteAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(role.indices().allowedIndicesMatcher(BulkAction.NAME).test(mockIndexAbstraction(index)), is(true)); } private void assertOnlyReadAllowed(Role role, String index) { - assertThat(role.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(index), is(false)); - assertThat(role.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(index), is(false)); - assertThat(role.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME).test(index), is(false)); - assertThat(role.indices().allowedIndicesMatcher(SearchAction.NAME).test(index), is(true)); - assertThat(role.indices().allowedIndicesMatcher(GetAction.NAME).test(index), is(true)); - assertThat(role.indices().allowedIndicesMatcher(IndexAction.NAME).test(index), is(false)); - assertThat(role.indices().allowedIndicesMatcher(UpdateAction.NAME).test(index), is(false)); - assertThat(role.indices().allowedIndicesMatcher(DeleteAction.NAME).test(index), is(false)); - assertThat(role.indices().allowedIndicesMatcher(BulkAction.NAME).test(index), is(false)); + assertThat(role.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(role.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(role.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(role.indices().allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(role.indices().allowedIndicesMatcher(GetAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(role.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(role.indices().allowedIndicesMatcher(UpdateAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(role.indices().allowedIndicesMatcher(DeleteAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(role.indices().allowedIndicesMatcher(BulkAction.NAME).test(mockIndexAbstraction(index)), is(false)); assertNoAccessAllowed(role, RestrictedIndicesNames.RESTRICTED_NAMES); assertNoAccessAllowed(role, RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)); @@ -1562,15 +1618,15 @@ private void assertNoAccessAllowed(Role role, Collection indices) { } private void assertNoAccessAllowed(Role role, String index) { - assertThat(role.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(index), is(false)); - assertThat(role.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(index), is(false)); - assertThat(role.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME).test(index), is(false)); - assertThat(role.indices().allowedIndicesMatcher(SearchAction.NAME).test(index), is(false)); - assertThat(role.indices().allowedIndicesMatcher(GetAction.NAME).test(index), is(false)); - assertThat(role.indices().allowedIndicesMatcher(IndexAction.NAME).test(index), is(false)); - assertThat(role.indices().allowedIndicesMatcher(UpdateAction.NAME).test(index), is(false)); - assertThat(role.indices().allowedIndicesMatcher(DeleteAction.NAME).test(index), is(false)); - assertThat(role.indices().allowedIndicesMatcher(BulkAction.NAME).test(index), is(false)); + assertThat(role.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(role.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(role.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(role.indices().allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(role.indices().allowedIndicesMatcher(GetAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(role.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(role.indices().allowedIndicesMatcher(UpdateAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(role.indices().allowedIndicesMatcher(DeleteAction.NAME).test(mockIndexAbstraction(index)), is(false)); + assertThat(role.indices().allowedIndicesMatcher(BulkAction.NAME).test(mockIndexAbstraction(index)), is(false)); } public void testLogstashAdminRole() { @@ -1590,21 +1646,30 @@ public void testLogstashAdminRole() { assertThat(logstashAdminRole.runAs().check(randomAlphaOfLengthBetween(1, 30)), is(false)); - assertThat(logstashAdminRole.indices().allowedIndicesMatcher(IndexAction.NAME).test("foo"), is(false)); - assertThat(logstashAdminRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(".reporting"), is(false)); - assertThat(logstashAdminRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(".logstash"), is(true)); - assertThat(logstashAdminRole.indices().allowedIndicesMatcher("indices:foo").test(randomAlphaOfLengthBetween(8, 24)), - is(false)); + assertThat(logstashAdminRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction("foo")), is(false)); + assertThat(logstashAdminRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction(".reporting")), is(false)); + assertThat(logstashAdminRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction(".logstash")), is(true)); + assertThat(logstashAdminRole.indices().allowedIndicesMatcher("indices:foo").test( + mockIndexAbstraction(randomAlphaOfLengthBetween(8, 24))), is(false)); final String index = ".logstash-" + randomIntBetween(0, 5); - assertThat(logstashAdminRole.indices().allowedIndicesMatcher(DeleteAction.NAME).test(index), is(true)); - assertThat(logstashAdminRole.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(index), is(true)); - assertThat(logstashAdminRole.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(index), is(true)); - assertThat(logstashAdminRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(index), is(true)); - assertThat(logstashAdminRole.indices().allowedIndicesMatcher(GetAction.NAME).test(index), is(true)); - assertThat(logstashAdminRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(index), is(true)); - assertThat(logstashAdminRole.indices().allowedIndicesMatcher(MultiSearchAction.NAME).test(index), is(true)); - assertThat(logstashAdminRole.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME).test(index), is(true)); + assertThat(logstashAdminRole.indices().allowedIndicesMatcher(DeleteAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(logstashAdminRole.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(logstashAdminRole.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(logstashAdminRole.indices().allowedIndicesMatcher(IndexAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(logstashAdminRole.indices().allowedIndicesMatcher(GetAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(logstashAdminRole.indices().allowedIndicesMatcher(SearchAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(logstashAdminRole.indices().allowedIndicesMatcher(MultiSearchAction.NAME).test(mockIndexAbstraction(index)), is(true)); + assertThat(logstashAdminRole.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME).test(mockIndexAbstraction(index)), + is(true)); + } + + private IndexAbstraction mockIndexAbstraction(String name) { + IndexAbstraction mock = mock(IndexAbstraction.class); + when(mock.getName()).thenReturn(name); + when(mock.getType()).thenReturn(randomFrom(IndexAbstraction.Type.CONCRETE_INDEX, + IndexAbstraction.Type.ALIAS, IndexAbstraction.Type.DATA_STREAM)); + return mock; } } diff --git a/x-pack/plugin/ml/qa/ml-with-security/roles.yml b/x-pack/plugin/ml/qa/ml-with-security/roles.yml index 18dcc435421ec..5407121ad705d 100644 --- a/x-pack/plugin/ml/qa/ml-with-security/roles.yml +++ b/x-pack/plugin/ml/qa/ml-with-security/roles.yml @@ -12,7 +12,7 @@ minimal: - create_index - indices:admin/refresh - read - - index + - write - view_index_metadata - indices:data/write/bulk - indices:data/write/index diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/RBACEngine.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/RBACEngine.java index d48275b0da5fd..12f7884b7debb 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/RBACEngine.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/RBACEngine.java @@ -494,7 +494,7 @@ GetUserPrivilegesResponse buildUserPrivilegesResponseObject(Role userRole) { } static List resolveAuthorizedIndicesFromRole(Role role, RequestInfo requestInfo, Map lookup) { - Predicate predicate = role.allowedIndicesMatcher(requestInfo.getAction()); + Predicate predicate = role.allowedIndicesMatcher(requestInfo.getAction()); // do not include data streams for actions that do not operate on data streams TransportRequest request = requestInfo.getRequest(); @@ -503,15 +503,15 @@ static List resolveAuthorizedIndicesFromRole(Role role, RequestInfo requ Set indicesAndAliases = new HashSet<>(); // TODO: can this be done smarter? I think there are usually more indices/aliases in the cluster then indices defined a roles? for (Map.Entry entry : lookup.entrySet()) { - String indexAbstraction = entry.getKey(); + IndexAbstraction indexAbstraction = entry.getValue(); if (predicate.test(indexAbstraction)) { - if (entry.getValue().getType() != IndexAbstraction.Type.DATA_STREAM) { - indicesAndAliases.add(indexAbstraction); + if (indexAbstraction.getType() != IndexAbstraction.Type.DATA_STREAM) { + indicesAndAliases.add(indexAbstraction.getName()); } else if (includeDataStreams) { // add data stream and its backing indices for any authorized data streams - indicesAndAliases.addAll(entry.getValue().getIndices().stream() + indicesAndAliases.add(indexAbstraction.getName()); + indicesAndAliases.addAll(indexAbstraction.getIndices().stream() .map(i -> i.getIndex().getName()).collect(Collectors.toList())); - indicesAndAliases.add(indexAbstraction); } } } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/integration/AbstractPrivilegeTestCase.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/integration/AbstractPrivilegeTestCase.java index 9317e9f8dcb5a..35cc53a8e143f 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/integration/AbstractPrivilegeTestCase.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/integration/AbstractPrivilegeTestCase.java @@ -29,7 +29,7 @@ */ public abstract class AbstractPrivilegeTestCase extends SecuritySingleNodeTestCase { - protected void assertAccessIsAllowed(String user, Request request) throws IOException { + protected Response assertAccessIsAllowed(String user, Request request) throws IOException { setUser(request, user); Response response = getRestClient().performRequest(request); StatusLine statusLine = response.getStatusLine(); @@ -37,12 +37,13 @@ protected void assertAccessIsAllowed(String user, Request request) throws IOExce request.getMethod(), request.getEndpoint(), statusLine.getStatusCode(), statusLine.getReasonPhrase(), EntityUtils.toString(response.getEntity())); assertThat(message, statusLine.getStatusCode(), is(not(greaterThanOrEqualTo(400)))); + return response; } - protected void assertAccessIsAllowed(String user, String method, String uri, String body) throws IOException { + protected Response assertAccessIsAllowed(String user, String method, String uri, String body) throws IOException { Request request = new Request(method, uri); request.setJsonEntity(body); - assertAccessIsAllowed(user, request); + return assertAccessIsAllowed(user, request); } protected void assertAccessIsAllowed(String user, String method, String uri) throws IOException { diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/integration/IndexPrivilegeTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/integration/IndexPrivilegeTests.java index 880186f0dbb03..b81521f91888f 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/integration/IndexPrivilegeTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/integration/IndexPrivilegeTests.java @@ -7,7 +7,9 @@ import org.elasticsearch.client.Request; import org.elasticsearch.client.RequestOptions; +import org.elasticsearch.client.Response; import org.elasticsearch.client.ResponseException; +import org.elasticsearch.common.UUIDs; import org.elasticsearch.common.settings.SecureString; import org.elasticsearch.xpack.core.security.authc.support.Hasher; import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken; @@ -16,6 +18,7 @@ import java.util.Locale; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoTimeout; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; public class IndexPrivilegeTests extends AbstractPrivilegeTestCase { @@ -504,7 +507,8 @@ private void assertUserExecutes(String user, String action, String index, boolea case "crud" : if (userIsAllowed) { assertUserIsAllowed(user, "read", index); - assertUserIsAllowed(user, "index", index); + assertAccessIsAllowed(user, "PUT", "/" + index + "/_doc/321", "{ \"foo\" : \"bar\" }"); + assertAccessIsAllowed(user, "POST", "/" + index + "/_update/321", "{ \"doc\" : { \"foo\" : \"baz\" } }"); } else { assertUserIsDenied(user, "read", index); assertUserIsDenied(user, "index", index); @@ -548,11 +552,25 @@ private void assertUserExecutes(String user, String action, String index, boolea case "index" : if (userIsAllowed) { - assertAccessIsAllowed(user, "PUT", "/" + index + "/_doc/321", "{ \"foo\" : \"bar\" }"); - assertAccessIsAllowed(user, "POST", "/" + index + "/_update/321", "{ \"doc\" : { \"foo\" : \"baz\" } }"); + assertAccessIsAllowed(user, "PUT", "/" + index + "/_doc/321", "{ \"foo\" : \"bar\" }"); + // test auto mapping update is allowed but deprecated + Response response = assertAccessIsAllowed(user, "PUT", "/" + index + "/_doc/4321", "{ \"" + + UUIDs.randomBase64UUID() + "\" : \"foo\" }"); + String warningHeader = response.getHeader("Warning"); + assertThat(warningHeader, containsString("the index privilege [index] allowed the update mapping action " + + "[indices:admin/mapping/auto_put] on index [" + index + "], this privilege will not permit mapping updates in" + + " the next major release - users who require access to update mappings must be granted explicit privileges")); + assertAccessIsAllowed(user, "POST", "/" + index + "/_update/321", "{ \"doc\" : { \"foo\" : \"baz\" } }"); + response = assertAccessIsAllowed(user, "POST", "/" + index + "/_update/321", + "{ \"doc\" : { \"" + UUIDs.randomBase64UUID() + "\" : \"baz\" } }"); + warningHeader = response.getHeader("Warning"); + assertThat(warningHeader, containsString("the index privilege [index] allowed the update mapping action " + + "[indices:admin/mapping/auto_put] on index [" + index + "], this privilege will not permit mapping updates in" + + " the next major release - users who require access to update mappings must be granted explicit privileges")); } else { - assertAccessIsDenied(user, "PUT", "/" + index + "/_doc/321", "{ \"foo\" : \"bar\" }"); - assertAccessIsDenied(user, "POST", "/" + index + "/_update/321", "{ \"doc\" : { \"foo\" : \"baz\" } }"); + assertAccessIsDenied(user, "PUT", "/" + index + "/_doc/321", "{ \"foo\" : \"bar\" }"); + assertAccessIsDenied(user, "PUT", "/" + index + "/_doc/321", "{ \"foo\" : \"bar\" }"); + assertAccessIsDenied(user, "POST", "/" + index + "/_update/321", "{ \"doc\" : { \"foo\" : \"baz\" } }"); } break; @@ -569,8 +587,21 @@ private void assertUserExecutes(String user, String action, String index, boolea case "write" : if (userIsAllowed) { - assertUserIsAllowed(user, "index", index); assertUserIsAllowed(user, "delete", index); + + assertAccessIsAllowed(user, "PUT", "/" + index + "/_doc/321", "{ \"foo\" : \"bar\" }"); + // test auto mapping update is allowed but deprecated + Response response = assertAccessIsAllowed(user, "PUT", "/" + index + "/_doc/4321", "{ \"" + + UUIDs.randomBase64UUID() + "\" : \"foo\" }"); + String warningHeader = response.getHeader("Warning"); + assertThat(warningHeader, containsString("the index privilege [write] allowed the update mapping action [" + + "indices:admin/mapping/auto_put] on index [" + index + "]")); + assertAccessIsAllowed(user, "POST", "/" + index + "/_update/321", "{ \"doc\" : { \"foo\" : \"baz\" } }"); + response = assertAccessIsAllowed(user, "POST", "/" + index + "/_update/321", + "{ \"doc\" : { \"" + UUIDs.randomBase64UUID() + "\" : \"baz\" } }"); + warningHeader = response.getHeader("Warning"); + assertThat(warningHeader, containsString("the index privilege [write] allowed the update mapping action [" + + "indices:admin/mapping/auto_put] on index [" + index + "]")); } else { assertUserIsDenied(user, "index", index); assertUserIsDenied(user, "delete", index); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/RBACEngineTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/RBACEngineTests.java index 8908762ca7a1d..e7d32a2686e68 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/RBACEngineTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/RBACEngineTests.java @@ -9,6 +9,8 @@ import org.elasticsearch.action.admin.cluster.health.ClusterHealthAction; import org.elasticsearch.action.admin.cluster.state.ClusterStateAction; import org.elasticsearch.action.admin.cluster.stats.ClusterStatsAction; +import org.elasticsearch.action.admin.indices.mapping.put.PutMappingAction; +import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; import org.elasticsearch.action.delete.DeleteAction; import org.elasticsearch.action.index.IndexAction; import org.elasticsearch.action.search.SearchAction; @@ -24,6 +26,7 @@ import org.elasticsearch.common.collect.MapBuilder; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.set.Sets; +import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.license.GetLicenseAction; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.transport.TransportRequest; @@ -1074,6 +1077,40 @@ public void testBackingIndicesAreIncludedForAuthorizedDataStreams() { .map(im -> im.getIndex().getName()).collect(Collectors.toList()).toArray(Strings.EMPTY_ARRAY))); } + public void testExplicitMappingUpdatesAreNotGrantedWithIngestPrivileges() { + final String dataStreamName = "my_data_stream"; + User user = new User(randomAlphaOfLengthBetween(4, 12)); + Authentication authentication = mock(Authentication.class); + when(authentication.getUser()).thenReturn(user); + Role role = Role.builder("test1") + .cluster(Collections.emptySet(), Collections.emptyList()) + .add(IndexPrivilege.CREATE, "my_*") + .add(IndexPrivilege.WRITE, "my_data*") + .build(); + + TreeMap lookup = new TreeMap<>(); + List backingIndices = new ArrayList<>(); + int numBackingIndices = randomIntBetween(1, 3); + for (int k = 0; k < numBackingIndices; k++) { + backingIndices.add(DataStreamTestHelper.createBackingIndex(dataStreamName, k + 1).build()); + } + DataStream ds = new DataStream(dataStreamName, null, + backingIndices.stream().map(IndexMetadata::getIndex).collect(Collectors.toList())); + IndexAbstraction.DataStream iads = new IndexAbstraction.DataStream(ds, backingIndices); + lookup.put(ds.getName(), iads); + for (IndexMetadata im : backingIndices) { + lookup.put(im.getIndex().getName(), new IndexAbstraction.Index(im, iads)); + } + + PutMappingRequest request = new PutMappingRequest("*"); + request.source("{ \"properties\": { \"message\": { \"type\": \"text\" } } }", + XContentType.JSON + ); + List authorizedIndices = + RBACEngine.resolveAuthorizedIndicesFromRole(role, getRequestInfo(request, PutMappingAction.NAME), lookup); + assertThat(authorizedIndices.isEmpty(), is(true)); + } + private GetUserPrivilegesResponse.Indices findIndexPrivilege(Set indices, String name) { return indices.stream().filter(i -> i.getIndices().contains(name)).findFirst().get(); } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/accesscontrol/IndicesPermissionTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/accesscontrol/IndicesPermissionTests.java index e3e1967144f66..347e9087664ff 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/accesscontrol/IndicesPermissionTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/accesscontrol/IndicesPermissionTests.java @@ -7,6 +7,8 @@ import org.elasticsearch.ElasticsearchSecurityException; import org.elasticsearch.Version; +import org.elasticsearch.action.admin.indices.mapping.put.AutoPutMappingAction; +import org.elasticsearch.action.admin.indices.mapping.put.PutMappingAction; import org.elasticsearch.action.search.SearchAction; import org.elasticsearch.cluster.metadata.AliasMetadata; import org.elasticsearch.cluster.metadata.DataStream; @@ -243,7 +245,7 @@ public void testCorePermissionAuthorize() { FieldPermissionsCache fieldPermissionsCache = new FieldPermissionsCache(Settings.EMPTY); IndicesPermission.Group group1 = new IndicesPermission.Group(IndexPrivilege.ALL, new FieldPermissions(), null, randomBoolean(), "a1"); - IndicesPermission.Group group2 = new IndicesPermission.Group(IndexPrivilege.ALL, + IndicesPermission.Group group2 = new IndicesPermission.Group(IndexPrivilege.READ, new FieldPermissions(fieldPermissionDef(null, new String[]{"denied_field"})), null, randomBoolean(), "a1"); IndicesPermission core = new IndicesPermission(group1, group2); Map authzMap = @@ -254,6 +256,8 @@ public void testCorePermissionAuthorize() { assertFalse(authzMap.get("ba").getFieldPermissions().hasFieldLevelSecurity()); assertTrue(core.check(SearchAction.NAME)); + assertTrue(core.check(PutMappingAction.NAME)); + assertTrue(core.check(AutoPutMappingAction.NAME)); assertFalse(core.check("unknown")); // test with two indices @@ -276,6 +280,8 @@ public void testCorePermissionAuthorize() { assertTrue(authzMap.get("a2").getFieldPermissions().hasFieldLevelSecurity()); assertTrue(core.check(SearchAction.NAME)); + assertTrue(core.check(PutMappingAction.NAME)); + assertTrue(core.check(AutoPutMappingAction.NAME)); assertFalse(core.check("unknown")); } @@ -369,17 +375,97 @@ public void testAuthorizationForBackingIndices() { FieldPermissionsCache fieldPermissionsCache = new FieldPermissionsCache(Settings.EMPTY); SortedMap lookup = metadata.getIndicesLookup(); - IndicesPermission.Group group = new IndicesPermission.Group(IndexPrivilege.ALL, new FieldPermissions(), null, false, - dataStreamName); + IndicesPermission.Group group = new IndicesPermission.Group(IndexPrivilege.READ, new FieldPermissions(), null, false, + dataStreamName); Map authzMap = new IndicesPermission(group).authorize( - SearchAction.NAME, - Sets.newHashSet(backingIndices.stream().map(im -> im.getIndex().getName()).collect(Collectors.toList())), - lookup, - fieldPermissionsCache); + SearchAction.NAME, + Sets.newHashSet(backingIndices.stream().map(im -> im.getIndex().getName()).collect(Collectors.toList())), + lookup, + fieldPermissionsCache); + + for (IndexMetadata im : backingIndices) { + assertThat(authzMap.get(im.getIndex().getName()).isGranted(), is(true)); + } + + group = new IndicesPermission.Group(IndexPrivilege.CREATE_DOC, new FieldPermissions(), null, false, dataStreamName); + authzMap = new IndicesPermission(group).authorize( + randomFrom(PutMappingAction.NAME, AutoPutMappingAction.NAME), + Sets.newHashSet(backingIndices.stream().map(im -> im.getIndex().getName()).collect(Collectors.toList())), + lookup, + fieldPermissionsCache); + + for (IndexMetadata im : backingIndices) { + assertThat(authzMap.get(im.getIndex().getName()).isGranted(), is(false)); + } + } + + public void testAuthorizationForMappingUpdates() { + final Settings indexSettings = Settings.builder().put("index.version.created", Version.CURRENT).build(); + final Metadata.Builder metadata = new Metadata.Builder() + .put(new IndexMetadata.Builder("test1").settings(indexSettings).numberOfShards(1).numberOfReplicas(0).build(), true) + .put(new IndexMetadata.Builder("test_write1").settings(indexSettings).numberOfShards(1).numberOfReplicas(0).build(), true); + + int numBackingIndices = randomIntBetween(1, 3); + List backingIndices = new ArrayList<>(); + for (int backingIndexNumber = 1; backingIndexNumber <= numBackingIndices; backingIndexNumber++) { + backingIndices.add(createIndexMetadata(DataStream.getDefaultBackingIndexName("test_write2", backingIndexNumber))); + } + DataStream ds = new DataStream("test_write2", createTimestampField("@timestamp"), + backingIndices.stream().map(IndexMetadata::getIndex).collect(Collectors.toList())); + metadata.put(ds); + for (IndexMetadata index : backingIndices) { + metadata.put(index, false); + } + + SortedMap lookup = metadata.build().getIndicesLookup(); + FieldPermissionsCache fieldPermissionsCache = new FieldPermissionsCache(Settings.EMPTY); + IndicesPermission.Group group1 = new IndicesPermission.Group(IndexPrivilege.INDEX, new FieldPermissions(), null, randomBoolean(), + "test*"); + IndicesPermission.Group group2 = new IndicesPermission.Group(IndexPrivilege.WRITE, + new FieldPermissions(fieldPermissionDef(null, new String[]{"denied_field"})), null, randomBoolean(), "test_write*"); + IndicesPermission core = new IndicesPermission(group1, group2); + Map authzMap = + core.authorize(PutMappingAction.NAME, Sets.newHashSet("test1", "test_write1"), lookup, fieldPermissionsCache); + assertThat(authzMap.get("test1").isGranted(), is(true)); + assertThat(authzMap.get("test_write1").isGranted(), is(true)); + assertWarnings("the index privilege [index] allowed the update mapping action [" + PutMappingAction.NAME + "] on " + + "index [test1], this privilege will not permit mapping updates in the next major release - " + + "users who require access to update mappings must be granted explicit privileges", + "the index privilege [index] allowed the update mapping action [" + PutMappingAction.NAME + "] on " + + "index [test_write1], this privilege will not permit mapping updates in the next major release - " + + "users who require access to update mappings must be granted explicit privileges", + "the index privilege [write] allowed the update mapping action [" + PutMappingAction.NAME + "] on " + + "index [test_write1], this privilege will not permit mapping updates in the next major release - " + + "users who require access to update mappings must be granted explicit privileges" + ); + authzMap = core.authorize(AutoPutMappingAction.NAME, Sets.newHashSet("test1", "test_write1"), lookup, fieldPermissionsCache); + assertThat(authzMap.get("test1").isGranted(), is(true)); + assertThat(authzMap.get("test_write1").isGranted(), is(true)); + assertWarnings("the index privilege [index] allowed the update mapping action [" + AutoPutMappingAction.NAME + "] on " + + "index [test1], this privilege will not permit mapping updates in the next major release - " + + "users who require access to update mappings must be granted explicit privileges"); + + authzMap = core.authorize(AutoPutMappingAction.NAME, Sets.newHashSet("test_write2"), lookup, fieldPermissionsCache); + assertThat(authzMap.get("test_write2").isGranted(), is(true)); + authzMap = core.authorize(PutMappingAction.NAME, Sets.newHashSet("test_write2"), lookup, fieldPermissionsCache); + assertThat(authzMap.get("test_write2").isGranted(), is(false)); + authzMap = core.authorize( + AutoPutMappingAction.NAME, + Sets.newHashSet(backingIndices.stream().map(im -> im.getIndex().getName()).collect(Collectors.toList())), + lookup, + fieldPermissionsCache); for (IndexMetadata im : backingIndices) { assertThat(authzMap.get(im.getIndex().getName()).isGranted(), is(true)); } + authzMap = core.authorize( + PutMappingAction.NAME, + Sets.newHashSet(backingIndices.stream().map(im -> im.getIndex().getName()).collect(Collectors.toList())), + lookup, + fieldPermissionsCache); + for (IndexMetadata im : backingIndices) { + assertThat(authzMap.get(im.getIndex().getName()).isGranted(), is(false)); + } } private static IndexMetadata createIndexMetadata(String name) { diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/permission/PermissionTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/permission/PermissionTests.java index 7dfd567b46033..969b9af250fa3 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/permission/PermissionTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/permission/PermissionTests.java @@ -5,18 +5,25 @@ */ package org.elasticsearch.xpack.security.authz.permission; +import org.elasticsearch.action.admin.indices.mapping.put.AutoPutMappingAction; +import org.elasticsearch.action.admin.indices.mapping.put.PutMappingAction; import org.elasticsearch.action.get.GetAction; +import org.elasticsearch.cluster.metadata.IndexAbstraction; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.core.security.authz.permission.Role; import org.elasticsearch.xpack.core.security.authz.privilege.Privilege; import org.junit.Before; +import java.util.List; import java.util.function.Predicate; +import static org.elasticsearch.xpack.core.security.authz.privilege.IndexPrivilege.CREATE; import static org.elasticsearch.xpack.core.security.authz.privilege.IndexPrivilege.MONITOR; import static org.elasticsearch.xpack.core.security.authz.privilege.IndexPrivilege.READ; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class PermissionTests extends ESTestCase { private Role permission; @@ -27,6 +34,7 @@ public void init() { builder.add(MONITOR, "test_*", "/foo.*/"); builder.add(READ, "baz_*foo", "/fool.*bar/"); builder.add(MONITOR, "/bar.*/"); + builder.add(CREATE, "ingest_foo*"); permission = builder.build(); } @@ -34,9 +42,28 @@ public void testAllowedIndicesMatcherAction() throws Exception { testAllowedIndicesMatcher(permission.indices().allowedIndicesMatcher(GetAction.NAME)); } + public void testAllowedIndicesMatcherForMappingUpdates() throws Exception { + for (String mappingUpdateActionName : List.of(PutMappingAction.NAME, AutoPutMappingAction.NAME)) { + IndexAbstraction mockIndexAbstraction = mock(IndexAbstraction.class); + Predicate indexPredicate = permission.indices().allowedIndicesMatcher(mappingUpdateActionName); + // mapping updates are still permitted on indices and aliases + when(mockIndexAbstraction.getName()).thenReturn("ingest_foo" + randomAlphaOfLength(3)); + when(mockIndexAbstraction.getType()).thenReturn(IndexAbstraction.Type.CONCRETE_INDEX); + assertThat(indexPredicate.test(mockIndexAbstraction), is(true)); + when(mockIndexAbstraction.getType()).thenReturn(IndexAbstraction.Type.ALIAS); + assertThat(indexPredicate.test(mockIndexAbstraction), is(true)); + // mapping updates are NOT permitted on data streams and backing indices + when(mockIndexAbstraction.getType()).thenReturn(IndexAbstraction.Type.DATA_STREAM); + assertThat(indexPredicate.test(mockIndexAbstraction), is(false)); + when(mockIndexAbstraction.getType()).thenReturn(IndexAbstraction.Type.CONCRETE_INDEX); + when(mockIndexAbstraction.getParentDataStream()).thenReturn(mock(IndexAbstraction.DataStream.class)); + assertThat(indexPredicate.test(mockIndexAbstraction), is(false)); + } + } + public void testAllowedIndicesMatcherActionCaching() throws Exception { - Predicate matcher1 = permission.indices().allowedIndicesMatcher(GetAction.NAME); - Predicate matcher2 = permission.indices().allowedIndicesMatcher(GetAction.NAME); + Predicate matcher1 = permission.indices().allowedIndicesMatcher(GetAction.NAME); + Predicate matcher2 = permission.indices().allowedIndicesMatcher(GetAction.NAME); assertThat(matcher1, is(matcher2)); } @@ -59,11 +86,19 @@ public void testRunAs() { } // "baz_*foo", "/fool.*bar/" - private void testAllowedIndicesMatcher(Predicate indicesMatcher) { - assertThat(indicesMatcher.test("foobar"), is(false)); - assertThat(indicesMatcher.test("fool"), is(false)); - assertThat(indicesMatcher.test("fool2bar"), is(true)); - assertThat(indicesMatcher.test("baz_foo"), is(true)); - assertThat(indicesMatcher.test("barbapapa"), is(false)); + private void testAllowedIndicesMatcher(Predicate indicesMatcher) { + assertThat(indicesMatcher.test(mockIndexAbstraction("foobar")), is(false)); + assertThat(indicesMatcher.test(mockIndexAbstraction("fool")), is(false)); + assertThat(indicesMatcher.test(mockIndexAbstraction("fool2bar")), is(true)); + assertThat(indicesMatcher.test(mockIndexAbstraction("baz_foo")), is(true)); + assertThat(indicesMatcher.test(mockIndexAbstraction("barbapapa")), is(false)); + } + + private IndexAbstraction mockIndexAbstraction(String name) { + IndexAbstraction mock = mock(IndexAbstraction.class); + when(mock.getName()).thenReturn(name); + when(mock.getType()).thenReturn(randomFrom(IndexAbstraction.Type.CONCRETE_INDEX, + IndexAbstraction.Type.ALIAS, IndexAbstraction.Type.DATA_STREAM)); + return mock; } } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/store/CompositeRolesStoreTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/store/CompositeRolesStoreTests.java index efd386c28807c..ccadcd9683428 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/store/CompositeRolesStoreTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/store/CompositeRolesStoreTests.java @@ -14,6 +14,7 @@ import org.elasticsearch.action.support.PlainActionFuture; import org.elasticsearch.client.Client; import org.elasticsearch.cluster.health.ClusterHealthStatus; +import org.elasticsearch.cluster.metadata.IndexAbstraction; import org.elasticsearch.cluster.metadata.IndexMetadata; import org.elasticsearch.cluster.metadata.Metadata; import org.elasticsearch.cluster.service.ClusterService; @@ -650,25 +651,25 @@ public ClusterPermission.Builder buildPermission(ClusterPermission.Builder build assertThat(role.cluster().check(PutUserAction.NAME, randomFrom(request1, request2), authentication), equalTo(true)); assertThat(role.cluster().check(PutUserAction.NAME, request3, authentication), equalTo(false)); - final Predicate allowedRead = role.indices().allowedIndicesMatcher(GetAction.NAME); - assertThat(allowedRead.test("abc-123"), equalTo(true)); - assertThat(allowedRead.test("xyz-000"), equalTo(true)); - assertThat(allowedRead.test("ind-1-a"), equalTo(true)); - assertThat(allowedRead.test("ind-2-a"), equalTo(true)); - assertThat(allowedRead.test("foo"), equalTo(false)); - assertThat(allowedRead.test("abc"), equalTo(false)); - assertThat(allowedRead.test("xyz"), equalTo(false)); - assertThat(allowedRead.test("ind-3-a"), equalTo(false)); - - final Predicate allowedWrite = role.indices().allowedIndicesMatcher(IndexAction.NAME); - assertThat(allowedWrite.test("abc-123"), equalTo(true)); - assertThat(allowedWrite.test("xyz-000"), equalTo(false)); - assertThat(allowedWrite.test("ind-1-a"), equalTo(true)); - assertThat(allowedWrite.test("ind-2-a"), equalTo(true)); - assertThat(allowedWrite.test("foo"), equalTo(false)); - assertThat(allowedWrite.test("abc"), equalTo(false)); - assertThat(allowedWrite.test("xyz"), equalTo(false)); - assertThat(allowedWrite.test("ind-3-a"), equalTo(false)); + final Predicate allowedRead = role.indices().allowedIndicesMatcher(GetAction.NAME); + assertThat(allowedRead.test(mockIndexAbstraction("abc-123")), equalTo(true)); + assertThat(allowedRead.test(mockIndexAbstraction("xyz-000")), equalTo(true)); + assertThat(allowedRead.test(mockIndexAbstraction("ind-1-a")), equalTo(true)); + assertThat(allowedRead.test(mockIndexAbstraction("ind-2-a")), equalTo(true)); + assertThat(allowedRead.test(mockIndexAbstraction("foo")), equalTo(false)); + assertThat(allowedRead.test(mockIndexAbstraction("abc")), equalTo(false)); + assertThat(allowedRead.test(mockIndexAbstraction("xyz")), equalTo(false)); + assertThat(allowedRead.test(mockIndexAbstraction("ind-3-a")), equalTo(false)); + + final Predicate allowedWrite = role.indices().allowedIndicesMatcher(IndexAction.NAME); + assertThat(allowedWrite.test(mockIndexAbstraction("abc-123")), equalTo(true)); + assertThat(allowedWrite.test(mockIndexAbstraction("xyz-000")), equalTo(false)); + assertThat(allowedWrite.test(mockIndexAbstraction("ind-1-a")), equalTo(true)); + assertThat(allowedWrite.test(mockIndexAbstraction("ind-2-a")), equalTo(true)); + assertThat(allowedWrite.test(mockIndexAbstraction("foo")), equalTo(false)); + assertThat(allowedWrite.test(mockIndexAbstraction("abc")), equalTo(false)); + assertThat(allowedWrite.test(mockIndexAbstraction("xyz")), equalTo(false)); + assertThat(allowedWrite.test(mockIndexAbstraction("ind-3-a")), equalTo(false)); role.application().grants(new ApplicationPrivilege("app1", "app1-read", "write"), "user/joe"); role.application().grants(new ApplicationPrivilege("app1", "app1-read", "read"), "settings/hostname"); @@ -1412,4 +1413,12 @@ public String getWriteableName() { public void writeTo(StreamOutput out) throws IOException { } } + + private IndexAbstraction mockIndexAbstraction(String name) { + IndexAbstraction mock = mock(IndexAbstraction.class); + when(mock.getName()).thenReturn(name); + when(mock.getType()).thenReturn(randomFrom(IndexAbstraction.Type.CONCRETE_INDEX, + IndexAbstraction.Type.ALIAS, IndexAbstraction.Type.DATA_STREAM)); + return mock; + } } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/user/AsyncSearchUserTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/user/AsyncSearchUserTests.java index 38722cf8a422a..f99e824f82a50 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/user/AsyncSearchUserTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/user/AsyncSearchUserTests.java @@ -12,6 +12,7 @@ import org.elasticsearch.action.get.GetAction; import org.elasticsearch.action.index.IndexAction; import org.elasticsearch.action.search.SearchAction; +import org.elasticsearch.cluster.metadata.IndexAbstraction; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.transport.TransportRequest; import org.elasticsearch.xpack.core.security.authc.Authentication; @@ -24,18 +25,19 @@ import java.util.function.Predicate; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class AsyncSearchUserTests extends ESTestCase { public void testAsyncSearchUserCannotAccessNonRestrictedIndices() { for (String action : Arrays.asList(GetAction.NAME, DeleteAction.NAME, SearchAction.NAME, IndexAction.NAME)) { - Predicate predicate = AsyncSearchUser.ROLE.indices().allowedIndicesMatcher(action); - String index = randomAlphaOfLengthBetween(3, 12); - if (false == RestrictedIndicesNames.isRestricted(index)) { + Predicate predicate = AsyncSearchUser.ROLE.indices().allowedIndicesMatcher(action); + IndexAbstraction index = mockIndexAbstraction(randomAlphaOfLengthBetween(3, 12)); + if (false == RestrictedIndicesNames.isRestricted(index.getName())) { assertThat(predicate.test(index), Matchers.is(false)); } - index = "." + randomAlphaOfLengthBetween(3, 12); - if (false == RestrictedIndicesNames.isRestricted(index)) { + index = mockIndexAbstraction("." + randomAlphaOfLengthBetween(3, 12)); + if (false == RestrictedIndicesNames.isRestricted(index.getName())) { assertThat(predicate.test(index), Matchers.is(false)); } } @@ -43,11 +45,12 @@ public void testAsyncSearchUserCannotAccessNonRestrictedIndices() { public void testAsyncSearchUserCanAccessOnlyAsyncSearchRestrictedIndices() { for (String action : Arrays.asList(GetAction.NAME, DeleteAction.NAME, SearchAction.NAME, IndexAction.NAME)) { - final Predicate predicate = AsyncSearchUser.ROLE.indices().allowedIndicesMatcher(action); + final Predicate predicate = AsyncSearchUser.ROLE.indices().allowedIndicesMatcher(action); for (String index : RestrictedIndicesNames.RESTRICTED_NAMES) { - assertThat(predicate.test(index), Matchers.is(false)); + assertThat(predicate.test(mockIndexAbstraction(index)), Matchers.is(false)); } - assertThat(predicate.test(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 3)), Matchers.is(true)); + assertThat(predicate.test(mockIndexAbstraction(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 3))), + Matchers.is(true)); } } @@ -57,4 +60,12 @@ public void testAsyncSearchUserHasNoClusterPrivileges() { Matchers.is(false)); } } + + private IndexAbstraction mockIndexAbstraction(String name) { + IndexAbstraction mock = mock(IndexAbstraction.class); + when(mock.getName()).thenReturn(name); + when(mock.getType()).thenReturn(randomFrom(IndexAbstraction.Type.CONCRETE_INDEX, + IndexAbstraction.Type.ALIAS, IndexAbstraction.Type.DATA_STREAM)); + return mock; + } } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/user/XPackUserTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/user/XPackUserTests.java index dc34ffad8d65f..39124e5f72d10 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/user/XPackUserTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/user/XPackUserTests.java @@ -10,6 +10,7 @@ import org.elasticsearch.action.index.IndexAction; import org.elasticsearch.action.search.SearchAction; import org.elasticsearch.action.update.UpdateAction; +import org.elasticsearch.cluster.metadata.IndexAbstraction; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.core.security.index.IndexAuditTrailField; import org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames; @@ -21,17 +22,20 @@ import java.util.Arrays; import java.util.function.Predicate; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + public class XPackUserTests extends ESTestCase { public void testXPackUserCanAccessNonSecurityIndices() { for (String action : Arrays.asList(GetAction.NAME, DeleteAction.NAME, SearchAction.NAME, IndexAction.NAME)) { - Predicate predicate = XPackUser.ROLE.indices().allowedIndicesMatcher(action); - String index = randomAlphaOfLengthBetween(3, 12); - if (false == RestrictedIndicesNames.isRestricted(index)) { + Predicate predicate = XPackUser.ROLE.indices().allowedIndicesMatcher(action); + IndexAbstraction index = mockIndexAbstraction(randomAlphaOfLengthBetween(3, 12)); + if (false == RestrictedIndicesNames.isRestricted(index.getName())) { assertThat(predicate.test(index), Matchers.is(true)); } - index = "." + randomAlphaOfLengthBetween(3, 12); - if (false == RestrictedIndicesNames.isRestricted(index)) { + index = mockIndexAbstraction("." + randomAlphaOfLengthBetween(3, 12)); + if (false == RestrictedIndicesNames.isRestricted(index.getName())) { assertThat(predicate.test(index), Matchers.is(true)); } } @@ -39,24 +43,25 @@ public void testXPackUserCanAccessNonSecurityIndices() { public void testXPackUserCannotAccessRestrictedIndices() { for (String action : Arrays.asList(GetAction.NAME, DeleteAction.NAME, SearchAction.NAME, IndexAction.NAME)) { - Predicate predicate = XPackUser.ROLE.indices().allowedIndicesMatcher(action); + Predicate predicate = XPackUser.ROLE.indices().allowedIndicesMatcher(action); for (String index : RestrictedIndicesNames.RESTRICTED_NAMES) { - assertThat(predicate.test(index), Matchers.is(false)); + assertThat(predicate.test(mockIndexAbstraction(index)), Matchers.is(false)); } - assertThat(predicate.test(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2)), Matchers.is(false)); + assertThat(predicate.test(mockIndexAbstraction(RestrictedIndicesNames.ASYNC_SEARCH_PREFIX + randomAlphaOfLengthBetween(0, 2))), + Matchers.is(false)); } } public void testXPackUserCanReadAuditTrail() { final String action = randomFrom(GetAction.NAME, SearchAction.NAME); - final Predicate predicate = XPackUser.ROLE.indices().allowedIndicesMatcher(action); - assertThat(predicate.test(getAuditLogName()), Matchers.is(true)); + final Predicate predicate = XPackUser.ROLE.indices().allowedIndicesMatcher(action); + assertThat(predicate.test(mockIndexAbstraction(getAuditLogName())), Matchers.is(true)); } public void testXPackUserCannotWriteToAuditTrail() { final String action = randomFrom(IndexAction.NAME, UpdateAction.NAME); - final Predicate predicate = XPackUser.ROLE.indices().allowedIndicesMatcher(action); - assertThat(predicate.test(getAuditLogName()), Matchers.is(false)); + final Predicate predicate = XPackUser.ROLE.indices().allowedIndicesMatcher(action); + assertThat(predicate.test(mockIndexAbstraction(getAuditLogName())), Matchers.is(false)); } private String getAuditLogName() { @@ -64,4 +69,12 @@ private String getAuditLogName() { final IndexNameResolver.Rollover rollover = randomFrom(IndexNameResolver.Rollover.values()); return IndexNameResolver.resolve(IndexAuditTrailField.INDEX_NAME_PREFIX, date, rollover); } + + private IndexAbstraction mockIndexAbstraction(String name) { + IndexAbstraction mock = mock(IndexAbstraction.class); + when(mock.getName()).thenReturn(name); + when(mock.getType()).thenReturn(randomFrom(IndexAbstraction.Type.CONCRETE_INDEX, + IndexAbstraction.Type.ALIAS, IndexAbstraction.Type.DATA_STREAM)); + return mock; + } } diff --git a/x-pack/plugin/src/test/resources/rest-api-spec/test/security/authz/15_auto_create.yml b/x-pack/plugin/src/test/resources/rest-api-spec/test/security/authz/15_auto_create.yml index 561f30afd3fab..bbe6f42f8270f 100644 --- a/x-pack/plugin/src/test/resources/rest-api-spec/test/security/authz/15_auto_create.yml +++ b/x-pack/plugin/src/test/resources/rest-api-spec/test/security/authz/15_auto_create.yml @@ -1,7 +1,7 @@ --- setup: - skip: - features: headers + features: ["headers", "allowed_warnings"] - do: cluster.health: @@ -44,6 +44,8 @@ teardown: "Test auto index creation": # Only auto creation of logs-foobar index works. - do: + allowed_warnings: + - "the index privilege [create_doc] allowed the update mapping action [indices:admin/mapping/auto_put] on index [logs-foobar], this privilege will not permit mapping updates in the next major release - users who require access to update mappings must be granted explicit privileges" headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user bulk: body: @@ -73,6 +75,8 @@ teardown: # Ensure that just appending data via both indices work now that the indices have been auto created - do: + allowed_warnings: + - "the index privilege [create_doc] allowed the update mapping action [indices:admin/mapping/auto_put] on index [logs-barbaz], this privilege will not permit mapping updates in the next major release - users who require access to update mappings must be granted explicit privileges" headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user bulk: body: diff --git a/x-pack/plugin/src/test/resources/rest-api-spec/test/security/authz/50_data_streams.yml b/x-pack/plugin/src/test/resources/rest-api-spec/test/security/authz/50_data_streams.yml index 07f3e9af406d7..8c2f3221eabe3 100644 --- a/x-pack/plugin/src/test/resources/rest-api-spec/test/security/authz/50_data_streams.yml +++ b/x-pack/plugin/src/test/resources/rest-api-spec/test/security/authz/50_data_streams.yml @@ -29,13 +29,24 @@ setup: ] } + - do: + security.put_role: + name: "data_stream_ingest_role" + body: > + { + "indices": [ + { "names": ["create-doc-data-stream*"], "privileges": ["create_doc"] }, + { "names": ["write-data-stream*"], "privileges": ["write"] } + ] + } + - do: security.put_user: username: "test_user" body: > { "password" : "x-pack-test-password", - "roles" : [ "data_stream_role" ], + "roles" : [ "data_stream_role", "data_stream_ingest_role" ], "full_name" : "user with privileges on some data streams" } @@ -51,16 +62,18 @@ setup: - do: allowed_warnings: - - "index template [my-template1] has index patterns [s*] matching patterns from existing older templates [global] with patterns (global => [*]); this template [my-template1] will take precedence during new index creation" + - "index template [my-template1] has index patterns [s*, create-doc-data-stream1, write-data-stream1] matching patterns from existing older templates [global] with patterns (global => [*]); this template [my-template1] will take precedence during new index creation" indices.put_index_template: name: my-template1 body: - index_patterns: [s*] + index_patterns: [s*, create-doc-data-stream1, write-data-stream1] template: mappings: properties: '@timestamp': type: date + 'foo': + type: keyword data_stream: {} --- @@ -85,6 +98,11 @@ teardown: name: "data_stream_role2" ignore: 404 + - do: + security.delete_role: + name: "data_stream_ingest_role" + ignore: 404 + --- "Test backing indices inherit parent data stream privileges": - skip: @@ -179,6 +197,93 @@ teardown: name: simple-data-stream1 - is_true: acknowledged +--- +"Test auto mapping updates unauthorized for create_doc privilege": + - skip: + version: " - 7.99.99" + reason: "change to 7.8.99 after backport" + + - do: # superuser + indices.create_data_stream: + name: create-doc-data-stream1 + - is_true: acknowledged + + - do: # superuser + indices.create_data_stream: + name: write-data-stream1 + - is_true: acknowledged + +# unmapped field on empty data stream + - do: + catch: forbidden + headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user + index: + index: create-doc-data-stream1 + body: { bar: baz, "@timestamp": "2000-12-12" } + +# mapped field does not update the mapping, hence it's authorized + - do: + headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user + index: + index: create-doc-data-stream1 + body: { foo: bar, "@timestamp": "2555-12-12" } + + - set: { _seq_no: seqno } + - set: { _primary_term: primary_term } + +# unmapped new field on non-empty data stream with create_doc privilege is not authorized + - do: + catch: forbidden + headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user + index: + index: create-doc-data-stream1 + body: { bar: baz, "@timestamp": "2000-12-12" } + +# unmapped new field on backing index when update with create_doc privilege is not allowed + - do: + catch: forbidden + headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user + index: + index: .ds-create-doc-data-stream1-000001 + id: 1 + op_type: index + if_seq_no: $seqno + if_primary_term: $primary_term + body: { foo: bar, bar: baz, "@timestamp": "2333-12-12" } + +# unmapped new field when write privilege is allowed + - do: + headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user + index: + id: 2 + op_type: create + index: write-data-stream1 + body: { foo: bar, bar: baz, "@timestamp": "2000-12-12" } + + - set: { _seq_no: seqno } + - set: { _primary_term: primary_term } + +# unmapped new field on backing index update when write is allowed + - do: + headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user + index: + index: .ds-write-data-stream1-000001 + id: 2 + op_type: index + if_seq_no: $seqno + if_primary_term: $primary_term + body: { new: field, bar: baz, "@timestamp": "2333-12-12" } + + - do: # superuser + indices.delete_data_stream: + name: create-doc-data-stream1 + - is_true: acknowledged + + - do: # superuser + indices.delete_data_stream: + name: write-data-stream1 + - is_true: acknowledged + --- "Test that create data stream is limited to authorized namespace": - skip: @@ -248,7 +353,7 @@ teardown: catch: forbidden headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user indices.get_data_stream: - name: outside_of_namespace + name: s-outside-of-authed-namespace - do: headers: { Authorization: "Basic bm9fYXV0aHpfdXNlcjp4LXBhY2stdGVzdC1wYXNzd29yZA==" } # no_authz_user diff --git a/x-pack/qa/smoke-test-security-with-mustache/src/test/resources/rest-api-spec/test/20_small_users_one_index.yml b/x-pack/qa/smoke-test-security-with-mustache/src/test/resources/rest-api-spec/test/20_small_users_one_index.yml index 4c4e673cd29ef..e3f706570a22a 100644 --- a/x-pack/qa/smoke-test-security-with-mustache/src/test/resources/rest-api-spec/test/20_small_users_one_index.yml +++ b/x-pack/qa/smoke-test-security-with-mustache/src/test/resources/rest-api-spec/test/20_small_users_one_index.yml @@ -1,7 +1,7 @@ --- setup: - skip: - features: headers + features: ["headers", "allowed_warnings"] - do: indices.create: @@ -84,6 +84,8 @@ teardown: } - do: + allowed_warnings: + - "the index privilege [create] allowed the update mapping action [indices:admin/mapping/auto_put] on index [shared_logs], this privilege will not permit mapping updates in the next major release - users who require access to update mappings must be granted explicit privileges" headers: Authorization: "Basic am9lOngtcGFjay10ZXN0LXBhc3N3b3Jk" index: @@ -152,6 +154,8 @@ teardown: } - do: + allowed_warnings: + - "the index privilege [create] allowed the update mapping action [indices:admin/mapping/auto_put] on index [shared_logs], this privilege will not permit mapping updates in the next major release - users who require access to update mappings must be granted explicit privileges" headers: Authorization: "Basic am9lOngtcGFjay10ZXN0LXBhc3N3b3Jk" index: