diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/SecurityClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/SecurityClient.java
index 93d29056a707a..b6d4bd110bd79 100644
--- a/client/rest-high-level/src/main/java/org/elasticsearch/client/SecurityClient.java
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/SecurityClient.java
@@ -38,6 +38,8 @@
import org.elasticsearch.client.security.DisableUserRequest;
import org.elasticsearch.client.security.EmptyResponse;
import org.elasticsearch.client.security.EnableUserRequest;
+import org.elasticsearch.client.security.GetPrivilegesRequest;
+import org.elasticsearch.client.security.GetPrivilegesResponse;
import org.elasticsearch.client.security.GetRoleMappingsRequest;
import org.elasticsearch.client.security.GetRoleMappingsResponse;
import org.elasticsearch.client.security.GetSslCertificatesRequest;
@@ -505,10 +507,47 @@ public void invalidateTokenAsync(InvalidateTokenRequest request, RequestOptions
InvalidateTokenResponse::fromXContent, listener, emptySet());
}
+ /**
+ * Synchronously get application privilege(s).
+ * See
+ * the docs for more.
+ *
+ * @param request {@link GetPrivilegesRequest} with the application name and the privilege name.
+ * If no application name is provided, information about all privileges for all applications is retrieved.
+ * If no privilege name is provided, information about all privileges of the specified application is retrieved.
+ * @param options the request options (e.g. headers), use
+ * {@link RequestOptions#DEFAULT} if nothing needs to be customized
+ * @return the response from the get privileges call
+ * @throws IOException in case there is a problem sending the request or
+ * parsing back the response
+ */
+ public GetPrivilegesResponse getPrivileges(final GetPrivilegesRequest request, final RequestOptions options) throws IOException {
+ return restHighLevelClient.performRequestAndParseEntity(request, SecurityRequestConverters::getPrivileges,
+ options, GetPrivilegesResponse::fromXContent, emptySet());
+ }
+
+ /**
+ * Asynchronously get application privilege(s).
+ * See
+ * the docs for more.
+ *
+ * @param request {@link GetPrivilegesRequest} with the application name and the privilege name.
+ * If no application name is provided, information about all privileges for all applications is retrieved.
+ * If no privilege name is provided, information about all privileges of the specified application is retrieved.
+ * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
+ * @param listener the listener to be notified upon request completion
+ */
+ public void getPrivilegesAsync(final GetPrivilegesRequest request, final RequestOptions options,
+ final ActionListener listener) {
+ restHighLevelClient.performRequestAsyncAndParseEntity(request, SecurityRequestConverters::getPrivileges,
+ options, GetPrivilegesResponse::fromXContent, listener, emptySet());
+ }
+
/**
* Removes application privilege(s)
* See
* the docs for more.
+ *
* @param request the request with the application privilege to delete
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
* @return the response from the delete application privilege call
@@ -523,12 +562,13 @@ public DeletePrivilegesResponse deletePrivileges(DeletePrivilegesRequest request
* Asynchronously removes an application privilege
* See
* the docs for more.
- * @param request the request with the application privilege to delete
- * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
+ *
+ * @param request the request with the application privilege to delete
+ * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
* @param listener the listener to be notified upon request completion
*/
public void deletePrivilegesAsync(DeletePrivilegesRequest request, RequestOptions options,
- ActionListener listener) {
+ ActionListener listener) {
restHighLevelClient.performRequestAsyncAndParseEntity(request, SecurityRequestConverters::deletePrivileges, options,
DeletePrivilegesResponse::fromXContent, listener, singleton(404));
}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/SecurityRequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/SecurityRequestConverters.java
index 216085af78a38..b07c68f999873 100644
--- a/client/rest-high-level/src/main/java/org/elasticsearch/client/SecurityRequestConverters.java
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/SecurityRequestConverters.java
@@ -28,14 +28,15 @@
import org.elasticsearch.client.security.ClearRolesCacheRequest;
import org.elasticsearch.client.security.CreateTokenRequest;
import org.elasticsearch.client.security.DeletePrivilegesRequest;
+import org.elasticsearch.client.security.GetPrivilegesRequest;
import org.elasticsearch.client.security.DeleteRoleMappingRequest;
import org.elasticsearch.client.security.DeleteRoleRequest;
+import org.elasticsearch.client.security.InvalidateTokenRequest;
+import org.elasticsearch.client.security.PutRoleMappingRequest;
import org.elasticsearch.client.security.HasPrivilegesRequest;
import org.elasticsearch.client.security.DisableUserRequest;
import org.elasticsearch.client.security.EnableUserRequest;
import org.elasticsearch.client.security.GetRoleMappingsRequest;
-import org.elasticsearch.client.security.InvalidateTokenRequest;
-import org.elasticsearch.client.security.PutRoleMappingRequest;
import org.elasticsearch.client.security.PutUserRequest;
import org.elasticsearch.client.security.SetUserEnabledRequest;
import org.elasticsearch.common.Strings;
@@ -181,6 +182,15 @@ static Request invalidateToken(InvalidateTokenRequest invalidateTokenRequest) th
return request;
}
+ static Request getPrivileges(GetPrivilegesRequest getPrivilegesRequest) {
+ String endpoint = new RequestConverters.EndpointBuilder()
+ .addPathPartAsIs("_xpack/security/privilege")
+ .addPathPart(getPrivilegesRequest.getApplicationName())
+ .addCommaSeparatedPathParts(getPrivilegesRequest.getPrivilegeNames())
+ .build();
+ return new Request(HttpGet.METHOD_NAME, endpoint);
+ }
+
static Request deletePrivileges(DeletePrivilegesRequest deletePrivilegeRequest) {
String endpoint = new RequestConverters.EndpointBuilder()
.addPathPartAsIs("_xpack/security/privilege")
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetPrivilegesRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetPrivilegesRequest.java
new file mode 100644
index 0000000000000..53e3c8c571e28
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetPrivilegesRequest.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.elasticsearch.client.security;
+
+import org.elasticsearch.client.Validatable;
+import org.elasticsearch.common.Nullable;
+import org.elasticsearch.common.Strings;
+import org.elasticsearch.common.util.CollectionUtils;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * Request object to get application privilege(s)
+ */
+public final class GetPrivilegesRequest implements Validatable {
+ private final String applicationName;
+ private final String[] privilegeNames;
+
+ public GetPrivilegesRequest(@Nullable final String applicationName, @Nullable final String... privilegeNames) {
+ if ((CollectionUtils.isEmpty(privilegeNames) == false) && Strings.isNullOrEmpty(applicationName)) {
+ throw new IllegalArgumentException("privilege cannot be specified when application is missing");
+ }
+ this.applicationName = applicationName;
+ this.privilegeNames = privilegeNames;
+ }
+
+ /**
+ * Constructs a {@link GetPrivilegesRequest} to request all the privileges defined for all applications
+ */
+ public static GetPrivilegesRequest getAllPrivileges() {
+ return new GetPrivilegesRequest(null);
+ }
+
+ /**
+ * Constructs a {@link GetPrivilegesRequest} to request all the privileges defined for the specified {@code applicationName}
+ *
+ * @param applicationName the name of the application for which the privileges are requested
+ */
+ public static GetPrivilegesRequest getApplicationPrivileges(String applicationName) {
+ if (Strings.isNullOrEmpty(applicationName)) {
+ throw new IllegalArgumentException("application name is required");
+ }
+ return new GetPrivilegesRequest(applicationName);
+ }
+
+ /**
+ * @return the name of the application for which to return certain privileges
+ */
+ public String getApplicationName() {
+ return applicationName;
+ }
+
+ /**
+ * @return an array of privilege names to return or null if all should be returned
+ */
+ public String[] getPrivilegeNames() {
+ return privilegeNames;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ GetPrivilegesRequest that = (GetPrivilegesRequest) o;
+ return Objects.equals(applicationName, that.applicationName) &&
+ Arrays.equals(privilegeNames, that.privilegeNames);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = Objects.hash(applicationName);
+ result = 31 * result + Arrays.hashCode(privilegeNames);
+ return result;
+ }
+}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetPrivilegesResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetPrivilegesResponse.java
new file mode 100644
index 0000000000000..182f14ef00c51
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetPrivilegesResponse.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.elasticsearch.client.security;
+
+import org.elasticsearch.client.security.user.privileges.ApplicationPrivilege;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.common.xcontent.XContentParserUtils;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Get application privileges response
+ */
+public final class GetPrivilegesResponse {
+
+ private Set privileges;
+
+ public Set getPrivileges() {
+ return privileges;
+ }
+
+ public GetPrivilegesResponse(Collection privileges) {
+ this.privileges = Collections.unmodifiableSet(new HashSet<>(privileges));
+ }
+
+ public static GetPrivilegesResponse fromXContent(XContentParser parser) throws IOException {
+ XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation);
+ List privileges = new ArrayList<>();
+ XContentParser.Token token;
+ while ((token = parser.nextToken()) != null) {
+ if (token == XContentParser.Token.FIELD_NAME) {
+ XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation);
+ while (parser.nextToken() != XContentParser.Token.END_OBJECT) {
+ privileges.add(ApplicationPrivilege.PARSER.parse(parser, null));
+ }
+ }
+ }
+ return new GetPrivilegesResponse(new HashSet<>(privileges));
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ GetPrivilegesResponse that = (GetPrivilegesResponse) o;
+ return Objects.equals(privileges, that.privileges);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(privileges);
+ }
+}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/security/user/privileges/ApplicationPrivilege.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/user/privileges/ApplicationPrivilege.java
new file mode 100644
index 0000000000000..1f5a4f08191cc
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/user/privileges/ApplicationPrivilege.java
@@ -0,0 +1,174 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.elasticsearch.client.security.user.privileges;
+
+import org.elasticsearch.common.Nullable;
+import org.elasticsearch.common.ParseField;
+import org.elasticsearch.common.Strings;
+import org.elasticsearch.common.xcontent.ConstructingObjectParser;
+import org.elasticsearch.common.xcontent.ObjectParser;
+import org.elasticsearch.common.xcontent.XContentParser;
+
+import java.io.IOException;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
+import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg;
+
+/**
+ * Represents an application specific privilege. The application name, privilege name,
+ * actions and metadata are completely managed by the client and can contain arbitrary
+ * string values.
+ */
+public final class ApplicationPrivilege {
+
+ private static final ParseField APPLICATION = new ParseField("application");
+ private static final ParseField NAME = new ParseField("name");
+ private static final ParseField ACTIONS = new ParseField("actions");
+ private static final ParseField METADATA = new ParseField("metadata");
+
+ private final String application;
+ private final String name;
+ private final Set actions;
+ private final Map metadata;
+
+ public ApplicationPrivilege(String application, String name, Collection actions, @Nullable Map metadata) {
+ if (Strings.isNullOrEmpty(application)) {
+ throw new IllegalArgumentException("application name must be provided");
+ } else {
+ this.application = application;
+ }
+ if (Strings.isNullOrEmpty(name)) {
+ throw new IllegalArgumentException("privilege name must be provided");
+ } else {
+ this.name = name;
+ }
+ if (actions == null || actions.isEmpty()) {
+ throw new IllegalArgumentException("actions must be provided");
+ } else {
+ this.actions = Collections.unmodifiableSet(new HashSet<>(actions));
+ }
+ if (metadata == null || metadata.isEmpty()) {
+ this.metadata = Collections.emptyMap();
+ } else {
+ this.metadata = Collections.unmodifiableMap(metadata);
+ }
+ }
+
+ public String getApplication() {
+ return application;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Set getActions() {
+ return actions;
+ }
+
+ public Map getMetadata() {
+ return metadata;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>(
+ "application_privilege",
+ true, args -> new ApplicationPrivilege((String) args[0], (String) args[1], (Collection) args[2],
+ (Map) args[3]));
+
+ static {
+ PARSER.declareString(constructorArg(), APPLICATION);
+ PARSER.declareString(constructorArg(), NAME);
+ PARSER.declareStringArray(constructorArg(), ACTIONS);
+ PARSER.declareField(optionalConstructorArg(), XContentParser::map, ApplicationPrivilege.METADATA, ObjectParser.ValueType.OBJECT);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ApplicationPrivilege that = (ApplicationPrivilege) o;
+ return Objects.equals(application, that.application) &&
+ Objects.equals(name, that.name) &&
+ Objects.equals(actions, that.actions) &&
+ Objects.equals(metadata, that.metadata);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(application, name, actions, metadata);
+ }
+
+ static ApplicationPrivilege fromXContent(XContentParser parser) throws IOException {
+ return PARSER.parse(parser, null);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static final class Builder {
+ private String applicationName = null;
+ private String privilegeName = null;
+ private Collection actions = null;
+ private Map metadata = null;
+
+ private Builder() {
+ }
+
+ public Builder application(String applicationName) {
+ this.applicationName = Objects.requireNonNull(applicationName, "application name must be provided");
+ return this;
+ }
+
+ public Builder privilege(String privilegeName) {
+ this.privilegeName = Objects.requireNonNull(privilegeName, "privilege name must be provided");
+ return this;
+ }
+
+ public Builder actions(String... actions) {
+ this.actions = Arrays.asList(Objects.requireNonNull(actions));
+ return this;
+ }
+
+ public Builder actions(Collection actions) {
+ this.actions = Objects.requireNonNull(actions);
+ return this;
+ }
+
+ public Builder metadata(Map metadata) {
+ this.metadata = metadata;
+ return this;
+ }
+
+ public ApplicationPrivilege build() {
+ return new ApplicationPrivilege(applicationName, privilegeName, actions, metadata);
+ }
+ }
+
+}
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/SecurityRequestConvertersTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/SecurityRequestConvertersTests.java
index 199356de2902e..eb1d030b0f6b8 100644
--- a/client/rest-high-level/src/test/java/org/elasticsearch/client/SecurityRequestConvertersTests.java
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/SecurityRequestConvertersTests.java
@@ -29,6 +29,7 @@
import org.elasticsearch.client.security.DeleteRoleRequest;
import org.elasticsearch.client.security.DisableUserRequest;
import org.elasticsearch.client.security.EnableUserRequest;
+import org.elasticsearch.client.security.GetPrivilegesRequest;
import org.elasticsearch.client.security.GetRoleMappingsRequest;
import org.elasticsearch.client.security.ChangePasswordRequest;
import org.elasticsearch.client.security.PutRoleMappingRequest;
@@ -243,6 +244,50 @@ public void testCreateTokenWithClientCredentialsGrant() throws Exception {
assertToXContentBody(createTokenRequest, request.getEntity());
}
+ public void testGetApplicationPrivilege() throws Exception {
+ final String application = randomAlphaOfLength(6);
+ final String privilege = randomAlphaOfLength(4);
+ GetPrivilegesRequest getPrivilegesRequest = new GetPrivilegesRequest(application, privilege);
+ Request request = SecurityRequestConverters.getPrivileges(getPrivilegesRequest);
+ assertEquals(HttpGet.METHOD_NAME, request.getMethod());
+ assertEquals("/_xpack/security/privilege/" + application + "/" + privilege, request.getEndpoint());
+ assertEquals(Collections.emptyMap(), request.getParameters());
+ assertNull(request.getEntity());
+ }
+
+ public void testGetAllApplicationPrivileges() throws Exception {
+ final String application = randomAlphaOfLength(6);
+ GetPrivilegesRequest getPrivilegesRequest = GetPrivilegesRequest.getApplicationPrivileges(application);
+ Request request = SecurityRequestConverters.getPrivileges(getPrivilegesRequest);
+ assertEquals(HttpGet.METHOD_NAME, request.getMethod());
+ assertEquals("/_xpack/security/privilege/" + application, request.getEndpoint());
+ assertEquals(Collections.emptyMap(), request.getParameters());
+ assertNull(request.getEntity());
+ }
+
+ public void testGetMultipleApplicationPrivileges() throws Exception {
+ final String application = randomAlphaOfLength(6);
+ final int numberOfPrivileges = randomIntBetween(1, 5);
+ final String[] privilegeNames =
+ randomArray(numberOfPrivileges, numberOfPrivileges, String[]::new, () -> randomAlphaOfLength(5));
+ GetPrivilegesRequest getPrivilegesRequest = new GetPrivilegesRequest(application, privilegeNames);
+ Request request = SecurityRequestConverters.getPrivileges(getPrivilegesRequest);
+ assertEquals(HttpGet.METHOD_NAME, request.getMethod());
+ assertEquals("/_xpack/security/privilege/" + application + "/" + Strings.arrayToCommaDelimitedString(privilegeNames),
+ request.getEndpoint());
+ assertEquals(Collections.emptyMap(), request.getParameters());
+ assertNull(request.getEntity());
+ }
+
+ public void testGetAllPrivileges() throws Exception {
+ GetPrivilegesRequest getPrivilegesRequest = GetPrivilegesRequest.getAllPrivileges();
+ Request request = SecurityRequestConverters.getPrivileges(getPrivilegesRequest);
+ assertEquals(HttpGet.METHOD_NAME, request.getMethod());
+ assertEquals("/_xpack/security/privilege", request.getEndpoint());
+ assertEquals(Collections.emptyMap(), request.getParameters());
+ assertNull(request.getEntity());
+ }
+
public void testDeletePrivileges() {
final String application = randomAlphaOfLengthBetween(1, 12);
final List privileges = randomSubsetOf(randomIntBetween(1, 3), "read", "write", "all");
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SecurityDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SecurityDocumentationIT.java
index 39f57706a3667..519d410fd2e37 100644
--- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SecurityDocumentationIT.java
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SecurityDocumentationIT.java
@@ -48,6 +48,8 @@
import org.elasticsearch.client.security.EmptyResponse;
import org.elasticsearch.client.security.EnableUserRequest;
import org.elasticsearch.client.security.ExpressionRoleMapping;
+import org.elasticsearch.client.security.GetPrivilegesRequest;
+import org.elasticsearch.client.security.GetPrivilegesResponse;
import org.elasticsearch.client.security.GetRoleMappingsRequest;
import org.elasticsearch.client.security.GetRoleMappingsResponse;
import org.elasticsearch.client.security.GetSslCertificatesResponse;
@@ -65,6 +67,7 @@
import org.elasticsearch.client.security.support.expressiondsl.expressions.AnyRoleMapperExpression;
import org.elasticsearch.client.security.support.expressiondsl.fields.FieldRoleMapperExpression;
import org.elasticsearch.client.security.user.User;
+import org.elasticsearch.client.security.user.privileges.ApplicationPrivilege;
import org.elasticsearch.client.security.user.privileges.IndicesPrivileges;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.util.set.Sets;
@@ -73,16 +76,19 @@
import org.hamcrest.Matchers;
import java.io.IOException;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.emptyIterable;
import static org.hamcrest.Matchers.equalTo;
@@ -475,7 +481,7 @@ public void testHasPrivileges() throws Exception {
}
{
- HasPrivilegesRequest request = new HasPrivilegesRequest(Collections.singleton("monitor"),null,null);
+ HasPrivilegesRequest request = new HasPrivilegesRequest(Collections.singleton("monitor"), null, null);
// tag::has-privileges-execute-listener
ActionListener listener = new ActionListener() {
@@ -987,6 +993,146 @@ public void onFailure(Exception e) {
}
}
+ public void testGetPrivileges() throws Exception {
+ final RestHighLevelClient client = highLevelClient();
+ final ApplicationPrivilege readTestappPrivilege =
+ new ApplicationPrivilege("testapp", "read", Arrays.asList("action:login", "data:read/*"), null);
+ final Map metadata = new HashMap<>();
+ metadata.put("key1", "value1");
+ final ApplicationPrivilege writeTestappPrivilege =
+ new ApplicationPrivilege("testapp", "write", Arrays.asList("action:login", "data:write/*"), metadata);
+ final ApplicationPrivilege allTestappPrivilege =
+ new ApplicationPrivilege("testapp", "all", Arrays.asList("action:login", "data:write/*", "manage:*"), null);
+ final Map metadata2 = new HashMap<>();
+ metadata2.put("key2", "value2");
+ final ApplicationPrivilege readTestapp2Privilege =
+ new ApplicationPrivilege("testapp2", "read", Arrays.asList("action:login", "data:read/*"), metadata2);
+ final ApplicationPrivilege writeTestapp2Privilege =
+ new ApplicationPrivilege("testapp2", "write", Arrays.asList("action:login", "data:write/*"), null);
+ final ApplicationPrivilege allTestapp2Privilege =
+ new ApplicationPrivilege("testapp2", "all", Arrays.asList("action:login", "data:write/*", "manage:*"), null);
+
+ {
+ //TODO Replace this with a call to PutPrivileges once it is implemented
+ final Request createPrivilegeRequest = new Request("POST", "/_xpack/security/privilege");
+ createPrivilegeRequest.setJsonEntity("{" +
+ " \"testapp\": {" +
+ " \"read\": {" +
+ " \"actions\": [ \"action:login\", \"data:read/*\" ]" +
+ " }," +
+ " \"write\": {" +
+ " \"actions\": [ \"action:login\", \"data:write/*\" ]," +
+ " \"metadata\": { \"key1\": \"value1\" }" +
+ " }," +
+ " \"all\": {" +
+ " \"actions\": [ \"action:login\", \"data:write/*\" , \"manage:*\"]" +
+ " }" +
+ " }," +
+ " \"testapp2\": {" +
+ " \"read\": {" +
+ " \"actions\": [ \"action:login\", \"data:read/*\" ]," +
+ " \"metadata\": { \"key2\": \"value2\" }" +
+ " }," +
+ " \"write\": {" +
+ " \"actions\": [ \"action:login\", \"data:write/*\" ]" +
+ " }," +
+ " \"all\": {" +
+ " \"actions\": [ \"action:login\", \"data:write/*\" , \"manage:*\"]" +
+ " }" +
+ " }" +
+ "}");
+ final Response createPrivilegeResponse = client.getLowLevelClient().performRequest(createPrivilegeRequest);
+ assertEquals(RestStatus.OK.getStatus(), createPrivilegeResponse.getStatusLine().getStatusCode());
+ }
+
+ {
+ //tag::get-privileges-request
+ GetPrivilegesRequest request = new GetPrivilegesRequest("testapp", "write");
+ //end::get-privileges-request
+ //tag::get-privileges-execute
+ GetPrivilegesResponse response = client.security().getPrivileges(request, RequestOptions.DEFAULT);
+ //end::get-privileges-execute
+ assertNotNull(response);
+ assertThat(response.getPrivileges().size(), equalTo(1));
+ assertThat(response.getPrivileges().contains(writeTestappPrivilege), equalTo(true));
+ }
+
+ {
+ //tag::get-all-application-privileges-request
+ GetPrivilegesRequest request = GetPrivilegesRequest.getApplicationPrivileges("testapp");
+ //end::get-all-application-privileges-request
+ GetPrivilegesResponse response = client.security().getPrivileges(request, RequestOptions.DEFAULT);
+
+ assertNotNull(response);
+ assertThat(response.getPrivileges().size(), equalTo(3));
+ final GetPrivilegesResponse exptectedResponse =
+ new GetPrivilegesResponse(Arrays.asList(readTestappPrivilege, writeTestappPrivilege, allTestappPrivilege));
+ assertThat(response, equalTo(exptectedResponse));
+ Set privileges = response.getPrivileges();
+ for (ApplicationPrivilege privilege : privileges) {
+ assertThat(privilege.getApplication(), equalTo("testapp"));
+ if (privilege.getName().equals("read")) {
+ assertThat(privilege.getActions(), containsInAnyOrder("action:login", "data:read/*"));
+ assertThat(privilege.getMetadata().isEmpty(), equalTo(true));
+ } else if (privilege.getName().equals("write")) {
+ assertThat(privilege.getActions(), containsInAnyOrder("action:login", "data:write/*"));
+ assertThat(privilege.getMetadata().isEmpty(), equalTo(false));
+ assertThat(privilege.getMetadata().get("key1"), equalTo("value1"));
+ } else if (privilege.getName().equals("all")) {
+ assertThat(privilege.getActions(), containsInAnyOrder("action:login", "data:write/*", "manage:*"));
+ assertThat(privilege.getMetadata().isEmpty(), equalTo(true));
+ }
+ }
+ }
+
+ {
+ //tag::get-all-privileges-request
+ GetPrivilegesRequest request = GetPrivilegesRequest.getAllPrivileges();
+ //end::get-all-privileges-request
+ GetPrivilegesResponse response = client.security().getPrivileges(request, RequestOptions.DEFAULT);
+
+ assertNotNull(response);
+ assertThat(response.getPrivileges().size(), equalTo(6));
+ final GetPrivilegesResponse exptectedResponse =
+ new GetPrivilegesResponse(Arrays.asList(readTestappPrivilege, writeTestappPrivilege, allTestappPrivilege,
+ readTestapp2Privilege, writeTestapp2Privilege, allTestapp2Privilege));
+ assertThat(response, equalTo(exptectedResponse));
+ }
+
+ {
+ GetPrivilegesRequest request = new GetPrivilegesRequest("testapp", "read");
+ //tag::get-privileges-execute-listener
+ ActionListener listener = new ActionListener() {
+ @Override
+ public void onResponse(GetPrivilegesResponse getPrivilegesResponse) {
+ // <1>
+ }
+
+ @Override
+ public void onFailure(Exception e) {
+ // <2>
+ }
+ };
+ //end::get-privileges-execute-listener
+
+ // Avoid unused variable warning
+ assertNotNull(listener);
+
+ // Replace the empty listener by a blocking listener in test
+ final PlainActionFuture future = new PlainActionFuture<>();
+ listener = future;
+
+ //tag::get-privileges-execute-async
+ client.security().getPrivilegesAsync(request, RequestOptions.DEFAULT, listener); // <1>
+ //end::get-privileges-execute-async
+
+ final GetPrivilegesResponse response = future.get(30, TimeUnit.SECONDS);
+ assertNotNull(response);
+ assertThat(response.getPrivileges().size(), equalTo(1));
+ assertThat(response.getPrivileges().contains(readTestappPrivilege), equalTo(true));
+ }
+ }
+
public void testDeletePrivilege() throws Exception {
RestHighLevelClient client = highLevelClient();
{
@@ -1061,3 +1207,4 @@ public void onFailure(Exception e) {
}
}
}
+
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/security/GetPrivilegesRequestTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/security/GetPrivilegesRequestTests.java
new file mode 100644
index 0000000000000..12638bef326c7
--- /dev/null
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/security/GetPrivilegesRequestTests.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.elasticsearch.client.security;
+
+import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.test.EqualsHashCodeTestUtils;
+
+import static org.hamcrest.Matchers.equalTo;
+
+public class GetPrivilegesRequestTests extends ESTestCase {
+
+ public void testGetPrivilegesRequest() {
+ final String applicationName = randomAlphaOfLength(5);
+ final int numberOfPrivileges = randomIntBetween(0, 5);
+ final String[] privilegeNames = randomBoolean() ? null : randomArray(numberOfPrivileges, numberOfPrivileges, String[]::new,
+ () -> randomAlphaOfLength(5));
+ final GetPrivilegesRequest getPrivilegesRequest = new GetPrivilegesRequest(applicationName, privilegeNames);
+ assertThat(getPrivilegesRequest.getApplicationName(), equalTo(applicationName));
+ assertThat(getPrivilegesRequest.getPrivilegeNames(), equalTo(privilegeNames));
+ }
+
+ public void testPrivilegeWithoutApplication() {
+ IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> {
+ new GetPrivilegesRequest(null, randomAlphaOfLength(5));
+ });
+ assertThat(e.getMessage(), equalTo("privilege cannot be specified when application is missing"));
+ }
+
+ public void testEqualsAndHashCode() {
+ final String applicationName = randomAlphaOfLength(5);
+ final int numberOfPrivileges = randomIntBetween(0, 5);
+ final String[] privilegeNames =
+ randomArray(numberOfPrivileges, numberOfPrivileges, String[]::new, () -> randomAlphaOfLength(5));
+ final GetPrivilegesRequest getPrivilegesRequest = new GetPrivilegesRequest(applicationName, privilegeNames);
+ final EqualsHashCodeTestUtils.MutateFunction mutate = r -> {
+ if (randomBoolean()) {
+ final int numberOfNewPrivileges = randomIntBetween(1, 5);
+ final String[] newPrivilegeNames =
+ randomArray(numberOfNewPrivileges, numberOfNewPrivileges, String[]::new, () -> randomAlphaOfLength(5));
+ return new GetPrivilegesRequest(applicationName, newPrivilegeNames);
+ } else {
+ return GetPrivilegesRequest.getApplicationPrivileges(randomAlphaOfLength(6));
+ }
+ };
+ EqualsHashCodeTestUtils.checkEqualsAndHashCode(getPrivilegesRequest,
+ r -> new GetPrivilegesRequest(r.getApplicationName(), r.getPrivilegeNames()), mutate);
+ }
+}
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/security/GetPrivilegesResponseTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/security/GetPrivilegesResponseTests.java
new file mode 100644
index 0000000000000..74211892a09e8
--- /dev/null
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/security/GetPrivilegesResponseTests.java
@@ -0,0 +1,154 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.elasticsearch.client.security;
+
+import org.elasticsearch.client.security.user.privileges.ApplicationPrivilege;
+import org.elasticsearch.common.xcontent.DeprecationHandler;
+import org.elasticsearch.common.xcontent.NamedXContentRegistry;
+import org.elasticsearch.common.xcontent.XContentType;
+import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.test.EqualsHashCodeTestUtils;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.hamcrest.Matchers.equalTo;
+
+public class GetPrivilegesResponseTests extends ESTestCase {
+
+ public void testFromXContent() throws IOException {
+ final String json = "{" +
+ " \"testapp\": {" +
+ " \"read\": {" +
+ " \"application\": \"testapp\"," +
+ " \"name\": \"read\"," +
+ " \"actions\": [ \"action:login\", \"data:read/*\" ]" +
+ " }," +
+ " \"write\": {" +
+ " \"application\": \"testapp\"," +
+ " \"name\": \"write\"," +
+ " \"actions\": [ \"action:login\", \"data:write/*\" ]," +
+ " \"metadata\": { \"key1\": \"value1\" }" +
+ " }," +
+ " \"all\": {" +
+ " \"application\": \"testapp\"," +
+ " \"name\": \"all\"," +
+ " \"actions\": [ \"action:login\", \"data:write/*\" , \"manage:*\"]" +
+ " }" +
+ " }," +
+ " \"testapp2\": {" +
+ " \"read\": {" +
+ " \"application\": \"testapp2\"," +
+ " \"name\": \"read\"," +
+ " \"actions\": [ \"action:login\", \"data:read/*\" ]," +
+ " \"metadata\": { \"key2\": \"value2\" }" +
+ " }," +
+ " \"write\": {" +
+ " \"application\": \"testapp2\"," +
+ " \"name\": \"write\"," +
+ " \"actions\": [ \"action:login\", \"data:write/*\" ]" +
+ " }," +
+ " \"all\": {" +
+ " \"application\": \"testapp2\"," +
+ " \"name\": \"all\"," +
+ " \"actions\": [ \"action:login\", \"data:write/*\" , \"manage:*\"]" +
+ " }" +
+ " }" +
+ "}";
+
+ final GetPrivilegesResponse response = GetPrivilegesResponse.fromXContent(XContentType.JSON.xContent().createParser(
+ new NamedXContentRegistry(Collections.emptyList()), new DeprecationHandler() {
+ @Override
+ public void usedDeprecatedName(String usedName, String modernName) {
+ }
+
+ @Override
+ public void usedDeprecatedField(String usedName, String replacedWith) {
+ }
+ }, json));
+
+ final ApplicationPrivilege readTestappPrivilege =
+ new ApplicationPrivilege("testapp", "read", Arrays.asList("action:login", "data:read/*"), null);
+ final Map metadata = new HashMap<>();
+ metadata.put("key1", "value1");
+ final ApplicationPrivilege writeTestappPrivilege =
+ new ApplicationPrivilege("testapp", "write", Arrays.asList("action:login", "data:write/*"), metadata);
+ final ApplicationPrivilege allTestappPrivilege =
+ new ApplicationPrivilege("testapp", "all", Arrays.asList("action:login", "data:write/*", "manage:*"), null);
+ final Map metadata2 = new HashMap<>();
+ metadata2.put("key2", "value2");
+ final ApplicationPrivilege readTestapp2Privilege =
+ new ApplicationPrivilege("testapp2", "read", Arrays.asList("action:login", "data:read/*"), metadata2);
+ final ApplicationPrivilege writeTestapp2Privilege =
+ new ApplicationPrivilege("testapp2", "write", Arrays.asList("action:login", "data:write/*"), null);
+ final ApplicationPrivilege allTestapp2Privilege =
+ new ApplicationPrivilege("testapp2", "all", Arrays.asList("action:login", "data:write/*", "manage:*"), null);
+ final GetPrivilegesResponse exptectedResponse =
+ new GetPrivilegesResponse(Arrays.asList(readTestappPrivilege, writeTestappPrivilege, allTestappPrivilege,
+ readTestapp2Privilege, writeTestapp2Privilege, allTestapp2Privilege));
+ assertThat(response, equalTo(exptectedResponse));
+ }
+
+ public void testEqualsHashCode() {
+ final List privileges = new ArrayList<>();
+ final List privileges2 = new ArrayList<>();
+ final Map metadata = new HashMap<>();
+ metadata.put("key1", "value1");
+ final ApplicationPrivilege writePrivilege =
+ new ApplicationPrivilege("testapp", "write", Arrays.asList("action:login", "data:write/*"),
+ metadata);
+ final ApplicationPrivilege readPrivilege =
+ new ApplicationPrivilege("testapp", "read", Arrays.asList("data:read/*", "action:login"),
+ metadata);
+ privileges.add(readPrivilege);
+ privileges.add(writePrivilege);
+ privileges2.add(writePrivilege);
+ privileges2.add(readPrivilege);
+ final GetPrivilegesResponse response = new GetPrivilegesResponse(privileges);
+ EqualsHashCodeTestUtils.checkEqualsAndHashCode(response, (original) -> {
+ return new GetPrivilegesResponse(original.getPrivileges());
+ });
+ EqualsHashCodeTestUtils.checkEqualsAndHashCode(response, (original) -> {
+ return new GetPrivilegesResponse(original.getPrivileges());
+ }, GetPrivilegesResponseTests::mutateTestItem);
+ }
+
+ private static GetPrivilegesResponse mutateTestItem(GetPrivilegesResponse original) {
+ if (randomBoolean()) {
+ Set originalPrivileges = original.getPrivileges();
+ List privileges = new ArrayList<>();
+ privileges.addAll(originalPrivileges);
+ privileges.add(new ApplicationPrivilege("testapp", "all", Arrays.asList("action:login", "data:read/*", "manage:*"), null));
+ return new GetPrivilegesResponse(privileges);
+ } else {
+ final List privileges = new ArrayList<>();
+ final ApplicationPrivilege privilege =
+ new ApplicationPrivilege("testapp", "all", Arrays.asList("action:login", "data:write/*", "manage:*"), null);
+ privileges.add(privilege);
+ return new GetPrivilegesResponse(privileges);
+ }
+ }
+}
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/security/user/privileges/ApplicationPrivilegeTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/security/user/privileges/ApplicationPrivilegeTests.java
new file mode 100644
index 0000000000000..f958cadaa7e80
--- /dev/null
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/security/user/privileges/ApplicationPrivilegeTests.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.elasticsearch.client.security.user.privileges;
+
+import org.elasticsearch.common.xcontent.DeprecationHandler;
+import org.elasticsearch.common.xcontent.NamedXContentRegistry;
+import org.elasticsearch.common.xcontent.XContentType;
+import org.elasticsearch.test.ESTestCase;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.equalTo;
+
+public class ApplicationPrivilegeTests extends ESTestCase {
+
+ public void testFromXContent() throws IOException {
+ String json =
+ " {" +
+ " \"application\": \"myapp\"," +
+ " \"name\": \"read\"," +
+ " \"actions\": [" +
+ " \"data:read/*\"," +
+ " \"action:login\"" +
+ " ],\n" +
+ " \"metadata\": {" +
+ " \"description\": \"Read access to myapp\"" +
+ " }" +
+ " }";
+ final ApplicationPrivilege privilege = ApplicationPrivilege.fromXContent(XContentType.JSON.xContent().createParser(
+ new NamedXContentRegistry(Collections.emptyList()), new DeprecationHandler() {
+ @Override
+ public void usedDeprecatedName(String usedName, String modernName) {
+ }
+
+ @Override
+ public void usedDeprecatedField(String usedName, String replacedWith) {
+ }
+ }, json));
+ final Map metadata = new HashMap<>();
+ metadata.put("description", "Read access to myapp");
+ final ApplicationPrivilege expectedPrivilege =
+ new ApplicationPrivilege("myapp", "read", Arrays.asList("data:read/*", "action:login"), metadata);
+ assertThat(privilege, equalTo(expectedPrivilege));
+ }
+
+ public void testEmptyApplicationName() {
+ final Map metadata = new HashMap<>();
+ metadata.put("description", "Read access to myapp");
+ final String applicationName = randomBoolean() ? null : "";
+ final IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () ->
+ new ApplicationPrivilege(applicationName, "read", Arrays.asList("data:read/*", "action:login"), metadata));
+ assertThat(e.getMessage(), equalTo("application name must be provided"));
+ }
+
+ public void testEmptyPrivilegeName() {
+ final Map metadata = new HashMap<>();
+ metadata.put("description", "Read access to myapp");
+ final String privilegenName = randomBoolean() ? null : "";
+ final IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () ->
+ new ApplicationPrivilege("myapp", privilegenName, Arrays.asList("data:read/*", "action:login"), metadata));
+ assertThat(e.getMessage(), equalTo("privilege name must be provided"));
+ }
+
+ public void testEmptyActions() {
+ final Map metadata = new HashMap<>();
+ metadata.put("description", "Read access to myapp");
+ final List actions = randomBoolean() ? null : Collections.emptyList();
+ final IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () ->
+ new ApplicationPrivilege("myapp", "read", actions, metadata));
+ assertThat(e.getMessage(), equalTo("actions must be provided"));
+ }
+
+ public void testBuilder() {
+ final Map metadata = new HashMap<>();
+ metadata.put("description", "Read access to myapp");
+ ApplicationPrivilege privilege = ApplicationPrivilege.builder()
+ .application("myapp")
+ .privilege("read")
+ .actions("data:read/*", "action:login")
+ .metadata(metadata)
+ .build();
+ assertThat(privilege.getApplication(), equalTo("myapp"));
+ assertThat(privilege.getName(), equalTo("read"));
+ assertThat(privilege.getActions(), containsInAnyOrder("data:read/*", "action:login"));
+ assertThat(privilege.getMetadata(), equalTo(metadata));
+ }
+}
diff --git a/docs/java-rest/high-level/security/get-privileges.asciidoc b/docs/java-rest/high-level/security/get-privileges.asciidoc
new file mode 100644
index 0000000000000..06ae51e669081
--- /dev/null
+++ b/docs/java-rest/high-level/security/get-privileges.asciidoc
@@ -0,0 +1,47 @@
+
+--
+:api: get-privileges
+:request: GetPrivilegesRequest
+:respnse: GetPrivilegesResponse
+--
+
+[id="{upid}-{api}"]
+=== Get Privileges API
+
+[id="{upid}-{api}-request"]
+==== Get Privileges Request
+
+The +{request}+ supports getting privilege(s) for all or for specific applications.
+
+===== Specific privilege of a specific application
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests-file}[{api}-request]
+--------------------------------------------------
+
+===== All privileges of a specific application
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests-file}[get-all-application-privileges-request]
+--------------------------------------------------
+
+===== All privileges of all applications
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests-file}[get-all-privileges-request]
+--------------------------------------------------
+
+include::../execution.asciidoc[]
+
+[id="{upid}-{api}-response"]
+==== Get Privileges Response
+
+The returned +{response}+ allows to get information about the retrieved privileges as follows.
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests-file}[{api}-response]
+--------------------------------------------------
\ No newline at end of file
diff --git a/docs/java-rest/high-level/supported-apis.asciidoc b/docs/java-rest/high-level/supported-apis.asciidoc
index cabd20d52ff07..3e3606bdd6789 100644
--- a/docs/java-rest/high-level/supported-apis.asciidoc
+++ b/docs/java-rest/high-level/supported-apis.asciidoc
@@ -365,6 +365,7 @@ The Java High Level REST Client supports the following Security APIs:
* <>
* <>
* <<{upid}-invalidate-token>>
+* <<{upid}-get-privileges>>
* <<{upid}-delete-privileges>>
include::security/put-user.asciidoc[]
@@ -373,6 +374,7 @@ include::security/disable-user.asciidoc[]
include::security/change-password.asciidoc[]
include::security/delete-role.asciidoc[]
include::security/delete-privileges.asciidoc[]
+include::security/get-privileges.asciidoc[]
include::security/clear-roles-cache.asciidoc[]
include::security/clear-realm-cache.asciidoc[]
include::security/authenticate.asciidoc[]