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 d02c15b59706f..48a1cdb778243 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
@@ -50,6 +50,8 @@
import org.elasticsearch.client.security.GetSslCertificatesResponse;
import org.elasticsearch.client.security.GetUserPrivilegesRequest;
import org.elasticsearch.client.security.GetUserPrivilegesResponse;
+import org.elasticsearch.client.security.GetUsersRequest;
+import org.elasticsearch.client.security.GetUsersResponse;
import org.elasticsearch.client.security.HasPrivilegesRequest;
import org.elasticsearch.client.security.HasPrivilegesResponse;
import org.elasticsearch.client.security.InvalidateTokenRequest;
@@ -81,6 +83,33 @@ public final class SecurityClient {
this.restHighLevelClient = restHighLevelClient;
}
+ /**
+ * Get a user, or list of users, in the native realm synchronously.
+ * See
+ * the docs for more information.
+ * @param request the request with the user's name
+ * @param options the request options (e.g., headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
+ * @return the response from the get users call
+ * @throws IOException in case there is a problem sending the request or parsing back the response
+ */
+ public GetUsersResponse getUsers(GetUsersRequest request, RequestOptions options) throws IOException {
+ return restHighLevelClient.performRequestAndParseEntity(request, SecurityRequestConverters::getUsers, options,
+ GetUsersResponse::fromXContent, emptySet());
+ }
+
+ /**
+ * Get a user, or list of users, in the native realm asynchronously.
+ * See
+ * the docs for more information.
+ * @param request the request with the user's name
+ * @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 getUsersAsync(GetUsersRequest request, RequestOptions options, ActionListener listener) {
+ restHighLevelClient.performRequestAsyncAndParseEntity(request, SecurityRequestConverters::getUsers, options,
+ GetUsersResponse::fromXContent, listener, emptySet());
+ }
+
/**
* Create/update a user in the native realm 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 aa09b9596a83f..9e9698ded1cd8 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
@@ -36,6 +36,7 @@
import org.elasticsearch.client.security.GetPrivilegesRequest;
import org.elasticsearch.client.security.GetRoleMappingsRequest;
import org.elasticsearch.client.security.GetRolesRequest;
+import org.elasticsearch.client.security.GetUsersRequest;
import org.elasticsearch.client.security.HasPrivilegesRequest;
import org.elasticsearch.client.security.InvalidateTokenRequest;
import org.elasticsearch.client.security.PutPrivilegesRequest;
@@ -67,6 +68,15 @@ static Request changePassword(ChangePasswordRequest changePasswordRequest) throw
return request;
}
+ static Request getUsers(GetUsersRequest getUsersRequest) {
+ RequestConverters.EndpointBuilder builder = new RequestConverters.EndpointBuilder()
+ .addPathPartAsIs("_security/user");
+ if (getUsersRequest.getUsernames().size() > 0) {
+ builder.addPathPart(Strings.collectionToCommaDelimitedString(getUsersRequest.getUsernames()));
+ }
+ return new Request(HttpGet.METHOD_NAME, builder.build());
+ }
+
static Request putUser(PutUserRequest putUserRequest) throws IOException {
String endpoint = new RequestConverters.EndpointBuilder()
.addPathPartAsIs("_security/user")
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetUsersRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetUsersRequest.java
new file mode 100644
index 0000000000000..0a6b5e9bb2578
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetUsersRequest.java
@@ -0,0 +1,58 @@
+/*
+ * 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 users from the native realm
+ */
+public class GetUsersRequest implements Validatable {
+ private final Set usernames;
+
+ public GetUsersRequest(final String... usernames) {
+ if (usernames != null) {
+ this.usernames = Collections.unmodifiableSet(Sets.newHashSet(usernames));
+ } else {
+ this.usernames = Collections.emptySet();
+ }
+ }
+
+ public Set getUsernames() {
+ return usernames;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof GetUsersRequest)) return false;
+ GetUsersRequest that = (GetUsersRequest) o;
+ return Objects.equals(usernames, that.usernames);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(usernames);
+ }
+}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetUsersResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetUsersResponse.java
new file mode 100644
index 0000000000000..107b93afe7ce4
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetUsersResponse.java
@@ -0,0 +1,134 @@
+/*
+ * 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.User;
+import org.elasticsearch.common.Nullable;
+import org.elasticsearch.common.ParseField;
+import org.elasticsearch.common.xcontent.ConstructingObjectParser;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.common.xcontent.XContentParser.Token;
+import org.elasticsearch.common.xcontent.XContentParserUtils;
+
+import java.io.IOException;
+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;
+
+/**
+ * Response when requesting zero or more users.
+ * Returns a List of {@link User} objects
+ */
+public class GetUsersResponse {
+ private final Set users;
+ private final Set enabledUsers;
+
+ public GetUsersResponse(Set users, Set enabledUsers) {
+ this.users = Collections.unmodifiableSet(users);
+ this.enabledUsers = Collections.unmodifiableSet(enabledUsers);
+ }
+
+ public Set getUsers() {
+ return users;
+ }
+
+ public Set getEnabledUsers() {
+ return enabledUsers;
+ }
+
+ public static GetUsersResponse fromXContent(XContentParser parser) throws IOException {
+ XContentParserUtils.ensureExpectedToken(Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation);
+ final Set users = new HashSet<>();
+ final Set enabledUsers = new HashSet<>();
+ Token token;
+ while ((token = parser.nextToken()) != Token.END_OBJECT) {
+ XContentParserUtils.ensureExpectedToken(Token.FIELD_NAME, token, parser::getTokenLocation);
+ ParsedUser parsedUser = USER_PARSER.parse(parser, parser.currentName());
+ users.add(parsedUser.user);
+ if (parsedUser.enabled) {
+ enabledUsers.add(parsedUser.user);
+ }
+ }
+ return new GetUsersResponse(users, enabledUsers);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof GetUsersResponse)) return false;
+ GetUsersResponse that = (GetUsersResponse) o;
+ return Objects.equals(users, that.users);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(users);
+ }
+
+ public static final ParseField USERNAME = new ParseField("username");
+ public static final ParseField ROLES = new ParseField("roles");
+ public static final ParseField FULL_NAME = new ParseField("full_name");
+ public static final ParseField EMAIL = new ParseField("email");
+ public static final ParseField METADATA = new ParseField("metadata");
+ public static final ParseField ENABLED = new ParseField("enabled");
+
+ @SuppressWarnings("unchecked")
+ public static final ConstructingObjectParser USER_PARSER = new ConstructingObjectParser<>("user_info",
+ (constructorObjects) -> {
+ int i = 0;
+ final String username = (String) constructorObjects[i++];
+ final Collection roles = (Collection) constructorObjects[i++];
+ final Map metadata = (Map) constructorObjects[i++];
+ final Boolean enabled = (Boolean) constructorObjects[i++];
+ final String fullName = (String) constructorObjects[i++];
+ final String email = (String) constructorObjects[i++];
+ return new ParsedUser(username, roles, metadata, enabled, fullName, email);
+ });
+
+ static {
+ USER_PARSER.declareString(constructorArg(), USERNAME);
+ USER_PARSER.declareStringArray(constructorArg(), ROLES);
+ USER_PARSER.declareObject(constructorArg(), (parser, c) -> parser.map(), METADATA);
+ USER_PARSER.declareBoolean(constructorArg(), ENABLED);
+ USER_PARSER.declareStringOrNull(optionalConstructorArg(), FULL_NAME);
+ USER_PARSER.declareStringOrNull(optionalConstructorArg(), EMAIL);
+ }
+
+ protected static final class ParsedUser {
+ protected User user;
+ protected boolean enabled;
+
+ public ParsedUser(String username, Collection roles, Map metadata, Boolean enabled,
+ @Nullable String fullName, @Nullable String email) {
+ String checkedUsername = username = Objects.requireNonNull(username, "`username` is required, cannot be null");
+ Collection checkedRoles = Collections.unmodifiableSet(new HashSet<>(
+ Objects.requireNonNull(roles, "`roles` is required, cannot be null. Pass an empty Collection instead.")));
+ Map checkedMetadata = Collections
+ .unmodifiableMap(Objects.requireNonNull(metadata, "`metadata` is required, cannot be null. Pass an empty map instead."));
+ this.user = new User(checkedUsername, checkedRoles, checkedMetadata, fullName, email);
+ this.enabled = enabled;
+ }
+ }
+}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/security/user/User.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/user/User.java
index ba6cd5f2f8ef5..4ac8f54c4741b 100644
--- a/client/rest-high-level/src/main/java/org/elasticsearch/client/security/user/User.java
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/user/User.java
@@ -29,7 +29,6 @@
import java.util.Objects;
import java.util.Set;
-
/**
* A user to be utilized with security APIs.
* Can be an existing authenticated user or it can be a new user to be enrolled to the native realm.
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/SecurityIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/SecurityIT.java
index 05a854299a6bb..abf65d19df3b7 100644
--- a/client/rest-high-level/src/test/java/org/elasticsearch/client/SecurityIT.java
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/SecurityIT.java
@@ -28,6 +28,8 @@
import org.elasticsearch.client.security.DeleteUserResponse;
import org.elasticsearch.client.security.GetRolesRequest;
import org.elasticsearch.client.security.GetRolesResponse;
+import org.elasticsearch.client.security.GetUsersRequest;
+import org.elasticsearch.client.security.GetUsersResponse;
import org.elasticsearch.client.security.PutRoleRequest;
import org.elasticsearch.client.security.PutRoleResponse;
import org.elasticsearch.client.security.PutUserRequest;
@@ -42,6 +44,7 @@
import org.elasticsearch.client.security.user.privileges.Role;
import org.elasticsearch.common.CharArrays;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashMap;
@@ -74,6 +77,22 @@ public void testPutUser() throws Exception {
highLevelClient().getLowLevelClient().performRequest(deleteUserRequest);
}
+ public void testGetUser() throws Exception {
+ final SecurityClient securityClient = highLevelClient().security();
+ // create user
+ final PutUserRequest putUserRequest = randomPutUserRequest(randomBoolean());
+ final PutUserResponse putUserResponse = execute(putUserRequest, securityClient::putUser, securityClient::putUserAsync);
+ // assert user created
+ assertThat(putUserResponse.isCreated(), is(true));
+ // get user
+ final GetUsersRequest getUsersRequest = new GetUsersRequest(putUserRequest.getUser().getUsername());
+ final GetUsersResponse getUsersResponse = execute(getUsersRequest, securityClient::getUsers, securityClient::getUsersAsync);
+ // assert user was correctly retrieved
+ ArrayList users = new ArrayList<>();
+ users.addAll(getUsersResponse.getUsers());
+ assertThat(users.get(0), is(putUserRequest.getUser()));
+ }
+
public void testAuthenticate() throws Exception {
final SecurityClient securityClient = highLevelClient().security();
// test fixture: put enabled user
@@ -89,6 +108,15 @@ public void testAuthenticate() throws Exception {
assertThat(authenticateResponse.getUser(), is(putUserRequest.getUser()));
assertThat(authenticateResponse.enabled(), is(true));
+ // get user
+ final GetUsersRequest getUsersRequest =
+ new GetUsersRequest(putUserRequest.getUser().getUsername());
+ final GetUsersResponse getUsersResponse =
+ execute(getUsersRequest, securityClient::getUsers, securityClient::getUsersAsync);
+ ArrayList users = new ArrayList<>();
+ users.addAll(getUsersResponse.getUsers());
+ assertThat(users.get(0), is(putUserRequest.getUser()));
+
// delete user
final DeleteUserRequest deleteUserRequest =
new DeleteUserRequest(putUserRequest.getUser().getUsername(), putUserRequest.getRefreshPolicy());
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 87c692d9f2a3b..900f4210a9952 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
@@ -34,6 +34,7 @@
import org.elasticsearch.client.security.GetPrivilegesRequest;
import org.elasticsearch.client.security.GetRoleMappingsRequest;
import org.elasticsearch.client.security.GetRolesRequest;
+import org.elasticsearch.client.security.GetUsersRequest;
import org.elasticsearch.client.security.PutPrivilegesRequest;
import org.elasticsearch.client.security.PutRoleMappingRequest;
import org.elasticsearch.client.security.PutRoleRequest;
@@ -101,6 +102,21 @@ public void testDeleteUser() {
assertNull(request.getEntity());
}
+ public void testGetUsers() {
+ final String[] users = randomArray(0, 5, String[]::new, () -> randomAlphaOfLength(5));
+ GetUsersRequest getUsersRequest = new GetUsersRequest(users);
+ Request request = SecurityRequestConverters.getUsers(getUsersRequest);
+ assertEquals(HttpGet.METHOD_NAME, request.getMethod());
+ if (users.length == 0) {
+ assertEquals("/_security/user", request.getEndpoint());
+ } else {
+ assertEquals("/_security/user/" + Strings.collectionToCommaDelimitedString(getUsersRequest.getUsernames()),
+ request.getEndpoint());
+ }
+ assertNull(request.getEntity());
+ assertEquals(Collections.emptyMap(), request.getParameters());
+ }
+
public void testPutRoleMapping() throws IOException {
final String username = randomAlphaOfLengthBetween(4, 7);
final String rolename = randomAlphaOfLengthBetween(4, 7);
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 7d0438238e50c..c225685ad646e 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
@@ -54,6 +54,8 @@
import org.elasticsearch.client.security.GetRolesResponse;
import org.elasticsearch.client.security.GetSslCertificatesResponse;
import org.elasticsearch.client.security.GetUserPrivilegesResponse;
+import org.elasticsearch.client.security.GetUsersRequest;
+import org.elasticsearch.client.security.GetUsersResponse;
import org.elasticsearch.client.security.HasPrivilegesRequest;
import org.elasticsearch.client.security.HasPrivilegesResponse;
import org.elasticsearch.client.security.InvalidateTokenRequest;
@@ -109,6 +111,96 @@
public class SecurityDocumentationIT extends ESRestHighLevelClientTestCase {
+ public void testGetUsers() throws Exception {
+ final RestHighLevelClient client = highLevelClient();
+ String[] usernames = new String[] {"user1", "user2", "user3"};
+ addUser(client, usernames[0], randomAlphaOfLength(4));
+ addUser(client, usernames[1], randomAlphaOfLength(4));
+ addUser(client, usernames[2], randomAlphaOfLength(4));
+ {
+ //tag::get-users-request
+ GetUsersRequest request = new GetUsersRequest(usernames[0]);
+ //end::get-users-request
+ //tag::get-users-execute
+ GetUsersResponse response = client.security().getUsers(request, RequestOptions.DEFAULT);
+ //end::get-users-execute
+ //tag::get-users-response
+ List users = new ArrayList<>(1);
+ users.addAll(response.getUsers());
+ //end::get-users-response
+
+ assertNotNull(response);
+ assertThat(users.size(), equalTo(1));
+ assertThat(users.get(0), is(usernames[0]));
+ }
+
+ {
+ //tag::get-users-list-request
+ GetUsersRequest request = new GetUsersRequest(usernames);
+ GetUsersResponse response = client.security().getUsers(request, RequestOptions.DEFAULT);
+ //end::get-users-list-request
+
+ List users = new ArrayList<>(3);
+ users.addAll(response.getUsers());
+ assertNotNull(response);
+ assertThat(users.size(), equalTo(3));
+ assertThat(users.get(0).getUsername(), equalTo(usernames[0]));
+ assertThat(users.get(1).getUsername(), equalTo(usernames[1]));
+ assertThat(users.get(2).getUsername(), equalTo(usernames[2]));
+ assertThat(users.size(), equalTo(3));
+ }
+
+ {
+ //tag::get-users-all-request
+ GetUsersRequest request = new GetUsersRequest();
+ GetUsersResponse response = client.security().getUsers(request, RequestOptions.DEFAULT);
+ //end::get-users-all-request
+
+ List users = new ArrayList<>(3);
+ users.addAll(response.getUsers());
+ assertNotNull(response);
+ // 4 system users plus the three we created
+ assertThat(users.size(), equalTo(7));
+ }
+
+ {
+ GetUsersRequest request = new GetUsersRequest(usernames[0]);
+ ActionListener listener;
+
+ //tag::get-roles-execute-listener
+ listener = new ActionListener() {
+ @Override
+ public void onResponse(GetUsersResponse getRolesResponse) {
+ // <1>
+ }
+
+ @Override
+ public void onFailure(Exception e) {
+ // <2>
+ }
+ };
+ //end::get-users-execute-listener
+
+ assertNotNull(listener);
+
+ // Replace the empty listener by a blocking listener in test
+ final PlainActionFuture future = new PlainActionFuture<>();
+ listener = future;
+
+ //tag::get-users-execute-async
+ client.security().getUsersAsync(request, RequestOptions.DEFAULT, listener); // <1>
+ //end::get-users-execute-async
+
+ final GetUsersResponse response = future.get(30, TimeUnit.SECONDS);
+ List users = new ArrayList<>(1);
+ users.addAll(response.getUsers());
+ assertNotNull(response);
+ assertThat(users.size(), equalTo(1));
+ assertThat(users.get(0).getUsername(), equalTo(usernames[0]));
+ }
+ }
+
+
public void testPutUser() throws Exception {
RestHighLevelClient client = highLevelClient();
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/security/AuthenticateResponseTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/security/AuthenticateResponseTests.java
index f09340fa09ffd..f59038af55af7 100644
--- a/client/rest-high-level/src/test/java/org/elasticsearch/client/security/AuthenticateResponseTests.java
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/security/AuthenticateResponseTests.java
@@ -38,12 +38,12 @@ public class AuthenticateResponseTests extends ESTestCase {
public void testFromXContent() throws IOException {
xContentTester(
- this::createParser,
- this::createTestInstance,
- this::toXContent,
- AuthenticateResponse::fromXContent)
- .supportsUnknownFields(false)
- .test();
+ this::createParser,
+ this::createTestInstance,
+ this::toXContent,
+ AuthenticateResponse::fromXContent)
+ .supportsUnknownFields(false)
+ .test();
}
public void testEqualsAndHashCode() {
@@ -108,7 +108,7 @@ private void toXContent(AuthenticateResponse response, XContentBuilder builder)
private AuthenticateResponse copy(AuthenticateResponse response) {
final User originalUser = response.getUser();
final User copyUser = new User(originalUser.getUsername(), originalUser.getRoles(), originalUser.getMetadata(),
- originalUser.getFullName(), originalUser.getEmail());
+ originalUser.getFullName(), originalUser.getEmail());
return new AuthenticateResponse(copyUser, response.enabled(), response.getAuthenticationRealm(),
response.getLookupRealm());
}
@@ -117,9 +117,9 @@ private AuthenticateResponse mutate(AuthenticateResponse response) {
final User originalUser = response.getUser();
switch (randomIntBetween(1, 8)) {
case 1:
- return new AuthenticateResponse(new User(originalUser.getUsername() + "wrong", originalUser.getRoles(),
+ return new AuthenticateResponse(new User(originalUser.getUsername() + "wrong", originalUser.getRoles(),
originalUser.getMetadata(), originalUser.getFullName(), originalUser.getEmail()), response.enabled(),
- response.getAuthenticationRealm(), response.getLookupRealm());
+ response.getAuthenticationRealm(), response.getLookupRealm());
case 2:
final Collection wrongRoles = new ArrayList<>(originalUser.getRoles());
wrongRoles.add(randomAlphaOfLengthBetween(1, 4));
@@ -134,11 +134,11 @@ private AuthenticateResponse mutate(AuthenticateResponse response) {
response.getLookupRealm());
case 4:
return new AuthenticateResponse(new User(originalUser.getUsername(), originalUser.getRoles(), originalUser.getMetadata(),
- originalUser.getFullName() + "wrong", originalUser.getEmail()), response.enabled(),
+ originalUser.getFullName() + "wrong", originalUser.getEmail()), response.enabled(),
response.getAuthenticationRealm(), response.getLookupRealm());
case 5:
return new AuthenticateResponse(new User(originalUser.getUsername(), originalUser.getRoles(), originalUser.getMetadata(),
- originalUser.getFullName(), originalUser.getEmail() + "wrong"), response.enabled(),
+ originalUser.getFullName(), originalUser.getEmail() + "wrong"), response.enabled(),
response.getAuthenticationRealm(), response.getLookupRealm());
case 6:
return new AuthenticateResponse(new User(originalUser.getUsername(), originalUser.getRoles(), originalUser.getMetadata(),
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/security/GetUsersRequestTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/security/GetUsersRequestTests.java
new file mode 100644
index 0000000000000..68b1751716e1f
--- /dev/null
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/security/GetUsersRequestTests.java
@@ -0,0 +1,53 @@
+/*
+ * 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 GetUsersRequestTests extends ESTestCase {
+
+ public void testGetUsersRequest() {
+ final String[] users = randomArray(0, 5, String[]::new, () -> randomAlphaOfLength(5));
+ GetUsersRequest getUsersRequest = new GetUsersRequest(users);
+ assertThat(getUsersRequest.getUsernames().size(), equalTo(users.length));
+ assertThat(getUsersRequest.getUsernames(), containsInAnyOrder(users));
+ }
+
+ public void testEqualsHashCode() {
+ final String[] users = randomArray(0, 5, String[]::new, () -> randomAlphaOfLength(5));
+ final GetUsersRequest getUsersRequest = new GetUsersRequest(users);
+ assertNotNull(getUsersRequest);
+ EqualsHashCodeTestUtils.checkEqualsAndHashCode(getUsersRequest, (original) -> {
+ return new GetUsersRequest(original.getUsernames().toArray(new String[0]));
+ });
+ EqualsHashCodeTestUtils.checkEqualsAndHashCode(getUsersRequest, (original) -> {
+ return new GetUsersRequest(original.getUsernames().toArray(new String[0]));
+ }, GetUsersRequestTests::mutateTestItem);
+ }
+
+ private static GetUsersRequest mutateTestItem(GetUsersRequest original) {
+ final int minRoles = original.getUsernames().isEmpty() ? 1 : 0;
+ return new GetUsersRequest(randomArray(minRoles, 5, String[]::new, () -> randomAlphaOfLength(6)));
+ }
+
+}
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/security/GetUsersResponseTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/security/GetUsersResponseTests.java
new file mode 100644
index 0000000000000..3025241bb3909
--- /dev/null
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/security/GetUsersResponseTests.java
@@ -0,0 +1,126 @@
+/*
+ * 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.User;
+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.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static org.hamcrest.Matchers.equalTo;
+
+/** tests the Response for getting users from the security HLRC */
+public class GetUsersResponseTests extends ESTestCase {
+ public void testFromXContent() throws IOException {
+ String json =
+ "{\n" +
+ " \"jacknich\": {\n" +
+ " \"username\": \"jacknich\",\n" +
+ " \"roles\": [\n" +
+ " \"admin\", \"other_role1\"\n" +
+ " ],\n" +
+ " \"full_name\": \"Jack Nicholson\",\n" +
+ " \"email\": \"jacknich@example.com\",\n" +
+ " \"metadata\": { \"intelligence\" : 7 },\n" +
+ " \"enabled\": true\n" +
+ " }\n" +
+ "}";
+ final GetUsersResponse response = GetUsersResponse.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.getUsers().size(), equalTo(1));
+ final User user = response.getUsers().iterator().next();
+ assertThat(user.getUsername(), equalTo("jacknich"));
+ assertThat(user.getRoles().size(), equalTo(2));
+ assertThat(user.getFullName(), equalTo("Jack Nicholson"));
+ assertThat(user.getEmail(), equalTo("jacknich@example.com"));
+ final Map metadata = new HashMap<>();
+ metadata.put("intelligence", 7);
+ assertThat(metadata, equalTo(user.getMetadata()));
+ }
+
+ public void testEqualsHashCode() {
+ final Set users = new HashSet<>();
+ final Set enabledUsers = new HashSet<>();
+ Map metadata = new HashMap<>();
+ metadata.put("intelligence", 1);
+ final User user1 = new User("testUser1", Arrays.asList(new String[] {"admin", "other_role1"}),
+ metadata, "Test User 1", null);
+ users.add(user1);
+ enabledUsers.add(user1);
+ Map metadata2 = new HashMap<>();
+ metadata2.put("intelligence", 9);
+ metadata2.put("specialty", "geo");
+ final User user2 = new User("testUser2", Arrays.asList(new String[] {"admin"}),
+ metadata, "Test User 2", "testuser2@example.com");
+ users.add(user2);
+ enabledUsers.add(user2);
+ final GetUsersResponse getUsersResponse = new GetUsersResponse(users, enabledUsers);
+ assertNotNull(getUsersResponse);
+ EqualsHashCodeTestUtils.checkEqualsAndHashCode(getUsersResponse, (original) -> {
+ return new GetUsersResponse(original.getUsers(), original.getEnabledUsers());
+ });
+ EqualsHashCodeTestUtils.checkEqualsAndHashCode(getUsersResponse, (original) -> {
+ return new GetUsersResponse(original.getUsers(), original.getEnabledUsers());
+ }, GetUsersResponseTests::mutateTestItem);
+ }
+
+ private static GetUsersResponse mutateTestItem(GetUsersResponse original) {
+ if (randomBoolean()) {
+ final Set users = new HashSet<>();
+ final Set enabledUsers = new HashSet<>();
+ Map metadata = new HashMap<>();
+ metadata.put("intelligence", 1);
+ final User user1 = new User("testUser1", Arrays.asList(new String[] {"admin", "other_role1"}),
+ metadata, "Test User 1", null);
+ users.add(user1);
+ enabledUsers.add(user1);
+ return new GetUsersResponse(users, enabledUsers);
+ }
+ Map metadata = new HashMap<>();
+ metadata.put("intelligence", 5); // change intelligence
+ final User user1 = new User("testUser1", Arrays.asList(new String[] {"admin", "other_role1"}),
+ metadata, "Test User 1", null);
+ Set newUsers = original.getUsers().stream().collect(Collectors.toSet());
+ Set enabledUsers = original.getEnabledUsers().stream().collect(Collectors.toSet());
+ newUsers.clear();
+ enabledUsers.clear();
+ newUsers.add(user1);
+ enabledUsers.add(user1);
+ return new GetUsersResponse(newUsers, enabledUsers);
+ }
+}
diff --git a/docs/java-rest/high-level/security/get-users.asciidoc b/docs/java-rest/high-level/security/get-users.asciidoc
new file mode 100644
index 0000000000000..e9e4a0d94911b
--- /dev/null
+++ b/docs/java-rest/high-level/security/get-users.asciidoc
@@ -0,0 +1,48 @@
+
+--
+:api: get-users
+:request: GetUsersRequest
+:respnse: GetUsersResponse
+--
+
+[id="{upid}-{api}"]
+=== Get Users API
+
+[id="{upid}-{api}-request"]
+==== Get Users Request
+
+Retrieving a user can be performed using the `security().getUsers()`
+method and by setting the username on +{request}+:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests-file}[{api}-request]
+--------------------------------------------------
+
+Retrieving multiple users can be performed using the `security().getUsers()`
+method and by setting multiple usernames on +{request}+:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests-file}[{api}-list-request]
+--------------------------------------------------
+
+Retrieving all users can be performed using the `security().getUsers()`
+method without specifying any usernames on +{request}+:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests-file}[{api}-all-request]
+--------------------------------------------------
+
+include::../execution.asciidoc[]
+
+[id="{upid}-{api}-response"]
+==== Get Users Response
+
+The returned +{response}+ allows getting information about the retrieved users 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 70b66074aadba..0b4a2570c896d 100644
--- a/docs/java-rest/high-level/supported-apis.asciidoc
+++ b/docs/java-rest/high-level/supported-apis.asciidoc
@@ -387,6 +387,7 @@ include::rollup/get_rollup_index_caps.asciidoc[]
The Java High Level REST Client supports the following Security APIs:
* <>
+* <<{upid}-get-users>>
* <<{upid}-delete-user>>
* <>
* <>
@@ -410,6 +411,7 @@ The Java High Level REST Client supports the following Security APIs:
* <<{upid}-delete-privileges>>
include::security/put-user.asciidoc[]
+include::security/get-users.asciidoc[]
include::security/delete-user.asciidoc[]
include::security/enable-user.asciidoc[]
include::security/disable-user.asciidoc[]