From a5ee134c40dd01e2b07008e8ff0211bb76017d2e Mon Sep 17 00:00:00 2001
From: Yogesh Gaikwad <902768+bizybot@users.noreply.github.com>
Date: Mon, 29 Oct 2018 10:12:13 +1100
Subject: [PATCH] [HLRC] Add support for get role mappings API (#34637)
This commit adds support for get role mappings API
in HLRC.
---
.../elasticsearch/client/SecurityClient.java | 36 +++++
.../client/SecurityRequestConverters.java | 12 ++
.../security/ExpressionRoleMapping.java | 153 ++++++++++++++++++
.../security/GetRoleMappingsRequest.java | 68 ++++++++
.../security/GetRoleMappingsResponse.java | 70 ++++++++
.../parser/RoleMapperExpressionParser.java | 12 ++
.../SecurityRequestConvertersTests.java | 22 +++
.../SecurityDocumentationIT.java | 122 ++++++++++++++
.../security/ExpressionRoleMappingTests.java | 108 +++++++++++++
.../security/GetRoleMappingsRequestTests.java | 55 +++++++
.../GetRoleMappingsResponseTests.java | 118 ++++++++++++++
.../security/get-role-mappings.asciidoc | 67 ++++++++
.../high-level/supported-apis.asciidoc | 2 +
13 files changed, 845 insertions(+)
create mode 100644 client/rest-high-level/src/main/java/org/elasticsearch/client/security/ExpressionRoleMapping.java
create mode 100644 client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetRoleMappingsRequest.java
create mode 100644 client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetRoleMappingsResponse.java
create mode 100644 client/rest-high-level/src/test/java/org/elasticsearch/client/security/ExpressionRoleMappingTests.java
create mode 100644 client/rest-high-level/src/test/java/org/elasticsearch/client/security/GetRoleMappingsRequestTests.java
create mode 100644 client/rest-high-level/src/test/java/org/elasticsearch/client/security/GetRoleMappingsResponseTests.java
create mode 100644 docs/java-rest/high-level/security/get-role-mappings.asciidoc
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 e528116da6c..4b94b07c315 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
@@ -29,6 +29,8 @@ import org.elasticsearch.client.security.PutRoleMappingResponse;
import org.elasticsearch.client.security.DisableUserRequest;
import org.elasticsearch.client.security.EmptyResponse;
import org.elasticsearch.client.security.EnableUserRequest;
+import org.elasticsearch.client.security.GetRoleMappingsRequest;
+import org.elasticsearch.client.security.GetRoleMappingsResponse;
import org.elasticsearch.client.security.GetSslCertificatesRequest;
import org.elasticsearch.client.security.GetSslCertificatesResponse;
import org.elasticsearch.client.security.PutUserRequest;
@@ -112,6 +114,40 @@ public final class SecurityClient {
PutRoleMappingResponse::fromXContent, listener, emptySet());
}
+ /**
+ * Synchronously get role mapping(s).
+ * See
+ * the docs for more.
+ *
+ * @param request {@link GetRoleMappingsRequest} with role mapping name(s).
+ * If no role mapping name is provided then retrieves all role mappings.
+ * @param options the request options (e.g. headers), use
+ * {@link RequestOptions#DEFAULT} if nothing needs to be customized
+ * @return the response from the get role mapping call
+ * @throws IOException in case there is a problem sending the request or
+ * parsing back the response
+ */
+ public GetRoleMappingsResponse getRoleMappings(final GetRoleMappingsRequest request, final RequestOptions options) throws IOException {
+ return restHighLevelClient.performRequestAndParseEntity(request, SecurityRequestConverters::getRoleMappings,
+ options, GetRoleMappingsResponse::fromXContent, emptySet());
+ }
+
+ /**
+ * Asynchronously get role mapping(s).
+ * See
+ * the docs for more.
+ *
+ * @param request {@link GetRoleMappingsRequest} with role mapping name(s).
+ * If no role mapping name is provided then retrieves all role mappings.
+ * @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 getRoleMappingsAsync(final GetRoleMappingsRequest request, final RequestOptions options,
+ final ActionListener listener) {
+ restHighLevelClient.performRequestAsyncAndParseEntity(request, SecurityRequestConverters::getRoleMappings,
+ options, GetRoleMappingsResponse::fromXContent, listener, emptySet());
+ }
+
/**
* Enable a native realm or built-in user synchronously.
* 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 e3acda9313a..eb727e13612 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
@@ -19,6 +19,7 @@
package org.elasticsearch.client;
+import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
@@ -28,9 +29,11 @@ import org.elasticsearch.client.security.DeleteRoleRequest;
import org.elasticsearch.client.security.PutRoleMappingRequest;
import org.elasticsearch.client.security.DisableUserRequest;
import org.elasticsearch.client.security.EnableUserRequest;
+import org.elasticsearch.client.security.GetRoleMappingsRequest;
import org.elasticsearch.client.security.ChangePasswordRequest;
import org.elasticsearch.client.security.PutUserRequest;
import org.elasticsearch.client.security.SetUserEnabledRequest;
+import org.elasticsearch.common.Strings;
import java.io.IOException;
@@ -78,6 +81,15 @@ final class SecurityRequestConverters {
return request;
}
+ static Request getRoleMappings(final GetRoleMappingsRequest getRoleMappingRequest) throws IOException {
+ RequestConverters.EndpointBuilder builder = new RequestConverters.EndpointBuilder();
+ builder.addPathPartAsIs("_xpack/security/role_mapping");
+ if (getRoleMappingRequest.getRoleMappingNames().size() > 0) {
+ builder.addPathPart(Strings.collectionToCommaDelimitedString(getRoleMappingRequest.getRoleMappingNames()));
+ }
+ return new Request(HttpGet.METHOD_NAME, builder.build());
+ }
+
static Request enableUser(EnableUserRequest enableUserRequest) {
return setUserEnabled(enableUserRequest);
}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/security/ExpressionRoleMapping.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/ExpressionRoleMapping.java
new file mode 100644
index 00000000000..9cb78dd9c83
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/ExpressionRoleMapping.java
@@ -0,0 +1,153 @@
+/*
+ * 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.support.expressiondsl.RoleMapperExpression;
+import org.elasticsearch.client.security.support.expressiondsl.parser.RoleMapperExpressionParser;
+import org.elasticsearch.common.ParseField;
+import org.elasticsearch.common.xcontent.ConstructingObjectParser;
+import org.elasticsearch.common.xcontent.ObjectParser;
+import org.elasticsearch.common.xcontent.XContentParser;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
+
+/**
+ * A representation of a single role-mapping.
+ *
+ * @see RoleMapperExpression
+ * @see RoleMapperExpressionParser
+ */
+public final class ExpressionRoleMapping {
+
+ @SuppressWarnings("unchecked")
+ static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>("role-mapping", true,
+ (args, name) -> new ExpressionRoleMapping(name, (RoleMapperExpression) args[0], (List) args[1],
+ (Map) args[2], (boolean) args[3]));
+
+ static {
+ PARSER.declareField(constructorArg(), (parser, context) -> RoleMapperExpressionParser.fromXContent(parser), Fields.RULES,
+ ObjectParser.ValueType.OBJECT);
+ PARSER.declareStringArray(constructorArg(), Fields.ROLES);
+ PARSER.declareField(constructorArg(), XContentParser::map, Fields.METADATA, ObjectParser.ValueType.OBJECT);
+ PARSER.declareBoolean(constructorArg(), Fields.ENABLED);
+ }
+
+ private final String name;
+ private final RoleMapperExpression expression;
+ private final List roles;
+ private final Map metadata;
+ private final boolean enabled;
+
+ /**
+ * Constructor for role mapping
+ *
+ * @param name role mapping name
+ * @param expr {@link RoleMapperExpression} Expression used for role mapping
+ * @param roles list of roles to be associated with the user
+ * @param metadata metadata that helps to identify which roles are assigned
+ * to the user
+ * @param enabled a flag when {@code true} signifies the role mapping is active
+ */
+ public ExpressionRoleMapping(final String name, final RoleMapperExpression expr, final List roles,
+ final Map metadata, boolean enabled) {
+ this.name = name;
+ this.expression = expr;
+ this.roles = Collections.unmodifiableList(roles);
+ this.metadata = (metadata == null) ? Collections.emptyMap() : Collections.unmodifiableMap(metadata);
+ this.enabled = enabled;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public RoleMapperExpression getExpression() {
+ return expression;
+ }
+
+ public List getRoles() {
+ return roles;
+ }
+
+ public Map getMetadata() {
+ return metadata;
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + (enabled ? 1231 : 1237);
+ result = prime * result + ((expression == null) ? 0 : expression.hashCode());
+ result = prime * result + ((metadata == null) ? 0 : metadata.hashCode());
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ result = prime * result + ((roles == null) ? 0 : roles.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final ExpressionRoleMapping other = (ExpressionRoleMapping) obj;
+ if (enabled != other.enabled)
+ return false;
+ if (expression == null) {
+ if (other.expression != null)
+ return false;
+ } else if (!expression.equals(other.expression))
+ return false;
+ if (metadata == null) {
+ if (other.metadata != null)
+ return false;
+ } else if (!metadata.equals(other.metadata))
+ return false;
+ if (name == null) {
+ if (other.name != null)
+ return false;
+ } else if (!name.equals(other.name))
+ return false;
+ if (roles == null) {
+ if (other.roles != null)
+ return false;
+ } else if (!roles.equals(other.roles))
+ return false;
+ return true;
+ }
+
+ public interface Fields {
+ ParseField ROLES = new ParseField("roles");
+ ParseField ENABLED = new ParseField("enabled");
+ ParseField RULES = new ParseField("rules");
+ ParseField METADATA = new ParseField("metadata");
+ }
+}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetRoleMappingsRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetRoleMappingsRequest.java
new file mode 100644
index 00000000000..ca9b85c724d
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetRoleMappingsRequest.java
@@ -0,0 +1,68 @@
+/*
+ * 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 get role mappings
+ */
+public final class GetRoleMappingsRequest implements Validatable {
+ private final Set roleMappingNames;
+
+ public GetRoleMappingsRequest(final String... roleMappingNames) {
+ if (roleMappingNames != null) {
+ this.roleMappingNames = Collections.unmodifiableSet(Sets.newHashSet(roleMappingNames));
+ } else {
+ this.roleMappingNames = Collections.emptySet();
+ }
+ }
+
+ public Set getRoleMappingNames() {
+ return roleMappingNames;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(roleMappingNames);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final GetRoleMappingsRequest other = (GetRoleMappingsRequest) obj;
+
+ return Objects.equals(roleMappingNames, other.roleMappingNames);
+ }
+
+}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetRoleMappingsResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetRoleMappingsResponse.java
new file mode 100644
index 00000000000..05e63cefbe5
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetRoleMappingsResponse.java
@@ -0,0 +1,70 @@
+/*
+ * 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.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;
+
+/**
+ * Get role mappings response
+ */
+public final class GetRoleMappingsResponse {
+
+ private final List mappings;
+
+ public GetRoleMappingsResponse(List mappings) {
+ this.mappings = Collections.unmodifiableList(mappings);
+ }
+
+ public List getMappings() {
+ return mappings;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ final GetRoleMappingsResponse that = (GetRoleMappingsResponse) o;
+ return this.mappings.equals(that.mappings);
+ }
+
+ @Override
+ public int hashCode() {
+ return mappings.hashCode();
+ }
+
+ public static GetRoleMappingsResponse fromXContent(XContentParser parser) throws IOException {
+ final List roleMappings = new ArrayList<>();
+
+ XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation);
+ XContentParser.Token token;
+ while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
+ XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser::getTokenLocation);
+ roleMappings.add(ExpressionRoleMapping.PARSER.parse(parser, parser.currentName()));
+ }
+
+ return new GetRoleMappingsResponse(roleMappings);
+ }
+}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/security/support/expressiondsl/parser/RoleMapperExpressionParser.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/support/expressiondsl/parser/RoleMapperExpressionParser.java
index 98de4f4c209..0f5aec7f596 100644
--- a/client/rest-high-level/src/main/java/org/elasticsearch/client/security/support/expressiondsl/parser/RoleMapperExpressionParser.java
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/support/expressiondsl/parser/RoleMapperExpressionParser.java
@@ -45,6 +45,18 @@ import java.util.List;
public final class RoleMapperExpressionParser {
public static final ParseField FIELD = new ParseField("field");
+ public static RoleMapperExpression fromXContent(final XContentParser parser) throws IOException {
+ return new RoleMapperExpressionParser().parse("rules", parser);
+ }
+
+ /**
+ * This function exists to be compatible with
+ * {@link org.elasticsearch.common.xcontent.ContextParser#parse(XContentParser, Object)}
+ */
+ public static RoleMapperExpression parseObject(XContentParser parser, String id) throws IOException {
+ return new RoleMapperExpressionParser().parse(id, parser);
+ }
+
/**
* @param name The name of the expression tree within its containing object.
* Used to provide descriptive error messages.
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 4267e238580..0cc283029e7 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
@@ -19,6 +19,7 @@
package org.elasticsearch.client;
+import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
@@ -26,6 +27,7 @@ import org.elasticsearch.client.security.DeleteRoleMappingRequest;
import org.elasticsearch.client.security.DeleteRoleRequest;
import org.elasticsearch.client.security.DisableUserRequest;
import org.elasticsearch.client.security.EnableUserRequest;
+import org.elasticsearch.client.security.GetRoleMappingsRequest;
import org.elasticsearch.client.security.ChangePasswordRequest;
import org.elasticsearch.client.security.PutRoleMappingRequest;
import org.elasticsearch.client.security.PutUserRequest;
@@ -33,6 +35,7 @@ import org.elasticsearch.client.security.RefreshPolicy;
import org.elasticsearch.client.security.support.expressiondsl.RoleMapperExpression;
import org.elasticsearch.client.security.support.expressiondsl.expressions.AnyRoleMapperExpression;
import org.elasticsearch.client.security.support.expressiondsl.fields.FieldRoleMapperExpression;
+import org.elasticsearch.common.Strings;
import org.elasticsearch.test.ESTestCase;
import java.io.IOException;
@@ -102,6 +105,25 @@ public class SecurityRequestConvertersTests extends ESTestCase {
assertToXContentBody(putRoleMappingRequest, request.getEntity());
}
+ public void testGetRoleMappings() throws IOException {
+ int noOfRoleMappingNames = randomIntBetween(0, 2);
+ final String[] roleMappingNames =
+ randomArray(noOfRoleMappingNames, noOfRoleMappingNames, String[]::new, () -> randomAlphaOfLength(5));
+ final GetRoleMappingsRequest getRoleMappingsRequest = new GetRoleMappingsRequest(roleMappingNames);
+
+ final Request request = SecurityRequestConverters.getRoleMappings(getRoleMappingsRequest);
+
+ assertEquals(HttpGet.METHOD_NAME, request.getMethod());
+ if (noOfRoleMappingNames == 0) {
+ assertEquals("/_xpack/security/role_mapping", request.getEndpoint());
+ } else {
+ assertEquals("/_xpack/security/role_mapping/" +
+ Strings.collectionToCommaDelimitedString(getRoleMappingsRequest.getRoleMappingNames()), request.getEndpoint());
+ }
+ assertEquals(Collections.emptyMap(), request.getParameters());
+ assertNull(request.getEntity());
+ }
+
public void testEnableUser() {
final String username = 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 96b4b311490..e003251f89b 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
@@ -38,6 +38,9 @@ import org.elasticsearch.client.security.DeleteRoleResponse;
import org.elasticsearch.client.security.DisableUserRequest;
import org.elasticsearch.client.security.EmptyResponse;
import org.elasticsearch.client.security.EnableUserRequest;
+import org.elasticsearch.client.security.ExpressionRoleMapping;
+import org.elasticsearch.client.security.GetRoleMappingsRequest;
+import org.elasticsearch.client.security.GetRoleMappingsResponse;
import org.elasticsearch.client.security.GetSslCertificatesResponse;
import org.elasticsearch.client.security.PutRoleMappingRequest;
import org.elasticsearch.client.security.PutRoleMappingResponse;
@@ -54,14 +57,20 @@ import org.hamcrest.Matchers;
import java.io.IOException;
import java.util.Collections;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.not;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.isIn;
public class SecurityDocumentationIT extends ESRestHighLevelClientTestCase {
@@ -165,6 +174,119 @@ public class SecurityDocumentationIT extends ESRestHighLevelClientTestCase {
}
}
+ public void testGetRoleMappings() throws Exception {
+ final RestHighLevelClient client = highLevelClient();
+
+ final RoleMapperExpression rules1 = AnyRoleMapperExpression.builder().addExpression(FieldRoleMapperExpression.ofUsername("*"))
+ .addExpression(FieldRoleMapperExpression.ofGroups("cn=admins,dc=example,dc=com")).build();
+ final PutRoleMappingRequest putRoleMappingRequest1 = new PutRoleMappingRequest("mapping-example-1", true, Collections.singletonList(
+ "superuser"), rules1, null, RefreshPolicy.NONE);
+ final PutRoleMappingResponse putRoleMappingResponse1 = client.security().putRoleMapping(putRoleMappingRequest1,
+ RequestOptions.DEFAULT);
+ boolean isCreated1 = putRoleMappingResponse1.isCreated();
+ assertTrue(isCreated1);
+ final RoleMapperExpression rules2 = AnyRoleMapperExpression.builder().addExpression(FieldRoleMapperExpression.ofGroups(
+ "cn=admins,dc=example,dc=com")).build();
+ final Map metadata2 = new HashMap<>();
+ metadata2.put("k1", "v1");
+ final PutRoleMappingRequest putRoleMappingRequest2 = new PutRoleMappingRequest("mapping-example-2", true, Collections.singletonList(
+ "monitoring"), rules2, metadata2, RefreshPolicy.NONE);
+ final PutRoleMappingResponse putRoleMappingResponse2 = client.security().putRoleMapping(putRoleMappingRequest2,
+ RequestOptions.DEFAULT);
+ boolean isCreated2 = putRoleMappingResponse2.isCreated();
+ assertTrue(isCreated2);
+
+ {
+ // tag::get-role-mappings-execute
+ final GetRoleMappingsRequest request = new GetRoleMappingsRequest("mapping-example-1");
+ final GetRoleMappingsResponse response = client.security().getRoleMappings(request, RequestOptions.DEFAULT);
+ // end::get-role-mappings-execute
+ // tag::get-role-mappings-response
+ List mappings = response.getMappings();
+ // end::get-role-mappings-response
+ assertNotNull(mappings);
+ assertThat(mappings.size(), is(1));
+ assertThat(mappings.get(0).isEnabled(), is(true));
+ assertThat(mappings.get(0).getName(), is("mapping-example-1"));
+ assertThat(mappings.get(0).getExpression(), equalTo(rules1));
+ assertThat(mappings.get(0).getMetadata(), equalTo(Collections.emptyMap()));
+ assertThat(mappings.get(0).getRoles(), contains("superuser"));
+ }
+
+ {
+ // tag::get-role-mappings-list-execute
+ final GetRoleMappingsRequest request = new GetRoleMappingsRequest("mapping-example-1", "mapping-example-2");
+ final GetRoleMappingsResponse response = client.security().getRoleMappings(request, RequestOptions.DEFAULT);
+ // end::get-role-mappings-all-execute
+ List mappings = response.getMappings();
+ assertNotNull(mappings);
+ assertThat(mappings.size(), is(2));
+ for (ExpressionRoleMapping roleMapping : mappings) {
+ assertThat(roleMapping.isEnabled(), is(true));
+ assertThat(roleMapping.getName(), isIn(new String[] { "mapping-example-1", "mapping-example-2" }));
+ if (roleMapping.getName().equals("mapping-example-1")) {
+ assertThat(roleMapping.getMetadata(), equalTo(Collections.emptyMap()));
+ assertThat(roleMapping.getExpression(), equalTo(rules1));
+ assertThat(roleMapping.getRoles(), contains("superuser"));
+ } else {
+ assertThat(roleMapping.getMetadata(), equalTo(metadata2));
+ assertThat(roleMapping.getExpression(), equalTo(rules2));
+ assertThat(roleMapping.getRoles(), contains("monitoring"));
+ }
+ }
+ }
+
+ {
+ // tag::get-role-mappings-all-execute
+ final GetRoleMappingsRequest request = new GetRoleMappingsRequest();
+ final GetRoleMappingsResponse response = client.security().getRoleMappings(request, RequestOptions.DEFAULT);
+ // end::get-role-mappings-all-execute
+ List mappings = response.getMappings();
+ assertNotNull(mappings);
+ assertThat(mappings.size(), is(2));
+ for (ExpressionRoleMapping roleMapping : mappings) {
+ assertThat(roleMapping.isEnabled(), is(true));
+ assertThat(roleMapping.getName(), isIn(new String[] { "mapping-example-1", "mapping-example-2" }));
+ if (roleMapping.getName().equals("mapping-example-1")) {
+ assertThat(roleMapping.getMetadata(), equalTo(Collections.emptyMap()));
+ assertThat(roleMapping.getExpression(), equalTo(rules1));
+ assertThat(roleMapping.getRoles(), contains("superuser"));
+ } else {
+ assertThat(roleMapping.getMetadata(), equalTo(metadata2));
+ assertThat(roleMapping.getExpression(), equalTo(rules2));
+ assertThat(roleMapping.getRoles(), contains("monitoring"));
+ }
+ }
+ }
+
+ {
+ final GetRoleMappingsRequest request = new GetRoleMappingsRequest();
+ // tag::get-role-mappings-execute-listener
+ ActionListener listener = new ActionListener() {
+ @Override
+ public void onResponse(GetRoleMappingsResponse response) {
+ // <1>
+ }
+
+ @Override
+ public void onFailure(Exception e) {
+ // <2>
+ }
+ };
+ // end::get-role-mappings-execute-listener
+
+ // Replace the empty listener by a blocking listener in test
+ final CountDownLatch latch = new CountDownLatch(1);
+ listener = new LatchedActionListener<>(listener, latch);
+
+ // tag::get-role-mappings-execute-async
+ client.security().getRoleMappingsAsync(request, RequestOptions.DEFAULT, listener); // <1>
+ // end::get-role-mappings-execute-async
+
+ assertTrue(latch.await(30L, TimeUnit.SECONDS));
+ }
+ }
+
public void testEnableUser() throws Exception {
RestHighLevelClient client = highLevelClient();
char[] password = new char[]{'p', 'a', 's', 's', 'w', 'o', 'r', 'd'};
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/security/ExpressionRoleMappingTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/security/ExpressionRoleMappingTests.java
new file mode 100644
index 00000000000..29bc7812f5b
--- /dev/null
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/security/ExpressionRoleMappingTests.java
@@ -0,0 +1,108 @@
+/*
+ * 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.support.expressiondsl.fields.FieldRoleMapperExpression;
+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.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.hamcrest.Matchers.equalTo;
+
+public class ExpressionRoleMappingTests extends ESTestCase {
+
+ public void testExpressionRoleMappingParser() throws IOException {
+ final String json =
+ "{\n" +
+ " \"enabled\" : true,\n" +
+ " \"roles\" : [\n" +
+ " \"superuser\"\n" +
+ " ],\n" +
+ " \"rules\" : {\n" +
+ " \"field\" : {\n" +
+ " \"realm.name\" : \"kerb1\"\n" +
+ " }\n" +
+ " },\n" +
+ " \"metadata\" : { }\n" +
+ " }";
+ final ExpressionRoleMapping expressionRoleMapping = ExpressionRoleMapping.PARSER.parse(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), "example-role-mapping");
+ final ExpressionRoleMapping expectedRoleMapping = new ExpressionRoleMapping("example-role-mapping", FieldRoleMapperExpression
+ .ofKeyValues("realm.name", "kerb1"), Collections.singletonList("superuser"), null, true);
+ assertThat(expressionRoleMapping, equalTo(expectedRoleMapping));
+ }
+
+ public void testEqualsHashCode() {
+ final ExpressionRoleMapping expressionRoleMapping = new ExpressionRoleMapping("kerberosmapping", FieldRoleMapperExpression
+ .ofKeyValues("realm.name", "kerb1"), Collections.singletonList("superuser"), null, true);
+ EqualsHashCodeTestUtils.checkEqualsAndHashCode(expressionRoleMapping, (original) -> {
+ return new ExpressionRoleMapping(original.getName(), original.getExpression(), original.getRoles(), original.getMetadata(),
+ original.isEnabled());
+ });
+ EqualsHashCodeTestUtils.checkEqualsAndHashCode(expressionRoleMapping, (original) -> {
+ return new ExpressionRoleMapping(original.getName(), original.getExpression(), original.getRoles(), original.getMetadata(),
+ original.isEnabled());
+ }, ExpressionRoleMappingTests::mutateTestItem);
+ }
+
+ private static ExpressionRoleMapping mutateTestItem(ExpressionRoleMapping original) {
+ ExpressionRoleMapping mutated = null;
+ switch (randomIntBetween(0, 4)) {
+ case 0:
+ mutated = new ExpressionRoleMapping("namechanged", FieldRoleMapperExpression.ofKeyValues("realm.name", "kerb1"), Collections
+ .singletonList("superuser"), null, true);
+ break;
+ case 1:
+ mutated = new ExpressionRoleMapping("kerberosmapping", FieldRoleMapperExpression.ofKeyValues("changed", "changed"), Collections
+ .singletonList("superuser"), null, true);
+ break;
+ case 2:
+ mutated = new ExpressionRoleMapping("kerberosmapping", FieldRoleMapperExpression.ofKeyValues("realm.name", "kerb1"), Collections
+ .singletonList("changed"), null, true);
+ break;
+ case 3:
+ Map metadata = new HashMap<>();
+ metadata.put("a", "b");
+ mutated = new ExpressionRoleMapping("kerberosmapping", FieldRoleMapperExpression.ofKeyValues("realm.name", "kerb1"), Collections
+ .singletonList("superuser"), metadata, true);
+ break;
+ case 4:
+ mutated = new ExpressionRoleMapping("kerberosmapping", FieldRoleMapperExpression.ofKeyValues("realm.name", "kerb1"), Collections
+ .singletonList("superuser"), null, false);
+ break;
+ }
+ return mutated;
+ }
+}
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/security/GetRoleMappingsRequestTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/security/GetRoleMappingsRequestTests.java
new file mode 100644
index 00000000000..8acd8ba17de
--- /dev/null
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/security/GetRoleMappingsRequestTests.java
@@ -0,0 +1,55 @@
+/*
+ * 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.is;
+
+public class GetRoleMappingsRequestTests extends ESTestCase {
+
+ public void testGetRoleMappingsRequest() {
+ int noOfRoleMappingNames = randomIntBetween(0, 2);
+ final String[] roleMappingNames = randomArray(noOfRoleMappingNames, noOfRoleMappingNames, String[]::new, () -> randomAlphaOfLength(
+ 5));
+ final GetRoleMappingsRequest getRoleMappingsRequest = new GetRoleMappingsRequest(roleMappingNames);
+ assertThat(getRoleMappingsRequest.getRoleMappingNames().size(), is(noOfRoleMappingNames));
+ assertThat(getRoleMappingsRequest.getRoleMappingNames(), containsInAnyOrder(roleMappingNames));
+ }
+
+ public void testEqualsHashCode() {
+ int noOfRoleMappingNames = randomIntBetween(0, 2);
+ final String[] roleMappingNames = randomArray(noOfRoleMappingNames, String[]::new, () -> randomAlphaOfLength(5));
+ final GetRoleMappingsRequest getRoleMappingsRequest = new GetRoleMappingsRequest(roleMappingNames);
+ assertNotNull(getRoleMappingsRequest);
+ EqualsHashCodeTestUtils.checkEqualsAndHashCode(getRoleMappingsRequest, (original) -> {
+ return new GetRoleMappingsRequest(original.getRoleMappingNames().toArray(new String[0]));
+ });
+ EqualsHashCodeTestUtils.checkEqualsAndHashCode(getRoleMappingsRequest, (original) -> {
+ return new GetRoleMappingsRequest(original.getRoleMappingNames().toArray(new String[0]));
+ }, GetRoleMappingsRequestTests::mutateTestItem);
+ }
+
+ private static GetRoleMappingsRequest mutateTestItem(GetRoleMappingsRequest original) {
+ return new GetRoleMappingsRequest(randomAlphaOfLength(8));
+ }
+}
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/security/GetRoleMappingsResponseTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/security/GetRoleMappingsResponseTests.java
new file mode 100644
index 00000000000..b612c9ead28
--- /dev/null
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/security/GetRoleMappingsResponseTests.java
@@ -0,0 +1,118 @@
+/*
+ * 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.support.expressiondsl.fields.FieldRoleMapperExpression;
+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.List;
+
+import static org.hamcrest.Matchers.equalTo;
+
+public class GetRoleMappingsResponseTests extends ESTestCase {
+
+ public void testFromXContent() throws IOException {
+ final String json = "{\n" +
+ " \"kerberosmapping\" : {\n" +
+ " \"enabled\" : true,\n" +
+ " \"roles\" : [\n" +
+ " \"superuser\"\n" +
+ " ],\n" +
+ " \"rules\" : {\n" +
+ " \"field\" : {\n" +
+ " \"realm.name\" : \"kerb1\"\n" +
+ " }\n" +
+ " },\n" +
+ " \"metadata\" : { }\n" +
+ " },\n" +
+ " \"ldapmapping\" : {\n" +
+ " \"enabled\" : false,\n" +
+ " \"roles\" : [\n" +
+ " \"monitoring\"\n" +
+ " ],\n" +
+ " \"rules\" : {\n" +
+ " \"field\" : {\n" +
+ " \"groups\" : \"cn=ipausers,cn=groups,cn=accounts,dc=ipademo,dc=local\"\n" +
+ " }\n" +
+ " },\n" +
+ " \"metadata\" : { }\n" +
+ " }\n" +
+ "}";
+ final GetRoleMappingsResponse response = GetRoleMappingsResponse.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 List expectedRoleMappingsList = new ArrayList<>();
+ expectedRoleMappingsList.add(new ExpressionRoleMapping("kerberosmapping", FieldRoleMapperExpression.ofKeyValues("realm.name",
+ "kerb1"), Collections.singletonList("superuser"), null, true));
+ expectedRoleMappingsList.add(new ExpressionRoleMapping("ldapmapping", FieldRoleMapperExpression.ofGroups(
+ "cn=ipausers,cn=groups,cn=accounts,dc=ipademo,dc=local"), Collections.singletonList("monitoring"), null, false));
+ final GetRoleMappingsResponse expectedResponse = new GetRoleMappingsResponse(expectedRoleMappingsList);
+ assertThat(response, equalTo(expectedResponse));
+ }
+
+ public void testEqualsHashCode() {
+ final List roleMappingsList = new ArrayList<>();
+ roleMappingsList.add(new ExpressionRoleMapping("kerberosmapping", FieldRoleMapperExpression.ofKeyValues("realm.name",
+ "kerb1"), Collections.singletonList("superuser"), null, true));
+ final GetRoleMappingsResponse response = new GetRoleMappingsResponse(roleMappingsList);
+ assertNotNull(response);
+ EqualsHashCodeTestUtils.checkEqualsAndHashCode(response, (original) -> {
+ return new GetRoleMappingsResponse(original.getMappings());
+ });
+ EqualsHashCodeTestUtils.checkEqualsAndHashCode(response, (original) -> {
+ return new GetRoleMappingsResponse(original.getMappings());
+ }, GetRoleMappingsResponseTests::mutateTestItem);
+ }
+
+ private static GetRoleMappingsResponse mutateTestItem(GetRoleMappingsResponse original) {
+ GetRoleMappingsResponse mutated = null;
+ switch(randomIntBetween(0, 1)) {
+ case 0:
+ final List roleMappingsList1 = new ArrayList<>();
+ roleMappingsList1.add(new ExpressionRoleMapping("ldapmapping", FieldRoleMapperExpression.ofGroups(
+ "cn=ipausers,cn=groups,cn=accounts,dc=ipademo,dc=local"), Collections.singletonList("monitoring"), null, false));
+ mutated = new GetRoleMappingsResponse(roleMappingsList1);
+ break;
+ case 1:
+ final List roleMappingsList2 = new ArrayList<>();
+ ExpressionRoleMapping orginialRoleMapping = original.getMappings().get(0);
+ roleMappingsList2.add(new ExpressionRoleMapping(orginialRoleMapping.getName(), FieldRoleMapperExpression.ofGroups(
+ "cn=ipausers,cn=groups,cn=accounts,dc=ipademo,dc=local"),
+ orginialRoleMapping.getRoles(), orginialRoleMapping.getMetadata(), !orginialRoleMapping.isEnabled()));
+ mutated = new GetRoleMappingsResponse(roleMappingsList2);
+ break;
+ }
+ return mutated;
+ }
+}
diff --git a/docs/java-rest/high-level/security/get-role-mappings.asciidoc b/docs/java-rest/high-level/security/get-role-mappings.asciidoc
new file mode 100644
index 00000000000..cc58d0980c3
--- /dev/null
+++ b/docs/java-rest/high-level/security/get-role-mappings.asciidoc
@@ -0,0 +1,67 @@
+[[java-rest-high-security-get-role-mappings]]
+=== Get Role Mappings API
+
+[[java-rest-high-security-get-role-mappings-execution]]
+==== Execution
+
+Retrieving a role mapping can be performed using the `security().getRoleMappings()`
+method and by setting role mapping name on `GetRoleMappingsRequest`:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SecurityDocumentationIT.java[get-role-mappings-execute]
+--------------------------------------------------
+
+Retrieving multiple role mappings can be performed using the `security.getRoleMappings()`
+method and by setting role mapping names on `GetRoleMappingsRequest`:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SecurityDocumentationIT.java[get-role-mappings-list-execute]
+--------------------------------------------------
+
+Retrieving all role mappings can be performed using the `security.getRoleMappings()`
+method and with no role mapping name on `GetRoleMappingsRequest`:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SecurityDocumentationIT.java[get-role-mappings-all-execute]
+--------------------------------------------------
+
+[[java-rest-high-security-get-role-mappings-response]]
+==== Response
+
+The returned `GetRoleMappingsResponse` contains the list of role mapping(s).
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SecurityDocumentationIT.java[get-role-mappings-response]
+--------------------------------------------------
+
+[[java-rest-high-security-get-role-mappings-async]]
+==== Asynchronous Execution
+
+This request can be executed asynchronously using the `security().getRoleMappingsAsync()`
+method:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SecurityDocumentationIT.java[get-role-mappings-execute-async]
+--------------------------------------------------
+<1> The `GetRoleMappingsRequest` to execute and the `ActionListener` to use when
+the execution completes
+
+The asynchronous method does not block and returns immediately. Once the request
+has completed the `ActionListener` is called back using the `onResponse` method
+if the execution successfully completed or using the `onFailure` method if
+it failed.
+
+A typical listener for a `GetRoleMappingsResponse` looks like:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/SecurityDocumentationIT.java[get-role-mappings-execute-listener]
+--------------------------------------------------
+<1> Called when the execution is successfully completed. The response is
+provided as an argument
+<2> Called in case of failure. The raised exception is provided as an argument
\ 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 6e233bec181..5eb68701059 100644
--- a/docs/java-rest/high-level/supported-apis.asciidoc
+++ b/docs/java-rest/high-level/supported-apis.asciidoc
@@ -327,6 +327,7 @@ The Java High Level REST Client supports the following Security APIs:
* <<{upid}-clear-roles-cache>>
* <>
* <>
+* <>
* <>
include::security/put-user.asciidoc[]
@@ -337,6 +338,7 @@ include::security/delete-role.asciidoc[]
include::security/clear-roles-cache.asciidoc[]
include::security/get-certificates.asciidoc[]
include::security/put-role-mapping.asciidoc[]
+include::security/get-role-mapping.asciidoc[]
include::security/delete-role-mapping.asciidoc[]
== Watcher APIs