shield: refresh on user and role modifications by default

This commit introduces the default refresh on user and role update and delete
operations. The behavior can be controlled via the `refresh` parameter on the
REST API and the refresh option in the Java API.

Closes elastic/elasticsearch#1494

Original commit: elastic/x-pack-elasticsearch@aff4d13886
This commit is contained in:
jaymode 2016-02-25 20:43:17 -05:00
parent ab3ee46104
commit d46f465ddb
16 changed files with 120 additions and 37 deletions

View File

@ -20,6 +20,7 @@ import static org.elasticsearch.action.ValidateActions.addValidationError;
public class DeleteRoleRequest extends ActionRequest<DeleteRoleRequest> {
private String name;
private boolean refresh = true;
public DeleteRoleRequest() {
}
@ -41,15 +42,25 @@ public class DeleteRoleRequest extends ActionRequest<DeleteRoleRequest> {
return name;
}
public void refresh(boolean refresh) {
this.refresh = refresh;
}
public boolean refresh() {
return refresh;
}
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
name = in.readString();
refresh = in.readBoolean();
}
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeString(name);
out.writeBoolean(refresh);
}
}

View File

@ -25,4 +25,9 @@ public class DeleteRoleRequestBuilder extends ActionRequestBuilder<DeleteRoleReq
request.name(name);
return this;
}
public DeleteRoleRequestBuilder refresh(boolean refresh) {
request.refresh(refresh);
return this;
}
}

View File

@ -30,6 +30,7 @@ public class PutRoleRequest extends ActionRequest<PutRoleRequest> {
private String[] clusterPrivileges = Strings.EMPTY_ARRAY;
private List<RoleDescriptor.IndicesPrivileges> indicesPrivileges = new ArrayList<>();
private String[] runAs = Strings.EMPTY_ARRAY;
private boolean refresh = true;
public PutRoleRequest() {
}
@ -68,6 +69,10 @@ public class PutRoleRequest extends ActionRequest<PutRoleRequest> {
this.runAs = usernames;
}
public void refresh(boolean refresh) {
this.refresh = refresh;
}
public String name() {
return name;
}
@ -84,6 +89,10 @@ public class PutRoleRequest extends ActionRequest<PutRoleRequest> {
return runAs;
}
public boolean refresh() {
return refresh;
}
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
@ -95,6 +104,7 @@ public class PutRoleRequest extends ActionRequest<PutRoleRequest> {
indicesPrivileges.add(RoleDescriptor.IndicesPrivileges.createFrom(in));
}
runAs = in.readStringArray();
refresh = in.readBoolean();
}
@Override
@ -107,6 +117,7 @@ public class PutRoleRequest extends ActionRequest<PutRoleRequest> {
index.writeTo(out);
}
out.writeStringArray(runAs);
out.writeBoolean(refresh);
}
RoleDescriptor roleDescriptor() {

View File

@ -53,4 +53,9 @@ public class PutRoleRequestBuilder extends ActionRequestBuilder<PutRoleRequest,
request.addIndex(indices, privileges, fields, query);
return this;
}
public PutRoleRequestBuilder refresh(boolean refresh) {
request.refresh(refresh);
return this;
}
}

View File

@ -29,7 +29,7 @@ public class TransportPutRoleAction extends HandledTransportAction<PutRoleReques
@Override
protected void doExecute(final PutRoleRequest request, final ActionListener<PutRoleResponse> listener) {
rolesStore.putRole(request.roleDescriptor(), new ActionListener<Boolean>() {
rolesStore.putRole(request, request.roleDescriptor(), new ActionListener<Boolean>() {
@Override
public void onResponse(Boolean created) {
if (created) {

View File

@ -20,6 +20,7 @@ import static org.elasticsearch.action.ValidateActions.addValidationError;
public class DeleteUserRequest extends ActionRequest<DeleteUserRequest> {
private String username;
private boolean refresh = true;
public DeleteUserRequest() {
}
@ -41,20 +42,30 @@ public class DeleteUserRequest extends ActionRequest<DeleteUserRequest> {
return this.username;
}
public boolean refresh() {
return refresh;
}
public void username(String username) {
this.username = username;
}
public void refresh(boolean refresh) {
this.refresh = refresh;
}
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
username = in.readString();
refresh = in.readBoolean();
}
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeString(username);
out.writeBoolean(refresh);
}
}

View File

@ -22,4 +22,9 @@ public class DeleteUserRequestBuilder extends ActionRequestBuilder<DeleteUserReq
request.username(username);
return this;
}
public DeleteUserRequestBuilder refresh(boolean refresh) {
request.refresh(refresh);
return this;
}
}

View File

@ -27,6 +27,7 @@ public class PutUserRequest extends ActionRequest<PutUserRequest> {
private String email;
private Map<String, Object> metadata;
private char[] passwordHash;
private boolean refresh = true;
public PutUserRequest() {
}
@ -70,6 +71,10 @@ public class PutUserRequest extends ActionRequest<PutUserRequest> {
this.passwordHash = passwordHash;
}
public void refresh(boolean refresh) {
this.refresh = refresh;
}
public String username() {
return username;
}
@ -94,6 +99,10 @@ public class PutUserRequest extends ActionRequest<PutUserRequest> {
return passwordHash;
}
public boolean refresh() {
return refresh;
}
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
@ -103,6 +112,7 @@ public class PutUserRequest extends ActionRequest<PutUserRequest> {
fullName = in.readOptionalString();
email = in.readOptionalString();
metadata = in.readBoolean() ? in.readMap() : null;
refresh = in.readBoolean();
}
@Override
@ -119,5 +129,6 @@ public class PutUserRequest extends ActionRequest<PutUserRequest> {
out.writeBoolean(true);
out.writeMap(metadata);
}
out.writeBoolean(refresh);
}
}

View File

@ -64,6 +64,11 @@ public class PutUserRequestBuilder extends ActionRequestBuilder<PutUserRequest,
return this;
}
public PutUserRequestBuilder refresh(boolean refresh) {
request.refresh(refresh);
return this;
}
public PutUserRequestBuilder source(String username, BytesReference source) throws IOException {
username(username);
try (XContentParser parser = XContentHelper.createParser(source)) {

View File

@ -302,6 +302,7 @@ public class ESNativeUsersStore extends AbstractComponent implements ClusterStat
User.Fields.FULL_NAME.getPreferredName(), request.fullName(),
User.Fields.EMAIL.getPreferredName(), request.email(),
User.Fields.METADATA.getPreferredName(), request.metadata())
.setRefresh(request.refresh())
.request();
client.index(indexRequest, new ActionListener<IndexResponse>() {
@ -337,6 +338,7 @@ public class ESNativeUsersStore extends AbstractComponent implements ClusterStat
DeleteRequest request = client.prepareDelete(ShieldTemplateService.SECURITY_INDEX_NAME,
USER_DOC_TYPE, deleteUserRequest.username()).request();
request.indicesOptions().ignoreUnavailable();
request.refresh(deleteUserRequest.refresh());
client.delete(request, new ActionListener<DeleteResponse>() {
@Override
public void onResponse(DeleteResponse deleteResponse) {

View File

@ -34,6 +34,7 @@ import org.elasticsearch.common.util.concurrent.FutureUtils;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.gateway.GatewayService;
import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.index.get.GetResult;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
@ -42,6 +43,7 @@ import org.elasticsearch.shield.ShieldTemplateService;
import org.elasticsearch.shield.action.role.ClearRolesCacheRequest;
import org.elasticsearch.shield.action.role.ClearRolesCacheResponse;
import org.elasticsearch.shield.action.role.DeleteRoleRequest;
import org.elasticsearch.shield.action.role.PutRoleRequest;
import org.elasticsearch.shield.authc.AuthenticationService;
import org.elasticsearch.shield.authz.RoleDescriptor;
import org.elasticsearch.shield.authz.permission.Role;
@ -257,7 +259,7 @@ public class ESNativeRolesStore extends AbstractComponent implements RolesStore,
try {
DeleteRequest request = client.prepareDelete(ShieldTemplateService.SECURITY_INDEX_NAME,
ROLE_DOC_TYPE, deleteRoleRequest.name()).request();
request.indicesOptions().ignoreUnavailable();
request.refresh(deleteRoleRequest.refresh());
client.delete(request, new ActionListener<DeleteResponse>() {
@Override
public void onResponse(DeleteResponse deleteResponse) {
@ -270,13 +272,16 @@ public class ESNativeRolesStore extends AbstractComponent implements RolesStore,
listener.onFailure(e);
}
});
} catch (IndexNotFoundException e) {
logger.trace("security index does not exist", e);
listener.onResponse(false);
} catch (Exception e) {
logger.error("unable to remove role", e);
listener.onFailure(e);
}
}
public void putRole(final RoleDescriptor role, final ActionListener<Boolean> listener) {
public void putRole(final PutRoleRequest request, final RoleDescriptor role, final ActionListener<Boolean> listener) {
if (state() != State.STARTED) {
logger.trace("attempted to put role before service was started");
listener.onResponse(false);
@ -284,6 +289,7 @@ public class ESNativeRolesStore extends AbstractComponent implements RolesStore,
try {
client.prepareIndex(ShieldTemplateService.SECURITY_INDEX_NAME, ROLE_DOC_TYPE, role.getName())
.setSource(role.toXContent(jsonBuilder(), ToXContent.EMPTY_PARAMS))
.setRefresh(request.refresh())
.execute(new ActionListener<IndexResponse>() {
@Override
public void onResponse(IndexResponse indexResponse) {
@ -363,8 +369,11 @@ public class ESNativeRolesStore extends AbstractComponent implements RolesStore,
private void executeGetRoleRequest(String role, ActionListener<GetResponse> listener) {
try {
GetRequest request = client.prepareGet(ShieldTemplateService.SECURITY_INDEX_NAME, ROLE_DOC_TYPE, role).request();
request.indicesOptions().ignoreUnavailable();
client.get(request, listener);
} catch (IndexNotFoundException e) {
logger.trace("security index does not exist", e);
listener.onResponse(new GetResponse(
new GetResult(ShieldTemplateService.SECURITY_INDEX_NAME, ROLE_DOC_TYPE, role, -1, false, null, null)));
} catch (Exception e) {
logger.error("unable to retrieve role", e);
listener.onFailure(e);

View File

@ -17,6 +17,7 @@ import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.RestResponse;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.rest.action.support.RestBuilderListener;
import org.elasticsearch.shield.action.role.DeleteRoleRequestBuilder;
import org.elasticsearch.shield.action.role.DeleteRoleResponse;
import org.elasticsearch.shield.client.SecurityClient;
@ -33,7 +34,11 @@ public class RestDeleteRoleAction extends BaseRestHandler {
@Override
protected void handleRequest(RestRequest request, final RestChannel channel, Client client) throws Exception {
new SecurityClient(client).prepareDeleteRole(request.param("name")).execute(new RestBuilderListener<DeleteRoleResponse>(channel) {
DeleteRoleRequestBuilder requestBuilder = new SecurityClient(client).prepareDeleteRole(request.param("name"));
if (request.hasParam("refresh")) {
requestBuilder.refresh(request.paramAsBoolean("refresh", true));
}
requestBuilder.execute(new RestBuilderListener<DeleteRoleResponse>(channel) {
@Override
public RestResponse buildResponse(DeleteRoleResponse response, XContentBuilder builder) throws Exception {
return new BytesRestResponse(response.found() ? RestStatus.OK : RestStatus.NOT_FOUND,

View File

@ -17,6 +17,7 @@ import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.RestResponse;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.rest.action.support.RestBuilderListener;
import org.elasticsearch.shield.action.role.PutRoleRequestBuilder;
import org.elasticsearch.shield.action.role.PutRoleResponse;
import org.elasticsearch.shield.client.SecurityClient;
@ -34,8 +35,11 @@ public class RestPutRoleAction extends BaseRestHandler {
@Override
protected void handleRequest(RestRequest request, final RestChannel channel, Client client) throws Exception {
new SecurityClient(client).preparePutRole(request.param("name"), request.content()).execute(
new RestBuilderListener<PutRoleResponse>(channel) {
PutRoleRequestBuilder requestBuilder = new SecurityClient(client).preparePutRole(request.param("name"), request.content());
if (request.hasParam("refresh")) {
requestBuilder.refresh(request.paramAsBoolean("refresh", true));
}
requestBuilder.execute(new RestBuilderListener<PutRoleResponse>(channel) {
@Override
public RestResponse buildResponse(PutRoleResponse putRoleResponse, XContentBuilder builder) throws Exception {
return new BytesRestResponse(RestStatus.OK,

View File

@ -18,6 +18,7 @@ import org.elasticsearch.rest.RestResponse;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.rest.action.support.RestBuilderListener;
import org.elasticsearch.shield.action.user.DeleteUserRequest;
import org.elasticsearch.shield.action.user.DeleteUserRequestBuilder;
import org.elasticsearch.shield.action.user.DeleteUserResponse;
import org.elasticsearch.shield.client.SecurityClient;
@ -36,7 +37,11 @@ public class RestDeleteUserAction extends BaseRestHandler {
protected void handleRequest(RestRequest request, final RestChannel channel, Client client) throws Exception {
String username = request.param("username");
new SecurityClient(client).prepareDeleteUser(username).execute(new RestBuilderListener<DeleteUserResponse>(channel) {
DeleteUserRequestBuilder requestBuilder = new SecurityClient(client).prepareDeleteUser(username);
if (request.hasParam("refresh")) {
requestBuilder.refresh(request.paramAsBoolean("refresh", true));
}
requestBuilder.execute(new RestBuilderListener<DeleteUserResponse>(channel) {
@Override
public RestResponse buildResponse(DeleteUserResponse response, XContentBuilder builder) throws Exception {
return new BytesRestResponse(response.found() ? RestStatus.OK : RestStatus.NOT_FOUND,

View File

@ -17,6 +17,7 @@ import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.RestResponse;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.rest.action.support.RestBuilderListener;
import org.elasticsearch.shield.action.user.PutUserRequestBuilder;
import org.elasticsearch.shield.action.user.PutUserResponse;
import org.elasticsearch.shield.client.SecurityClient;
@ -34,8 +35,11 @@ public class RestPutUserAction extends BaseRestHandler {
@Override
protected void handleRequest(RestRequest request, final RestChannel channel, Client client) throws Exception {
new SecurityClient(client).preparePutUser(request.param("username"), request.content())
.execute(new RestBuilderListener<PutUserResponse>(channel) {
PutUserRequestBuilder requestBuilder = new SecurityClient(client).preparePutUser(request.param("username"), request.content());
if (request.hasParam("refresh")) {
requestBuilder.refresh(request.paramAsBoolean("refresh", true));
}
requestBuilder.execute(new RestBuilderListener<PutUserResponse>(channel) {
@Override
public RestResponse buildResponse(PutUserResponse putUserResponse, XContentBuilder builder) throws Exception {
return new BytesRestResponse(RestStatus.OK,

View File

@ -74,8 +74,6 @@ public class ESNativeTests extends ShieldIntegTestCase {
logger.info("--> adding two more users");
c.preparePutUser("joe2", "s3kirt2".toCharArray(), "role2", "user").get();
c.preparePutUser("joe3", "s3kirt3".toCharArray(), "role3", "user").get();
// Since getting multiple users relies on them being visible to search, perform a refresh
refresh();
GetUsersResponse allUsersResp = c.prepareGetUsers().get();
assertTrue("users should exist", allUsersResp.hasUsers());
assertEquals("should be 3 users total", 3, allUsersResp.users().length);
@ -134,9 +132,6 @@ public class ESNativeTests extends ShieldIntegTestCase {
new String[]{"body", "title"}, new BytesArray("{\"query\": {\"match_all\": {}}}"))
.get();
// Refresh to make new roles visible
refresh();
logger.info("--> retrieving all roles");
GetRolesResponse allRolesResp = c.prepareGetRoles().get();
assertTrue("roles should exist", allRolesResp.hasRoles());
@ -165,7 +160,6 @@ public class ESNativeTests extends ShieldIntegTestCase {
.get();
logger.error("--> creating user");
c.preparePutUser("joe", "s3krit".toCharArray(), "test_role").get();
refresh();
logger.error("--> waiting for .shield index");
ensureGreen(ShieldTemplateService.SECURITY_INDEX_NAME);
logger.info("--> retrieving user");
@ -187,7 +181,6 @@ public class ESNativeTests extends ShieldIntegTestCase {
SecurityClient c = securityClient();
logger.error("--> creating user");
c.preparePutUser("joe", "s3krit".toCharArray(), ShieldSettingsSource.DEFAULT_ROLE).get();
refresh();
logger.error("--> waiting for .shield index");
ensureGreen(ShieldTemplateService.SECURITY_INDEX_NAME);
logger.info("--> retrieving user");
@ -223,7 +216,6 @@ public class ESNativeTests extends ShieldIntegTestCase {
SecurityClient c = securityClient();
logger.error("--> creating user");
c.preparePutUser("joe", "s3krit".toCharArray(), ShieldSettingsSource.DEFAULT_ROLE).get();
refresh();
logger.error("--> waiting for .shield index");
ensureGreen(ShieldTemplateService.SECURITY_INDEX_NAME);
logger.info("--> retrieving user");
@ -262,7 +254,6 @@ public class ESNativeTests extends ShieldIntegTestCase {
.get();
logger.error("--> creating user");
c.preparePutUser("joe", "s3krit".toCharArray(), "test_role").get();
refresh();
logger.error("--> waiting for .shield index");
ensureGreen(ShieldTemplateService.SECURITY_INDEX_NAME);
@ -310,7 +301,6 @@ public class ESNativeTests extends ShieldIntegTestCase {
new String[]{"body", "title"}, new BytesArray("{\"match_all\": {}}"))
.get();
c.preparePutUser("joe", "s3krit".toCharArray(), "test_role").get();
refresh();
logger.error("--> waiting for .shield index");
ensureGreen(ShieldTemplateService.SECURITY_INDEX_NAME);