From e2a0a5b9bb5205f4174df54a36e76f6375ac3853 Mon Sep 17 00:00:00 2001 From: Yogesh Gaikwad Date: Thu, 22 Aug 2019 02:10:22 +1000 Subject: [PATCH 01/17] Append only index privilege `append_only` index privilege allows users to index new documents but not update existing documents. Wherever the op-type is `index` and `_id` is specified for the document to be indexed, we would deny access even if the document does not exist. We do not know in authz service whether this document exists or not. --- .../authz/privilege/IndexPrivilege.java | 4 + .../security/authz/AuthorizationService.java | 9 +- .../AppendOnlyIndexPrivilegeTests.java | 94 +++++++++++++++++++ 3 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 x-pack/plugin/security/src/test/java/org/elasticsearch/integration/AppendOnlyIndexPrivilegeTests.java 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 32f90993d019f..3e24fe702b9e1 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 @@ -43,6 +43,8 @@ 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 APPEND_ONLY_AUTOMATON = Automatons.minusAndMinimize(patterns("indices:data/write/index*", "indices:data/write/bulk*", + PutMappingAction.NAME), patterns("indices:data/write/index[op_type:i]")); private static final Automaton CREATE_AUTOMATON = patterns("indices:data/write/index*", "indices:data/write/bulk*", PutMappingAction.NAME); private static final Automaton INDEX_AUTOMATON = @@ -68,6 +70,7 @@ public final class IndexPrivilege extends Privilege { public static final IndexPrivilege READ_CROSS_CLUSTER = new IndexPrivilege("read_cross_cluster", READ_CROSS_CLUSTER_AUTOMATON); public static final IndexPrivilege CREATE = new IndexPrivilege("create", CREATE_AUTOMATON); public static final IndexPrivilege INDEX = new IndexPrivilege("index", INDEX_AUTOMATON); + public static final IndexPrivilege APPEND_ONLY = new IndexPrivilege("append_only", APPEND_ONLY_AUTOMATON); public static final IndexPrivilege DELETE = new IndexPrivilege("delete", DELETE_AUTOMATON); public static final IndexPrivilege WRITE = new IndexPrivilege("write", WRITE_AUTOMATON); public static final IndexPrivilege MONITOR = new IndexPrivilege("monitor", MONITOR_AUTOMATON); @@ -90,6 +93,7 @@ public final class IndexPrivilege extends Privilege { entry("delete", DELETE), entry("write", WRITE), entry("create", CREATE), + entry("append_only", APPEND_ONLY), entry("delete_index", DELETE_INDEX), entry("view_index_metadata", VIEW_METADATA), entry("read_cross_cluster", READ_CROSS_CLUSTER), diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java index 69153379f3b15..cdafcdea24c28 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java @@ -20,6 +20,7 @@ import org.elasticsearch.action.bulk.TransportShardBulkAction; import org.elasticsearch.action.delete.DeleteAction; import org.elasticsearch.action.index.IndexAction; +import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.support.GroupedActionListener; import org.elasticsearch.action.support.replication.TransportReplicationAction.ConcreteShardRequest; import org.elasticsearch.action.update.UpdateAction; @@ -535,8 +536,14 @@ private static String getAction(BulkItemRequest item) { final DocWriteRequest docWriteRequest = item.request(); switch (docWriteRequest.opType()) { case INDEX: + IndexRequest request = (IndexRequest) item.request(); + if (request.getAutoGeneratedTimestamp() > 0) { + // auto generated + return IndexAction.NAME + "[op_type:c]"; + } + return IndexAction.NAME + "[op_type:i]"; case CREATE: - return IndexAction.NAME; + return IndexAction.NAME + "[op_type:c]"; case UPDATE: return UpdateAction.NAME; case DELETE: diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/integration/AppendOnlyIndexPrivilegeTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/integration/AppendOnlyIndexPrivilegeTests.java new file mode 100644 index 0000000000000..0126a1e07b799 --- /dev/null +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/integration/AppendOnlyIndexPrivilegeTests.java @@ -0,0 +1,94 @@ +/* + * + * * 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.integration; + +import org.elasticsearch.client.Request; +import org.elasticsearch.common.settings.SecureString; +import org.elasticsearch.xpack.core.security.authc.support.Hasher; +import org.junit.Before; + +import java.io.IOException; + +public class AppendOnlyIndexPrivilegeTests extends AbstractPrivilegeTestCase { + private static final String INDEX_NAME = "index-1"; + private String jsonDoc = "{ \"name\" : \"elasticsearch\", \"body\": \"foo bar\" }"; + private static final String ROLES = + "all_indices_role:\n" + + " indices:\n" + + " - names: '*'\n" + + " privileges: [ all ]\n" + + "append_only_role:\n" + + " indices:\n" + + " - names: '*'\n" + + " privileges: [ append_only ]\n" + ; + + private static final String USERS_ROLES = + "all_indices_role:admin\n" + + "append_only_role:append_only_user\n"; + + @Override + protected boolean addMockHttpTransport() { + return false; // enable http + } + + @Override + protected String configRoles() { + return super.configRoles() + "\n" + ROLES; + } + + @Override + protected String configUsers() { + final String usersPasswdHashed = new String(Hasher.resolve( + randomFrom("pbkdf2", "pbkdf2_1000", "bcrypt", "bcrypt9")).hash(new SecureString("passwd".toCharArray()))); + + return super.configUsers() + + "admin:" + usersPasswdHashed + "\n" + + "append_only_user:" + usersPasswdHashed + "\n"; + } + + @Override + protected String configUsersRoles() { + return super.configUsersRoles() + USERS_ROLES; + } + + @Before + public void insertBaseDocumentsAsAdmin() throws Exception { + Request request = new Request("PUT", "/" + INDEX_NAME + "/_doc/1"); + request.setJsonEntity(jsonDoc); + request.addParameter("refresh", "true"); + assertAccessIsAllowed("admin", request); + } + + public void testAppendOnlyUser() throws IOException { + String user = "append_only_user"; + // append_only_user must be able to index a new document via Index API with auto generate id + assertAccessIsAllowed(user, "POST", "/" + INDEX_NAME + "/_doc", "{ \"foo\" : \"bar\" }"); + // append_only_user is allowed to index document if it does not exist when Id is specified and op_type is create + assertAccessIsAllowed(user, "PUT", "/" + INDEX_NAME + "/_doc/123?op_type=create", "{ \"foo\" : \"bar\" }"); + + // append_only_user is not allowed to index document even if it does not exist when Id is specified and op_type is default (index) + assertAccessIsDenied(user, "PUT", "/" + INDEX_NAME + "/_doc/321", "{ \"foo\" : \"bar\" }"); + // no updates allowed + assertAccessIsDenied(user, "POST", "/" + INDEX_NAME + "/_doc/1/_update", "{ \"doc\" : { \"foo\" : \"baz\" } }"); + assertAccessIsDenied(user, "PUT", "/" + INDEX_NAME + "/_doc/1", "{ \"foo\" : \"baz\" }"); + + // bulk API with create and index with no id only + assertAccessIsAllowed(user, randomFrom("PUT", "POST"), + "/" + INDEX_NAME + "/_bulk", "{ \"create\" : { \"_id\" : \"145\" } }\n{ \"foo\" : \"bar\" }\n"); + assertAccessIsAllowed(user, randomFrom("PUT", "POST"), + "/" + INDEX_NAME + "/_bulk", "{ \"index\" : { } }\n{ \"foo\" : \"bar\" }\n"); + + // Bulk API deny access for update or index with id (we do not know if it exists) + assertBodyHasAccessIsDenied(user, randomFrom("PUT", "POST"), + "/" + INDEX_NAME + "/_bulk", "{ \"update\" : { \"_id\" : \"145\" } }\n{ \"doc\" : {\"foo\" : \"bazbaz\"} }\n"); + assertBodyHasAccessIsDenied(user, randomFrom("PUT", "POST"), + "/" + INDEX_NAME + "/_bulk", "{ \"index\" : { \"_id\" : \"149\" } }\n{ \"foo\" : \"bar\" }\n"); + } +} From 6066680341e6a2b5f625ce977b56d3062c8bf930 Mon Sep 17 00:00:00 2001 From: Yogesh Gaikwad Date: Thu, 22 Aug 2019 09:38:21 +1000 Subject: [PATCH 02/17] precommit errors --- .../xpack/core/security/authz/privilege/IndexPrivilege.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 3e24fe702b9e1..73ab35cea12bc 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 @@ -43,10 +43,10 @@ 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 APPEND_ONLY_AUTOMATON = Automatons.minusAndMinimize(patterns("indices:data/write/index*", "indices:data/write/bulk*", - PutMappingAction.NAME), patterns("indices:data/write/index[op_type:i]")); private static final Automaton CREATE_AUTOMATON = patterns("indices:data/write/index*", "indices:data/write/bulk*", PutMappingAction.NAME); + private static final Automaton APPEND_ONLY_AUTOMATON = Automatons.minusAndMinimize(CREATE_AUTOMATON, + patterns("indices:data/write/index[op_type:i]")); private static final Automaton INDEX_AUTOMATON = patterns("indices:data/write/index*", "indices:data/write/bulk*", "indices:data/write/update*", PutMappingAction.NAME); private static final Automaton DELETE_AUTOMATON = patterns("indices:data/write/delete*", "indices:data/write/bulk*"); From 460deae52be4f73f95ef87155c046e4f3e99b0f9 Mon Sep 17 00:00:00 2001 From: Yogesh Gaikwad Date: Thu, 22 Aug 2019 09:40:47 +1000 Subject: [PATCH 03/17] fix test --- .../test/resources/rest-api-spec/test/privileges/11_builtin.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugin/src/test/resources/rest-api-spec/test/privileges/11_builtin.yml b/x-pack/plugin/src/test/resources/rest-api-spec/test/privileges/11_builtin.yml index 2e23a85b7e737..20964c44783c4 100644 --- a/x-pack/plugin/src/test/resources/rest-api-spec/test/privileges/11_builtin.yml +++ b/x-pack/plugin/src/test/resources/rest-api-spec/test/privileges/11_builtin.yml @@ -16,4 +16,4 @@ setup: # I would much prefer we could just check that specific entries are in the array, but we don't have # an assertion for that - length: { "cluster" : 28 } - - length: { "index" : 16 } + - length: { "index" : 17 } From 8d5fceb9c3dc7fcd867d45e5594c21f23a6f36ea Mon Sep 17 00:00:00 2001 From: Yogesh Gaikwad Date: Thu, 22 Aug 2019 12:20:10 +1000 Subject: [PATCH 04/17] fix test --- .../xpack/security/authz/AuthorizationServiceTests.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java index d7f3252dd95a5..1fa14e2dd41ac 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java @@ -1192,16 +1192,16 @@ public void testAuthorizationOfIndividualBulkItems() throws IOException { eq(DeleteAction.NAME), eq("alias-2"), eq(BulkItemRequest.class.getSimpleName()), eq(request.remoteAddress()), authzInfoRoles(new String[] { role.getName() })); verify(auditTrail).explicitIndexAccessEvent(eq(requestId), eq(AuditLevel.ACCESS_GRANTED), eq(authentication), - eq(IndexAction.NAME), eq("concrete-index"), eq(BulkItemRequest.class.getSimpleName()), + eq(IndexAction.NAME + "[op_type:i]"), eq("concrete-index"), eq(BulkItemRequest.class.getSimpleName()), eq(request.remoteAddress()), authzInfoRoles(new String[] { role.getName() })); verify(auditTrail).explicitIndexAccessEvent(eq(requestId), eq(AuditLevel.ACCESS_GRANTED), eq(authentication), - eq(IndexAction.NAME), eq("alias-1"), eq(BulkItemRequest.class.getSimpleName()), + eq(IndexAction.NAME + "[op_type:i]"), eq("alias-1"), eq(BulkItemRequest.class.getSimpleName()), eq(request.remoteAddress()), authzInfoRoles(new String[] { role.getName() })); verify(auditTrail).explicitIndexAccessEvent(eq(requestId), eq(AuditLevel.ACCESS_DENIED), eq(authentication), eq(DeleteAction.NAME), eq("alias-1"), eq(BulkItemRequest.class.getSimpleName()), eq(request.remoteAddress()), authzInfoRoles(new String[] { role.getName() })); verify(auditTrail).explicitIndexAccessEvent(eq(requestId), eq(AuditLevel.ACCESS_DENIED), eq(authentication), - eq(IndexAction.NAME), eq("alias-2"), eq(BulkItemRequest.class.getSimpleName()), + eq(IndexAction.NAME + "[op_type:i]"), eq("alias-2"), eq(BulkItemRequest.class.getSimpleName()), eq(request.remoteAddress()), authzInfoRoles(new String[] { role.getName() })); verify(auditTrail).accessGranted(eq(requestId), eq(authentication), eq(action), eq(request), authzInfoRoles(new String[] { role.getName() })); // bulk request is allowed @@ -1235,7 +1235,7 @@ public void testAuthorizationOfIndividualBulkItemsWithDateMath() throws IOExcept eq(DeleteAction.NAME), Matchers.startsWith("datemath-"), eq(BulkItemRequest.class.getSimpleName()), eq(request.remoteAddress()), authzInfoRoles(new String[] { role.getName() })); verify(auditTrail, times(2)).explicitIndexAccessEvent(eq(requestId), eq(AuditLevel.ACCESS_GRANTED), eq(authentication), - eq(IndexAction.NAME), Matchers.startsWith("datemath-"), eq(BulkItemRequest.class.getSimpleName()), + eq(IndexAction.NAME + "[op_type:i]"), Matchers.startsWith("datemath-"), eq(BulkItemRequest.class.getSimpleName()), eq(request.remoteAddress()), authzInfoRoles(new String[] { role.getName() })); // bulk request is allowed verify(auditTrail).accessGranted(eq(requestId), eq(authentication), eq(action), eq(request), From 9b3987d237b2a45e860071c71069368e1a892f2e Mon Sep 17 00:00:00 2001 From: Yogesh Gaikwad Date: Thu, 22 Aug 2019 17:48:32 +1000 Subject: [PATCH 05/17] follow the conventions naming an action --- .../xpack/core/security/authz/privilege/IndexPrivilege.java | 2 +- .../xpack/security/authz/AuthorizationService.java | 6 +++--- .../xpack/security/authz/AuthorizationServiceTests.java | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) 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 73ab35cea12bc..897f94cf7cb55 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 @@ -46,7 +46,7 @@ public final class IndexPrivilege extends Privilege { private static final Automaton CREATE_AUTOMATON = patterns("indices:data/write/index*", "indices:data/write/bulk*", PutMappingAction.NAME); private static final Automaton APPEND_ONLY_AUTOMATON = Automatons.minusAndMinimize(CREATE_AUTOMATON, - patterns("indices:data/write/index[op_type:i]")); + patterns("indices:data/write/index:op_type/index")); private static final Automaton INDEX_AUTOMATON = patterns("indices:data/write/index*", "indices:data/write/bulk*", "indices:data/write/update*", PutMappingAction.NAME); private static final Automaton DELETE_AUTOMATON = patterns("indices:data/write/delete*", "indices:data/write/bulk*"); diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java index cdafcdea24c28..05adab7623ffc 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java @@ -539,11 +539,11 @@ private static String getAction(BulkItemRequest item) { IndexRequest request = (IndexRequest) item.request(); if (request.getAutoGeneratedTimestamp() > 0) { // auto generated - return IndexAction.NAME + "[op_type:c]"; + return IndexAction.NAME + ":op_type/create"; } - return IndexAction.NAME + "[op_type:i]"; + return IndexAction.NAME + ":op_type/index"; case CREATE: - return IndexAction.NAME + "[op_type:c]"; + return IndexAction.NAME + ":op_type/create"; case UPDATE: return UpdateAction.NAME; case DELETE: diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java index 1fa14e2dd41ac..f6aecce28923a 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java @@ -1192,16 +1192,16 @@ public void testAuthorizationOfIndividualBulkItems() throws IOException { eq(DeleteAction.NAME), eq("alias-2"), eq(BulkItemRequest.class.getSimpleName()), eq(request.remoteAddress()), authzInfoRoles(new String[] { role.getName() })); verify(auditTrail).explicitIndexAccessEvent(eq(requestId), eq(AuditLevel.ACCESS_GRANTED), eq(authentication), - eq(IndexAction.NAME + "[op_type:i]"), eq("concrete-index"), eq(BulkItemRequest.class.getSimpleName()), + eq(IndexAction.NAME + ":op_type/index"), eq("concrete-index"), eq(BulkItemRequest.class.getSimpleName()), eq(request.remoteAddress()), authzInfoRoles(new String[] { role.getName() })); verify(auditTrail).explicitIndexAccessEvent(eq(requestId), eq(AuditLevel.ACCESS_GRANTED), eq(authentication), - eq(IndexAction.NAME + "[op_type:i]"), eq("alias-1"), eq(BulkItemRequest.class.getSimpleName()), + eq(IndexAction.NAME + ":op_type/index"), eq("alias-1"), eq(BulkItemRequest.class.getSimpleName()), eq(request.remoteAddress()), authzInfoRoles(new String[] { role.getName() })); verify(auditTrail).explicitIndexAccessEvent(eq(requestId), eq(AuditLevel.ACCESS_DENIED), eq(authentication), eq(DeleteAction.NAME), eq("alias-1"), eq(BulkItemRequest.class.getSimpleName()), eq(request.remoteAddress()), authzInfoRoles(new String[] { role.getName() })); verify(auditTrail).explicitIndexAccessEvent(eq(requestId), eq(AuditLevel.ACCESS_DENIED), eq(authentication), - eq(IndexAction.NAME + "[op_type:i]"), eq("alias-2"), eq(BulkItemRequest.class.getSimpleName()), + eq(IndexAction.NAME + ":op_type/index"), eq("alias-2"), eq(BulkItemRequest.class.getSimpleName()), eq(request.remoteAddress()), authzInfoRoles(new String[] { role.getName() })); verify(auditTrail).accessGranted(eq(requestId), eq(authentication), eq(action), eq(request), authzInfoRoles(new String[] { role.getName() })); // bulk request is allowed From 0d320578e14d4807ec78d5d105b45f0d120dd3e6 Mon Sep 17 00:00:00 2001 From: Yogesh Gaikwad Date: Thu, 22 Aug 2019 18:10:01 +1000 Subject: [PATCH 06/17] fix test --- .../xpack/security/authz/AuthorizationServiceTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java index f6aecce28923a..33191e60211ef 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java @@ -1235,7 +1235,7 @@ public void testAuthorizationOfIndividualBulkItemsWithDateMath() throws IOExcept eq(DeleteAction.NAME), Matchers.startsWith("datemath-"), eq(BulkItemRequest.class.getSimpleName()), eq(request.remoteAddress()), authzInfoRoles(new String[] { role.getName() })); verify(auditTrail, times(2)).explicitIndexAccessEvent(eq(requestId), eq(AuditLevel.ACCESS_GRANTED), eq(authentication), - eq(IndexAction.NAME + "[op_type:i]"), Matchers.startsWith("datemath-"), eq(BulkItemRequest.class.getSimpleName()), + eq(IndexAction.NAME + ":op_type/index"), Matchers.startsWith("datemath-"), eq(BulkItemRequest.class.getSimpleName()), eq(request.remoteAddress()), authzInfoRoles(new String[] { role.getName() })); // bulk request is allowed verify(auditTrail).accessGranted(eq(requestId), eq(authentication), eq(action), eq(request), From 20707d35eb3dc92f273ee3d2b6bfed5fab819a16 Mon Sep 17 00:00:00 2001 From: Yogesh Gaikwad Date: Fri, 23 Aug 2019 01:55:30 +1000 Subject: [PATCH 07/17] fix test --- x-pack/docs/en/rest-api/security/get-builtin-privileges.asciidoc | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/docs/en/rest-api/security/get-builtin-privileges.asciidoc b/x-pack/docs/en/rest-api/security/get-builtin-privileges.asciidoc index b6afc70715a55..50f124636cde3 100644 --- a/x-pack/docs/en/rest-api/security/get-builtin-privileges.asciidoc +++ b/x-pack/docs/en/rest-api/security/get-builtin-privileges.asciidoc @@ -95,6 +95,7 @@ A successful call returns an object with "cluster" and "index" fields. ], "index" : [ "all", + "append_only", "create", "create_index", "delete", From 99c24921616864188bda0c1316df22636c940984 Mon Sep 17 00:00:00 2001 From: Yogesh Gaikwad Date: Fri, 23 Aug 2019 01:58:56 +1000 Subject: [PATCH 08/17] check the auto generated timestamp against the constant IndexRequest.UNSET_AUTO_GENERATED_TIMESTAMP --- .../xpack/security/authz/AuthorizationService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java index 05adab7623ffc..ce18e81b315b6 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java @@ -537,7 +537,7 @@ private static String getAction(BulkItemRequest item) { switch (docWriteRequest.opType()) { case INDEX: IndexRequest request = (IndexRequest) item.request(); - if (request.getAutoGeneratedTimestamp() > 0) { + if (request.getAutoGeneratedTimestamp() != IndexRequest.UNSET_AUTO_GENERATED_TIMESTAMP) { // auto generated return IndexAction.NAME + ":op_type/create"; } From e2ddaad22092ee4f6220eb04636c7025b8e38be1 Mon Sep 17 00:00:00 2001 From: Yogesh Gaikwad Date: Mon, 26 Aug 2019 13:40:55 +1000 Subject: [PATCH 09/17] use constants --- .../xpack/security/authz/AuthorizationService.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java index ce18e81b315b6..e02cc3cd1f31b 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java @@ -93,6 +93,8 @@ public class AuthorizationService { public static final String AUTHORIZATION_INFO_KEY = "_authz_info"; private static final AuthorizationInfo SYSTEM_AUTHZ_INFO = () -> Collections.singletonMap(PRINCIPAL_ROLES_FIELD_NAME, new String[] { SystemUser.ROLE_NAME }); + private static final String IMPLIED_INDEX_ACTION = IndexAction.NAME + ":op_type/index"; + private static final String IMPLIED_CREATE_ACTION = IndexAction.NAME + ":op_type/create"; private static final Logger logger = LogManager.getLogger(AuthorizationService.class); @@ -538,12 +540,12 @@ private static String getAction(BulkItemRequest item) { case INDEX: IndexRequest request = (IndexRequest) item.request(); if (request.getAutoGeneratedTimestamp() != IndexRequest.UNSET_AUTO_GENERATED_TIMESTAMP) { - // auto generated - return IndexAction.NAME + ":op_type/create"; + // it is auto generated so create is implied + return IMPLIED_CREATE_ACTION; } - return IndexAction.NAME + ":op_type/index"; + return IMPLIED_INDEX_ACTION; case CREATE: - return IndexAction.NAME + ":op_type/create"; + return IMPLIED_CREATE_ACTION; case UPDATE: return UpdateAction.NAME; case DELETE: From 7cab8e95322779561092a4dd9fcb81bd33fa3491 Mon Sep 17 00:00:00 2001 From: Yogesh Gaikwad Date: Mon, 9 Sep 2019 16:27:44 +1000 Subject: [PATCH 10/17] split into individual test cases --- .../AppendOnlyIndexPrivilegeTests.java | 68 +++++++++++-------- 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/integration/AppendOnlyIndexPrivilegeTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/integration/AppendOnlyIndexPrivilegeTests.java index 0126a1e07b799..686ef8687bcd9 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/integration/AppendOnlyIndexPrivilegeTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/integration/AppendOnlyIndexPrivilegeTests.java @@ -17,21 +17,21 @@ public class AppendOnlyIndexPrivilegeTests extends AbstractPrivilegeTestCase { private static final String INDEX_NAME = "index-1"; + private static final String APPEND_ONLY_USER = "append_only_user"; private String jsonDoc = "{ \"name\" : \"elasticsearch\", \"body\": \"foo bar\" }"; private static final String ROLES = - "all_indices_role:\n" + + "all_indices_role:\n" + " indices:\n" + " - names: '*'\n" + " privileges: [ all ]\n" + - "append_only_role:\n" + + "append_only_role:\n" + " indices:\n" + " - names: '*'\n" + - " privileges: [ append_only ]\n" - ; + " privileges: [ append_only ]\n"; private static final String USERS_ROLES = "all_indices_role:admin\n" + - "append_only_role:append_only_user\n"; + "append_only_role:" + APPEND_ONLY_USER + "\n"; @Override protected boolean addMockHttpTransport() { @@ -66,29 +66,43 @@ public void insertBaseDocumentsAsAdmin() throws Exception { assertAccessIsAllowed("admin", request); } - public void testAppendOnlyUser() throws IOException { - String user = "append_only_user"; - // append_only_user must be able to index a new document via Index API with auto generate id - assertAccessIsAllowed(user, "POST", "/" + INDEX_NAME + "/_doc", "{ \"foo\" : \"bar\" }"); - // append_only_user is allowed to index document if it does not exist when Id is specified and op_type is create - assertAccessIsAllowed(user, "PUT", "/" + INDEX_NAME + "/_doc/123?op_type=create", "{ \"foo\" : \"bar\" }"); - - // append_only_user is not allowed to index document even if it does not exist when Id is specified and op_type is default (index) - assertAccessIsDenied(user, "PUT", "/" + INDEX_NAME + "/_doc/321", "{ \"foo\" : \"bar\" }"); - // no updates allowed - assertAccessIsDenied(user, "POST", "/" + INDEX_NAME + "/_doc/1/_update", "{ \"doc\" : { \"foo\" : \"baz\" } }"); - assertAccessIsDenied(user, "PUT", "/" + INDEX_NAME + "/_doc/1", "{ \"foo\" : \"baz\" }"); - - // bulk API with create and index with no id only - assertAccessIsAllowed(user, randomFrom("PUT", "POST"), - "/" + INDEX_NAME + "/_bulk", "{ \"create\" : { \"_id\" : \"145\" } }\n{ \"foo\" : \"bar\" }\n"); - assertAccessIsAllowed(user, randomFrom("PUT", "POST"), + public void testAppendOnlyUserCanIndexNewDocumentsWithAutoGeneratedId() throws IOException { + assertAccessIsAllowed(APPEND_ONLY_USER, "POST", "/" + INDEX_NAME + "/_doc", "{ \"foo\" : \"bar\" }"); + } + + public void testAppendOnlyUserCanIndexNewDocumentsWithExternalIdAndOpTypeIsCreate() throws IOException { + assertAccessIsAllowed(APPEND_ONLY_USER, "PUT", "/" + INDEX_NAME + "/_doc/2?op_type=create", "{ \"foo\" : \"bar\" }"); + } + + public void testAppendOnlyUserIsDeniedToIndexNewDocumentsWithExternalIdAndOpTypeIsIndex() throws IOException { + assertAccessIsDenied(APPEND_ONLY_USER, "PUT", "/" + INDEX_NAME + "/_doc/3", "{ \"foo\" : \"bar\" }"); + } + + public void testAppendOnlyUserIsDeniedToIndexUpdatesToExistingDocument() throws IOException { + assertAccessIsDenied(APPEND_ONLY_USER, "POST", "/" + INDEX_NAME + "/_doc/1/_update", "{ \"doc\" : { \"foo\" : \"baz\" } }"); + assertAccessIsDenied(APPEND_ONLY_USER, "PUT", "/" + INDEX_NAME + "/_doc/1", "{ \"foo\" : \"baz\" }"); + } + + public void testAppendOnlyUserCanIndexNewDocumentsWithAutoGeneratedIdUsingBulkApi() throws IOException { + assertAccessIsAllowed(APPEND_ONLY_USER, randomFrom("PUT", "POST"), "/" + INDEX_NAME + "/_bulk", "{ \"index\" : { } }\n{ \"foo\" : \"bar\" }\n"); + } + + public void testAppendOnlyUserCanIndexNewDocumentsWithExternalIdAndOpTypeIsCreateUsingBulkApi() throws IOException { + assertAccessIsAllowed(APPEND_ONLY_USER, randomFrom("PUT", "POST"), + "/" + INDEX_NAME + "/_bulk", "{ \"create\" : { \"_id\" : \"4\" } }\n{ \"foo\" : \"bar\" }\n"); + } - // Bulk API deny access for update or index with id (we do not know if it exists) - assertBodyHasAccessIsDenied(user, randomFrom("PUT", "POST"), - "/" + INDEX_NAME + "/_bulk", "{ \"update\" : { \"_id\" : \"145\" } }\n{ \"doc\" : {\"foo\" : \"bazbaz\"} }\n"); - assertBodyHasAccessIsDenied(user, randomFrom("PUT", "POST"), - "/" + INDEX_NAME + "/_bulk", "{ \"index\" : { \"_id\" : \"149\" } }\n{ \"foo\" : \"bar\" }\n"); + public void testAppendOnlyUserIsDeniedToIndexNewDocumentsWithExternalIdAndOpTypeIsIndexUsingBulkApi() throws IOException { + assertBodyHasAccessIsDenied(APPEND_ONLY_USER, randomFrom("PUT", "POST"), + "/" + INDEX_NAME + "/_bulk", "{ \"index\" : { \"_id\" : \"5\" } }\n{ \"foo\" : \"bar\" }\n"); } + + public void testAppendOnlyUserIsDeniedToIndexUpdatesToExistingDocumentUsingBulkApi() throws IOException { + assertBodyHasAccessIsDenied(APPEND_ONLY_USER, randomFrom("PUT", "POST"), + "/" + INDEX_NAME + "/_bulk", "{ \"index\" : { \"_id\" : \"1\" } }\n{ \"doc\" : {\"foo\" : \"bazbaz\"} }\n"); + assertBodyHasAccessIsDenied(APPEND_ONLY_USER, randomFrom("PUT", "POST"), + "/" + INDEX_NAME + "/_bulk", "{ \"update\" : { \"_id\" : \"1\" } }\n{ \"doc\" : {\"foo\" : \"bazbaz\"} }\n"); + } + } From dca6df00544ca88b30ef46e319d5cfc0440fe028 Mon Sep 17 00:00:00 2001 From: Yogesh Gaikwad Date: Mon, 23 Sep 2019 20:36:29 +1000 Subject: [PATCH 11/17] 'create_docs' as index privilege name instead of append-only --- .../security/get-builtin-privileges.asciidoc | 2 +- .../authz/privilege/IndexPrivilege.java | 6 +-- ...ava => CreateDocsIndexPrivilegeTests.java} | 40 +++++++++---------- 3 files changed, 23 insertions(+), 25 deletions(-) rename x-pack/plugin/security/src/test/java/org/elasticsearch/integration/{AppendOnlyIndexPrivilegeTests.java => CreateDocsIndexPrivilegeTests.java} (74%) diff --git a/x-pack/docs/en/rest-api/security/get-builtin-privileges.asciidoc b/x-pack/docs/en/rest-api/security/get-builtin-privileges.asciidoc index 9718a6a9f1261..7602644db486d 100644 --- a/x-pack/docs/en/rest-api/security/get-builtin-privileges.asciidoc +++ b/x-pack/docs/en/rest-api/security/get-builtin-privileges.asciidoc @@ -95,8 +95,8 @@ A successful call returns an object with "cluster" and "index" fields. ], "index" : [ "all", - "append_only", "create", + "create_docs", "create_index", "delete", "delete_index", 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 897f94cf7cb55..9cd66eeda2e0d 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 @@ -45,7 +45,7 @@ public final class IndexPrivilege extends Privilege { ClusterSearchShardsAction.NAME); private static final Automaton CREATE_AUTOMATON = patterns("indices:data/write/index*", "indices:data/write/bulk*", PutMappingAction.NAME); - private static final Automaton APPEND_ONLY_AUTOMATON = Automatons.minusAndMinimize(CREATE_AUTOMATON, + private static final Automaton CREATE_DOCS_AUTOMATON = Automatons.minusAndMinimize(CREATE_AUTOMATON, patterns("indices:data/write/index:op_type/index")); private static final Automaton INDEX_AUTOMATON = patterns("indices:data/write/index*", "indices:data/write/bulk*", "indices:data/write/update*", PutMappingAction.NAME); @@ -70,9 +70,9 @@ public final class IndexPrivilege extends Privilege { public static final IndexPrivilege READ_CROSS_CLUSTER = new IndexPrivilege("read_cross_cluster", READ_CROSS_CLUSTER_AUTOMATON); public static final IndexPrivilege CREATE = new IndexPrivilege("create", CREATE_AUTOMATON); public static final IndexPrivilege INDEX = new IndexPrivilege("index", INDEX_AUTOMATON); - public static final IndexPrivilege APPEND_ONLY = new IndexPrivilege("append_only", APPEND_ONLY_AUTOMATON); public static final IndexPrivilege DELETE = new IndexPrivilege("delete", DELETE_AUTOMATON); public static final IndexPrivilege WRITE = new IndexPrivilege("write", WRITE_AUTOMATON); + public static final IndexPrivilege CREATE_DOCS = new IndexPrivilege("create_docs", CREATE_DOCS_AUTOMATON); public static final IndexPrivilege MONITOR = new IndexPrivilege("monitor", MONITOR_AUTOMATON); public static final IndexPrivilege MANAGE = new IndexPrivilege("manage", MANAGE_AUTOMATON); public static final IndexPrivilege DELETE_INDEX = new IndexPrivilege("delete_index", DELETE_INDEX_AUTOMATON); @@ -93,7 +93,7 @@ public final class IndexPrivilege extends Privilege { entry("delete", DELETE), entry("write", WRITE), entry("create", CREATE), - entry("append_only", APPEND_ONLY), + entry("create_docs", CREATE_DOCS), entry("delete_index", DELETE_INDEX), entry("view_index_metadata", VIEW_METADATA), entry("read_cross_cluster", READ_CROSS_CLUSTER), diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/integration/AppendOnlyIndexPrivilegeTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/integration/CreateDocsIndexPrivilegeTests.java similarity index 74% rename from x-pack/plugin/security/src/test/java/org/elasticsearch/integration/AppendOnlyIndexPrivilegeTests.java rename to x-pack/plugin/security/src/test/java/org/elasticsearch/integration/CreateDocsIndexPrivilegeTests.java index 686ef8687bcd9..6acd1fcc00cf5 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/integration/AppendOnlyIndexPrivilegeTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/integration/CreateDocsIndexPrivilegeTests.java @@ -1,9 +1,7 @@ /* - * - * * 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. - * + * 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.integration; @@ -15,23 +13,23 @@ import java.io.IOException; -public class AppendOnlyIndexPrivilegeTests extends AbstractPrivilegeTestCase { +public class CreateDocsIndexPrivilegeTests extends AbstractPrivilegeTestCase { private static final String INDEX_NAME = "index-1"; - private static final String APPEND_ONLY_USER = "append_only_user"; + private static final String CREATE_DOCS_USER = "create_docs_user"; private String jsonDoc = "{ \"name\" : \"elasticsearch\", \"body\": \"foo bar\" }"; private static final String ROLES = "all_indices_role:\n" + " indices:\n" + " - names: '*'\n" + " privileges: [ all ]\n" + - "append_only_role:\n" + + "create_docs_role:\n" + " indices:\n" + " - names: '*'\n" + - " privileges: [ append_only ]\n"; + " privileges: [ create_docs ]\n"; private static final String USERS_ROLES = "all_indices_role:admin\n" + - "append_only_role:" + APPEND_ONLY_USER + "\n"; + "create_docs_role:" + CREATE_DOCS_USER + "\n"; @Override protected boolean addMockHttpTransport() { @@ -50,7 +48,7 @@ protected String configUsers() { return super.configUsers() + "admin:" + usersPasswdHashed + "\n" + - "append_only_user:" + usersPasswdHashed + "\n"; + CREATE_DOCS_USER + ":" + usersPasswdHashed + "\n"; } @Override @@ -67,41 +65,41 @@ public void insertBaseDocumentsAsAdmin() throws Exception { } public void testAppendOnlyUserCanIndexNewDocumentsWithAutoGeneratedId() throws IOException { - assertAccessIsAllowed(APPEND_ONLY_USER, "POST", "/" + INDEX_NAME + "/_doc", "{ \"foo\" : \"bar\" }"); + assertAccessIsAllowed(CREATE_DOCS_USER, "POST", "/" + INDEX_NAME + "/_doc", "{ \"foo\" : \"bar\" }"); } public void testAppendOnlyUserCanIndexNewDocumentsWithExternalIdAndOpTypeIsCreate() throws IOException { - assertAccessIsAllowed(APPEND_ONLY_USER, "PUT", "/" + INDEX_NAME + "/_doc/2?op_type=create", "{ \"foo\" : \"bar\" }"); + assertAccessIsAllowed(CREATE_DOCS_USER, "PUT", "/" + INDEX_NAME + "/_doc/2?op_type=create", "{ \"foo\" : \"bar\" }"); } public void testAppendOnlyUserIsDeniedToIndexNewDocumentsWithExternalIdAndOpTypeIsIndex() throws IOException { - assertAccessIsDenied(APPEND_ONLY_USER, "PUT", "/" + INDEX_NAME + "/_doc/3", "{ \"foo\" : \"bar\" }"); + assertAccessIsDenied(CREATE_DOCS_USER, "PUT", "/" + INDEX_NAME + "/_doc/3", "{ \"foo\" : \"bar\" }"); } public void testAppendOnlyUserIsDeniedToIndexUpdatesToExistingDocument() throws IOException { - assertAccessIsDenied(APPEND_ONLY_USER, "POST", "/" + INDEX_NAME + "/_doc/1/_update", "{ \"doc\" : { \"foo\" : \"baz\" } }"); - assertAccessIsDenied(APPEND_ONLY_USER, "PUT", "/" + INDEX_NAME + "/_doc/1", "{ \"foo\" : \"baz\" }"); + assertAccessIsDenied(CREATE_DOCS_USER, "POST", "/" + INDEX_NAME + "/_doc/1/_update", "{ \"doc\" : { \"foo\" : \"baz\" } }"); + assertAccessIsDenied(CREATE_DOCS_USER, "PUT", "/" + INDEX_NAME + "/_doc/1", "{ \"foo\" : \"baz\" }"); } public void testAppendOnlyUserCanIndexNewDocumentsWithAutoGeneratedIdUsingBulkApi() throws IOException { - assertAccessIsAllowed(APPEND_ONLY_USER, randomFrom("PUT", "POST"), + assertAccessIsAllowed(CREATE_DOCS_USER, randomFrom("PUT", "POST"), "/" + INDEX_NAME + "/_bulk", "{ \"index\" : { } }\n{ \"foo\" : \"bar\" }\n"); } public void testAppendOnlyUserCanIndexNewDocumentsWithExternalIdAndOpTypeIsCreateUsingBulkApi() throws IOException { - assertAccessIsAllowed(APPEND_ONLY_USER, randomFrom("PUT", "POST"), + assertAccessIsAllowed(CREATE_DOCS_USER, randomFrom("PUT", "POST"), "/" + INDEX_NAME + "/_bulk", "{ \"create\" : { \"_id\" : \"4\" } }\n{ \"foo\" : \"bar\" }\n"); } public void testAppendOnlyUserIsDeniedToIndexNewDocumentsWithExternalIdAndOpTypeIsIndexUsingBulkApi() throws IOException { - assertBodyHasAccessIsDenied(APPEND_ONLY_USER, randomFrom("PUT", "POST"), + assertBodyHasAccessIsDenied(CREATE_DOCS_USER, randomFrom("PUT", "POST"), "/" + INDEX_NAME + "/_bulk", "{ \"index\" : { \"_id\" : \"5\" } }\n{ \"foo\" : \"bar\" }\n"); } public void testAppendOnlyUserIsDeniedToIndexUpdatesToExistingDocumentUsingBulkApi() throws IOException { - assertBodyHasAccessIsDenied(APPEND_ONLY_USER, randomFrom("PUT", "POST"), + assertBodyHasAccessIsDenied(CREATE_DOCS_USER, randomFrom("PUT", "POST"), "/" + INDEX_NAME + "/_bulk", "{ \"index\" : { \"_id\" : \"1\" } }\n{ \"doc\" : {\"foo\" : \"bazbaz\"} }\n"); - assertBodyHasAccessIsDenied(APPEND_ONLY_USER, randomFrom("PUT", "POST"), + assertBodyHasAccessIsDenied(CREATE_DOCS_USER, randomFrom("PUT", "POST"), "/" + INDEX_NAME + "/_bulk", "{ \"update\" : { \"_id\" : \"1\" } }\n{ \"doc\" : {\"foo\" : \"bazbaz\"} }\n"); } From 931823dd10d0fbefa4b9cf945e7a301568b136d2 Mon Sep 17 00:00:00 2001 From: Yogesh Gaikwad Date: Wed, 25 Sep 2019 13:06:37 +1000 Subject: [PATCH 12/17] address review comment - use create_doc --- .../client/security/user/privileges/Role.java | 3 +- .../security/get-builtin-privileges.asciidoc | 2 +- .../authz/privilege/IndexPrivilege.java | 6 ++-- .../CreateDocsIndexPrivilegeTests.java | 30 +++++++++---------- .../test/privileges/11_builtin.yml | 2 +- 5 files changed, 22 insertions(+), 21 deletions(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/security/user/privileges/Role.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/user/privileges/Role.java index e8e1a104d8c2c..c1eae86c9f18a 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/security/user/privileges/Role.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/user/privileges/Role.java @@ -345,8 +345,9 @@ public static class IndexPrivilegeName { public static final String VIEW_INDEX_METADATA = "view_index_metadata"; public static final String MANAGE_FOLLOW_INDEX = "manage_follow_index"; public static final String MANAGE_ILM = "manage_ilm"; + public static final String CREATE_DOC = "create_doc"; public static final String[] ALL_ARRAY = new String[] { NONE, ALL, READ, READ_CROSS, CREATE, INDEX, DELETE, WRITE, MONITOR, MANAGE, - DELETE_INDEX, CREATE_INDEX, VIEW_INDEX_METADATA, MANAGE_FOLLOW_INDEX, MANAGE_ILM }; + DELETE_INDEX, CREATE_INDEX, VIEW_INDEX_METADATA, MANAGE_FOLLOW_INDEX, MANAGE_ILM, CREATE_DOC }; } } diff --git a/x-pack/docs/en/rest-api/security/get-builtin-privileges.asciidoc b/x-pack/docs/en/rest-api/security/get-builtin-privileges.asciidoc index 7602644db486d..3c954a8d44bbd 100644 --- a/x-pack/docs/en/rest-api/security/get-builtin-privileges.asciidoc +++ b/x-pack/docs/en/rest-api/security/get-builtin-privileges.asciidoc @@ -96,7 +96,7 @@ A successful call returns an object with "cluster" and "index" fields. "index" : [ "all", "create", - "create_docs", + "create_doc", "create_index", "delete", "delete_index", 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 9cd66eeda2e0d..9a76d7bf39bbb 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 @@ -45,7 +45,7 @@ public final class IndexPrivilege extends Privilege { ClusterSearchShardsAction.NAME); private static final Automaton CREATE_AUTOMATON = patterns("indices:data/write/index*", "indices:data/write/bulk*", PutMappingAction.NAME); - private static final Automaton CREATE_DOCS_AUTOMATON = Automatons.minusAndMinimize(CREATE_AUTOMATON, + private static final Automaton CREATE_DOC_AUTOMATON = Automatons.minusAndMinimize(CREATE_AUTOMATON, patterns("indices:data/write/index:op_type/index")); private static final Automaton INDEX_AUTOMATON = patterns("indices:data/write/index*", "indices:data/write/bulk*", "indices:data/write/update*", PutMappingAction.NAME); @@ -72,7 +72,7 @@ public final class IndexPrivilege extends Privilege { public static final IndexPrivilege INDEX = new IndexPrivilege("index", INDEX_AUTOMATON); public static final IndexPrivilege DELETE = new IndexPrivilege("delete", DELETE_AUTOMATON); public static final IndexPrivilege WRITE = new IndexPrivilege("write", WRITE_AUTOMATON); - public static final IndexPrivilege CREATE_DOCS = new IndexPrivilege("create_docs", CREATE_DOCS_AUTOMATON); + public static final IndexPrivilege CREATE_DOC = new IndexPrivilege("create_doc", CREATE_DOC_AUTOMATON); public static final IndexPrivilege MONITOR = new IndexPrivilege("monitor", MONITOR_AUTOMATON); public static final IndexPrivilege MANAGE = new IndexPrivilege("manage", MANAGE_AUTOMATON); public static final IndexPrivilege DELETE_INDEX = new IndexPrivilege("delete_index", DELETE_INDEX_AUTOMATON); @@ -93,7 +93,7 @@ public final class IndexPrivilege extends Privilege { entry("delete", DELETE), entry("write", WRITE), entry("create", CREATE), - entry("create_docs", CREATE_DOCS), + entry("create_doc", CREATE_DOC), entry("delete_index", DELETE_INDEX), entry("view_index_metadata", VIEW_METADATA), entry("read_cross_cluster", READ_CROSS_CLUSTER), diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/integration/CreateDocsIndexPrivilegeTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/integration/CreateDocsIndexPrivilegeTests.java index 6acd1fcc00cf5..f61171ecd93ce 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/integration/CreateDocsIndexPrivilegeTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/integration/CreateDocsIndexPrivilegeTests.java @@ -15,21 +15,21 @@ public class CreateDocsIndexPrivilegeTests extends AbstractPrivilegeTestCase { private static final String INDEX_NAME = "index-1"; - private static final String CREATE_DOCS_USER = "create_docs_user"; + private static final String CREATE_DOC_USER = "create_doc_user"; private String jsonDoc = "{ \"name\" : \"elasticsearch\", \"body\": \"foo bar\" }"; private static final String ROLES = "all_indices_role:\n" + " indices:\n" + " - names: '*'\n" + " privileges: [ all ]\n" + - "create_docs_role:\n" + + "create_doc_role:\n" + " indices:\n" + " - names: '*'\n" + - " privileges: [ create_docs ]\n"; + " privileges: [ create_doc ]\n"; private static final String USERS_ROLES = "all_indices_role:admin\n" + - "create_docs_role:" + CREATE_DOCS_USER + "\n"; + "create_doc_role:" + CREATE_DOC_USER + "\n"; @Override protected boolean addMockHttpTransport() { @@ -48,7 +48,7 @@ protected String configUsers() { return super.configUsers() + "admin:" + usersPasswdHashed + "\n" + - CREATE_DOCS_USER + ":" + usersPasswdHashed + "\n"; + CREATE_DOC_USER + ":" + usersPasswdHashed + "\n"; } @Override @@ -65,41 +65,41 @@ public void insertBaseDocumentsAsAdmin() throws Exception { } public void testAppendOnlyUserCanIndexNewDocumentsWithAutoGeneratedId() throws IOException { - assertAccessIsAllowed(CREATE_DOCS_USER, "POST", "/" + INDEX_NAME + "/_doc", "{ \"foo\" : \"bar\" }"); + assertAccessIsAllowed(CREATE_DOC_USER, "POST", "/" + INDEX_NAME + "/_doc", "{ \"foo\" : \"bar\" }"); } public void testAppendOnlyUserCanIndexNewDocumentsWithExternalIdAndOpTypeIsCreate() throws IOException { - assertAccessIsAllowed(CREATE_DOCS_USER, "PUT", "/" + INDEX_NAME + "/_doc/2?op_type=create", "{ \"foo\" : \"bar\" }"); + assertAccessIsAllowed(CREATE_DOC_USER, "PUT", "/" + INDEX_NAME + "/_doc/2?op_type=create", "{ \"foo\" : \"bar\" }"); } public void testAppendOnlyUserIsDeniedToIndexNewDocumentsWithExternalIdAndOpTypeIsIndex() throws IOException { - assertAccessIsDenied(CREATE_DOCS_USER, "PUT", "/" + INDEX_NAME + "/_doc/3", "{ \"foo\" : \"bar\" }"); + assertAccessIsDenied(CREATE_DOC_USER, "PUT", "/" + INDEX_NAME + "/_doc/3", "{ \"foo\" : \"bar\" }"); } public void testAppendOnlyUserIsDeniedToIndexUpdatesToExistingDocument() throws IOException { - assertAccessIsDenied(CREATE_DOCS_USER, "POST", "/" + INDEX_NAME + "/_doc/1/_update", "{ \"doc\" : { \"foo\" : \"baz\" } }"); - assertAccessIsDenied(CREATE_DOCS_USER, "PUT", "/" + INDEX_NAME + "/_doc/1", "{ \"foo\" : \"baz\" }"); + assertAccessIsDenied(CREATE_DOC_USER, "POST", "/" + INDEX_NAME + "/_doc/1/_update", "{ \"doc\" : { \"foo\" : \"baz\" } }"); + assertAccessIsDenied(CREATE_DOC_USER, "PUT", "/" + INDEX_NAME + "/_doc/1", "{ \"foo\" : \"baz\" }"); } public void testAppendOnlyUserCanIndexNewDocumentsWithAutoGeneratedIdUsingBulkApi() throws IOException { - assertAccessIsAllowed(CREATE_DOCS_USER, randomFrom("PUT", "POST"), + assertAccessIsAllowed(CREATE_DOC_USER, randomFrom("PUT", "POST"), "/" + INDEX_NAME + "/_bulk", "{ \"index\" : { } }\n{ \"foo\" : \"bar\" }\n"); } public void testAppendOnlyUserCanIndexNewDocumentsWithExternalIdAndOpTypeIsCreateUsingBulkApi() throws IOException { - assertAccessIsAllowed(CREATE_DOCS_USER, randomFrom("PUT", "POST"), + assertAccessIsAllowed(CREATE_DOC_USER, randomFrom("PUT", "POST"), "/" + INDEX_NAME + "/_bulk", "{ \"create\" : { \"_id\" : \"4\" } }\n{ \"foo\" : \"bar\" }\n"); } public void testAppendOnlyUserIsDeniedToIndexNewDocumentsWithExternalIdAndOpTypeIsIndexUsingBulkApi() throws IOException { - assertBodyHasAccessIsDenied(CREATE_DOCS_USER, randomFrom("PUT", "POST"), + assertBodyHasAccessIsDenied(CREATE_DOC_USER, randomFrom("PUT", "POST"), "/" + INDEX_NAME + "/_bulk", "{ \"index\" : { \"_id\" : \"5\" } }\n{ \"foo\" : \"bar\" }\n"); } public void testAppendOnlyUserIsDeniedToIndexUpdatesToExistingDocumentUsingBulkApi() throws IOException { - assertBodyHasAccessIsDenied(CREATE_DOCS_USER, randomFrom("PUT", "POST"), + assertBodyHasAccessIsDenied(CREATE_DOC_USER, randomFrom("PUT", "POST"), "/" + INDEX_NAME + "/_bulk", "{ \"index\" : { \"_id\" : \"1\" } }\n{ \"doc\" : {\"foo\" : \"bazbaz\"} }\n"); - assertBodyHasAccessIsDenied(CREATE_DOCS_USER, randomFrom("PUT", "POST"), + assertBodyHasAccessIsDenied(CREATE_DOC_USER, randomFrom("PUT", "POST"), "/" + INDEX_NAME + "/_bulk", "{ \"update\" : { \"_id\" : \"1\" } }\n{ \"doc\" : {\"foo\" : \"bazbaz\"} }\n"); } diff --git a/x-pack/plugin/src/test/resources/rest-api-spec/test/privileges/11_builtin.yml b/x-pack/plugin/src/test/resources/rest-api-spec/test/privileges/11_builtin.yml index 234e56278535e..9ac2fdf23c9af 100644 --- a/x-pack/plugin/src/test/resources/rest-api-spec/test/privileges/11_builtin.yml +++ b/x-pack/plugin/src/test/resources/rest-api-spec/test/privileges/11_builtin.yml @@ -15,5 +15,5 @@ setup: # This is fragile - it needs to be updated every time we add a new cluster/index privilege # I would much prefer we could just check that specific entries are in the array, but we don't have # an assertion for that - - length: { "cluster" : 31 } + - length: { "cluster" : 30 } - length: { "index" : 17 } From 9829bd4efeb85973f8ccaa8c8633cb1f20bd3162 Mon Sep 17 00:00:00 2001 From: Yogesh Gaikwad Date: Thu, 26 Sep 2019 20:43:55 +1000 Subject: [PATCH 13/17] address review comment --- .../CreateDocsIndexPrivilegeTests.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/integration/CreateDocsIndexPrivilegeTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/integration/CreateDocsIndexPrivilegeTests.java index f61171ecd93ce..4be34448a8c8b 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/integration/CreateDocsIndexPrivilegeTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/integration/CreateDocsIndexPrivilegeTests.java @@ -64,39 +64,39 @@ public void insertBaseDocumentsAsAdmin() throws Exception { assertAccessIsAllowed("admin", request); } - public void testAppendOnlyUserCanIndexNewDocumentsWithAutoGeneratedId() throws IOException { + public void testCreateDocUserCanIndexNewDocumentsWithAutoGeneratedId() throws IOException { assertAccessIsAllowed(CREATE_DOC_USER, "POST", "/" + INDEX_NAME + "/_doc", "{ \"foo\" : \"bar\" }"); } - public void testAppendOnlyUserCanIndexNewDocumentsWithExternalIdAndOpTypeIsCreate() throws IOException { + public void testCreateDocUserCanIndexNewDocumentsWithExternalIdAndOpTypeIsCreate() throws IOException { assertAccessIsAllowed(CREATE_DOC_USER, "PUT", "/" + INDEX_NAME + "/_doc/2?op_type=create", "{ \"foo\" : \"bar\" }"); } - public void testAppendOnlyUserIsDeniedToIndexNewDocumentsWithExternalIdAndOpTypeIsIndex() throws IOException { + public void testCreateDocUserIsDeniedToIndexNewDocumentsWithExternalIdAndOpTypeIsIndex() throws IOException { assertAccessIsDenied(CREATE_DOC_USER, "PUT", "/" + INDEX_NAME + "/_doc/3", "{ \"foo\" : \"bar\" }"); } - public void testAppendOnlyUserIsDeniedToIndexUpdatesToExistingDocument() throws IOException { + public void testCreateDocUserIsDeniedToIndexUpdatesToExistingDocument() throws IOException { assertAccessIsDenied(CREATE_DOC_USER, "POST", "/" + INDEX_NAME + "/_doc/1/_update", "{ \"doc\" : { \"foo\" : \"baz\" } }"); assertAccessIsDenied(CREATE_DOC_USER, "PUT", "/" + INDEX_NAME + "/_doc/1", "{ \"foo\" : \"baz\" }"); } - public void testAppendOnlyUserCanIndexNewDocumentsWithAutoGeneratedIdUsingBulkApi() throws IOException { + public void testCreateDocUserCanIndexNewDocumentsWithAutoGeneratedIdUsingBulkApi() throws IOException { assertAccessIsAllowed(CREATE_DOC_USER, randomFrom("PUT", "POST"), "/" + INDEX_NAME + "/_bulk", "{ \"index\" : { } }\n{ \"foo\" : \"bar\" }\n"); } - public void testAppendOnlyUserCanIndexNewDocumentsWithExternalIdAndOpTypeIsCreateUsingBulkApi() throws IOException { + public void testCreateDocUserCanIndexNewDocumentsWithExternalIdAndOpTypeIsCreateUsingBulkApi() throws IOException { assertAccessIsAllowed(CREATE_DOC_USER, randomFrom("PUT", "POST"), "/" + INDEX_NAME + "/_bulk", "{ \"create\" : { \"_id\" : \"4\" } }\n{ \"foo\" : \"bar\" }\n"); } - public void testAppendOnlyUserIsDeniedToIndexNewDocumentsWithExternalIdAndOpTypeIsIndexUsingBulkApi() throws IOException { + public void testCreateDocUserIsDeniedToIndexNewDocumentsWithExternalIdAndOpTypeIsIndexUsingBulkApi() throws IOException { assertBodyHasAccessIsDenied(CREATE_DOC_USER, randomFrom("PUT", "POST"), "/" + INDEX_NAME + "/_bulk", "{ \"index\" : { \"_id\" : \"5\" } }\n{ \"foo\" : \"bar\" }\n"); } - public void testAppendOnlyUserIsDeniedToIndexUpdatesToExistingDocumentUsingBulkApi() throws IOException { + public void testCreateDocUserIsDeniedToIndexUpdatesToExistingDocumentUsingBulkApi() throws IOException { assertBodyHasAccessIsDenied(CREATE_DOC_USER, randomFrom("PUT", "POST"), "/" + INDEX_NAME + "/_bulk", "{ \"index\" : { \"_id\" : \"1\" } }\n{ \"doc\" : {\"foo\" : \"bazbaz\"} }\n"); assertBodyHasAccessIsDenied(CREATE_DOC_USER, randomFrom("PUT", "POST"), From 39270635ad9fe90f251b3691733f205b1690db0a Mon Sep 17 00:00:00 2001 From: Yogesh Gaikwad Date: Fri, 4 Oct 2019 13:02:45 +1000 Subject: [PATCH 14/17] remove the logic to determine effective op_type --- .../xpack/security/authz/AuthorizationService.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java index 609241cad0d84..828666a0be1dc 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java @@ -539,11 +539,6 @@ private static String getAction(BulkItemRequest item) { final DocWriteRequest docWriteRequest = item.request(); switch (docWriteRequest.opType()) { case INDEX: - IndexRequest request = (IndexRequest) item.request(); - if (request.getAutoGeneratedTimestamp() != IndexRequest.UNSET_AUTO_GENERATED_TIMESTAMP) { - // it is auto generated so create is implied - return IMPLIED_CREATE_ACTION; - } return IMPLIED_INDEX_ACTION; case CREATE: return IMPLIED_CREATE_ACTION; From 9e79797fd8a62bec154c661a359c0145addb18ea Mon Sep 17 00:00:00 2001 From: Yogesh Gaikwad Date: Fri, 4 Oct 2019 16:01:11 +1000 Subject: [PATCH 15/17] remove unused import --- .../elasticsearch/xpack/security/authz/AuthorizationService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java index 828666a0be1dc..a9a971a091422 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java @@ -20,7 +20,6 @@ import org.elasticsearch.action.bulk.TransportShardBulkAction; import org.elasticsearch.action.delete.DeleteAction; import org.elasticsearch.action.index.IndexAction; -import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.support.GroupedActionListener; import org.elasticsearch.action.support.replication.TransportReplicationAction.ConcreteShardRequest; import org.elasticsearch.action.update.UpdateAction; From 635ccaad92503575f424706025a854b9924ed84d Mon Sep 17 00:00:00 2001 From: Yogesh Gaikwad Date: Sat, 5 Oct 2019 21:24:46 +1000 Subject: [PATCH 16/17] add test case for bulk with create op_type --- .../integration/CreateDocsIndexPrivilegeTests.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/integration/CreateDocsIndexPrivilegeTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/integration/CreateDocsIndexPrivilegeTests.java index 4be34448a8c8b..edc9e7e4fd94b 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/integration/CreateDocsIndexPrivilegeTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/integration/CreateDocsIndexPrivilegeTests.java @@ -69,11 +69,12 @@ public void testCreateDocUserCanIndexNewDocumentsWithAutoGeneratedId() throws IO } public void testCreateDocUserCanIndexNewDocumentsWithExternalIdAndOpTypeIsCreate() throws IOException { - assertAccessIsAllowed(CREATE_DOC_USER, "PUT", "/" + INDEX_NAME + "/_doc/2?op_type=create", "{ \"foo\" : \"bar\" }"); + assertAccessIsAllowed(CREATE_DOC_USER, randomFrom("PUT", "POST"), "/" + INDEX_NAME + "/_doc/2?op_type=create", "{ \"foo\" : " + + "\"bar\" }"); } public void testCreateDocUserIsDeniedToIndexNewDocumentsWithExternalIdAndOpTypeIsIndex() throws IOException { - assertAccessIsDenied(CREATE_DOC_USER, "PUT", "/" + INDEX_NAME + "/_doc/3", "{ \"foo\" : \"bar\" }"); + assertAccessIsDenied(CREATE_DOC_USER, randomFrom("PUT", "POST"), "/" + INDEX_NAME + "/_doc/3", "{ \"foo\" : \"bar\" }"); } public void testCreateDocUserIsDeniedToIndexUpdatesToExistingDocument() throws IOException { @@ -86,6 +87,11 @@ public void testCreateDocUserCanIndexNewDocumentsWithAutoGeneratedIdUsingBulkApi "/" + INDEX_NAME + "/_bulk", "{ \"index\" : { } }\n{ \"foo\" : \"bar\" }\n"); } + public void testCreateDocUserCanIndexNewDocumentsWithAutoGeneratedIdAndOpTypeCreateUsingBulkApi() throws IOException { + assertAccessIsAllowed(CREATE_DOC_USER, randomFrom("PUT", "POST"), + "/" + INDEX_NAME + "/_bulk", "{ \"create\" : { } }\n{ \"foo\" : \"bar\" }\n"); + } + public void testCreateDocUserCanIndexNewDocumentsWithExternalIdAndOpTypeIsCreateUsingBulkApi() throws IOException { assertAccessIsAllowed(CREATE_DOC_USER, randomFrom("PUT", "POST"), "/" + INDEX_NAME + "/_bulk", "{ \"create\" : { \"_id\" : \"4\" } }\n{ \"foo\" : \"bar\" }\n"); From e55225aa161c18943457a05425f3fbbce2ad3c5a Mon Sep 17 00:00:00 2001 From: Yogesh Gaikwad Date: Mon, 7 Oct 2019 16:14:35 +1100 Subject: [PATCH 17/17] address review comments --- .../xpack/core/security/authz/privilege/IndexPrivilege.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 ef9101316e6e8..8ae7337ba195f 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 @@ -48,8 +48,8 @@ public final class IndexPrivilege extends Privilege { ClusterSearchShardsAction.NAME); private static final Automaton CREATE_AUTOMATON = patterns("indices:data/write/index*", "indices:data/write/bulk*", PutMappingAction.NAME); - private static final Automaton CREATE_DOC_AUTOMATON = Automatons.minusAndMinimize(CREATE_AUTOMATON, - patterns("indices:data/write/index:op_type/index")); + 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); private static final Automaton INDEX_AUTOMATON = patterns("indices:data/write/index*", "indices:data/write/bulk*", "indices:data/write/update*", PutMappingAction.NAME); private static final Automaton DELETE_AUTOMATON = patterns("indices:data/write/delete*", "indices:data/write/bulk*"); @@ -75,7 +75,7 @@ public final class IndexPrivilege extends Privilege { public static final IndexPrivilege INDEX = new IndexPrivilege("index", INDEX_AUTOMATON); public static final IndexPrivilege DELETE = new IndexPrivilege("delete", DELETE_AUTOMATON); public static final IndexPrivilege WRITE = new IndexPrivilege("write", WRITE_AUTOMATON); - public static final IndexPrivilege CREATE_DOC = new IndexPrivilege("create_doc", CREATE_DOC_AUTOMATON); + public static final IndexPrivilege CREATE_DOC = new IndexPrivilege("create_doc", CREATE_DOC_AUTOMATON); public static final IndexPrivilege MONITOR = new IndexPrivilege("monitor", MONITOR_AUTOMATON); public static final IndexPrivilege MANAGE = new IndexPrivilege("manage", MANAGE_AUTOMATON); public static final IndexPrivilege DELETE_INDEX = new IndexPrivilege("delete_index", DELETE_INDEX_AUTOMATON);