Skip to content

Commit 4fd2752

Browse files
committed
Support builtin privileges in get privileges API
Adds a new "/_security/privilege/_builtin" endpoint so that builtin index and cluster privileges can be retrieved via the Rest API Backport of: elastic#42134
1 parent 461aa39 commit 4fd2752

File tree

29 files changed

+677
-23
lines changed

29 files changed

+677
-23
lines changed

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@
4343
import org.elasticsearch.client.security.EnableUserRequest;
4444
import org.elasticsearch.client.security.GetApiKeyRequest;
4545
import org.elasticsearch.client.security.GetApiKeyResponse;
46+
import org.elasticsearch.client.security.GetBuiltinPrivilegesRequest;
47+
import org.elasticsearch.client.security.GetBuiltinPrivilegesResponse;
4648
import org.elasticsearch.client.security.GetPrivilegesRequest;
4749
import org.elasticsearch.client.security.GetPrivilegesResponse;
4850
import org.elasticsearch.client.security.GetRoleMappingsRequest;
@@ -751,6 +753,34 @@ public void invalidateTokenAsync(InvalidateTokenRequest request, RequestOptions
751753
InvalidateTokenResponse::fromXContent, listener, emptySet());
752754
}
753755

756+
/**
757+
* Synchronously get builtin (cluster & index) privilege(s).
758+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-builtin-privileges.html">
759+
* the docs</a> for more.
760+
*
761+
* @param options the request options (e.g. headers), use
762+
* {@link RequestOptions#DEFAULT} if nothing needs to be customized
763+
* @return the response from the get builtin privileges call
764+
* @throws IOException in case there is a problem sending the request or parsing back the response
765+
*/
766+
public GetBuiltinPrivilegesResponse getBuiltinPrivileges(final RequestOptions options) throws IOException {
767+
return restHighLevelClient.performRequestAndParseEntity(GetBuiltinPrivilegesRequest.INSTANCE,
768+
GetBuiltinPrivilegesRequest::getRequest, options, GetBuiltinPrivilegesResponse::fromXContent, emptySet());
769+
}
770+
771+
/**
772+
* Asynchronously get builtin (cluster &amp; index) privilege(s).
773+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-builtin-privileges.html">
774+
* the docs</a> for more.
775+
*
776+
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
777+
* @param listener the listener to be notified upon request completion
778+
*/
779+
public void getBuiltinPrivilegesAsync(final RequestOptions options, final ActionListener<GetBuiltinPrivilegesResponse> listener) {
780+
restHighLevelClient.performRequestAsyncAndParseEntity(GetBuiltinPrivilegesRequest.INSTANCE,
781+
GetBuiltinPrivilegesRequest::getRequest, options, GetBuiltinPrivilegesResponse::fromXContent, listener, emptySet());
782+
}
783+
754784
/**
755785
* Synchronously get application privilege(s).
756786
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-privileges.html">
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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.apache.http.client.methods.HttpGet;
23+
import org.elasticsearch.client.Request;
24+
import org.elasticsearch.client.Validatable;
25+
26+
/**
27+
* Request object to retrieve the privilege that are builtin to the Elasticsearch cluster.
28+
*/
29+
public final class GetBuiltinPrivilegesRequest implements Validatable {
30+
31+
public static final GetBuiltinPrivilegesRequest INSTANCE = new GetBuiltinPrivilegesRequest();
32+
33+
private GetBuiltinPrivilegesRequest() {
34+
}
35+
36+
public Request getRequest() {
37+
return new Request(HttpGet.METHOD_NAME, "/_security/privilege/_builtin");
38+
}
39+
40+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
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.common.ParseField;
23+
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
24+
import org.elasticsearch.common.xcontent.XContentParser;
25+
26+
import java.io.IOException;
27+
import java.util.Collection;
28+
import java.util.Collections;
29+
import java.util.HashSet;
30+
import java.util.Objects;
31+
import java.util.Set;
32+
33+
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
34+
35+
/**
36+
* Get builtin privileges response
37+
*/
38+
public final class GetBuiltinPrivilegesResponse {
39+
40+
private final Set<String> clusterPrivileges;
41+
private final Set<String> indexPrivileges;
42+
43+
public GetBuiltinPrivilegesResponse(Collection<String> cluster, Collection<String> index) {
44+
this.clusterPrivileges = Collections.unmodifiableSet(new HashSet<>(cluster));
45+
this.indexPrivileges = Collections.unmodifiableSet(new HashSet<>(index));
46+
}
47+
48+
public Set<String> getClusterPrivileges() {
49+
return clusterPrivileges;
50+
}
51+
52+
public Set<String> getIndexPrivileges() {
53+
return indexPrivileges;
54+
}
55+
56+
public static GetBuiltinPrivilegesResponse fromXContent(XContentParser parser) throws IOException {
57+
return PARSER.parse(parser, null);
58+
}
59+
60+
@Override
61+
public boolean equals(Object o) {
62+
if (this == o) return true;
63+
if (o == null || getClass() != o.getClass()) return false;
64+
GetBuiltinPrivilegesResponse that = (GetBuiltinPrivilegesResponse) o;
65+
return Objects.equals(this.clusterPrivileges, that.clusterPrivileges)
66+
&& Objects.equals(this.indexPrivileges, that.indexPrivileges);
67+
}
68+
69+
@Override
70+
public int hashCode() {
71+
return Objects.hash(clusterPrivileges, indexPrivileges);
72+
}
73+
74+
75+
@SuppressWarnings("unchecked")
76+
private static final ConstructingObjectParser<GetBuiltinPrivilegesResponse, Void> PARSER = new ConstructingObjectParser<>(
77+
"get_builtin_privileges", true,
78+
args -> new GetBuiltinPrivilegesResponse((Collection<String>) args[0], (Collection<String>) args[1]));
79+
80+
static {
81+
PARSER.declareStringArray(constructorArg(), new ParseField("cluster"));
82+
PARSER.declareStringArray(constructorArg(), new ParseField("index"));
83+
}
84+
}

client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ public class RestHighLevelClientTests extends ESTestCase {
141141
// core
142142
"ping", "info",
143143
// security
144-
"security.get_ssl_certificates", "security.authenticate", "security.get_user_privileges",
144+
"security.get_ssl_certificates", "security.authenticate", "security.get_user_privileges", "security.get_builtin_privileges",
145145
// license
146146
"license.get_trial_status", "license.get_basic_status"
147147

client/rest-high-level/src/test/java/org/elasticsearch/client/SecurityRequestConvertersTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ public void testGetApplicationPrivilege() throws Exception {
316316
assertNull(request.getEntity());
317317
}
318318

319-
public void testGetAllApplicationPrivileges() throws Exception {
319+
public void testGetAllPrivilegesForApplication() throws Exception {
320320
final String application = randomAlphaOfLength(6);
321321
GetPrivilegesRequest getPrivilegesRequest = GetPrivilegesRequest.getApplicationPrivileges(application);
322322
Request request = SecurityRequestConverters.getPrivileges(getPrivilegesRequest);
@@ -340,7 +340,7 @@ public void testGetMultipleApplicationPrivileges() throws Exception {
340340
assertNull(request.getEntity());
341341
}
342342

343-
public void testGetAllPrivileges() throws Exception {
343+
public void testGetAllApplicationPrivileges() throws Exception {
344344
GetPrivilegesRequest getPrivilegesRequest = GetPrivilegesRequest.getAllPrivileges();
345345
Request request = SecurityRequestConverters.getPrivileges(getPrivilegesRequest);
346346
assertEquals(HttpGet.METHOD_NAME, request.getMethod());

client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SecurityDocumentationIT.java

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
import org.elasticsearch.client.security.ExpressionRoleMapping;
5151
import org.elasticsearch.client.security.GetApiKeyRequest;
5252
import org.elasticsearch.client.security.GetApiKeyResponse;
53+
import org.elasticsearch.client.security.GetBuiltinPrivilegesResponse;
5354
import org.elasticsearch.client.security.GetPrivilegesRequest;
5455
import org.elasticsearch.client.security.GetPrivilegesResponse;
5556
import org.elasticsearch.client.security.GetRoleMappingsRequest;
@@ -118,6 +119,7 @@
118119
import static org.hamcrest.Matchers.emptyIterable;
119120
import static org.hamcrest.Matchers.equalTo;
120121
import static org.hamcrest.Matchers.greaterThan;
122+
import static org.hamcrest.Matchers.hasItem;
121123
import static org.hamcrest.Matchers.is;
122124
import static org.hamcrest.Matchers.isIn;
123125
import static org.hamcrest.Matchers.iterableWithSize;
@@ -1497,6 +1499,60 @@ public void onFailure(Exception e) {
14971499
}
14981500
}
14991501

1502+
public void testGetBuiltinPrivileges() throws Exception {
1503+
final RestHighLevelClient client = highLevelClient();
1504+
{
1505+
//tag::get-builtin-privileges-execute
1506+
GetBuiltinPrivilegesResponse response = client.security().getBuiltinPrivileges(RequestOptions.DEFAULT);
1507+
//end::get-builtin-privileges-execute
1508+
1509+
assertNotNull(response);
1510+
//tag::get-builtin-privileges-response
1511+
final Set<String> cluster = response.getClusterPrivileges();
1512+
final Set<String> index = response.getIndexPrivileges();
1513+
//end::get-builtin-privileges-response
1514+
1515+
assertThat(cluster, hasItem("all"));
1516+
assertThat(cluster, hasItem("manage"));
1517+
assertThat(cluster, hasItem("monitor"));
1518+
assertThat(cluster, hasItem("manage_security"));
1519+
1520+
assertThat(index, hasItem("all"));
1521+
assertThat(index, hasItem("manage"));
1522+
assertThat(index, hasItem("monitor"));
1523+
assertThat(index, hasItem("read"));
1524+
assertThat(index, hasItem("write"));
1525+
}
1526+
{
1527+
// tag::get-builtin-privileges-execute-listener
1528+
ActionListener<GetBuiltinPrivilegesResponse> listener = new ActionListener<GetBuiltinPrivilegesResponse>() {
1529+
@Override
1530+
public void onResponse(GetBuiltinPrivilegesResponse response) {
1531+
// <1>
1532+
}
1533+
1534+
@Override
1535+
public void onFailure(Exception e) {
1536+
// <2>
1537+
}
1538+
};
1539+
// end::get-builtin-privileges-execute-listener
1540+
1541+
// Replace the empty listener by a blocking listener in test
1542+
final PlainActionFuture<GetBuiltinPrivilegesResponse> future = new PlainActionFuture<>();
1543+
listener = future;
1544+
1545+
// tag::get-builtin-privileges-execute-async
1546+
client.security().getBuiltinPrivilegesAsync(RequestOptions.DEFAULT, listener); // <1>
1547+
// end::get-builtin-privileges-execute-async
1548+
1549+
final GetBuiltinPrivilegesResponse response = future.get(30, TimeUnit.SECONDS);
1550+
assertNotNull(response);
1551+
assertThat(response.getClusterPrivileges(), hasItem("manage_security"));
1552+
assertThat(response.getIndexPrivileges(), hasItem("read"));
1553+
}
1554+
}
1555+
15001556
public void testGetPrivileges() throws Exception {
15011557
final RestHighLevelClient client = highLevelClient();
15021558
final ApplicationPrivilege readTestappPrivilege =
@@ -1556,9 +1612,9 @@ public void testGetPrivileges() throws Exception {
15561612

15571613
assertNotNull(response);
15581614
assertThat(response.getPrivileges().size(), equalTo(3));
1559-
final GetPrivilegesResponse exptectedResponse =
1615+
final GetPrivilegesResponse expectedResponse =
15601616
new GetPrivilegesResponse(Arrays.asList(readTestappPrivilege, writeTestappPrivilege, allTestappPrivilege));
1561-
assertThat(response, equalTo(exptectedResponse));
1617+
assertThat(response, equalTo(expectedResponse));
15621618
//tag::get-privileges-response
15631619
Set<ApplicationPrivilege> privileges = response.getPrivileges();
15641620
//end::get-privileges-response
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--
2+
:api: get-builtin-privileges
3+
:request: GetBuiltinPrivilegesRequest
4+
:response: GetBuiltinPrivilegesResponse
5+
--
6+
7+
[id="{upid}-{api}"]
8+
=== Get Builtin Privileges API
9+
10+
include::../execution-no-req.asciidoc[]
11+
12+
[id="{upid}-{api}-response"]
13+
==== Get Builtin Privileges Response
14+
15+
The returned +{response}+ contains the following properties
16+
17+
`clusterPrivileges`::
18+
A `Set` of all _cluster_ privileges that are understood by this node.
19+
20+
`indexPrivileges`::
21+
A `Set` of all _index_ privileges that are understood by this node.
22+
23+
["source","java",subs="attributes,callouts,macros"]
24+
--------------------------------------------------
25+
include-tagged::{doc-tests-file}[{api}-response]
26+
--------------------------------------------------
27+

docs/java-rest/high-level/supported-apis.asciidoc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,7 @@ The Java High Level REST Client supports the following Security APIs:
418418
* <<java-rest-high-security-delete-role-mapping>>
419419
* <<java-rest-high-security-create-token>>
420420
* <<{upid}-invalidate-token>>
421+
* <<{upid}-get-builtin-privileges>>
421422
* <<{upid}-get-privileges>>
422423
* <<{upid}-put-privileges>>
423424
* <<{upid}-delete-privileges>>
@@ -435,6 +436,7 @@ include::security/put-role.asciidoc[]
435436
include::security/get-roles.asciidoc[]
436437
include::security/delete-role.asciidoc[]
437438
include::security/delete-privileges.asciidoc[]
439+
include::security/get-builtin-privileges.asciidoc[]
438440
include::security/get-privileges.asciidoc[]
439441
include::security/clear-roles-cache.asciidoc[]
440442
include::security/clear-realm-cache.asciidoc[]
@@ -582,4 +584,4 @@ include::dataframe/put_data_frame.asciidoc[]
582584
include::dataframe/delete_data_frame.asciidoc[]
583585
include::dataframe/preview_data_frame.asciidoc[]
584586
include::dataframe/start_data_frame.asciidoc[]
585-
include::dataframe/stop_data_frame.asciidoc[]
587+
include::dataframe/stop_data_frame.asciidoc[]

x-pack/docs/en/rest-api/security.asciidoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ You can use the following APIs to perform security activities.
88
* <<security-api-clear-cache>>
99
* <<security-api-has-privileges>>
1010
* <<security-api-ssl>>
11+
* <<security-api-get-builtin-privileges>>
1112

1213
[float]
1314
[[security-api-app-privileges]]
@@ -105,6 +106,7 @@ include::security/disable-users.asciidoc[]
105106
include::security/enable-users.asciidoc[]
106107
include::security/get-api-keys.asciidoc[]
107108
include::security/get-app-privileges.asciidoc[]
109+
include::security/get-builtin-privileges.asciidoc[]
108110
include::security/get-role-mappings.asciidoc[]
109111
include::security/get-roles.asciidoc[]
110112
include::security/get-tokens.asciidoc[]

0 commit comments

Comments
 (0)