public void testFiltersAggs()

in x-pack/plugin/security/qa/security-basic/src/javaRestTest/java/org/elasticsearch/xpack/security/ApiKeyAggsIT.java [33:284]


    public void testFiltersAggs() throws IOException {
        // admin keys
        createApiKey(
            "key1",
            Map.of("tags", List.of("prod", "est"), "label", "value1", "environment", Map.of("system", false, "hostname", "my-org-host-1")),
            API_KEY_ADMIN_AUTH_HEADER
        );
        createApiKey(
            "key2",
            Map.of("tags", List.of("prod", "west"), "label", "value2", "environment", Map.of("system", false, "hostname", "my-org-host-2")),
            API_KEY_ADMIN_AUTH_HEADER
        );
        createApiKey(
            "key3",
            Map.of("tags", List.of("prod", "south"), "label", "value3", "environment", Map.of("system", true, "hostname", "my-org-host-2")),
            API_KEY_ADMIN_AUTH_HEADER
        );
        // user keys
        createApiKey(
            "key4",
            Map.of("tags", List.of("prod", "north"), "label", "value4", "environment", Map.of("system", true, "hostname", "my-org-host-1")),
            API_KEY_USER_AUTH_HEADER
        );
        createApiKey(
            "wild",
            Map.of(
                "tags",
                List.of("staging", "west"),
                "label",
                "value5",
                "environment",
                Map.of("system", true, "hostname", "my-org-host-3")
            ),
            API_KEY_USER_AUTH_HEADER
        );
        final boolean typedAggs = randomBoolean();
        assertAggs(API_KEY_ADMIN_AUTH_HEADER, typedAggs, """
            {
              "aggs": {
                "hostnames": {
                  "filters": {
                    "filters": {
                      "my-org-host-1": { "term": {"metadata.environment.hostname": "my-org-host-1"}},
                      "my-org-host-2": { "match": {"metadata": "my-org-host-2"}}
                    }
                  }
                }
              }
            }
            """, aggs -> {
            String aggName = typedAggs ? "filters#hostnames" : "hostnames";
            assertThat(((Map<String, Object>) ((Map<String, Object>) aggs.get(aggName)).get("buckets")).size(), is(2));
            assertThat(
                ((Map<String, Object>) ((Map<String, Object>) ((Map<String, Object>) aggs.get(aggName)).get("buckets")).get(
                    "my-org-host-1"
                )).get("doc_count"),
                is(2)
            );
            assertThat(
                ((Map<String, Object>) ((Map<String, Object>) ((Map<String, Object>) aggs.get(aggName)).get("buckets")).get(
                    "my-org-host-2"
                )).get("doc_count"),
                is(2)
            );
        });
        // other bucket
        assertAggs(API_KEY_USER_AUTH_HEADER, typedAggs, """
            {
              "aggregations": {
                "only_user_keys": {
                  "filters": {
                    "other_bucket_key": "other_user_keys",
                    "filters": {
                      "only_key4_match": { "bool": { "should": [{"prefix": {"name": "key"}}, {"match": {"metadata.tags": "prod"}}]}}
                    }
                  }
                }
              }
            }
            """, aggs -> {
            String aggName = typedAggs ? "filters#only_user_keys" : "only_user_keys";
            assertThat(((Map<String, Object>) ((Map<String, Object>) aggs.get(aggName)).get("buckets")).size(), is(2));
            assertThat(
                ((Map<String, Object>) ((Map<String, Object>) ((Map<String, Object>) aggs.get(aggName)).get("buckets")).get(
                    "only_key4_match"
                )).get("doc_count"),
                is(1)
            );
            assertThat(
                ((Map<String, Object>) ((Map<String, Object>) ((Map<String, Object>) aggs.get(aggName)).get("buckets")).get(
                    "other_user_keys"
                )).get("doc_count"),
                is(1)
            );
        });
        // anonymous filters
        assertAggs(API_KEY_USER_AUTH_HEADER, typedAggs, """
            {
              "aggs": {
                "all_user_keys": {
                  "filters": {
                    "other_bucket_key": "other_user_keys",
                    "filters": [
                      {"match_all": {}},
                      {"exists": {"field": "username"}},
                      {"wildcard": {"name": {"value": "*"}}}
                    ]
                  }
                }
              }
            }
            """, aggs -> {
            String aggName = typedAggs ? "filters#all_user_keys" : "all_user_keys";
            assertThat(((List<Map<String, Object>>) ((Map<String, Object>) aggs.get(aggName)).get("buckets")).size(), is(4));
            assertThat(
                ((List<Map<String, Object>>) ((Map<String, Object>) aggs.get(aggName)).get("buckets")).get(0).get("doc_count"),
                is(2)
            );
            assertThat(
                ((List<Map<String, Object>>) ((Map<String, Object>) aggs.get(aggName)).get("buckets")).get(1).get("doc_count"),
                is(2)
            );
            assertThat(
                ((List<Map<String, Object>>) ((Map<String, Object>) aggs.get(aggName)).get("buckets")).get(2).get("doc_count"),
                is(2)
            );
            // the "other" bucket
            assertThat(
                ((List<Map<String, Object>>) ((Map<String, Object>) aggs.get(aggName)).get("buckets")).get(3).get("doc_count"),
                is(0)
            );
        });
        // nested filters
        assertAggs(API_KEY_USER_AUTH_HEADER, typedAggs, """
            {
              "aggs": {
                "level1": {
                  "filters": {
                    "keyed": false,
                    "filters": {
                      "rest-filter": {"term": {"type": "rest"}},
                      "user-filter": {"wildcard": {"username": "api_*_user"}}
                    }
                  },
                  "aggs": {
                    "level2": {
                      "filters": {
                        "filters": {
                          "invalidated": {"term": {"invalidated": true}},
                          "not-invalidated": {"term": {"invalidated": false}}
                        }
                      }
                    }
                  }
                }
              }
            }
            """, aggs -> {
            String level1AggName = typedAggs ? "filters#level1" : "level1";
            List<Map<String, Object>> level1Buckets = (List<Map<String, Object>>) ((Map<String, Object>) aggs.get(level1AggName)).get(
                "buckets"
            );
            assertThat(level1Buckets.size(), is(2));
            assertThat(level1Buckets.get(0).get("doc_count"), is(2));
            assertThat(level1Buckets.get(0).get("key"), is("rest-filter"));
            String level2AggName = typedAggs ? "filters#level2" : "level2";
            assertThat(
                ((Map<String, Object>) ((Map<String, Object>) ((Map<String, Object>) level1Buckets.get(0).get(level2AggName)).get(
                    "buckets"
                )).get("invalidated")).get("doc_count"),
                is(0)
            );
            assertThat(
                ((Map<String, Object>) ((Map<String, Object>) ((Map<String, Object>) level1Buckets.get(0).get(level2AggName)).get(
                    "buckets"
                )).get("not-invalidated")).get("doc_count"),
                is(2)
            );
            assertThat(level1Buckets.get(1).get("doc_count"), is(2));
            assertThat(level1Buckets.get(1).get("key"), is("user-filter"));
            assertThat(
                ((Map<String, Object>) ((Map<String, Object>) ((Map<String, Object>) level1Buckets.get(1).get(level2AggName)).get(
                    "buckets"
                )).get("invalidated")).get("doc_count"),
                is(0)
            );
            assertThat(
                ((Map<String, Object>) ((Map<String, Object>) ((Map<String, Object>) level1Buckets.get(1).get(level2AggName)).get(
                    "buckets"
                )).get("not-invalidated")).get("doc_count"),
                is(2)
            );
        });
        // filter on disallowed fields
        {
            Request request = new Request("GET", "/_security/_query/api_key" + (randomBoolean() ? "?typed_keys" : ""));
            request.setOptions(
                request.getOptions()
                    .toBuilder()
                    .addHeader(HttpHeaders.AUTHORIZATION, randomFrom(API_KEY_ADMIN_AUTH_HEADER, API_KEY_USER_AUTH_HEADER))
            );
            request.setJsonEntity("""
                {
                  "aggs": {
                    "wrong-field": {
                      "filters": {
                        "filters": {
                          "wrong-api-key-invalidated": { "term": {"api_key_invalidated": false}}
                        }
                      }
                    }
                  }
                }
                """);
            ResponseException exception = expectThrows(ResponseException.class, () -> client().performRequest(request));
            assertThat(exception.getResponse().toString(), exception.getResponse().getStatusLine().getStatusCode(), is(400));
            assertThat(exception.getMessage(), containsString("Field [api_key_invalidated] is not allowed for querying or aggregation"));
        }
        {
            Request request = new Request("GET", "/_security/_query/api_key" + (randomBoolean() ? "?typed_keys" : ""));
            request.setOptions(
                request.getOptions()
                    .toBuilder()
                    .addHeader(HttpHeaders.AUTHORIZATION, randomFrom(API_KEY_ADMIN_AUTH_HEADER, API_KEY_USER_AUTH_HEADER))
            );
            request.setJsonEntity("""
                {
                  "aggs": {
                    "good-field": {
                      "filters": {
                        "filters": {
                          "good-api-key-invalidated": { "term": {"invalidated": false}}
                        }
                      },
                      "aggregations": {
                        "wrong-field": {
                          "filters": {
                            "filters": {
                              "wrong-creator-realm": {"wildcard": {"creator.realm": "whatever"}}
                            }
                          }
                        }
                      }
                    }
                  }
                }
                """);
            ResponseException exception = expectThrows(ResponseException.class, () -> client().performRequest(request));
            assertThat(exception.getResponse().toString(), exception.getResponse().getStatusLine().getStatusCode(), is(400));
            assertThat(exception.getMessage(), containsString("Field [creator.realm] is not allowed for querying or aggregation"));
        }
    }