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 b6d4bd110bd79..ab7b3e33905b7 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
@@ -42,6 +42,8 @@
import org.elasticsearch.client.security.GetPrivilegesResponse;
import org.elasticsearch.client.security.GetRoleMappingsRequest;
import org.elasticsearch.client.security.GetRoleMappingsResponse;
+import org.elasticsearch.client.security.GetRolesRequest;
+import org.elasticsearch.client.security.GetRolesResponse;
import org.elasticsearch.client.security.GetSslCertificatesRequest;
import org.elasticsearch.client.security.GetSslCertificatesResponse;
import org.elasticsearch.client.security.HasPrivilegesRequest;
@@ -407,6 +409,35 @@ public DeleteRoleMappingResponse deleteRoleMapping(DeleteRoleMappingRequest requ
DeleteRoleMappingResponse::fromXContent, emptySet());
}
+ /**
+ * Asynchronously retrieves roles from the native roles store.
+ * See
+ * the docs for more.
+ *
+ * @param request the request with the roles to get
+ * @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 getRolesAsync(GetRolesRequest request, RequestOptions options, ActionListener listener) {
+ restHighLevelClient.performRequestAsyncAndParseEntity(request, SecurityRequestConverters::getRoles, options,
+ GetRolesResponse::fromXContent, listener, emptySet());
+ }
+
+ /**
+ * Retrieves roles from the native roles store.
+ * See
+ * the docs for more.
+ *
+ * @param request the request with the roles to get
+ * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
+ * @return the response from the delete role call
+ * @throws IOException in case there is a problem sending the request or parsing back the response
+ */
+ public GetRolesResponse getRoles(final GetRolesRequest request, final RequestOptions options) throws IOException {
+ return restHighLevelClient.performRequestAndParseEntity(request, SecurityRequestConverters::getRoles, options,
+ GetRolesResponse::fromXContent, emptySet());
+ }
+
/**
* Asynchronously delete a role mapping.
* See
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 b07c68f999873..a1123de725110 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
@@ -32,6 +32,7 @@
import org.elasticsearch.client.security.DeleteRoleMappingRequest;
import org.elasticsearch.client.security.DeleteRoleRequest;
import org.elasticsearch.client.security.InvalidateTokenRequest;
+import org.elasticsearch.client.security.GetRolesRequest;
import org.elasticsearch.client.security.PutRoleMappingRequest;
import org.elasticsearch.client.security.HasPrivilegesRequest;
import org.elasticsearch.client.security.DisableUserRequest;
@@ -170,6 +171,15 @@ static Request deleteRole(DeleteRoleRequest deleteRoleRequest) {
return request;
}
+ static Request getRoles(GetRolesRequest getRolesRequest) {
+ RequestConverters.EndpointBuilder builder = new RequestConverters.EndpointBuilder();
+ builder.addPathPartAsIs("_xpack/security/role");
+ if (getRolesRequest.getRoleNames().size() > 0) {
+ builder.addPathPart(Strings.collectionToCommaDelimitedString(getRolesRequest.getRoleNames()));
+ }
+ return new Request(HttpGet.METHOD_NAME, builder.build());
+ }
+
static Request createToken(CreateTokenRequest createTokenRequest) throws IOException {
Request request = new Request(HttpPost.METHOD_NAME, "/_xpack/security/oauth2/token");
request.setEntity(createEntity(createTokenRequest, REQUEST_BODY_CONTENT_TYPE));
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetRolesRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetRolesRequest.java
new file mode 100644
index 0000000000000..7692e24c28bb5
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetRolesRequest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.util.set.Sets;
+
+import java.util.Collections;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Request object to retrieve roles from the native roles store
+ */
+public final class GetRolesRequest implements Validatable {
+
+ private final Set roleNames;
+
+ public GetRolesRequest(final String... roleNames) {
+ if (roleNames != null) {
+ this.roleNames = Collections.unmodifiableSet(Sets.newHashSet(roleNames));
+ } else {
+ this.roleNames = Collections.emptySet();
+ }
+ }
+
+ public Set getRoleNames() {
+ return roleNames;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ final GetRolesRequest that = (GetRolesRequest) o;
+ return Objects.equals(roleNames, that.roleNames);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(roleNames);
+ }
+}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetRolesResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetRolesResponse.java
new file mode 100644
index 0000000000000..91b7527c3235e
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetRolesResponse.java
@@ -0,0 +1,71 @@
+/*
+ * 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.Role;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.common.xcontent.XContentParserUtils;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Response when requesting one or more roles.
+ * Returns a List of {@link Role} objects
+ */
+public final class GetRolesResponse {
+
+ private final List roles;
+
+ public GetRolesResponse(List roles) {
+ this.roles = Collections.unmodifiableList(roles);
+ }
+
+ public List getRoles() {
+ return roles;
+ }
+
+ public static GetRolesResponse fromXContent(XContentParser parser) throws IOException {
+ XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation);
+ final List roles = new ArrayList<>();
+ XContentParser.Token token;
+ while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
+ XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser::getTokenLocation);
+ roles.add(Role.PARSER.parse(parser, parser.currentName()));
+ }
+ return new GetRolesResponse(roles);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ GetRolesResponse response = (GetRolesResponse) o;
+ return Objects.equals(roles, response.roles);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(roles);
+ }
+}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/security/user/privileges/IndicesPrivileges.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/user/privileges/IndicesPrivileges.java
index e693a4fea34fa..393b8613f25e7 100644
--- a/client/rest-high-level/src/main/java/org/elasticsearch/client/security/user/privileges/IndicesPrivileges.java
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/user/privileges/IndicesPrivileges.java
@@ -249,7 +249,7 @@ public static final class Builder {
private @Nullable Collection deniedFields = null;
private @Nullable String query = null;
- private Builder() {
+ public Builder() {
}
public Builder indices(String... indices) {
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/security/user/privileges/Role.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/user/privileges/Role.java
index 78265196ee819..e332971a512fd 100644
--- a/client/rest-high-level/src/main/java/org/elasticsearch/client/security/user/privileges/Role.java
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/user/privileges/Role.java
@@ -21,15 +21,11 @@
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.ToXContentObject;
-import org.elasticsearch.common.xcontent.XContentBuilder;
-import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentParser;
-import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.common.xcontent.ObjectParser.ValueType;
-import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -42,10 +38,9 @@
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg;
/**
- * Represents an aggregation of privileges. This does not have a name
- * identifier.
+ * Represents an aggregation of privileges.
*/
-public final class Role implements ToXContentObject {
+public final class Role {
public static final ParseField CLUSTER = new ParseField("cluster");
public static final ParseField GLOBAL = new ParseField("global");
@@ -53,10 +48,11 @@ public final class Role implements ToXContentObject {
public static final ParseField APPLICATIONS = new ParseField("applications");
public static final ParseField RUN_AS = new ParseField("run_as");
public static final ParseField METADATA = new ParseField("metadata");
+ public static final ParseField TRANSIENT_METADATA = new ParseField("transient_metadata");
@SuppressWarnings("unchecked")
- private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>("role_descriptor", false,
- constructorObjects -> {
+ public static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>("role_descriptor", false,
+ (constructorObjects, roleName) -> {
// Don't ignore unknown fields. It is dangerous if the object we parse is also
// part of a request that we build later on, and the fields that we now ignore
// will end up being implicitly set to null in that request.
@@ -67,31 +63,44 @@ public final class Role implements ToXContentObject {
final Collection applicationResourcePrivileges =
(Collection) constructorObjects[i++];
final Collection runAsPrivilege = (Collection) constructorObjects[i++];
- final Map metadata = (Map) constructorObjects[i];
- return new Role(clusterPrivileges, globalApplicationPrivileges, indicesPrivileges, applicationResourcePrivileges,
- runAsPrivilege, metadata);
+ final Map metadata = (Map) constructorObjects[i++];
+ final Map transientMetadata = (Map) constructorObjects[i];
+ return new Role(roleName, clusterPrivileges, globalApplicationPrivileges, indicesPrivileges, applicationResourcePrivileges,
+ runAsPrivilege, metadata, transientMetadata);
});
static {
PARSER.declareStringArray(optionalConstructorArg(), CLUSTER);
- PARSER.declareObject(optionalConstructorArg(), GlobalPrivileges.PARSER, GLOBAL);
- PARSER.declareFieldArray(optionalConstructorArg(), IndicesPrivileges.PARSER, INDICES, ValueType.OBJECT_ARRAY);
- PARSER.declareFieldArray(optionalConstructorArg(), ApplicationResourcePrivileges.PARSER, APPLICATIONS, ValueType.OBJECT_ARRAY);
+ PARSER.declareObject(optionalConstructorArg(), (parser,c)-> GlobalPrivileges.PARSER.parse(parser,null), GLOBAL);
+ PARSER.declareFieldArray(optionalConstructorArg(), (parser,c)->IndicesPrivileges.PARSER.parse(parser,null), INDICES,
+ ValueType.OBJECT_ARRAY);
+ PARSER.declareFieldArray(optionalConstructorArg(), (parser,c)->ApplicationResourcePrivileges.PARSER.parse(parser,null),
+ APPLICATIONS, ValueType.OBJECT_ARRAY);
PARSER.declareStringArray(optionalConstructorArg(), RUN_AS);
PARSER.declareObject(constructorArg(), (parser, c) -> parser.map(), METADATA);
+ PARSER.declareObject(constructorArg(), (parser, c) -> parser.map(), TRANSIENT_METADATA);
}
+ private final String name;
private final Set clusterPrivileges;
private final @Nullable GlobalPrivileges globalApplicationPrivileges;
private final Set indicesPrivileges;
private final Set applicationResourcePrivileges;
private final Set runAsPrivilege;
private final Map metadata;
-
- private Role(@Nullable Collection clusterPrivileges, @Nullable GlobalPrivileges globalApplicationPrivileges,
- @Nullable Collection indicesPrivileges,
- @Nullable Collection applicationResourcePrivileges, @Nullable Collection runAsPrivilege,
- @Nullable Map metadata) {
+ private final Map transientMetadata;
+
+ private Role(String name, @Nullable Collection clusterPrivileges,
+ @Nullable GlobalPrivileges globalApplicationPrivileges,
+ @Nullable Collection indicesPrivileges,
+ @Nullable Collection applicationResourcePrivileges,
+ @Nullable Collection runAsPrivilege, @Nullable Map metadata,
+ @Nullable Map transientMetadata) {
+ if (Strings.hasText(name) == false){
+ throw new IllegalArgumentException("role name must be provided");
+ } else {
+ this.name = name;
+ }
// no cluster privileges are granted unless otherwise specified
this.clusterPrivileges = Collections
.unmodifiableSet(clusterPrivileges != null ? new HashSet<>(clusterPrivileges) : Collections.emptySet());
@@ -105,6 +114,11 @@ private Role(@Nullable Collection clusterPrivileges, @Nullable GlobalPri
// no run as privileges are granted unless otherwise specified
this.runAsPrivilege = Collections.unmodifiableSet(runAsPrivilege != null ? new HashSet<>(runAsPrivilege) : Collections.emptySet());
this.metadata = metadata != null ? Collections.unmodifiableMap(metadata) : Collections.emptyMap();
+ this.transientMetadata = transientMetadata != null ? Collections.unmodifiableMap(transientMetadata) : Collections.emptyMap();
+ }
+
+ public String getName() {
+ return name;
}
public Set getClusterPrivileges() {
@@ -136,55 +150,67 @@ public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Role that = (Role) o;
- return clusterPrivileges.equals(that.clusterPrivileges)
- && Objects.equals(globalApplicationPrivileges, that.globalApplicationPrivileges)
- && indicesPrivileges.equals(that.indicesPrivileges)
- && applicationResourcePrivileges.equals(that.applicationResourcePrivileges)
- && runAsPrivilege.equals(that.runAsPrivilege)
- && metadata.equals(that.metadata);
+ return name.equals(that.name)
+ && clusterPrivileges.equals(that.clusterPrivileges)
+ && Objects.equals(globalApplicationPrivileges, that.globalApplicationPrivileges)
+ && indicesPrivileges.equals(that.indicesPrivileges)
+ && applicationResourcePrivileges.equals(that.applicationResourcePrivileges)
+ && runAsPrivilege.equals(that.runAsPrivilege)
+ && metadata.equals(that.metadata)
+ && transientMetadata.equals(that.transientMetadata);
}
@Override
public int hashCode() {
- return Objects.hash(clusterPrivileges, globalApplicationPrivileges, indicesPrivileges, applicationResourcePrivileges,
- runAsPrivilege, metadata);
+ return Objects.hash(name, clusterPrivileges, globalApplicationPrivileges, indicesPrivileges, applicationResourcePrivileges,
+ runAsPrivilege, metadata, transientMetadata);
}
@Override
public String toString() {
- try {
- return XContentHelper.toXContent(this, XContentType.JSON, true).utf8ToString();
- } catch (IOException e) {
- throw new RuntimeException("Unexpected", e);
- }
- }
-
- @Override
- public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
- builder.startObject();
+ StringBuilder sb = new StringBuilder("{");
+ sb.append("Name=").append(name).append(",");
if (false == clusterPrivileges.isEmpty()) {
- builder.field(CLUSTER.getPreferredName(), clusterPrivileges);
+ sb.append("ClusterPrivileges=");
+ sb.append(clusterPrivileges.toString());
+ sb.append(", ");
}
- if (null != globalApplicationPrivileges) {
- builder.field(GLOBAL.getPreferredName(), globalApplicationPrivileges);
+ if (globalApplicationPrivileges != null) {
+ sb.append("GlobalApplcationPrivileges=");
+ sb.append(globalApplicationPrivileges.toString());
+ sb.append(", ");
}
if (false == indicesPrivileges.isEmpty()) {
- builder.field(INDICES.getPreferredName(), indicesPrivileges);
+ sb.append("IndicesPrivileges=");
+ sb.append(indicesPrivileges.toString());
+ sb.append(", ");
}
if (false == applicationResourcePrivileges.isEmpty()) {
- builder.field(APPLICATIONS.getPreferredName(), applicationResourcePrivileges);
+ sb.append("ApplicationPrivileges=");
+ sb.append(applicationResourcePrivileges.toString());
+ sb.append(", ");
}
if (false == runAsPrivilege.isEmpty()) {
- builder.field(RUN_AS.getPreferredName(), runAsPrivilege);
+ sb.append("RunAsPrivilege=");
+ sb.append(runAsPrivilege.toString());
+ sb.append(", ");
}
if (false == metadata.isEmpty()) {
- builder.field(METADATA.getPreferredName(), metadata);
+ sb.append("Metadata=[");
+ sb.append(metadata.toString());
+ sb.append("], ");
}
- return builder.endObject();
+ if (false == transientMetadata.isEmpty()) {
+ sb.append("TransientMetadata=[");
+ sb.append(transientMetadata.toString());
+ sb.append("] ");
+ }
+ sb.append("}");
+ return sb.toString();
}
- public static Role fromXContent(XContentParser parser) {
- return PARSER.apply(parser, null);
+ public static Role fromXContent(XContentParser parser, String name) {
+ return PARSER.apply(parser, name);
}
public static Builder builder() {
@@ -193,16 +219,27 @@ public static Builder builder() {
public static final class Builder {
+ private @Nullable String name = null;
private @Nullable Collection clusterPrivileges = null;
private @Nullable GlobalPrivileges globalApplicationPrivileges = null;
private @Nullable Collection indicesPrivileges = null;
private @Nullable Collection applicationResourcePrivileges = null;
private @Nullable Collection runAsPrivilege = null;
private @Nullable Map metadata = null;
+ private @Nullable Map transientMetadata = null;
private Builder() {
}
+ public Builder name(String name) {
+ if (Strings.hasText(name) == false){
+ throw new IllegalArgumentException("role name must be provided");
+ } else {
+ this.name = name;
+ }
+ return this;
+ }
+
public Builder clusterPrivileges(String... clusterPrivileges) {
return clusterPrivileges(Arrays
.asList(Objects.requireNonNull(clusterPrivileges, "Cluster privileges cannot be null. Pass an empty array instead.")));
@@ -214,7 +251,7 @@ public Builder clusterPrivileges(Collection clusterPrivileges) {
return this;
}
- public Builder glabalApplicationPrivileges(GlobalPrivileges globalApplicationPrivileges) {
+ public Builder globalApplicationPrivileges(GlobalPrivileges globalApplicationPrivileges) {
this.globalApplicationPrivileges = globalApplicationPrivileges;
return this;
}
@@ -257,9 +294,15 @@ public Builder metadata(Map metadata) {
return this;
}
+ public Builder transientMetadata(Map transientMetadata) {
+ this.transientMetadata =
+ Objects.requireNonNull(transientMetadata, "Transient metadata cannot be null. Pass an empty map instead.");
+ return this;
+ }
+
public Role build() {
- return new Role(clusterPrivileges, globalApplicationPrivileges, indicesPrivileges, applicationResourcePrivileges,
- runAsPrivilege, metadata);
+ return new Role(name, clusterPrivileges, globalApplicationPrivileges, indicesPrivileges, applicationResourcePrivileges,
+ runAsPrivilege, metadata, transientMetadata);
}
}
@@ -282,6 +325,7 @@ public static class ClusterPrivilegeName {
public static final String TRANSPORT_CLIENT = "transport_client";
public static final String MANAGE_SECURITY = "manage_security";
public static final String MANAGE_SAML = "manage_saml";
+ public static final String MANAGE_TOKEN = "manage_token";
public static final String MANAGE_PIPELINE = "manage_pipeline";
public static final String MANAGE_CCR = "manage_ccr";
public static final String READ_CCR = "read_ccr";
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 eb1d030b0f6b8..dcfa9210094de 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
@@ -32,6 +32,7 @@
import org.elasticsearch.client.security.GetPrivilegesRequest;
import org.elasticsearch.client.security.GetRoleMappingsRequest;
import org.elasticsearch.client.security.ChangePasswordRequest;
+import org.elasticsearch.client.security.GetRolesRequest;
import org.elasticsearch.client.security.PutRoleMappingRequest;
import org.elasticsearch.client.security.PutUserRequest;
import org.elasticsearch.client.security.RefreshPolicy;
@@ -202,6 +203,22 @@ public void testDeleteRoleMapping() throws IOException {
assertNull(request.getEntity());
}
+ public void testGetRoles() {
+ final String[] roles = randomArray(0, 5, String[]::new, () -> randomAlphaOfLength(5));
+ final GetRolesRequest getRolesRequest = new GetRolesRequest(roles);
+ final Request request = SecurityRequestConverters.getRoles(getRolesRequest);
+
+ assertEquals(HttpGet.METHOD_NAME, request.getMethod());
+ if (roles.length == 0) {
+ assertEquals("/_xpack/security/role", request.getEndpoint());
+ } else {
+ assertEquals("/_xpack/security/role/" + Strings.collectionToCommaDelimitedString(getRolesRequest.getRoleNames()),
+ request.getEndpoint());
+ }
+ assertNull(request.getEntity());
+ assertEquals(Collections.emptyMap(), request.getParameters());
+ }
+
public void testDeleteRole() {
final String name = randomAlphaOfLengthBetween(1, 12);
final RefreshPolicy refreshPolicy = randomFrom(RefreshPolicy.values());
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 a8477bc6c9452..8d36381eeaa06 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
@@ -52,6 +52,8 @@
import org.elasticsearch.client.security.GetPrivilegesResponse;
import org.elasticsearch.client.security.GetRoleMappingsRequest;
import org.elasticsearch.client.security.GetRoleMappingsResponse;
+import org.elasticsearch.client.security.GetRolesRequest;
+import org.elasticsearch.client.security.GetRolesResponse;
import org.elasticsearch.client.security.GetSslCertificatesResponse;
import org.elasticsearch.client.security.HasPrivilegesRequest;
import org.elasticsearch.client.security.HasPrivilegesResponse;
@@ -67,6 +69,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.Role;
import org.elasticsearch.client.security.user.privileges.ApplicationPrivilege;
import org.elasticsearch.client.security.user.privileges.IndicesPrivileges;
import org.elasticsearch.common.Strings;
@@ -401,6 +404,89 @@ public void onFailure(Exception e) {
}
}
+ public void testGetRoles() throws Exception {
+ final RestHighLevelClient client = highLevelClient();
+ addRole("my_role");
+ addRole("my_role2");
+ addRole("my_role3");
+ {
+ //tag::get-roles-request
+ GetRolesRequest request = new GetRolesRequest("my_role");
+ //end::get-roles-request
+ //tag::get-roles-execute
+ GetRolesResponse response = client.security().getRoles(request, RequestOptions.DEFAULT);
+ //end::get-roles-execute
+ //tag::get-roles-response
+ List roles = response.getRoles();
+ //end::get-roles-response
+
+ assertNotNull(response);
+ assertThat(roles.size(), equalTo(1));
+ assertThat(roles.get(0).getName(), equalTo("my_role"));
+ assertThat(roles.get(0).getClusterPrivileges().contains("all"), equalTo(true));
+ }
+
+ {
+ //tag::get-roles-list-request
+ GetRolesRequest request = new GetRolesRequest("my_role", "my_role2");
+ GetRolesResponse response = client.security().getRoles(request, RequestOptions.DEFAULT);
+ //end::get-roles-list-request
+
+ List roles = response.getRoles();
+ assertNotNull(response);
+ assertThat(roles.size(), equalTo(2));
+ assertThat(roles.get(0).getClusterPrivileges().contains("all"), equalTo(true));
+ assertThat(roles.get(1).getClusterPrivileges().contains("all"), equalTo(true));
+ }
+
+ {
+ //tag::get-roles-all-request
+ GetRolesRequest request = new GetRolesRequest();
+ GetRolesResponse response = client.security().getRoles(request, RequestOptions.DEFAULT);
+ //end::get-roles-all-request
+
+ List roles = response.getRoles();
+ assertNotNull(response);
+ // 21 system roles plus the three we created
+ assertThat(roles.size(), equalTo(24));
+ }
+
+ {
+ GetRolesRequest request = new GetRolesRequest("my_role");
+ ActionListener listener;
+
+ //tag::get-roles-execute-listener
+ listener = new ActionListener() {
+ @Override
+ public void onResponse(GetRolesResponse getRolesResponse) {
+ // <1>
+ }
+
+ @Override
+ public void onFailure(Exception e) {
+ // <2>
+ }
+ };
+ //end::get-roles-execute-listener
+
+ assertNotNull(listener);
+
+ // Replace the empty listener by a blocking listener in test
+ final PlainActionFuture future = new PlainActionFuture<>();
+ listener = future;
+
+ //tag::get-roles-execute-async
+ client.security().getRolesAsync(request, RequestOptions.DEFAULT, listener); // <1>
+ //end::get-roles-execute-async
+
+ final GetRolesResponse response = future.get(30, TimeUnit.SECONDS);
+ assertNotNull(response);
+ assertThat(response.getRoles().size(), equalTo(1));
+ assertThat(response.getRoles().get(0).getName(), equalTo("my_role"));
+ assertThat(response.getRoles().get(0).getClusterPrivileges().contains("all"), equalTo(true));
+ }
+ }
+
public void testAuthenticate() throws Exception {
RestHighLevelClient client = highLevelClient();
{
@@ -414,7 +500,7 @@ public void testAuthenticate() throws Exception {
//end::authenticate-response
assertThat(user.getUsername(), is("test_user"));
- assertThat(user.getRoles(), contains(new String[] {"superuser"}));
+ assertThat(user.getRoles(), contains(new String[]{"superuser"}));
assertThat(user.getFullName(), nullValue());
assertThat(user.getEmail(), nullValue());
assertThat(user.getMetadata().isEmpty(), is(true));
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/security/GetRolesRequestTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/security/GetRolesRequestTests.java
new file mode 100644
index 0000000000000..4bf970d096bcf
--- /dev/null
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/security/GetRolesRequestTests.java
@@ -0,0 +1,52 @@
+/*
+ * 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.containsInAnyOrder;
+import static org.hamcrest.Matchers.equalTo;
+
+public class GetRolesRequestTests extends ESTestCase {
+
+ public void testGetRolesRequest() {
+ final String[] roles = randomArray(0, 5, String[]::new, () -> randomAlphaOfLength(5));
+ final GetRolesRequest getRolesRequest = new GetRolesRequest(roles);
+ assertThat(getRolesRequest.getRoleNames().size(), equalTo(roles.length));
+ assertThat(getRolesRequest.getRoleNames(), containsInAnyOrder(roles));
+ }
+
+ public void testEqualsHashCode() {
+ final String[] roles = randomArray(0, 5, String[]::new, () -> randomAlphaOfLength(5));
+ final GetRolesRequest getRolesRequest = new GetRolesRequest(roles);
+ assertNotNull(getRolesRequest);
+ EqualsHashCodeTestUtils.checkEqualsAndHashCode(getRolesRequest, (original) -> {
+ return new GetRolesRequest(original.getRoleNames().toArray(new String[0]));
+ });
+ EqualsHashCodeTestUtils.checkEqualsAndHashCode(getRolesRequest, (original) -> {
+ return new GetRolesRequest(original.getRoleNames().toArray(new String[0]));
+ }, GetRolesRequestTests::mutateTestItem);
+ }
+
+ private static GetRolesRequest mutateTestItem(GetRolesRequest original) {
+ return new GetRolesRequest(randomArray(0, 5, String[]::new, () -> randomAlphaOfLength(5)));
+ }
+}
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/security/GetRolesResponseTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/security/GetRolesResponseTests.java
new file mode 100644
index 0000000000000..41de52a8cef75
--- /dev/null
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/security/GetRolesResponseTests.java
@@ -0,0 +1,199 @@
+/*
+ * 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.IndicesPrivileges;
+import org.elasticsearch.client.security.user.privileges.Role;
+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.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import static org.hamcrest.Matchers.equalTo;
+
+public class GetRolesResponseTests extends ESTestCase {
+
+ public void testFromXContent() throws IOException {
+ String json =
+ "{\n" +
+ " \"my_admin_role\": {\n" +
+ " \"cluster\" : [ \"all\" ],\n" +
+ " \"indices\" : [\n" +
+ " {\n" +
+ " \"names\" : [ \"index1\", \"index2\" ],\n" +
+ " \"privileges\" : [ \"all\" ],\n" +
+ " \"field_security\" : {\n" +
+ " \"grant\" : [ \"title\", \"body\" ]}\n" +
+ " }\n" +
+ " ],\n" +
+ " \"applications\" : [ ],\n" +
+ " \"run_as\" : [ \"other_user\" ],\n" +
+ " \"metadata\" : {\n" +
+ " \"version\" : 1\n" +
+ " },\n" +
+ " \"transient_metadata\" : {\n" +
+ " \"enabled\" : true\n" +
+ " }\n" +
+ " }\n" +
+ "}";
+ final GetRolesResponse response = GetRolesResponse.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)));
+ assertThat(response.getRoles().size(), equalTo(1));
+ final Role role = response.getRoles().get(0);
+ assertThat(role.getName(), equalTo("my_admin_role"));
+ assertThat(role.getClusterPrivileges().size(), equalTo(1));
+ IndicesPrivileges expectedIndicesPrivileges = new IndicesPrivileges.Builder()
+ .indices("index1", "index2")
+ .privileges("all")
+ .grantedFields("title", "body")
+ .build();
+ assertThat(role.getIndicesPrivileges().contains(expectedIndicesPrivileges), equalTo(true));
+ final Map expectedMetadata = new HashMap<>();
+ expectedMetadata.put("version", 1);
+ final Map expectedTransientMetadata = new HashMap<>();
+ expectedTransientMetadata.put("enabled", true);
+ final Role expectedRole = Role.builder()
+ .name("my_admin_role")
+ .clusterPrivileges("all")
+ .indicesPrivileges(expectedIndicesPrivileges)
+ .runAsPrivilege("other_user")
+ .metadata(expectedMetadata)
+ .transientMetadata(expectedTransientMetadata)
+ .build();
+ assertThat(role, equalTo(expectedRole));
+ }
+
+ public void testEqualsHashCode() {
+ final List roles = new ArrayList<>();
+ IndicesPrivileges indicesPrivileges = new IndicesPrivileges.Builder()
+ .indices("index1", "index2")
+ .privileges("write", "monitor", "delete")
+ .grantedFields("field1", "field2")
+ .deniedFields("field3", "field4")
+ .build();
+ Map metadata = new HashMap<>();
+ metadata.put("key", "value");
+ Map transientMetadata = new HashMap<>();
+ transientMetadata.put("transient_key", "transient_value");
+ final Role role = Role.builder()
+ .name("role_name")
+ .clusterPrivileges("monitor", "manage", "manage_saml")
+ .indicesPrivileges(indicesPrivileges)
+ .runAsPrivilege("run_as_user")
+ .metadata(metadata)
+ .transientMetadata(transientMetadata)
+ .build();
+ roles.add(role);
+ IndicesPrivileges indicesPrivileges2 = new IndicesPrivileges.Builder()
+ .indices("other_index1", "other_index2")
+ .privileges("write", "monitor", "delete")
+ .grantedFields("other_field1", "other_field2")
+ .deniedFields("other_field3", "other_field4")
+ .build();
+ Map metadata2 = new HashMap<>();
+ metadata.put("other_key", "other_value");
+ Map transientMetadata2 = new HashMap<>();
+ transientMetadata2.put("other_transient_key", "other_transient_value");
+ final Role role2 = Role.builder()
+ .name("role2_name")
+ .clusterPrivileges("monitor", "manage", "manage_saml")
+ .indicesPrivileges(indicesPrivileges2)
+ .runAsPrivilege("other_run_as_user")
+ .metadata(metadata2)
+ .transientMetadata(transientMetadata2)
+ .build();
+ roles.add(role2);
+ final GetRolesResponse getRolesResponse = new GetRolesResponse(roles);
+ assertNotNull(getRolesResponse);
+ EqualsHashCodeTestUtils.checkEqualsAndHashCode(getRolesResponse, (original) -> {
+ return new GetRolesResponse(original.getRoles());
+ });
+ EqualsHashCodeTestUtils.checkEqualsAndHashCode(getRolesResponse, (original) -> {
+ return new GetRolesResponse(original.getRoles());
+ }, GetRolesResponseTests::mutateTestItem);
+
+ }
+
+ private static GetRolesResponse mutateTestItem(GetRolesResponse original) {
+ if (randomBoolean()) {
+ final List roles = new ArrayList<>();
+ IndicesPrivileges indicesPrivileges = new IndicesPrivileges.Builder()
+ .indices("index1", "index2")
+ .privileges("write", "monitor", "delete")
+ .grantedFields("field1", "field2")
+ .deniedFields("field3", "field4")
+ .build();
+ Map metadata = new HashMap();
+ metadata.put("key", "value");
+ Map transientMetadata = new HashMap<>();
+ transientMetadata.put("transient_key", "transient_value");
+ final Role role = Role.builder()
+ .name("role_name")
+ .clusterPrivileges("monitor", "manage", "manage_saml")
+ .indicesPrivileges(indicesPrivileges)
+ .runAsPrivilege("run_as_user")
+ .metadata(metadata)
+ .transientMetadata(transientMetadata)
+ .build();
+ roles.add(role);
+ return new GetRolesResponse(roles);
+ } else {
+ IndicesPrivileges indicesPrivileges = new IndicesPrivileges.Builder()
+ .indices("index1_changed", "index2")
+ .privileges("write", "monitor", "delete")
+ .grantedFields("field1", "field2")
+ .deniedFields("field3", "field4")
+ .build();
+ Map metadata = new HashMap();
+ metadata.put("key", "value");
+ Map transientMetadata = new HashMap<>();
+ transientMetadata.put("transient_key", "transient_value");
+ final Role role = Role.builder()
+ .name("role_name")
+ .clusterPrivileges("monitor", "manage", "manage_saml")
+ .indicesPrivileges(indicesPrivileges)
+ .runAsPrivilege("run_as_user")
+ .metadata(metadata)
+ .transientMetadata(transientMetadata)
+ .build();
+ List newRoles = original.getRoles().stream().collect(Collectors.toList());
+ newRoles.remove(0);
+ newRoles.add(role);
+ return new GetRolesResponse(newRoles);
+ }
+ }
+}
diff --git a/docs/java-rest/high-level/security/get-roles.asciidoc b/docs/java-rest/high-level/security/get-roles.asciidoc
new file mode 100644
index 0000000000000..9ecf36353c3e8
--- /dev/null
+++ b/docs/java-rest/high-level/security/get-roles.asciidoc
@@ -0,0 +1,48 @@
+
+--
+:api: get-roles
+:request: GetRolesRequest
+:respnse: GetRolesResponse
+--
+
+[id="{upid}-{api}"]
+=== Get Roles API
+
+[id="{upid}-{api}-request"]
+==== Get Roles Request
+
+Retrieving a role can be performed using the `security().getRoles()`
+method and by setting the role name on +{request}+:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests-file}[{api}-request]
+--------------------------------------------------
+
+Retrieving multiple roles can be performed using the `security().getRoles()`
+method and by setting multiple role names on +{request}+:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests-file}[{api}-list-request]
+--------------------------------------------------
+
+Retrieving all roles can be performed using the `security().getRoles()`
+method without specifying any role names on +{request}+:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests-file}[{api}-all-request]
+--------------------------------------------------
+
+include::../execution.asciidoc[]
+
+[id="{upid}-{api}-response"]
+==== Get Roles Response
+
+The returned +{response}+ allows getting information about the retrieved roles 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 02158673da210..a7233dd9a7536 100644
--- a/docs/java-rest/high-level/supported-apis.asciidoc
+++ b/docs/java-rest/high-level/supported-apis.asciidoc
@@ -366,6 +366,7 @@ The Java High Level REST Client supports the following Security APIs:
* <>
* <>
* <>
+* <<{upid}-get-roles>>
* <>
* <<{upid}-clear-roles-cache>>
* <<{upid}-clear-realm-cache>>