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/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 0ccd1aabeba55..c6dc6910d97b0 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
@@ -315,9 +315,11 @@ public static class ClusterPrivilegeName {
public static final String MANAGE_PIPELINE = "manage_pipeline";
public static final String MANAGE_CCR = "manage_ccr";
public static final String READ_CCR = "read_ccr";
+ public static final String MANAGE_ILM = "manage_ilm";
+ public static final String READ_ILM = "read_ilm";
public static final String[] ALL_ARRAY = new String[] { NONE, ALL, MONITOR, MONITOR_ML, MONITOR_WATCHER, MONITOR_ROLLUP, MANAGE,
MANAGE_ML, MANAGE_WATCHER, MANAGE_ROLLUP, MANAGE_INDEX_TEMPLATES, MANAGE_INGEST_PIPELINES, TRANSPORT_CLIENT,
- MANAGE_SECURITY, MANAGE_SAML, MANAGE_TOKEN, MANAGE_PIPELINE, MANAGE_CCR, READ_CCR };
+ MANAGE_SECURITY, MANAGE_SAML, MANAGE_TOKEN, MANAGE_PIPELINE, MANAGE_CCR, READ_CCR, MANAGE_ILM, READ_ILM };
}
/**
@@ -338,8 +340,9 @@ public static class IndexPrivilegeName {
public static final String CREATE_INDEX = "create_index";
public static final String VIEW_INDEX_METADATA = "view_index_metadata";
public static final String MANAGE_FOLLOW_INDEX = "manage_follow_index";
+ public static final String MANAGE_ILM = "manage_ilm";
public static final String[] ALL_ARRAY = new String[] { NONE, ALL, READ, READ_CROSS, CREATE, INDEX, DELETE, WRITE, MONITOR, MANAGE,
- DELETE_INDEX, CREATE_INDEX, VIEW_INDEX_METADATA, MANAGE_FOLLOW_INDEX };
+ DELETE_INDEX, CREATE_INDEX, VIEW_INDEX_METADATA, MANAGE_FOLLOW_INDEX, MANAGE_ILM };
}
}
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[]
diff --git a/server/src/main/java/org/elasticsearch/index/query/MultiMatchQueryBuilder.java b/server/src/main/java/org/elasticsearch/index/query/MultiMatchQueryBuilder.java
index 996e878dba85c..d8476d791d7ec 100644
--- a/server/src/main/java/org/elasticsearch/index/query/MultiMatchQueryBuilder.java
+++ b/server/src/main/java/org/elasticsearch/index/query/MultiMatchQueryBuilder.java
@@ -67,7 +67,6 @@ public class MultiMatchQueryBuilder extends AbstractQueryBuilderTie-Breaker for "best-match" disjunction queries (OR-Queries).
* The tie breaker capability allows documents that match more than one query clause
@@ -593,9 +581,6 @@ public void doXContent(XContentBuilder builder, Params params) throws IOExceptio
if (fuzzyRewrite != null) {
builder.field(FUZZY_REWRITE_FIELD.getPreferredName(), fuzzyRewrite);
}
- if (useDisMax != null) {
- builder.field(USE_DIS_MAX_FIELD.getPreferredName(), useDisMax);
- }
if (tieBreaker != null) {
builder.field(TIE_BREAKER_FIELD.getPreferredName(), tieBreaker);
}
@@ -674,8 +659,6 @@ public static MultiMatchQueryBuilder fromXContent(XContentParser parser) throws
minimumShouldMatch = parser.textOrNull();
} else if (FUZZY_REWRITE_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
fuzzyRewrite = parser.textOrNull();
- } else if (USE_DIS_MAX_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
- useDisMax = parser.booleanValue();
} else if (TIE_BREAKER_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
tieBreaker = parser.floatValue();
} else if (CUTOFF_FREQUENCY_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
@@ -724,7 +707,6 @@ public static MultiMatchQueryBuilder fromXContent(XContentParser parser) throws
.cutoffFrequency(cutoffFrequency)
.fuzziness(fuzziness)
.fuzzyRewrite(fuzzyRewrite)
- .useDisMax(useDisMax)
.maxExpansions(maxExpansions)
.minimumShouldMatch(minimumShouldMatch)
.operator(operator)
@@ -798,16 +780,6 @@ protected Query doToQuery(QueryShardContext context) throws IOException {
multiMatchQuery.setAutoGenerateSynonymsPhraseQuery(autoGenerateSynonymsPhraseQuery);
multiMatchQuery.setTranspositions(fuzzyTranspositions);
- if (useDisMax != null) { // backwards foobar
- boolean typeUsesDismax = type.tieBreaker() != 1.0f;
- if (typeUsesDismax != useDisMax) {
- if (useDisMax && tieBreaker == null) {
- multiMatchQuery.setTieBreaker(0.0f);
- } else {
- multiMatchQuery.setTieBreaker(1.0f);
- }
- }
- }
Map newFieldsBoosts;
if (fieldsBoosts.isEmpty()) {
// no fields provided, defaults to index.query.default_field
@@ -828,7 +800,7 @@ protected Query doToQuery(QueryShardContext context) throws IOException {
@Override
protected int doHashCode() {
return Objects.hash(value, fieldsBoosts, type, operator, analyzer, slop, fuzziness,
- prefixLength, maxExpansions, minimumShouldMatch, fuzzyRewrite, useDisMax, tieBreaker, lenient,
+ prefixLength, maxExpansions, minimumShouldMatch, fuzzyRewrite, tieBreaker, lenient,
cutoffFrequency, zeroTermsQuery, autoGenerateSynonymsPhraseQuery, fuzzyTranspositions);
}
@@ -845,7 +817,6 @@ protected boolean doEquals(MultiMatchQueryBuilder other) {
Objects.equals(maxExpansions, other.maxExpansions) &&
Objects.equals(minimumShouldMatch, other.minimumShouldMatch) &&
Objects.equals(fuzzyRewrite, other.fuzzyRewrite) &&
- Objects.equals(useDisMax, other.useDisMax) &&
Objects.equals(tieBreaker, other.tieBreaker) &&
Objects.equals(lenient, other.lenient) &&
Objects.equals(cutoffFrequency, other.cutoffFrequency) &&
diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/support/MultiValuesSourceAggregationBuilder.java b/server/src/main/java/org/elasticsearch/search/aggregations/support/MultiValuesSourceAggregationBuilder.java
index 333eb777ac422..acc0d2ee20bcb 100644
--- a/server/src/main/java/org/elasticsearch/search/aggregations/support/MultiValuesSourceAggregationBuilder.java
+++ b/server/src/main/java/org/elasticsearch/search/aggregations/support/MultiValuesSourceAggregationBuilder.java
@@ -207,7 +207,9 @@ protected boolean serializeTargetValueType() {
public final XContentBuilder internalXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
if (fields != null) {
- builder.field(CommonFields.FIELDS.getPreferredName(), fields);
+ for (Map.Entry fieldEntry : fields.entrySet()) {
+ builder.field(fieldEntry.getKey(), fieldEntry.getValue());
+ }
}
if (format != null) {
builder.field(CommonFields.FORMAT.getPreferredName(), format);
diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/support/MultiValuesSourceFieldConfig.java b/server/src/main/java/org/elasticsearch/search/aggregations/support/MultiValuesSourceFieldConfig.java
index 56ceae69ff78e..fbc3081758f96 100644
--- a/server/src/main/java/org/elasticsearch/search/aggregations/support/MultiValuesSourceFieldConfig.java
+++ b/server/src/main/java/org/elasticsearch/search/aggregations/support/MultiValuesSourceFieldConfig.java
@@ -25,16 +25,17 @@
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.common.xcontent.ObjectParser;
-import org.elasticsearch.common.xcontent.ToXContentFragment;
+import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.script.Script;
import org.joda.time.DateTimeZone;
import java.io.IOException;
+import java.util.Objects;
import java.util.function.BiFunction;
-public class MultiValuesSourceFieldConfig implements Writeable, ToXContentFragment {
+public class MultiValuesSourceFieldConfig implements Writeable, ToXContentObject {
private String fieldName;
private Object missing;
private Script script;
@@ -110,6 +111,7 @@ public void writeTo(StreamOutput out) throws IOException {
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
+ builder.startObject();
if (missing != null) {
builder.field(ParseField.CommonFields.MISSING.getPreferredName(), missing);
}
@@ -120,11 +122,33 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
builder.field(ParseField.CommonFields.FIELD.getPreferredName(), fieldName);
}
if (timeZone != null) {
- builder.field(ParseField.CommonFields.TIME_ZONE.getPreferredName(), timeZone);
+ builder.field(ParseField.CommonFields.TIME_ZONE.getPreferredName(), timeZone.getID());
}
+ builder.endObject();
return builder;
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ MultiValuesSourceFieldConfig that = (MultiValuesSourceFieldConfig) o;
+ return Objects.equals(fieldName, that.fieldName)
+ && Objects.equals(missing, that.missing)
+ && Objects.equals(script, that.script)
+ && Objects.equals(timeZone, that.timeZone);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(fieldName, missing, script, timeZone);
+ }
+
+ @Override
+ public String toString() {
+ return Strings.toString(this);
+ }
+
public static class Builder {
private String fieldName;
private Object missing = null;
diff --git a/server/src/test/java/org/elasticsearch/discovery/ZenFaultDetectionTests.java b/server/src/test/java/org/elasticsearch/discovery/ZenFaultDetectionTests.java
index 03c0df43591ba..fbe3ef00a0656 100644
--- a/server/src/test/java/org/elasticsearch/discovery/ZenFaultDetectionTests.java
+++ b/server/src/test/java/org/elasticsearch/discovery/ZenFaultDetectionTests.java
@@ -32,7 +32,7 @@
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.ByteSizeValue;
-import org.elasticsearch.common.util.BigArrays;
+import org.elasticsearch.common.util.PageCacheRecycler;
import org.elasticsearch.discovery.zen.FaultDetection;
import org.elasticsearch.discovery.zen.MasterFaultDetection;
import org.elasticsearch.discovery.zen.NodesFaultDetection;
@@ -43,10 +43,10 @@
import org.elasticsearch.test.transport.MockTransportService;
import org.elasticsearch.threadpool.TestThreadPool;
import org.elasticsearch.threadpool.ThreadPool;
-import org.elasticsearch.transport.MockTcpTransport;
import org.elasticsearch.transport.TransportConnectionListener;
import org.elasticsearch.transport.TransportRequestOptions;
import org.elasticsearch.transport.TransportService;
+import org.elasticsearch.transport.nio.MockNioTransport;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers;
import org.junit.After;
@@ -138,8 +138,8 @@ protected MockTransportService build(Settings settings, Version version) {
// trace zenfd actions but keep the default otherwise
.putList(TransportService.TRACE_LOG_EXCLUDE_SETTING.getKey(), TransportLivenessAction.NAME)
.build(),
- new MockTcpTransport(settings, threadPool, BigArrays.NON_RECYCLING_INSTANCE, circuitBreakerService,
- namedWriteableRegistry, new NetworkService(Collections.emptyList()), version),
+ new MockNioTransport(settings, version, threadPool, new NetworkService(Collections.emptyList()),
+ PageCacheRecycler.NON_RECYCLING_INSTANCE, namedWriteableRegistry, circuitBreakerService),
threadPool,
TransportService.NOOP_TRANSPORT_INTERCEPTOR,
(boundAddress) ->
diff --git a/server/src/test/java/org/elasticsearch/discovery/zen/UnicastZenPingTests.java b/server/src/test/java/org/elasticsearch/discovery/zen/UnicastZenPingTests.java
index 1c0329a51e32a..c380341b51b86 100644
--- a/server/src/test/java/org/elasticsearch/discovery/zen/UnicastZenPingTests.java
+++ b/server/src/test/java/org/elasticsearch/discovery/zen/UnicastZenPingTests.java
@@ -38,6 +38,7 @@
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.BigArrays;
+import org.elasticsearch.common.util.PageCacheRecycler;
import org.elasticsearch.common.util.concurrent.AbstractRunnable;
import org.elasticsearch.common.util.concurrent.ConcurrentCollections;
import org.elasticsearch.common.util.concurrent.EsExecutors;
@@ -56,6 +57,7 @@
import org.elasticsearch.transport.TransportRequestOptions;
import org.elasticsearch.transport.TransportResponseHandler;
import org.elasticsearch.transport.TransportService;
+import org.elasticsearch.transport.nio.MockNioTransport;
import org.junit.After;
import org.junit.Before;
import org.mockito.Matchers;
@@ -143,14 +145,14 @@ public void testSimplePings() throws IOException, InterruptedException, Executio
NetworkService networkService = new NetworkService(Collections.emptyList());
- final BiFunction supplier = (s, v) -> new MockTcpTransport(
+ final BiFunction supplier = (s, v) -> new MockNioTransport(
s,
+ v,
threadPool,
- BigArrays.NON_RECYCLING_INSTANCE,
- new NoneCircuitBreakerService(),
- new NamedWriteableRegistry(Collections.emptyList()),
networkService,
- v);
+ PageCacheRecycler.NON_RECYCLING_INSTANCE,
+ new NamedWriteableRegistry(Collections.emptyList()),
+ new NoneCircuitBreakerService());
NetworkHandle handleA = startServices(settings, threadPool, "UZP_A", Version.CURRENT, supplier);
closeables.push(handleA.transportService);
@@ -268,14 +270,14 @@ public void testUnknownHostNotCached() throws ExecutionException, InterruptedExc
final NetworkService networkService = new NetworkService(Collections.emptyList());
final Map addresses = new HashMap<>();
- final BiFunction supplier = (s, v) -> new MockTcpTransport(
+ final BiFunction supplier = (s, v) -> new MockNioTransport(
s,
+ v,
threadPool,
- BigArrays.NON_RECYCLING_INSTANCE,
- new NoneCircuitBreakerService(),
- new NamedWriteableRegistry(Collections.emptyList()),
networkService,
- v) {
+ PageCacheRecycler.NON_RECYCLING_INSTANCE,
+ new NamedWriteableRegistry(Collections.emptyList()),
+ new NoneCircuitBreakerService()) {
@Override
public TransportAddress[] addressesFromString(String address, int perAddressLimit) throws UnknownHostException {
final TransportAddress[] transportAddresses = addresses.get(address);
@@ -634,14 +636,14 @@ public void testPingingTemporalPings() throws ExecutionException, InterruptedExc
NetworkService networkService = new NetworkService(Collections.emptyList());
- final BiFunction supplier = (s, v) -> new MockTcpTransport(
+ final BiFunction supplier = (s, v) -> new MockNioTransport(
s,
+ v,
threadPool,
- BigArrays.NON_RECYCLING_INSTANCE,
- new NoneCircuitBreakerService(),
- new NamedWriteableRegistry(Collections.emptyList()),
networkService,
- v);
+ PageCacheRecycler.NON_RECYCLING_INSTANCE,
+ new NamedWriteableRegistry(Collections.emptyList()),
+ new NoneCircuitBreakerService());
NetworkHandle handleA = startServices(settings, threadPool, "UZP_A", Version.CURRENT, supplier, EnumSet.allOf(Role.class));
closeables.push(handleA.transportService);
@@ -689,15 +691,14 @@ public void testPingingTemporalPings() throws ExecutionException, InterruptedExc
public void testInvalidHosts() throws InterruptedException {
final Logger logger = mock(Logger.class);
- final NetworkService networkService = new NetworkService(Collections.emptyList());
- final Transport transport = new MockTcpTransport(
+ final Transport transport = new MockNioTransport(
Settings.EMPTY,
+ Version.CURRENT,
threadPool,
- BigArrays.NON_RECYCLING_INSTANCE,
- new NoneCircuitBreakerService(),
+ new NetworkService(Collections.emptyList()),
+ PageCacheRecycler.NON_RECYCLING_INSTANCE,
new NamedWriteableRegistry(Collections.emptyList()),
- networkService,
- Version.CURRENT) {
+ new NoneCircuitBreakerService()) {
@Override
public BoundTransportAddress boundAddress() {
return new BoundTransportAddress(
diff --git a/server/src/test/java/org/elasticsearch/index/query/MultiMatchQueryBuilderTests.java b/server/src/test/java/org/elasticsearch/index/query/MultiMatchQueryBuilderTests.java
index 58604f7e83c47..43c76f028e22e 100644
--- a/server/src/test/java/org/elasticsearch/index/query/MultiMatchQueryBuilderTests.java
+++ b/server/src/test/java/org/elasticsearch/index/query/MultiMatchQueryBuilderTests.java
@@ -118,9 +118,6 @@ protected MultiMatchQueryBuilder doCreateTestQueryBuilder() {
if (randomBoolean()) {
query.fuzzyRewrite(getRandomRewriteMethod());
}
- if (randomBoolean()) {
- query.useDisMax(randomBoolean());
- }
if (randomBoolean()) {
query.tieBreaker(randomFloat());
}
@@ -189,7 +186,7 @@ public void testToQueryBoost() throws IOException {
}
public void testToQueryMultipleTermsBooleanQuery() throws Exception {
- Query query = multiMatchQuery("test1 test2").field(STRING_FIELD_NAME).useDisMax(false).toQuery(createShardContext());
+ Query query = multiMatchQuery("test1 test2").field(STRING_FIELD_NAME).toQuery(createShardContext());
assertThat(query, instanceOf(BooleanQuery.class));
BooleanQuery bQuery = (BooleanQuery) query;
assertThat(bQuery.clauses().size(), equalTo(2));
@@ -198,8 +195,8 @@ public void testToQueryMultipleTermsBooleanQuery() throws Exception {
}
public void testToQueryMultipleFieldsDisableDismax() throws Exception {
- Query query = multiMatchQuery("test").field(STRING_FIELD_NAME).field(STRING_FIELD_NAME_2).useDisMax(false)
- .toQuery(createShardContext());
+ Query query = multiMatchQuery("test").field(STRING_FIELD_NAME).field(STRING_FIELD_NAME_2).tieBreaker(1.0f)
+ .toQuery(createShardContext());
assertThat(query, instanceOf(DisjunctionMaxQuery.class));
DisjunctionMaxQuery dQuery = (DisjunctionMaxQuery) query;
assertThat(dQuery.getTieBreakerMultiplier(), equalTo(1.0f));
@@ -209,8 +206,7 @@ public void testToQueryMultipleFieldsDisableDismax() throws Exception {
}
public void testToQueryMultipleFieldsDisMaxQuery() throws Exception {
- Query query = multiMatchQuery("test").field(STRING_FIELD_NAME).field(STRING_FIELD_NAME_2).useDisMax(true)
- .toQuery(createShardContext());
+ Query query = multiMatchQuery("test").field(STRING_FIELD_NAME).field(STRING_FIELD_NAME_2).toQuery(createShardContext());
assertThat(query, instanceOf(DisjunctionMaxQuery.class));
DisjunctionMaxQuery disMaxQuery = (DisjunctionMaxQuery) query;
assertThat(disMaxQuery.getTieBreakerMultiplier(), equalTo(0.0f));
@@ -222,7 +218,7 @@ public void testToQueryMultipleFieldsDisMaxQuery() throws Exception {
}
public void testToQueryFieldsWildcard() throws Exception {
- Query query = multiMatchQuery("test").field("mapped_str*").useDisMax(false).toQuery(createShardContext());
+ Query query = multiMatchQuery("test").field("mapped_str*").tieBreaker(1.0f).toQuery(createShardContext());
assertThat(query, instanceOf(DisjunctionMaxQuery.class));
DisjunctionMaxQuery dQuery = (DisjunctionMaxQuery) query;
assertThat(dQuery.getTieBreakerMultiplier(), equalTo(1.0f));
diff --git a/server/src/test/java/org/elasticsearch/search/aggregations/metrics/weighted_avg/WeightedAvgAggregationBuilderTests.java b/server/src/test/java/org/elasticsearch/search/aggregations/metrics/weighted_avg/WeightedAvgAggregationBuilderTests.java
new file mode 100644
index 0000000000000..0b7c5cd0f86e0
--- /dev/null
+++ b/server/src/test/java/org/elasticsearch/search/aggregations/metrics/weighted_avg/WeightedAvgAggregationBuilderTests.java
@@ -0,0 +1,78 @@
+/*
+ * 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.search.aggregations.metrics.weighted_avg;
+
+import org.elasticsearch.common.io.stream.Writeable;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.xcontent.NamedXContentRegistry;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.search.SearchModule;
+import org.elasticsearch.search.aggregations.AggregatorFactories;
+import org.elasticsearch.search.aggregations.metrics.WeightedAvgAggregationBuilder;
+import org.elasticsearch.search.aggregations.support.MultiValuesSourceFieldConfig;
+import org.elasticsearch.test.AbstractSerializingTestCase;
+import org.junit.Before;
+
+import java.io.IOException;
+import java.util.Collections;
+
+import static org.hamcrest.Matchers.hasSize;
+
+public class WeightedAvgAggregationBuilderTests extends AbstractSerializingTestCase {
+ String aggregationName;
+
+ @Before
+ public void setupName() {
+ aggregationName = randomAlphaOfLength(10);
+ }
+
+ @Override
+ protected NamedXContentRegistry xContentRegistry() {
+ SearchModule searchModule = new SearchModule(Settings.EMPTY, false, Collections.emptyList());
+ return new NamedXContentRegistry(searchModule.getNamedXContents());
+ }
+
+ @Override
+ protected WeightedAvgAggregationBuilder doParseInstance(XContentParser parser) throws IOException {
+ assertSame(XContentParser.Token.START_OBJECT, parser.nextToken());
+ AggregatorFactories.Builder parsed = AggregatorFactories.parseAggregators(parser);
+ assertThat(parsed.getAggregatorFactories(), hasSize(1));
+ assertThat(parsed.getPipelineAggregatorFactories(), hasSize(0));
+ WeightedAvgAggregationBuilder agg = (WeightedAvgAggregationBuilder) parsed.getAggregatorFactories().iterator().next();
+ assertNull(parser.nextToken());
+ assertNotNull(agg);
+ return agg;
+ }
+
+ @Override
+ protected WeightedAvgAggregationBuilder createTestInstance() {
+ MultiValuesSourceFieldConfig valueConfig = new MultiValuesSourceFieldConfig.Builder().setFieldName("value_field").build();
+ MultiValuesSourceFieldConfig weightConfig = new MultiValuesSourceFieldConfig.Builder().setFieldName("weight_field").build();
+ WeightedAvgAggregationBuilder aggregationBuilder = new WeightedAvgAggregationBuilder(aggregationName)
+ .value(valueConfig)
+ .weight(weightConfig);
+ return aggregationBuilder;
+ }
+
+ @Override
+ protected Writeable.Reader instanceReader() {
+ return WeightedAvgAggregationBuilder::new;
+ }
+}
diff --git a/server/src/test/java/org/elasticsearch/search/aggregations/support/MultiValuesSourceFieldConfigTests.java b/server/src/test/java/org/elasticsearch/search/aggregations/support/MultiValuesSourceFieldConfigTests.java
index ac1c07a40490e..5007784a3d9a9 100644
--- a/server/src/test/java/org/elasticsearch/search/aggregations/support/MultiValuesSourceFieldConfigTests.java
+++ b/server/src/test/java/org/elasticsearch/search/aggregations/support/MultiValuesSourceFieldConfigTests.java
@@ -19,12 +19,37 @@
package org.elasticsearch.search.aggregations.support;
+import org.elasticsearch.common.io.stream.Writeable;
+import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.script.Script;
-import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.test.AbstractSerializingTestCase;
+import org.joda.time.DateTimeZone;
+
+import java.io.IOException;
import static org.hamcrest.Matchers.equalTo;
-public class MultiValuesSourceFieldConfigTests extends ESTestCase {
+public class MultiValuesSourceFieldConfigTests extends AbstractSerializingTestCase {
+
+ @Override
+ protected MultiValuesSourceFieldConfig doParseInstance(XContentParser parser) throws IOException {
+ return MultiValuesSourceFieldConfig.PARSER.apply(true, true).apply(parser, null).build();
+ }
+
+ @Override
+ protected MultiValuesSourceFieldConfig createTestInstance() {
+ String field = randomAlphaOfLength(10);
+ Object missing = randomBoolean() ? randomAlphaOfLength(10) : null;
+ DateTimeZone timeZone = randomBoolean() ? randomDateTimeZone() : null;
+ return new MultiValuesSourceFieldConfig.Builder()
+ .setFieldName(field).setMissing(missing).setScript(null).setTimeZone(timeZone).build();
+ }
+
+ @Override
+ protected Writeable.Reader instanceReader() {
+ return MultiValuesSourceFieldConfig::new;
+ }
+
public void testMissingFieldScript() {
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> new MultiValuesSourceFieldConfig.Builder().build());
assertThat(e.getMessage(), equalTo("[field] and [script] cannot both be null. Please specify one or the other."));
diff --git a/server/src/test/java/org/elasticsearch/search/query/MultiMatchQueryIT.java b/server/src/test/java/org/elasticsearch/search/query/MultiMatchQueryIT.java
index f5688e0a4215e..76850a197d969 100644
--- a/server/src/test/java/org/elasticsearch/search/query/MultiMatchQueryIT.java
+++ b/server/src/test/java/org/elasticsearch/search/query/MultiMatchQueryIT.java
@@ -203,7 +203,7 @@ public void testDefaults() throws ExecutionException, InterruptedException {
searchResponse = client().prepareSearch("test")
.setQuery(randomizeType(multiMatchQuery("marvel hero captain america", "full_name", "first_name", "last_name", "category")
- .operator(Operator.OR).useDisMax(false).type(type))).get();
+ .operator(Operator.OR).type(type))).get();
assertFirstHit(searchResponse, anyOf(hasId("theone"), hasId("theother")));
assertThat(searchResponse.getHits().getHits()[0].getScore(), greaterThan(searchResponse.getHits().getHits()[1].getScore()));
@@ -323,14 +323,14 @@ public void testCutoffFreq() throws ExecutionException, InterruptedException {
cutoffFrequency = randomBoolean() ? Math.min(1, numDocs * 1.f / between(10, 20)) : 1.f / between(10, 20);
searchResponse = client().prepareSearch("test")
.setQuery(randomizeType(multiMatchQuery("marvel hero captain america", "full_name", "first_name", "last_name", "category")
- .operator(Operator.OR).useDisMax(false).cutoffFrequency(cutoffFrequency).type(type))).get();
+ .operator(Operator.OR).cutoffFrequency(cutoffFrequency).type(type))).get();
assertFirstHit(searchResponse, anyOf(hasId("theone"), hasId("theother")));
assertThat(searchResponse.getHits().getHits()[0].getScore(), greaterThan(searchResponse.getHits().getHits()[1].getScore()));
long size = searchResponse.getHits().getTotalHits().value;
searchResponse = client().prepareSearch("test")
.setQuery(randomizeType(multiMatchQuery("marvel hero captain america", "full_name", "first_name", "last_name", "category")
- .operator(Operator.OR).useDisMax(false).type(type))).get();
+ .operator(Operator.OR).type(type))).get();
assertFirstHit(searchResponse, anyOf(hasId("theone"), hasId("theother")));
assertThat("common terms expected to be a way smaller result set", size, lessThan(searchResponse.getHits().getTotalHits().value));
@@ -399,7 +399,7 @@ public void testEquivalence() {
SearchResponse left = client().prepareSearch("test").setSize(numDocs)
.addSort(SortBuilders.scoreSort()).addSort(SortBuilders.fieldSort("_id"))
.setQuery(randomizeType(multiMatchQueryBuilder
- .operator(op).useDisMax(false).minimumShouldMatch(minShouldMatch).type(type))).get();
+ .operator(op).tieBreaker(1.0f).minimumShouldMatch(minShouldMatch).type(type))).get();
SearchResponse right = client().prepareSearch("test").setSize(numDocs)
.addSort(SortBuilders.scoreSort()).addSort(SortBuilders.fieldSort("_id"))
@@ -418,7 +418,7 @@ public void testEquivalence() {
SearchResponse left = client().prepareSearch("test").setSize(numDocs)
.addSort(SortBuilders.scoreSort()).addSort(SortBuilders.fieldSort("_id"))
.setQuery(randomizeType(multiMatchQuery("capta", "full_name", "first_name", "last_name", "category")
- .type(MatchQuery.Type.PHRASE_PREFIX).useDisMax(false).minimumShouldMatch(minShouldMatch))).get();
+ .type(MatchQuery.Type.PHRASE_PREFIX).tieBreaker(1.0f).minimumShouldMatch(minShouldMatch))).get();
SearchResponse right = client().prepareSearch("test").setSize(numDocs)
.addSort(SortBuilders.scoreSort()).addSort(SortBuilders.fieldSort("_id"))
@@ -437,7 +437,7 @@ public void testEquivalence() {
left = client().prepareSearch("test").setSize(numDocs)
.addSort(SortBuilders.scoreSort()).addSort(SortBuilders.fieldSort("_id"))
.setQuery(randomizeType(multiMatchQuery("captain america", "full_name", "first_name", "last_name", "category")
- .type(MatchQuery.Type.PHRASE).useDisMax(false).minimumShouldMatch(minShouldMatch))).get();
+ .type(MatchQuery.Type.PHRASE).minimumShouldMatch(minShouldMatch))).get();
} else {
left = client().prepareSearch("test").setSize(numDocs)
.addSort(SortBuilders.scoreSort()).addSort(SortBuilders.fieldSort("_id"))
diff --git a/server/src/test/java/org/elasticsearch/search/query/SearchQueryIT.java b/server/src/test/java/org/elasticsearch/search/query/SearchQueryIT.java
index ebfd4dbbebf29..2b6b8b1c60bcc 100644
--- a/server/src/test/java/org/elasticsearch/search/query/SearchQueryIT.java
+++ b/server/src/test/java/org/elasticsearch/search/query/SearchQueryIT.java
@@ -681,7 +681,6 @@ public void testMultiMatchQuery() throws Exception {
// this uses dismax so scores are equal and the order can be arbitrary
assertSearchHits(searchResponse, "1", "2");
- builder.useDisMax(false);
searchResponse = client().prepareSearch()
.setQuery(builder)
.get();
@@ -786,7 +785,6 @@ public void testMultiMatchQueryMinShouldMatch() {
MultiMatchQueryBuilder multiMatchQuery = multiMatchQuery("value1 value2 foo", "field1", "field2");
- multiMatchQuery.useDisMax(true);
multiMatchQuery.minimumShouldMatch("70%");
SearchResponse searchResponse = client().prepareSearch()
.setQuery(multiMatchQuery)
@@ -800,7 +798,6 @@ public void testMultiMatchQueryMinShouldMatch() {
assertFirstHit(searchResponse, hasId("1"));
assertSecondHit(searchResponse, hasId("2"));
- multiMatchQuery.useDisMax(false);
multiMatchQuery.minimumShouldMatch("70%");
searchResponse = client().prepareSearch().setQuery(multiMatchQuery).get();
assertHitCount(searchResponse, 1L);
@@ -1475,11 +1472,11 @@ public void testMultiMatchLenientIssue3797() {
refresh();
SearchResponse searchResponse = client().prepareSearch("test")
- .setQuery(multiMatchQuery("value2", "field2").field("field1", 2).lenient(true).useDisMax(false)).get();
+ .setQuery(multiMatchQuery("value2", "field2").field("field1", 2).lenient(true)).get();
assertHitCount(searchResponse, 1L);
searchResponse = client().prepareSearch("test")
- .setQuery(multiMatchQuery("value2", "field2").field("field1", 2).lenient(true).useDisMax(true)).get();
+ .setQuery(multiMatchQuery("value2", "field2").field("field1", 2).lenient(true)).get();
assertHitCount(searchResponse, 1L);
searchResponse = client().prepareSearch("test")
diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/ClusterPrivilege.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/ClusterPrivilege.java
index 9c03941b0313a..fba595e7a09e4 100644
--- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/ClusterPrivilege.java
+++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/ClusterPrivilege.java
@@ -9,6 +9,8 @@
import org.elasticsearch.action.admin.cluster.state.ClusterStateAction;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.collect.MapBuilder;
+import org.elasticsearch.xpack.core.indexlifecycle.action.GetLifecycleAction;
+import org.elasticsearch.xpack.core.indexlifecycle.action.GetStatusAction;
import org.elasticsearch.xpack.core.security.action.token.InvalidateTokenAction;
import org.elasticsearch.xpack.core.security.action.token.RefreshTokenAction;
import org.elasticsearch.xpack.core.security.action.user.HasPrivilegesAction;
@@ -47,6 +49,8 @@ public final class ClusterPrivilege extends Privilege {
private static final Automaton MANAGE_CCR_AUTOMATON =
patterns("cluster:admin/xpack/ccr/*", ClusterStateAction.NAME, HasPrivilegesAction.NAME);
private static final Automaton READ_CCR_AUTOMATON = patterns(ClusterStateAction.NAME, HasPrivilegesAction.NAME);
+ private static final Automaton MANAGE_ILM_AUTOMATON = patterns("cluster:admin/ilm/*");
+ private static final Automaton READ_ILM_AUTOMATON = patterns(GetLifecycleAction.NAME, GetStatusAction.NAME);
public static final ClusterPrivilege NONE = new ClusterPrivilege("none", Automatons.EMPTY);
public static final ClusterPrivilege ALL = new ClusterPrivilege("all", ALL_CLUSTER_AUTOMATON);
@@ -69,6 +73,8 @@ public final class ClusterPrivilege extends Privilege {
public static final ClusterPrivilege MANAGE_PIPELINE = new ClusterPrivilege("manage_pipeline", "cluster:admin/ingest/pipeline/*");
public static final ClusterPrivilege MANAGE_CCR = new ClusterPrivilege("manage_ccr", MANAGE_CCR_AUTOMATON);
public static final ClusterPrivilege READ_CCR = new ClusterPrivilege("read_ccr", READ_CCR_AUTOMATON);
+ public static final ClusterPrivilege MANAGE_ILM = new ClusterPrivilege("manage_ilm", MANAGE_ILM_AUTOMATON);
+ public static final ClusterPrivilege READ_ILM = new ClusterPrivilege("read_ilm", READ_ILM_AUTOMATON);
public static final Predicate ACTION_MATCHER = ClusterPrivilege.ALL.predicate();
@@ -92,6 +98,8 @@ public final class ClusterPrivilege extends Privilege {
.put("manage_rollup", MANAGE_ROLLUP)
.put("manage_ccr", MANAGE_CCR)
.put("read_ccr", READ_CCR)
+ .put("manage_ilm", MANAGE_ILM)
+ .put("read_ilm", READ_ILM)
.immutableMap();
private static final ConcurrentHashMap, ClusterPrivilege> CACHE = new ConcurrentHashMap<>();
diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/IndexPrivilege.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/IndexPrivilege.java
index 6281fbb2c8fd6..d6549df5f9d5a 100644
--- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/IndexPrivilege.java
+++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/IndexPrivilege.java
@@ -24,6 +24,7 @@
import org.elasticsearch.common.collect.MapBuilder;
import org.elasticsearch.xpack.core.ccr.action.PutFollowAction;
import org.elasticsearch.xpack.core.ccr.action.UnfollowAction;
+import org.elasticsearch.xpack.core.indexlifecycle.action.ExplainLifecycleAction;
import org.elasticsearch.xpack.core.security.support.Automatons;
import java.util.Arrays;
@@ -57,9 +58,11 @@ public final class IndexPrivilege extends Privilege {
private static final Automaton DELETE_INDEX_AUTOMATON = patterns(DeleteIndexAction.NAME);
private static final Automaton VIEW_METADATA_AUTOMATON = patterns(GetAliasesAction.NAME, AliasesExistAction.NAME,
GetIndexAction.NAME, IndicesExistsAction.NAME, GetFieldMappingsAction.NAME + "*", GetMappingsAction.NAME,
- ClusterSearchShardsAction.NAME, TypesExistsAction.NAME, ValidateQueryAction.NAME + "*", GetSettingsAction.NAME);
+ ClusterSearchShardsAction.NAME, TypesExistsAction.NAME, ValidateQueryAction.NAME + "*", GetSettingsAction.NAME,
+ ExplainLifecycleAction.NAME);
private static final Automaton MANAGE_FOLLOW_INDEX_AUTOMATON = patterns(PutFollowAction.NAME, UnfollowAction.NAME,
CloseIndexAction.NAME);
+ private static final Automaton MANAGE_ILM_AUTOMATON = patterns("indices:admin/ilm/*");
public static final IndexPrivilege NONE = new IndexPrivilege("none", Automatons.EMPTY);
public static final IndexPrivilege ALL = new IndexPrivilege("all", ALL_AUTOMATON);
@@ -75,6 +78,7 @@ public final class IndexPrivilege extends Privilege {
public static final IndexPrivilege CREATE_INDEX = new IndexPrivilege("create_index", CREATE_INDEX_AUTOMATON);
public static final IndexPrivilege VIEW_METADATA = new IndexPrivilege("view_index_metadata", VIEW_METADATA_AUTOMATON);
public static final IndexPrivilege MANAGE_FOLLOW_INDEX = new IndexPrivilege("manage_follow_index", MANAGE_FOLLOW_INDEX_AUTOMATON);
+ public static final IndexPrivilege MANAGE_ILM = new IndexPrivilege("manage_ilm", MANAGE_ILM_AUTOMATON);
private static final Map VALUES = MapBuilder.newMapBuilder()
.put("none", NONE)
@@ -91,6 +95,7 @@ public final class IndexPrivilege extends Privilege {
.put("view_index_metadata", VIEW_METADATA)
.put("read_cross_cluster", READ_CROSS_CLUSTER)
.put("manage_follow_index", MANAGE_FOLLOW_INDEX)
+ .put("manage_ilm", MANAGE_ILM)
.immutableMap();
public static final Predicate ACTION_MATCHER = ALL.predicate();
diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/privilege/PrivilegeTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/privilege/PrivilegeTests.java
index f2bfd8d2d8e6b..58432cdf6c79e 100644
--- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/privilege/PrivilegeTests.java
+++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/privilege/PrivilegeTests.java
@@ -138,4 +138,57 @@ public void testManageCcrPrivilege() {
assertThat(predicate.test("cluster:admin/xpack/whatever"), is(false));
}
+ public void testIlmPrivileges() {
+ {
+ Predicate predicate = ClusterPrivilege.MANAGE_ILM.predicate();
+ // check cluster actions
+ assertThat(predicate.test("cluster:admin/ilm/delete"), is(true));
+ assertThat(predicate.test("cluster:admin/ilm/_move/post"), is(true));
+ assertThat(predicate.test("cluster:admin/ilm/put"), is(true));
+ assertThat(predicate.test("cluster:admin/ilm/start"), is(true));
+ assertThat(predicate.test("cluster:admin/ilm/stop"), is(true));
+ assertThat(predicate.test("cluster:admin/ilm/brand_new_api"), is(true));
+ assertThat(predicate.test("cluster:admin/ilm/get"), is(true));
+ assertThat(predicate.test("cluster:admin/ilm/operation_mode/get"), is(true));
+ // check non-ilm action
+ assertThat(predicate.test("cluster:admin/whatever"), is(false));
+ }
+
+ {
+ Predicate predicate = ClusterPrivilege.READ_ILM.predicate();
+ // check cluster actions
+ assertThat(predicate.test("cluster:admin/ilm/delete"), is(false));
+ assertThat(predicate.test("cluster:admin/ilm/_move/post"), is(false));
+ assertThat(predicate.test("cluster:admin/ilm/put"), is(false));
+ assertThat(predicate.test("cluster:admin/ilm/start"), is(false));
+ assertThat(predicate.test("cluster:admin/ilm/stop"), is(false));
+ assertThat(predicate.test("cluster:admin/ilm/brand_new_api"), is(false));
+ assertThat(predicate.test("cluster:admin/ilm/get"), is(true));
+ assertThat(predicate.test("cluster:admin/ilm/operation_mode/get"), is(true));
+ // check non-ilm action
+ assertThat(predicate.test("cluster:admin/whatever"), is(false));
+ }
+
+ {
+ Predicate predicate = IndexPrivilege.MANAGE_ILM.predicate();
+ // check indices actions
+ assertThat(predicate.test("indices:admin/ilm/retry"), is(true));
+ assertThat(predicate.test("indices:admin/ilm/remove_policy"), is(true));
+ assertThat(predicate.test("indices:admin/ilm/brand_new_api"), is(true));
+ assertThat(predicate.test("indices:admin/ilm/explain"), is(true));
+ // check non-ilm action
+ assertThat(predicate.test("indices:admin/whatever"), is(false));
+ }
+
+ {
+ Predicate predicate = IndexPrivilege.VIEW_METADATA.predicate();
+ // check indices actions
+ assertThat(predicate.test("indices:admin/ilm/retry"), is(false));
+ assertThat(predicate.test("indices:admin/ilm/remove_policy"), is(false));
+ assertThat(predicate.test("indices:admin/ilm/brand_new_api"), is(false));
+ assertThat(predicate.test("indices:admin/ilm/explain"), is(true));
+ // check non-ilm action
+ assertThat(predicate.test("indices:admin/whatever"), is(false));
+ }
+ }
}
diff --git a/x-pack/plugin/ilm/qa/with-security/roles.yml b/x-pack/plugin/ilm/qa/with-security/roles.yml
index baf89bea34568..64d437bbfd291 100644
--- a/x-pack/plugin/ilm/qa/with-security/roles.yml
+++ b/x-pack/plugin/ilm/qa/with-security/roles.yml
@@ -1,8 +1,11 @@
ilm:
cluster:
- monitor
- - manage
+ - manage_ilm
indices:
+ - names: [ 'view-only-*' ]
+ privileges:
+ - view_index_metadata
- names: [ 'ilm-*' ]
privileges:
- monitor
diff --git a/x-pack/plugin/ilm/qa/with-security/src/test/java/org/elasticsearch/xpack/security/PermissionsIT.java b/x-pack/plugin/ilm/qa/with-security/src/test/java/org/elasticsearch/xpack/security/PermissionsIT.java
index 01eb07bb35b4f..a0c21f4614de3 100644
--- a/x-pack/plugin/ilm/qa/with-security/src/test/java/org/elasticsearch/xpack/security/PermissionsIT.java
+++ b/x-pack/plugin/ilm/qa/with-security/src/test/java/org/elasticsearch/xpack/security/PermissionsIT.java
@@ -119,6 +119,13 @@ public void testCanManageIndexWithNoPermissions() throws Exception {
});
}
+ public void testCanViewExplainOnUnmanagedIndex() throws Exception {
+ createIndexAsAdmin("view-only-ilm", indexSettingsWithPolicy, "");
+ Request request = new Request("GET", "/view-only-ilm/_ilm/explain");
+ // test_ilm user has permissions to view
+ assertOK(client().performRequest(request));
+ }
+
private void createNewSingletonPolicy(String policy, String phaseName, LifecycleAction action) throws IOException {
Phase phase = new Phase(phaseName, TimeValue.ZERO, singletonMap(action.getWriteableName(), action));
LifecyclePolicy lifecyclePolicy = new LifecyclePolicy(policy, singletonMap(phase.getName(), phase));
diff --git a/x-pack/plugin/sql/qa/src/main/resources/fulltext.csv-spec b/x-pack/plugin/sql/qa/src/main/resources/fulltext.csv-spec
index 93493ffdc2acb..0cfcf743414b9 100644
--- a/x-pack/plugin/sql/qa/src/main/resources/fulltext.csv-spec
+++ b/x-pack/plugin/sql/qa/src/main/resources/fulltext.csv-spec
@@ -59,14 +59,14 @@ SELECT emp_no, first_name, gender, last_name FROM test_emp WHERE MATCH('first_na
;
multiMatchQueryAllOptions
-SELECT emp_no, first_name, gender, last_name FROM test_emp WHERE MATCH('first_name,last_name', 'Morton', 'slop=1;lenient=true;cutoff_frequency=2;tie_breaker=0.1;use_dis_max=true;fuzzy_rewrite=scoring_boolean;minimum_should_match=1;operator=AND;max_expansions=30;prefix_length=1;analyzer=english;type=best_fields;auto_generate_synonyms_phrase_query=true;fuzzy_transpositions=true');
+SELECT emp_no, first_name, gender, last_name FROM test_emp WHERE MATCH('first_name,last_name', 'Morton', 'slop=1;lenient=true;cutoff_frequency=2;tie_breaker=0.1;fuzzy_rewrite=scoring_boolean;minimum_should_match=1;operator=AND;max_expansions=30;prefix_length=1;analyzer=english;type=best_fields;auto_generate_synonyms_phrase_query=true;fuzzy_transpositions=true');
emp_no:i | first_name:s | gender:s | last_name:s
10095 |Hilari |M |Morton
;
multiMatchQueryWithInMultipleCommaSeparatedStrings
-SELECT emp_no, first_name, gender, last_name FROM test_emp WHERE MATCH('first_name,last_name', 'Morton', 'slop=1;lenient=true', 'cutoff_frequency=2','tie_breaker=0.1;use_dis_max=true;fuzzy_rewrite=scoring_boolean','minimum_should_match=1;operator=AND;max_expansions=30;prefix_length=1;analyzer=english;type=best_fields;auto_generate_synonyms_phrase_query=true;fuzzy_transpositions=true');
+SELECT emp_no, first_name, gender, last_name FROM test_emp WHERE MATCH('first_name,last_name', 'Morton', 'slop=1;lenient=true', 'cutoff_frequency=2','tie_breaker=0.1;fuzzy_rewrite=scoring_boolean','minimum_should_match=1;operator=AND;max_expansions=30;prefix_length=1;analyzer=english;type=best_fields;auto_generate_synonyms_phrase_query=true;fuzzy_transpositions=true');
emp_no:i | first_name:s | gender:s | last_name:s
10095 |Hilari |M |Morton
diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/querydsl/query/MultiMatchQuery.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/querydsl/query/MultiMatchQuery.java
index 81c990f85bdb4..30def4db3dac4 100644
--- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/querydsl/query/MultiMatchQuery.java
+++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/querydsl/query/MultiMatchQuery.java
@@ -6,10 +6,10 @@
package org.elasticsearch.xpack.sql.querydsl.query;
import org.elasticsearch.common.Booleans;
-import org.elasticsearch.index.query.Operator;
-import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
+import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.xpack.sql.expression.predicate.fulltext.MultiMatchQueryPredicate;
import org.elasticsearch.xpack.sql.tree.Location;
@@ -32,7 +32,6 @@ public class MultiMatchQuery extends LeafQuery {
appliers.put("lenient", (qb, s) -> qb.lenient(Booleans.parseBoolean(s)));
appliers.put("cutoff_frequency", (qb, s) -> qb.cutoffFrequency(Float.valueOf(s)));
appliers.put("tie_breaker", (qb, s) -> qb.tieBreaker(Float.valueOf(s)));
- appliers.put("use_dis_max", (qb, s) -> qb.useDisMax(Booleans.parseBoolean(s)));
appliers.put("fuzzy_rewrite", (qb, s) -> qb.fuzzyRewrite(s));
appliers.put("minimum_should_match", (qb, s) -> qb.minimumShouldMatch(s));
appliers.put("operator", (qb, s) -> qb.operator(Operator.fromString(s)));
diff --git a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/querydsl/query/MultiMatchQueryTests.java b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/querydsl/query/MultiMatchQueryTests.java
index ba2d548cde9dd..2e26c7c0595c2 100644
--- a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/querydsl/query/MultiMatchQueryTests.java
+++ b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/querydsl/query/MultiMatchQueryTests.java
@@ -23,8 +23,7 @@ public void testQueryBuilding() {
MultiMatchQueryBuilder qb = getBuilder("lenient=true");
assertThat(qb.lenient(), equalTo(true));
- qb = getBuilder("use_dis_max=true;type=best_fields");
- assertThat(qb.useDisMax(), equalTo(true));
+ qb = getBuilder("type=best_fields");
assertThat(qb.getType(), equalTo(MultiMatchQueryBuilder.Type.BEST_FIELDS));
Exception e = expectThrows(IllegalArgumentException.class, () -> getBuilder("pizza=yummy"));