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 a970115f1861b..e70627c0c3744 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 @@ -85,6 +85,7 @@ A successful call returns an object with "cluster" and "index" fields. "manage_rollup", "manage_saml", "manage_search_application", + "manage_query_rules", "manage_security", "manage_service_account", "manage_slm", diff --git a/x-pack/docs/en/security/authorization/privileges.asciidoc b/x-pack/docs/en/security/authorization/privileges.asciidoc index d5bb89b0a9365..7fa02a68609e8 100644 --- a/x-pack/docs/en/security/authorization/privileges.asciidoc +++ b/x-pack/docs/en/security/authorization/privileges.asciidoc @@ -112,6 +112,9 @@ on behalf of other users. `manage_search_application`:: All CRUD operations on <>. +`manage_search_query_rules`:: +All CRUD operations on <>. + `manage_security`:: All security-related operations such as CRUD operations on users and roles and cache clearing. diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/ClusterPrivilegeResolver.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/ClusterPrivilegeResolver.java index bbdd0d7cd658f..edf1ccf3fcfff 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/ClusterPrivilegeResolver.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/ClusterPrivilegeResolver.java @@ -155,6 +155,7 @@ public class ClusterPrivilegeResolver { private static final Set READ_SLM_PATTERN = Set.of(GetSnapshotLifecycleAction.NAME, GetStatusAction.NAME); private static final Set MANAGE_SEARCH_APPLICATION_PATTERN = Set.of("cluster:admin/xpack/application/search_application/*"); + private static final Set MANAGE_SEARCH_QUERY_RULES_PATTERN = Set.of("cluster:admin/xpack/query_rules/*"); private static final Set MANAGE_SEARCH_SYNONYMS_PATTERN = Set.of( "cluster:admin/synonyms/*", "cluster:admin/synonyms_sets/*", @@ -297,6 +298,10 @@ public class ClusterPrivilegeResolver { POST_BEHAVIORAL_ANALYTICS_EVENT_PATTERN ); + public static final NamedClusterPrivilege MANAGE_SEARCH_QUERY_RULES = new ActionClusterPrivilege( + "manage_search_query_rules", + MANAGE_SEARCH_QUERY_RULES_PATTERN + ); public static final NamedClusterPrivilege CROSS_CLUSTER_SEARCH = new ActionClusterPrivilege( "cross_cluster_search", CROSS_CLUSTER_SEARCH_PATTERN @@ -356,6 +361,7 @@ public class ClusterPrivilegeResolver { SynonymsAPI.isEnabled() ? MANAGE_SEARCH_SYNONYMS : null, MANAGE_BEHAVIORAL_ANALYTICS, POST_BEHAVIORAL_ANALYTICS_EVENT, + MANAGE_SEARCH_QUERY_RULES, TcpTransport.isUntrustedRemoteClusterEnabled() ? CROSS_CLUSTER_SEARCH : null, TcpTransport.isUntrustedRemoteClusterEnabled() ? CROSS_CLUSTER_REPLICATION : null ).filter(Objects::nonNull).toList() diff --git a/x-pack/plugin/ent-search/qa/rest/build.gradle b/x-pack/plugin/ent-search/qa/rest/build.gradle index 32bb2dbcce4a8..cc202aa01c69e 100644 --- a/x-pack/plugin/ent-search/qa/rest/build.gradle +++ b/x-pack/plugin/ent-search/qa/rest/build.gradle @@ -19,4 +19,5 @@ testClusters.configureEach { user username: 'entsearch-superuser', password: 'entsearch-superuser-password', role: 'superuser' user username: 'entsearch-admin', password: 'entsearch-admin-password', role: 'admin' user username: 'entsearch-user', password: 'entsearch-user-password', role: 'user' + user username: 'entsearch-unprivileged', password: 'entsearch-unprivileged-password', role: 'unprivileged' } diff --git a/x-pack/plugin/ent-search/qa/rest/roles.yml b/x-pack/plugin/ent-search/qa/rest/roles.yml index 1e1c4739c4b8f..8d2ad43d02d08 100644 --- a/x-pack/plugin/ent-search/qa/rest/roles.yml +++ b/x-pack/plugin/ent-search/qa/rest/roles.yml @@ -25,3 +25,12 @@ user: ] privileges: [ "read" ] +unprivileged: + indices: + - names: [ + # indices and search applications + "test-*", + "another-test-search-application" + ] + privileges: [ "manage", "write", "read" ] + diff --git a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/20_search_application_put.yml b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/20_search_application_put.yml index d0bd5f8ee2dd4..4c4cfccf92a49 100644 --- a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/20_search_application_put.yml +++ b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/20_search_application_put.yml @@ -62,6 +62,37 @@ teardown: index: [ "test-index1", "test-index2", "test-index3", "test-index4" ] ignore: 404 +--- +"Create search application fails for unprivileged user": + - skip: + features: headers + + - do: + catch: unauthorized + headers: { Authorization: "Basic ZW50c2VhcmNoLXVucHJpdmlsZWdlZDplbnRzZWFyY2gtdW5wcml2aWxlZ2VkLXVzZXI=" } # unprivileged + search_application.put: + name: test-search-application + body: + indices: [ "test-index1", "test-index2" ] + template: + script: + source: + query: + query_string: + query: "{{query_string}}" + dictionary: + additionalProperties: false + required: [ "query_string" ] + properties: + query_string: + type: string + + - do: + indices.exists_alias: + name: test-search-application + + - is_false: '' + --- "Create Search Application": - do: diff --git a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/30_search_application_get.yml b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/30_search_application_get.yml index c5343a5d39003..b396c18f4b1ef 100644 --- a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/30_search_application_get.yml +++ b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/30_search_application_get.yml @@ -180,3 +180,14 @@ teardown: } } - gte: { updated_at_millis: 0 } + +--- +"Get search application fails for unprivileged user": + - skip: + features: headers + + - do: + catch: unauthorized + headers: { Authorization: "Basic ZW50c2VhcmNoLXVucHJpdmlsZWdlZDplbnRzZWFyY2gtdW5wcml2aWxlZ2VkLXVzZXI=" } # unprivileged + search_application.get: + name: test-search-application-1 diff --git a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/40_search_application_delete.yml b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/40_search_application_delete.yml index 9bb0918c10b04..88120b6f6ff44 100644 --- a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/40_search_application_delete.yml +++ b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/40_search_application_delete.yml @@ -20,6 +20,21 @@ teardown: name: test-search-application-to-delete ignore: 404 +--- +"Delete search application fails for unprivileged user": + - skip: + features: headers + + - do: + catch: unauthorized + headers: { Authorization: "Basic ZW50c2VhcmNoLXVucHJpdmlsZWdlZDplbnRzZWFyY2gtdW5wcml2aWxlZ2VkLXVzZXI=" } # unprivileged + search_application.delete: + name: test-search-application-to-delete + + - do: + search_application.get: + name: test-search-application-to-delete + --- "Delete Search Application": - do: diff --git a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/50_search_application_list.yml b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/50_search_application_list.yml index 7060fdfa2e209..47ef84cf91e0a 100644 --- a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/50_search_application_list.yml +++ b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/50_search_application_list.yml @@ -159,3 +159,15 @@ teardown: - match: { count: 0 } - match: { results: [] } + +--- +"List search applications fails for unprivileged user": + - skip: + features: headers + + - do: + catch: unauthorized + headers: { Authorization: "Basic ZW50c2VhcmNoLXVucHJpdmlsZWdlZDplbnRzZWFyY2gtdW5wcml2aWxlZ2VkLXVzZXI=" } # unprivileged + search_application.list: + from: 0 + size: 10 diff --git a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/52_search_application_render_query.yml b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/52_search_application_render_query.yml index 92b5d9832001d..3885b85ede686 100644 --- a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/52_search_application_render_query.yml +++ b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/52_search_application_render_query.yml @@ -152,3 +152,17 @@ teardown: params: field_name: field3 field_value: value3 + +--- +"Render search application query fails for unprivileged user": + - skip: + features: headers + + - do: + catch: unauthorized + headers: { Authorization: "Basic ZW50c2VhcmNoLXVucHJpdmlsZWdlZDplbnRzZWFyY2gtdW5wcml2aWxlZ2VkLXVzZXI=" } # unprivileged + search_application.render_query: + name: test-search-application + body: + params: + field_value: puggles diff --git a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/55_search_application_search.yml b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/55_search_application_search.yml index 08acaf01477a1..2c8c9154ba1ca 100644 --- a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/55_search_application_search.yml +++ b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/55_search_application_search.yml @@ -301,3 +301,18 @@ teardown: - match: { hits.total.value: 1 } - match: { hits.hits.0._id: "doc1" } + +--- +"Search application search fails for unprivileged user": + - skip: + features: headers + + - do: + catch: unauthorized + headers: { Authorization: "Basic ZW50c2VhcmNoLXVucHJpdmlsZWdlZDplbnRzZWFyY2gtdW5wcml2aWxlZ2VkLXVzZXI=" } # unprivileged + search_application.search: + name: test-search-application + body: + params: + field_value: puggles + diff --git a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/privileges/11_builtin.yml b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/privileges/11_builtin.yml index 7467d1760efc2..30303223410e1 100644 --- a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/privileges/11_builtin.yml +++ b/x-pack/plugin/src/yamlRestTest/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" : 49 } + - length: { "cluster" : 50 } - length: { "index" : 22 }