From 635a4fe2bd6bd88ea0122602f6fe68e6f72fbb3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BCscher?= Date: Thu, 1 Dec 2022 11:22:12 +0100 Subject: [PATCH] Mark empty `_terms_enum` results due to DLS as incomplete (#91720) Today `_terms_enum` returns empty results for indices with document level security. Elasticsearch should return some hint in case the user hits empty results due to DLS limitation so the caller (ie. Kibana) can fall back to other strategies or notify the user with some appropriate error message. This changes the behaviour of the NodeTransportHandler so that it returns a NodeTermsEnumResponse with an error indication. The resulting API response will flag the enum as "incomplete" and list the error in the shard errors section. Clients can choose to react to this in the appropriate way. Closes #88321 --- docs/changelog/91720.yaml | 6 ++++ .../action/TransportTermsEnumAction.java | 15 ++++++++- .../test/terms_enum/10_basic.yml | 31 +++++++++++++------ 3 files changed, 42 insertions(+), 10 deletions(-) create mode 100644 docs/changelog/91720.yaml diff --git a/docs/changelog/91720.yaml b/docs/changelog/91720.yaml new file mode 100644 index 0000000000000..4994330c8aaa6 --- /dev/null +++ b/docs/changelog/91720.yaml @@ -0,0 +1,6 @@ +pr: 91720 +summary: Mark empty `_terms_enum` results due to DLS as incomplete +area: Search +type: enhancement +issues: + - 88321 diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/termsenum/action/TransportTermsEnumAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/termsenum/action/TransportTermsEnumAction.java index 42729bebec943..c4a587814a541 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/termsenum/action/TransportTermsEnumAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/termsenum/action/TransportTermsEnumAction.java @@ -715,7 +715,20 @@ private void asyncNodeOperation(NodeTermsEnumRequest request, Task task, ActionL ThreadContext threadContext = transportService.getThreadPool().getThreadContext(); final XPackLicenseState frozenLicenseState = licenseState.copyCurrentLicenseState(); for (ShardId shardId : request.shardIds().toArray(new ShardId[0])) { - if (canAccess(shardId, request, frozenLicenseState, threadContext) == false || canMatchShard(shardId, request) == false) { + if (canAccess(shardId, request, frozenLicenseState, threadContext) == false) { + listener.onResponse( + new NodeTermsEnumResponse( + request.nodeId(), + Collections.emptyList(), + "cannot execute [_terms_enum] request on index [" + + shardId.getIndexName() + + "] due to " + + "DLS/FLS security restrictions.", + false + ) + ); + } + if (canMatchShard(shardId, request) == false) { // Permission denied or can't match, remove shardID from request request.remove(shardId); } diff --git a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/terms_enum/10_basic.yml b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/terms_enum/10_basic.yml index 359e14b935f82..a592768d8336e 100644 --- a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/terms_enum/10_basic.yml +++ b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/terms_enum/10_basic.yml @@ -549,18 +549,25 @@ teardown: - length: { terms: 1 } - do: - headers: { Authorization: "Basic ZGxzX3NvbWVfdXNlcjp4LXBhY2stdGVzdC1wYXNzd29yZA==" } # dls_some_user sees selected docs + headers: { Authorization: "Basic ZGxzX3NvbWVfdXNlcjp4LXBhY2stdGVzdC1wYXNzd29yZA==" } # dls_some_user doesn't see all docs terms_enum: - index: test_security - body: {"field": "foo", "string":"b"} - - length: {terms: 0} + index: test_security + body: { "field": "foo", "string": "b" } + + - length: { terms: 0 } + - match: { complete: false } + - match: { _shards.failed: 1 } + - match: { _shards.failures.0.reason.type: "broadcast_shard_operation_failed_exception" } + - match: { _shards.failures.0.reason.reason: "cannot execute [_terms_enum] request on index [test_security] due to DLS/FLS security restrictions." } - do: headers: { Authorization: "Basic ZmxzX3VzZXI6eC1wYWNrLXRlc3QtcGFzc3dvcmQ=" } # fls_user can't see field terms_enum: - index: test_security - body: {"field": "foo", "string":"b"} - - length: {terms: 0} + index: test_security + body: { "field": "foo", "string": "b" } + - length: { terms: 0 } + - match: { complete: true } + - match: { _shards.failed: 0 } --- "Test security with API keys": @@ -612,7 +619,7 @@ teardown: } } - match: { name: "dls_all_user_bad_key" } - - set: { encoded: login_creds} + - set: { encoded: login_creds } - do: headers: Authorization: ApiKey ${login_creds} # dls_all_user bad API key sees selected docs @@ -620,6 +627,9 @@ teardown: index: test_security body: { "field": "foo", "string": "b" } - length: { terms: 0 } + - match: { complete: false } + - match: { _shards.failed: 1 } + - match: { _shards.failures.0.reason.type: "broadcast_shard_operation_failed_exception" } - do: headers: { Authorization: "Basic ZGxzX3NvbWVfdXNlcjp4LXBhY2stdGVzdC1wYXNzd29yZA==" } # dls_some_user @@ -641,7 +651,7 @@ teardown: } } - match: { name: "dls_some_user_key" } - - set: { encoded: login_creds} + - set: { encoded: login_creds } - do: headers: Authorization: ApiKey ${login_creds} # dls_some_user's API key sees selected user regardless of the key's role descriptor @@ -649,3 +659,6 @@ teardown: index: test_security body: { "field": "foo", "string": "b" } - length: { terms: 0 } + - match: { complete: false } + - match: { _shards.failed: 1 } + - match: { _shards.failures.0.reason.type: "broadcast_shard_operation_failed_exception" }