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: