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"));
}
}