Skip to content

Commit 6f6b265

Browse files
authored
HLRC: add support for the clear realm cache API (#35163)
This change adds support for clearing the cache of a realm. The realms cache may contain a stale set of credentials or incorrect role assignment, which can be corrected by clearing the cache of the entire realm or just that of a specific user. Relates #29827
1 parent a4b26fe commit 6f6b265

File tree

11 files changed

+462
-67
lines changed

11 files changed

+462
-67
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.client;
21+
22+
import org.elasticsearch.common.ParseField;
23+
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
24+
25+
/**
26+
* Base class for responses that are node responses. These responses always contain the cluster
27+
* name and the {@link NodesResponseHeader}.
28+
*/
29+
public abstract class NodesResponse {
30+
31+
private final NodesResponseHeader header;
32+
private final String clusterName;
33+
34+
protected NodesResponse(NodesResponseHeader header, String clusterName) {
35+
this.header = header;
36+
this.clusterName = clusterName;
37+
}
38+
39+
/**
40+
* Get the cluster name associated with all of the nodes.
41+
*
42+
* @return Never {@code null}.
43+
*/
44+
public String getClusterName() {
45+
return clusterName;
46+
}
47+
48+
/**
49+
* Gets information about the number of total, successful and failed nodes the request was run on.
50+
* Also includes exceptions if relevant.
51+
*/
52+
public NodesResponseHeader getHeader() {
53+
return header;
54+
}
55+
56+
public static <T extends NodesResponse> void declareCommonNodesResponseParsing(ConstructingObjectParser<T, Void> parser) {
57+
parser.declareObject(ConstructingObjectParser.constructorArg(), NodesResponseHeader::fromXContent, new ParseField("_nodes"));
58+
parser.declareString(ConstructingObjectParser.constructorArg(), new ParseField("cluster_name"));
59+
}
60+
}

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

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import org.elasticsearch.client.security.AuthenticateRequest;
2424
import org.elasticsearch.client.security.AuthenticateResponse;
2525
import org.elasticsearch.client.security.ChangePasswordRequest;
26+
import org.elasticsearch.client.security.ClearRealmCacheRequest;
27+
import org.elasticsearch.client.security.ClearRealmCacheResponse;
2628
import org.elasticsearch.client.security.ClearRolesCacheRequest;
2729
import org.elasticsearch.client.security.ClearRolesCacheResponse;
2830
import org.elasticsearch.client.security.CreateTokenRequest;
@@ -241,13 +243,43 @@ public void authenticateAsync(RequestOptions options, ActionListener<Authenticat
241243
}
242244

243245
/**
244-
* Clears the native roles cache for a set of roles.
246+
* Clears the cache in one or more realms.
247+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-clear-cache.html">
248+
* the docs</a> for more.
249+
*
250+
* @param request the request with the realm names and usernames to clear the cache for
251+
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
252+
* @return the response from the clear realm cache call
253+
* @throws IOException in case there is a problem sending the request or parsing back the response
254+
*/
255+
public ClearRealmCacheResponse clearRealmCache(ClearRealmCacheRequest request, RequestOptions options) throws IOException {
256+
return restHighLevelClient.performRequestAndParseEntity(request, SecurityRequestConverters::clearRealmCache, options,
257+
ClearRealmCacheResponse::fromXContent, emptySet());
258+
}
259+
260+
/**
261+
* Clears the cache in one or more realms asynchronously.
262+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-clear-cache.html">
263+
* the docs</a> for more.
264+
*
265+
* @param request the request with the realm names and usernames to clear the cache for
266+
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
267+
* @param listener the listener to be notified upon request completion
268+
*/
269+
public void clearRealmCacheAsync(ClearRealmCacheRequest request, RequestOptions options,
270+
ActionListener<ClearRealmCacheResponse> listener) {
271+
restHighLevelClient.performRequestAsyncAndParseEntity(request, SecurityRequestConverters::clearRealmCache, options,
272+
ClearRealmCacheResponse::fromXContent, listener, emptySet());
273+
}
274+
275+
/**
276+
* Clears the roles cache for a set of roles.
245277
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-clear-role-cache.html">
246278
* the docs</a> for more.
247279
*
248280
* @param request the request with the roles for which the cache should be cleared.
249281
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
250-
* @return the response from the enable user call
282+
* @return the response from the clear roles cache call
251283
* @throws IOException in case there is a problem sending the request or parsing back the response
252284
*/
253285
public ClearRolesCacheResponse clearRolesCache(ClearRolesCacheRequest request, RequestOptions options) throws IOException {
@@ -256,7 +288,7 @@ public ClearRolesCacheResponse clearRolesCache(ClearRolesCacheRequest request, R
256288
}
257289

258290
/**
259-
* Clears the native roles cache for a set of roles asynchronously.
291+
* Clears the roles cache for a set of roles asynchronously.
260292
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-clear-role-cache.html">
261293
* the docs</a> for more.
262294
*

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.apache.http.client.methods.HttpDelete;
2424
import org.apache.http.client.methods.HttpPost;
2525
import org.apache.http.client.methods.HttpPut;
26+
import org.elasticsearch.client.security.ClearRealmCacheRequest;
2627
import org.elasticsearch.client.security.ClearRolesCacheRequest;
2728
import org.elasticsearch.client.security.CreateTokenRequest;
2829
import org.elasticsearch.client.security.DeleteRoleMappingRequest;
@@ -112,6 +113,23 @@ private static Request setUserEnabled(SetUserEnabledRequest setUserEnabledReques
112113
return request;
113114
}
114115

116+
static Request clearRealmCache(ClearRealmCacheRequest clearRealmCacheRequest) {
117+
RequestConverters.EndpointBuilder builder = new RequestConverters.EndpointBuilder()
118+
.addPathPartAsIs("_xpack/security/realm");
119+
if (clearRealmCacheRequest.getRealms().isEmpty() == false) {
120+
builder.addCommaSeparatedPathParts(clearRealmCacheRequest.getRealms().toArray(Strings.EMPTY_ARRAY));
121+
} else {
122+
builder.addPathPart("_all");
123+
}
124+
final String endpoint = builder.addPathPartAsIs("_clear_cache").build();
125+
Request request = new Request(HttpPost.METHOD_NAME, endpoint);
126+
if (clearRealmCacheRequest.getUsernames().isEmpty() == false) {
127+
RequestConverters.Params params = new RequestConverters.Params(request);
128+
params.putParam("usernames", Strings.collectionToCommaDelimitedString(clearRealmCacheRequest.getUsernames()));
129+
}
130+
return request;
131+
}
132+
115133
static Request clearRolesCache(ClearRolesCacheRequest disableCacheRequest) {
116134
String endpoint = new RequestConverters.EndpointBuilder()
117135
.addPathPartAsIs("_xpack/security/role")
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.client.security;
21+
22+
import org.elasticsearch.client.Validatable;
23+
24+
import java.util.Collections;
25+
import java.util.List;
26+
import java.util.Objects;
27+
28+
/**
29+
* Request for clearing the cache of one or more realms
30+
*/
31+
public final class ClearRealmCacheRequest implements Validatable {
32+
33+
private final List<String> realms;
34+
private final List<String> usernames;
35+
36+
/**
37+
* Create a new request to clear cache of realms
38+
* @param realms the realms to clear the cache of. Must not be {@code null}. An empty list
39+
* indicates that all realms should have their caches cleared.
40+
* @param usernames the usernames to clear the cache of. Must not be {@code null}. An empty
41+
* list indicates that every user in the listed realms should have their cache
42+
* cleared.
43+
*/
44+
public ClearRealmCacheRequest(List<String> realms, List<String> usernames) {
45+
this.realms = Collections.unmodifiableList(Objects.requireNonNull(realms, "the realms list must not be null"));
46+
this.usernames = Collections.unmodifiableList(Objects.requireNonNull(usernames, "usernames list must no be null"));
47+
}
48+
49+
public List<String> getRealms() {
50+
return realms;
51+
}
52+
53+
public List<String> getUsernames() {
54+
return usernames;
55+
}
56+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.client.security;
21+
22+
import org.elasticsearch.client.NodesResponseHeader;
23+
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
24+
import org.elasticsearch.common.xcontent.XContentParser;
25+
26+
import java.io.IOException;
27+
import java.util.List;
28+
29+
/**
30+
* Response for a clear realm cache request. The response includes a header that contains the
31+
* number of successful and failed nodes.
32+
*/
33+
public final class ClearRealmCacheResponse extends SecurityNodesResponse {
34+
35+
@SuppressWarnings("unchecked")
36+
public static final ConstructingObjectParser<ClearRealmCacheResponse, Void> PARSER =
37+
new ConstructingObjectParser<>("clear_realm_cache_response_parser",
38+
args -> new ClearRealmCacheResponse((List<Node>) args[0], (NodesResponseHeader) args[1], (String) args[2]));
39+
40+
static {
41+
SecurityNodesResponse.declareCommonNodesResponseParsing(PARSER);
42+
}
43+
44+
public ClearRealmCacheResponse(List<Node> nodes, NodesResponseHeader header, String clusterName) {
45+
super(nodes, header, clusterName);
46+
}
47+
48+
public static ClearRealmCacheResponse fromXContent(XContentParser parser) throws IOException {
49+
return PARSER.parse(parser, null);
50+
}
51+
}

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

Lines changed: 4 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -20,87 +20,28 @@
2020
package org.elasticsearch.client.security;
2121

2222
import org.elasticsearch.client.NodesResponseHeader;
23-
import org.elasticsearch.common.ParseField;
2423
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
2524
import org.elasticsearch.common.xcontent.XContentParser;
2625

2726
import java.io.IOException;
2827
import java.util.List;
29-
import java.util.Objects;
3028

3129
/**
32-
* The response object that will be returned when clearing the cache of native roles
30+
* The response object that will be returned when clearing the roles cache
3331
*/
34-
public final class ClearRolesCacheResponse {
32+
public final class ClearRolesCacheResponse extends SecurityNodesResponse {
3533

3634
@SuppressWarnings("unchecked")
3735
private static final ConstructingObjectParser<ClearRolesCacheResponse, Void> PARSER =
3836
new ConstructingObjectParser<>("clear_roles_cache_response", false,
3937
args -> new ClearRolesCacheResponse((List<Node>)args[0], (NodesResponseHeader) args[1], (String) args[2]));
4038

4139
static {
42-
PARSER.declareNamedObjects(ConstructingObjectParser.constructorArg(), (p, c, n) -> Node.PARSER.apply(p, n),
43-
new ParseField("nodes"));
44-
PARSER.declareObject(ConstructingObjectParser.constructorArg(), NodesResponseHeader::fromXContent, new ParseField("_nodes"));
45-
PARSER.declareString(ConstructingObjectParser.constructorArg(), new ParseField("cluster_name"));
40+
SecurityNodesResponse.declareCommonNodesResponseParsing(PARSER);
4641
}
4742

48-
private final List<Node> nodes;
49-
private final NodesResponseHeader header;
50-
private final String clusterName;
51-
5243
public ClearRolesCacheResponse(List<Node> nodes, NodesResponseHeader header, String clusterName) {
53-
this.nodes = nodes;
54-
this.header = header;
55-
this.clusterName = Objects.requireNonNull(clusterName, "cluster name must be provided");
56-
}
57-
58-
/** returns a list of nodes in which the cache was cleared */
59-
public List<Node> getNodes() {
60-
return nodes;
61-
}
62-
63-
/**
64-
* Get the cluster name associated with all of the nodes.
65-
*
66-
* @return Never {@code null}.
67-
*/
68-
public String getClusterName() {
69-
return clusterName;
70-
}
71-
72-
/**
73-
* Gets information about the number of total, successful and failed nodes the request was run on.
74-
* Also includes exceptions if relevant.
75-
*/
76-
public NodesResponseHeader getHeader() {
77-
return header;
78-
}
79-
80-
public static class Node {
81-
82-
private static final ConstructingObjectParser<Node, String> PARSER =
83-
new ConstructingObjectParser<>("clear_roles_cache_response_node", false, (args, id) -> new Node(id, (String) args[0]));
84-
85-
static {
86-
PARSER.declareString(ConstructingObjectParser.constructorArg(), new ParseField("name"));
87-
}
88-
89-
private final String id;
90-
private final String name;
91-
92-
public Node(String id, String name) {
93-
this.id = id;
94-
this.name = name;
95-
}
96-
97-
public String getId() {
98-
return id;
99-
}
100-
101-
public String getName() {
102-
return name;
103-
}
44+
super(nodes, header, clusterName);
10445
}
10546

10647
public static ClearRolesCacheResponse fromXContent(XContentParser parser) throws IOException {

0 commit comments

Comments
 (0)