Skip to content

Commit 7bb1185

Browse files
authored
HLRC support for query API key API (#76520)
This PR adds HLRC for the new Query API key API added with #75335 and #76144 Relates: #71023
1 parent c1a3244 commit 7bb1185

File tree

12 files changed

+774
-5
lines changed

12 files changed

+774
-5
lines changed

client/rest-high-level/src/main/java/org/elasticsearch/client/SecurityClient.java

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@
8080
import org.elasticsearch.client.security.PutUserResponse;
8181
import org.elasticsearch.client.security.KibanaEnrollmentRequest;
8282
import org.elasticsearch.client.security.KibanaEnrollmentResponse;
83+
import org.elasticsearch.client.security.QueryApiKeyRequest;
84+
import org.elasticsearch.client.security.QueryApiKeyResponse;
8385

8486
import java.io.IOException;
8587

@@ -1054,7 +1056,7 @@ public Cancellable createApiKeyAsync(final CreateApiKeyRequest request, final Re
10541056
*
10551057
* @param request the request to retrieve API key(s)
10561058
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
1057-
* @return the response from the create API key call
1059+
* @return the response from the get API key call
10581060
* @throws IOException in case there is a problem sending the request or parsing back the response
10591061
*/
10601062
public GetApiKeyResponse getApiKey(final GetApiKeyRequest request, final RequestOptions options) throws IOException {
@@ -1141,6 +1143,37 @@ public Cancellable grantApiKeyAsync(final GrantApiKeyRequest request, final Requ
11411143
CreateApiKeyResponse::fromXContent, listener, emptySet());
11421144
}
11431145

1146+
/**
1147+
* Query and retrieve API Key(s) information.<br>
1148+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-query-api-key.html">
1149+
* the docs</a> for more.
1150+
*
1151+
* @param request the request to query and retrieve API key(s)
1152+
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
1153+
* @return the response from the query API key call
1154+
* @throws IOException in case there is a problem sending the request or parsing back the response
1155+
*/
1156+
public QueryApiKeyResponse queryApiKey(final QueryApiKeyRequest request, final RequestOptions options) throws IOException {
1157+
return restHighLevelClient.performRequestAndParseEntity(request, SecurityRequestConverters::queryApiKey, options,
1158+
QueryApiKeyResponse::fromXContent, emptySet());
1159+
}
1160+
1161+
/**
1162+
* Asynchronously query and retrieve API Key(s) information.<br>
1163+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-query-api-key.html">
1164+
* the docs</a> for more.
1165+
*
1166+
* @param request the request to query and retrieve API key(s)
1167+
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
1168+
* @param listener the listener to be notified upon request completion
1169+
* @return cancellable that may be used to cancel the request
1170+
*/
1171+
public Cancellable queryApiKeyAsync(final QueryApiKeyRequest request, final RequestOptions options,
1172+
final ActionListener<QueryApiKeyResponse> listener) {
1173+
return restHighLevelClient.performRequestAsyncAndParseEntity(request, SecurityRequestConverters::queryApiKey, options,
1174+
QueryApiKeyResponse::fromXContent, listener, emptySet());
1175+
}
1176+
11441177
/**
11451178
* Get a service account, or list of service accounts synchronously.
11461179
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-service-accounts.html">

client/rest-high-level/src/main/java/org/elasticsearch/client/SecurityRequestConverters.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import org.elasticsearch.client.security.PutRoleMappingRequest;
4545
import org.elasticsearch.client.security.PutRoleRequest;
4646
import org.elasticsearch.client.security.PutUserRequest;
47+
import org.elasticsearch.client.security.QueryApiKeyRequest;
4748
import org.elasticsearch.client.security.SetUserEnabledRequest;
4849
import org.elasticsearch.common.Strings;
4950

@@ -346,6 +347,12 @@ static Request invalidateApiKey(final InvalidateApiKeyRequest invalidateApiKeyRe
346347
return request;
347348
}
348349

350+
static Request queryApiKey(final QueryApiKeyRequest queryApiKeyRequest) throws IOException {
351+
final Request request = new Request(HttpGet.METHOD_NAME, "/_security/_query/api_key");
352+
request.setEntity(createEntity(queryApiKeyRequest, REQUEST_BODY_CONTENT_TYPE));
353+
return request;
354+
}
355+
349356
static Request getServiceAccounts(final GetServiceAccountsRequest getServiceAccountsRequest) {
350357
final RequestConverters.EndpointBuilder endpointBuilder = new RequestConverters.EndpointBuilder()
351358
.addPathPartAsIs("_security/service");
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
package org.elasticsearch.client.security;
10+
11+
import org.elasticsearch.client.Validatable;
12+
import org.elasticsearch.client.ValidationException;
13+
import org.elasticsearch.common.xcontent.ToXContentObject;
14+
import org.elasticsearch.common.xcontent.XContentBuilder;
15+
import org.elasticsearch.core.Nullable;
16+
import org.elasticsearch.index.query.QueryBuilder;
17+
import org.elasticsearch.search.searchafter.SearchAfterBuilder;
18+
import org.elasticsearch.search.sort.FieldSortBuilder;
19+
20+
import java.io.IOException;
21+
import java.util.List;
22+
import java.util.Objects;
23+
import java.util.Optional;
24+
25+
public final class QueryApiKeyRequest implements Validatable, ToXContentObject {
26+
27+
@Nullable
28+
private QueryBuilder queryBuilder;
29+
private Integer from;
30+
private Integer size;
31+
@Nullable
32+
private List<FieldSortBuilder> fieldSortBuilders;
33+
@Nullable
34+
private SearchAfterBuilder searchAfterBuilder;
35+
36+
public QueryApiKeyRequest() {
37+
this(null, null, null, null, null);
38+
}
39+
40+
public QueryApiKeyRequest(
41+
@Nullable QueryBuilder queryBuilder,
42+
@Nullable Integer from,
43+
@Nullable Integer size,
44+
@Nullable List<FieldSortBuilder> fieldSortBuilders,
45+
@Nullable SearchAfterBuilder searchAfterBuilder) {
46+
this.queryBuilder = queryBuilder;
47+
this.from = from;
48+
this.size = size;
49+
this.fieldSortBuilders = fieldSortBuilders;
50+
this.searchAfterBuilder = searchAfterBuilder;
51+
}
52+
53+
public QueryBuilder getQueryBuilder() {
54+
return queryBuilder;
55+
}
56+
57+
public int getFrom() {
58+
return from;
59+
}
60+
61+
public int getSize() {
62+
return size;
63+
}
64+
65+
public List<FieldSortBuilder> getFieldSortBuilders() {
66+
return fieldSortBuilders;
67+
}
68+
69+
public SearchAfterBuilder getSearchAfterBuilder() {
70+
return searchAfterBuilder;
71+
}
72+
73+
public QueryApiKeyRequest queryBuilder(QueryBuilder queryBuilder) {
74+
this.queryBuilder = queryBuilder;
75+
return this;
76+
}
77+
78+
public QueryApiKeyRequest from(int from) {
79+
this.from = from;
80+
return this;
81+
}
82+
83+
public QueryApiKeyRequest size(int size) {
84+
this.size = size;
85+
return this;
86+
}
87+
88+
public QueryApiKeyRequest fieldSortBuilders(List<FieldSortBuilder> fieldSortBuilders) {
89+
this.fieldSortBuilders = fieldSortBuilders;
90+
return this;
91+
}
92+
93+
public QueryApiKeyRequest searchAfterBuilder(SearchAfterBuilder searchAfterBuilder) {
94+
this.searchAfterBuilder = searchAfterBuilder;
95+
return this;
96+
}
97+
98+
@Override
99+
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
100+
builder.startObject();
101+
if (queryBuilder != null) {
102+
builder.field("query");
103+
queryBuilder.toXContent(builder, params);
104+
}
105+
if (from != null) {
106+
builder.field("from", from);
107+
}
108+
if (size != null) {
109+
builder.field("size", size);
110+
}
111+
if (fieldSortBuilders != null && false == fieldSortBuilders.isEmpty()) {
112+
builder.field("sort", fieldSortBuilders);
113+
}
114+
if (searchAfterBuilder != null) {
115+
builder.array(SearchAfterBuilder.SEARCH_AFTER.getPreferredName(), searchAfterBuilder.getSortValues());
116+
}
117+
return builder.endObject();
118+
}
119+
120+
@Override
121+
public Optional<ValidationException> validate() {
122+
ValidationException validationException = null;
123+
if (from != null && from < 0) {
124+
validationException = addValidationError(validationException, "from must be non-negative");
125+
}
126+
if (size != null && size < 0) {
127+
validationException = addValidationError(validationException, "size must be non-negative");
128+
}
129+
return validationException == null ? Optional.empty() : Optional.of(validationException);
130+
}
131+
132+
@Override
133+
public boolean equals(Object o) {
134+
if (this == o)
135+
return true;
136+
if (o == null || getClass() != o.getClass())
137+
return false;
138+
QueryApiKeyRequest that = (QueryApiKeyRequest) o;
139+
return Objects.equals(queryBuilder, that.queryBuilder) && Objects.equals(from, that.from) && Objects.equals(
140+
size,
141+
that.size) && Objects.equals(fieldSortBuilders, that.fieldSortBuilders) && Objects.equals(
142+
searchAfterBuilder,
143+
that.searchAfterBuilder);
144+
}
145+
146+
@Override
147+
public int hashCode() {
148+
return Objects.hash(queryBuilder, from, size, fieldSortBuilders, searchAfterBuilder);
149+
}
150+
151+
private ValidationException addValidationError(ValidationException validationException, String message) {
152+
if (validationException == null) {
153+
validationException = new ValidationException();
154+
}
155+
validationException.addValidationError(message);
156+
return validationException;
157+
}
158+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
package org.elasticsearch.client.security;
10+
11+
import org.elasticsearch.client.security.support.ApiKey;
12+
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
13+
import org.elasticsearch.common.xcontent.ParseField;
14+
import org.elasticsearch.common.xcontent.XContentParser;
15+
16+
import java.io.IOException;
17+
import java.util.List;
18+
19+
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
20+
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg;
21+
22+
public final class QueryApiKeyResponse {
23+
24+
private final long total;
25+
private final List<ApiKey> apiKeys;
26+
27+
public QueryApiKeyResponse(long total, List<ApiKey> apiKeys) {
28+
this.total = total;
29+
this.apiKeys = apiKeys;
30+
}
31+
32+
public long getTotal() {
33+
return total;
34+
}
35+
36+
public int getCount() {
37+
return apiKeys.size();
38+
}
39+
40+
public List<ApiKey> getApiKeys() {
41+
return apiKeys;
42+
}
43+
44+
public static QueryApiKeyResponse fromXContent(XContentParser parser) throws IOException {
45+
return PARSER.parse(parser, null);
46+
}
47+
48+
static final ConstructingObjectParser<QueryApiKeyResponse, Void> PARSER = new ConstructingObjectParser<>(
49+
"query_api_key_response",
50+
args -> {
51+
final long total = (long) args[0];
52+
final int count = (int) args[1];
53+
@SuppressWarnings("unchecked")
54+
final List<ApiKey> items = (List<ApiKey>) args[2];
55+
if (count != items.size()) {
56+
throw new IllegalArgumentException("count [" + count + "] is not equal to number of items ["
57+
+ items.size() + "]");
58+
}
59+
return new QueryApiKeyResponse(total, items);
60+
}
61+
);
62+
63+
static {
64+
PARSER.declareLong(constructorArg(), new ParseField("total"));
65+
PARSER.declareInt(constructorArg(), new ParseField("count"));
66+
PARSER.declareObjectArray(optionalConstructorArg(), (p, c) -> ApiKey.fromXContent(p), new ParseField("api_keys"));
67+
}
68+
}

0 commit comments

Comments
 (0)