diff --git a/x-pack/plugin/security/qa/security-trial/src/javaRestTest/java/org/elasticsearch/xpack/security/failurestore/FailureStoreSecurityRestIT.java b/x-pack/plugin/security/qa/security-trial/src/javaRestTest/java/org/elasticsearch/xpack/security/failurestore/FailureStoreSecurityRestIT.java index 76df8ab96dbe9..b9fe685fb0eb2 100644 --- a/x-pack/plugin/security/qa/security-trial/src/javaRestTest/java/org/elasticsearch/xpack/security/failurestore/FailureStoreSecurityRestIT.java +++ b/x-pack/plugin/security/qa/security-trial/src/javaRestTest/java/org/elasticsearch/xpack/security/failurestore/FailureStoreSecurityRestIT.java @@ -2159,6 +2159,155 @@ public void testFailureStoreAccessWithApiKeys() throws Exception { expectThrowsWithApiKey(apiKey, new Search("test1"), 403); } + public void testFieldCapabilities() throws Exception { + setupDataStream(); + + final Tuple backingIndices = getSingleDataAndFailureIndices("test1"); + final String dataIndexName = backingIndices.v1(); + final String failureIndexName = backingIndices.v2(); + + createUser("user", PASSWORD, "role"); + upsertRole(""" + { + "cluster": ["all"], + "indices": [ + { + "names": ["test*"], + "privileges": ["read"] + } + ] + }""", "role"); + + { + expectThrows(() -> performRequest("user", new Request("POST", "/test1::failures/_field_caps?fields=name")), 403); + assertFieldCapsResponseContainsIndexAndFields( + performRequest("user", new Request("POST", Strings.format("/%s/_field_caps?fields=name", "test1"))), + dataIndexName, + Set.of("name") + ); + } + + upsertRole(""" + { + "cluster": ["all"], + "indices": [ + { + "names": ["test*"], + "privileges": ["read_failure_store"] + } + ] + }""", "role"); + + { + expectThrows(() -> performRequest("user", new Request("POST", "/test1/_field_caps?fields=name")), 403); + assertFieldCapsResponseContainsIndexAndFields( + performRequest("user", new Request("POST", "/test1::failures/_field_caps?fields=error.*")), + failureIndexName, + Set.of( + "error.message", + "error.pipeline_trace", + "error.processor_type", + "error.type", + "error.processor_tag", + "error.pipeline", + "error.stack_trace", + "error" + ) + ); + } + + upsertRole(""" + { + "cluster": ["all"], + "indices": [ + { + "names": ["test*"], + "privileges": ["read_failure_store"], + "field_security": { + "grant": ["error*"], + "except": ["error.message"] + } + } + ] + }""", "role"); + { + expectThrows(() -> performRequest("user", new Request("POST", "/test1/_field_caps?fields=name")), 403); + assertFieldCapsResponseContainsIndexAndFields( + performRequest("user", new Request("POST", "/test1::failures/_field_caps?fields=error.*")), + failureIndexName, + Set.of( + "error.pipeline_trace", + "error.processor_type", + "error.type", + "error.processor_tag", + "error.pipeline", + "error.stack_trace", + "error" + ) + ); + } + + upsertRole(""" + { + "cluster": ["all"], + "indices": [ + { + "names": ["test*"], + "privileges": ["read_failure_store", "read"], + "field_security": { + "grant": ["error*", "name"], + "except": ["error.type"] + } + } + ] + }""", "role"); + { + assertFieldCapsResponseContainsIndexAndFields( + performRequest("user", new Request("POST", "/test1/_field_caps?fields=name,age,email")), + dataIndexName, + Set.of("name") + ); + assertFieldCapsResponseContainsIndexAndFields( + performRequest("user", new Request("POST", "/test1::failures/_field_caps?fields=error.*")), + failureIndexName, + Set.of( + "error.pipeline_trace", + "error.processor_type", + "error.message", + "error.processor_tag", + "error.pipeline", + "error.stack_trace", + "error" + ) + ); + } + + upsertRole(""" + { + "cluster": ["all"], + "indices": [ + { + "names": ["other*"], + "privileges": ["read_failure_store", "read"] + } + ] + }""", "role"); + expectThrows(() -> performRequest("user", new Request("POST", "/test1/_field_caps?fields=name")), 403); + expectThrows(() -> performRequest("user", new Request("POST", "/test1::failures/_field_caps?fields=name")), 403); + } + + private void assertFieldCapsResponseContainsIndexAndFields(Response fieldCapsResponse, String indexName, Set expectedFields) + throws IOException { + assertOK(fieldCapsResponse); + ObjectPath objectPath = ObjectPath.createFromResponse(fieldCapsResponse); + + List indices = objectPath.evaluate("indices"); + assertThat(indices, containsInAnyOrder(indexName)); + + Map fields = objectPath.evaluate("fields"); + assertThat(fields.keySet(), containsInAnyOrder(expectedFields.toArray())); + } + public void testPit() throws Exception { List docIds = setupDataStream(); String dataDocId = "1";