From 5f4e6164e5ecd0e560b055e9dd93c2b998608abc Mon Sep 17 00:00:00 2001 From: jaymode Date: Wed, 7 Sep 2016 08:20:54 -0400 Subject: [PATCH] security: add a built-in role for reporting This commit adds a built-in role that grants read and write privileges to the reporting indices. See elastic/elasticsearch#2374 Closes elastic/elasticsearch#3196 Original commit: elastic/x-pack-elasticsearch@c8c1b465f8684ab0a995bf8957ed43183628c66c --- .../authz/permission/ReportingUserRole.java | 34 +++++++++ .../authz/store/ReservedRolesStore.java | 13 +++- .../permission/ReportingUserRoleTests.java | 74 +++++++++++++++++++ .../authz/store/ReservedRolesStoreTests.java | 12 ++- 4 files changed, 128 insertions(+), 5 deletions(-) create mode 100644 elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/permission/ReportingUserRole.java create mode 100644 elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/permission/ReportingUserRoleTests.java diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/permission/ReportingUserRole.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/permission/ReportingUserRole.java new file mode 100644 index 00000000000..9d3845a7460 --- /dev/null +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/permission/ReportingUserRole.java @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.security.authz.permission; + +import org.elasticsearch.xpack.security.authz.RoleDescriptor; +import org.elasticsearch.xpack.security.authz.permission.ClusterPermission.Core; +import org.elasticsearch.xpack.security.support.MetadataUtils; + +/** + * A role for users of the reporting features in xpack + */ +public class ReportingUserRole extends Role { + private static final RoleDescriptor.IndicesPrivileges[] INDICES_PRIVILEGES = new RoleDescriptor.IndicesPrivileges[] { + RoleDescriptor.IndicesPrivileges.builder() + .indices(".reporting-*") + .privileges("read", "write") + .build() + }; + + public static final String NAME = "reporting_user"; + public static final RoleDescriptor DESCRIPTOR = + new RoleDescriptor(NAME, null, INDICES_PRIVILEGES, null, MetadataUtils.DEFAULT_RESERVED_METADATA); + public static final ReportingUserRole INSTANCE = new ReportingUserRole(); + + private ReportingUserRole() { + super(DESCRIPTOR.getName(), + Core.NONE, + new IndicesPermission.Core(Role.Builder.convertFromIndicesPrivileges(DESCRIPTOR.getIndicesPrivileges())), + RunAsPermission.Core.NONE); + } +} diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/store/ReservedRolesStore.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/store/ReservedRolesStore.java index d1a56cdbfc7..5f0987d5b6f 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/store/ReservedRolesStore.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/store/ReservedRolesStore.java @@ -19,6 +19,7 @@ import org.elasticsearch.xpack.security.authz.permission.KibanaRole; import org.elasticsearch.xpack.security.authz.permission.KibanaUserRole; import org.elasticsearch.xpack.security.authz.permission.MonitoringUserRole; import org.elasticsearch.xpack.security.authz.permission.RemoteMonitoringAgentRole; +import org.elasticsearch.xpack.security.authz.permission.ReportingUserRole; import org.elasticsearch.xpack.security.authz.permission.Role; import org.elasticsearch.xpack.security.authz.permission.SuperuserRole; import org.elasticsearch.xpack.security.authz.permission.TransportClientRole; @@ -53,6 +54,8 @@ public class ReservedRolesStore implements RolesStore { return RemoteMonitoringAgentRole.INSTANCE; case IngestAdminRole.NAME: return IngestAdminRole.INSTANCE; + case ReportingUserRole.NAME: + return ReportingUserRole.INSTANCE; case KibanaRole.NAME: // The only user that should know about this role is the kibana user itself (who has this role). The reason we want to hide // this role is that it was created specifically for kibana, with all the permissions that the kibana user needs. @@ -86,6 +89,8 @@ public class ReservedRolesStore implements RolesStore { return RemoteMonitoringAgentRole.DESCRIPTOR; case IngestAdminRole.NAME: return IngestAdminRole.DESCRIPTOR; + case ReportingUserRole.NAME: + return ReportingUserRole.DESCRIPTOR; case KibanaRole.NAME: // The only user that should know about this role is the kibana user itself (who has this role). The reason we want to hide // this role is that it was created specifically for kibana, with all the permissions that the kibana user needs. @@ -103,15 +108,16 @@ public class ReservedRolesStore implements RolesStore { if (DEFAULT_ENABLED_KIBANA_USER.equals(securityContext.getUser())) { return Arrays.asList(SuperuserRole.DESCRIPTOR, TransportClientRole.DESCRIPTOR, KibanaUserRole.DESCRIPTOR, KibanaRole.DESCRIPTOR, MonitoringUserRole.DESCRIPTOR, RemoteMonitoringAgentRole.DESCRIPTOR, - IngestAdminRole.DESCRIPTOR); + IngestAdminRole.DESCRIPTOR, ReportingUserRole.DESCRIPTOR); } return Arrays.asList(SuperuserRole.DESCRIPTOR, TransportClientRole.DESCRIPTOR, KibanaUserRole.DESCRIPTOR, - MonitoringUserRole.DESCRIPTOR, RemoteMonitoringAgentRole.DESCRIPTOR, IngestAdminRole.DESCRIPTOR); + MonitoringUserRole.DESCRIPTOR, RemoteMonitoringAgentRole.DESCRIPTOR, IngestAdminRole.DESCRIPTOR, + ReportingUserRole.DESCRIPTOR); } public static Set names() { return Sets.newHashSet(SuperuserRole.NAME, KibanaRole.NAME, TransportClientRole.NAME, KibanaUserRole.NAME, - MonitoringUserRole.NAME, RemoteMonitoringAgentRole.NAME, IngestAdminRole.NAME); + MonitoringUserRole.NAME, RemoteMonitoringAgentRole.NAME, IngestAdminRole.NAME, ReportingUserRole.NAME); } public static boolean isReserved(String role) { @@ -124,6 +130,7 @@ public class ReservedRolesStore implements RolesStore { case RemoteMonitoringAgentRole.NAME: case SystemUser.ROLE_NAME: case IngestAdminRole.NAME: + case ReportingUserRole.NAME: return true; default: return false; diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/permission/ReportingUserRoleTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/permission/ReportingUserRoleTests.java new file mode 100644 index 00000000000..34544b51a45 --- /dev/null +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/permission/ReportingUserRoleTests.java @@ -0,0 +1,74 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.security.authz.permission; + +import org.elasticsearch.action.admin.cluster.health.ClusterHealthAction; +import org.elasticsearch.action.admin.cluster.reroute.ClusterRerouteAction; +import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsAction; +import org.elasticsearch.action.admin.cluster.state.ClusterStateAction; +import org.elasticsearch.action.admin.cluster.stats.ClusterStatsAction; +import org.elasticsearch.action.admin.indices.create.CreateIndexAction; +import org.elasticsearch.action.admin.indices.delete.DeleteIndexAction; +import org.elasticsearch.action.admin.indices.settings.put.UpdateSettingsAction; +import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateAction; +import org.elasticsearch.action.bulk.BulkAction; +import org.elasticsearch.action.delete.DeleteAction; +import org.elasticsearch.action.get.GetAction; +import org.elasticsearch.action.index.IndexAction; +import org.elasticsearch.action.search.SearchAction; +import org.elasticsearch.action.update.UpdateAction; +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.transport.TransportRequest; +import org.elasticsearch.xpack.monitoring.action.MonitoringBulkAction; +import org.elasticsearch.xpack.security.authc.Authentication; + +import static org.hamcrest.Matchers.is; +import static org.mockito.Mockito.mock; + +/** + * Unit tests for the built in reporting user role + */ +public class ReportingUserRoleTests extends ESTestCase { + + public void testCluster() { + final TransportRequest request = new TransportRequest.Empty(); + final Authentication authentication = mock(Authentication.class); + assertThat(ReportingUserRole.INSTANCE.cluster().check(ClusterHealthAction.NAME, request, authentication), is(false)); + assertThat(ReportingUserRole.INSTANCE.cluster().check(ClusterStateAction.NAME, request, authentication), is(false)); + assertThat(ReportingUserRole.INSTANCE.cluster().check(ClusterStatsAction.NAME, request, authentication), is(false)); + assertThat(ReportingUserRole.INSTANCE.cluster().check(PutIndexTemplateAction.NAME, request, authentication), is(false)); + assertThat(ReportingUserRole.INSTANCE.cluster().check(ClusterRerouteAction.NAME, request, authentication), is(false)); + assertThat(ReportingUserRole.INSTANCE.cluster().check(ClusterUpdateSettingsAction.NAME, request, authentication), is(false)); + assertThat(ReportingUserRole.INSTANCE.cluster().check(MonitoringBulkAction.NAME, request, authentication), is(false)); + } + + public void testRunAs() { + assertThat(ReportingUserRole.INSTANCE.runAs().isEmpty(), is(true)); + } + + public void testUnauthorizedIndices() { + assertThat(ReportingUserRole.INSTANCE.indices().allowedIndicesMatcher(SearchAction.NAME).test("foo"), is(false)); + assertThat(ReportingUserRole.INSTANCE.indices().allowedIndicesMatcher(SearchAction.NAME).test(".reporting"), is(false)); + assertThat(ReportingUserRole.INSTANCE.indices().allowedIndicesMatcher(SearchAction.NAME).test(".kibana"), is(false)); + assertThat(ReportingUserRole.INSTANCE.indices().allowedIndicesMatcher("indices:foo").test(randomAsciiOfLengthBetween(8, 24)), + is(false)); + } + + public void testReadWriteAccess() { + final String index = ".reporting-" + randomAsciiOfLength(randomIntBetween(0, 13)); + assertThat(ReportingUserRole.INSTANCE.indices().allowedIndicesMatcher("indices:foo").test(index), is(false)); + assertThat(ReportingUserRole.INSTANCE.indices().allowedIndicesMatcher("indices:bar").test(index), is(false)); + assertThat(ReportingUserRole.INSTANCE.indices().allowedIndicesMatcher(DeleteIndexAction.NAME).test(index), is(false)); + assertThat(ReportingUserRole.INSTANCE.indices().allowedIndicesMatcher(CreateIndexAction.NAME).test(index), is(false)); + assertThat(ReportingUserRole.INSTANCE.indices().allowedIndicesMatcher(UpdateSettingsAction.NAME).test(index), is(false)); + assertThat(ReportingUserRole.INSTANCE.indices().allowedIndicesMatcher(SearchAction.NAME).test(index), is(true)); + assertThat(ReportingUserRole.INSTANCE.indices().allowedIndicesMatcher(GetAction.NAME).test(index), is(true)); + assertThat(ReportingUserRole.INSTANCE.indices().allowedIndicesMatcher(IndexAction.NAME).test(index), is(true)); + assertThat(ReportingUserRole.INSTANCE.indices().allowedIndicesMatcher(UpdateAction.NAME).test(index), is(true)); + assertThat(ReportingUserRole.INSTANCE.indices().allowedIndicesMatcher(DeleteAction.NAME).test(index), is(true)); + assertThat(ReportingUserRole.INSTANCE.indices().allowedIndicesMatcher(BulkAction.NAME).test(index), is(true)); + } +} diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/store/ReservedRolesStoreTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/store/ReservedRolesStoreTests.java index 0036f141872..418fdba6b6f 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/store/ReservedRolesStoreTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/store/ReservedRolesStoreTests.java @@ -11,6 +11,7 @@ import org.elasticsearch.xpack.security.authz.permission.KibanaRole; import org.elasticsearch.xpack.security.authz.permission.KibanaUserRole; import org.elasticsearch.xpack.security.authz.permission.MonitoringUserRole; import org.elasticsearch.xpack.security.authz.permission.RemoteMonitoringAgentRole; +import org.elasticsearch.xpack.security.authz.permission.ReportingUserRole; import org.elasticsearch.xpack.security.authz.permission.SuperuserRole; import org.elasticsearch.xpack.security.authz.permission.TransportClientRole; import org.elasticsearch.xpack.security.user.ElasticUser; @@ -66,9 +67,12 @@ public class ReservedRolesStoreTests extends ESTestCase { assertThat(reservedRolesStore.role(RemoteMonitoringAgentRole.NAME), sameInstance(RemoteMonitoringAgentRole.INSTANCE)); assertThat(reservedRolesStore.roleDescriptor(RemoteMonitoringAgentRole.NAME), sameInstance(RemoteMonitoringAgentRole.DESCRIPTOR)); + assertThat(reservedRolesStore.role(ReportingUserRole.NAME), sameInstance(ReportingUserRole.INSTANCE)); + assertThat(reservedRolesStore.roleDescriptor(ReportingUserRole.NAME), sameInstance(ReportingUserRole.DESCRIPTOR)); + assertThat(reservedRolesStore.roleDescriptors(), contains(SuperuserRole.DESCRIPTOR, TransportClientRole.DESCRIPTOR, KibanaUserRole.DESCRIPTOR, MonitoringUserRole.DESCRIPTOR, RemoteMonitoringAgentRole.DESCRIPTOR, - IngestAdminRole.DESCRIPTOR)); + IngestAdminRole.DESCRIPTOR, ReportingUserRole.DESCRIPTOR)); assertThat(reservedRolesStore.role(KibanaRole.NAME), nullValue()); assertThat(reservedRolesStore.roleDescriptor(KibanaRole.NAME), nullValue()); @@ -99,9 +103,12 @@ public class ReservedRolesStoreTests extends ESTestCase { assertThat(reservedRolesStore.role(RemoteMonitoringAgentRole.NAME), sameInstance(RemoteMonitoringAgentRole.INSTANCE)); assertThat(reservedRolesStore.roleDescriptor(RemoteMonitoringAgentRole.NAME), sameInstance(RemoteMonitoringAgentRole.DESCRIPTOR)); + assertThat(reservedRolesStore.role(ReportingUserRole.NAME), sameInstance(ReportingUserRole.INSTANCE)); + assertThat(reservedRolesStore.roleDescriptor(ReportingUserRole.NAME), sameInstance(ReportingUserRole.DESCRIPTOR)); + assertThat(reservedRolesStore.roleDescriptors(), contains(SuperuserRole.DESCRIPTOR, TransportClientRole.DESCRIPTOR, KibanaUserRole.DESCRIPTOR, KibanaRole.DESCRIPTOR, MonitoringUserRole.DESCRIPTOR, RemoteMonitoringAgentRole.DESCRIPTOR, - IngestAdminRole.DESCRIPTOR)); + IngestAdminRole.DESCRIPTOR, ReportingUserRole.DESCRIPTOR)); assertThat(reservedRolesStore.role(SystemUser.ROLE_NAME), nullValue()); } @@ -116,5 +123,6 @@ public class ReservedRolesStoreTests extends ESTestCase { assertThat(ReservedRolesStore.isReserved(IngestAdminRole.NAME), is(true)); assertThat(ReservedRolesStore.isReserved(RemoteMonitoringAgentRole.NAME), is(true)); assertThat(ReservedRolesStore.isReserved(MonitoringUserRole.NAME), is(true)); + assertThat(ReservedRolesStore.isReserved(ReportingUserRole.NAME), is(true)); } }