From 590eea57acd2850e497d05b34fb3ad6ca0b3bb11 Mon Sep 17 00:00:00 2001 From: Jay Modi Date: Tue, 9 May 2017 14:47:11 -0400 Subject: [PATCH] Add a base security rest handler (elastic/x-pack-elasticsearch#1239) This commit adds a base rest handler for security that handles the license checking in the security apis. This was done previously in some rest handlers but not all and actually had issues where a value would be returned but we may not have consumed all of the request parameters, which could lead to a different response being returned than what we would have expected. relates elastic/x-pack-elasticsearch#1236 Original commit: elastic/x-pack-elasticsearch@2f1100b64a517c58c6f0b6818bfc5ec64e28d663 --- .../xpack/security/Security.java | 32 +++++----- .../rest/action/RestAuthenticateAction.java | 21 ++----- .../rest/action/SecurityBaseRestHandler.java | 62 +++++++++++++++++++ .../action/oauth2/RestGetTokenAction.java | 21 ++----- .../oauth2/RestInvalidateTokenAction.java | 23 ++----- .../realm/RestClearRealmCacheAction.java | 13 ++-- .../role/RestClearRolesCacheAction.java | 13 ++-- .../action/role/RestDeleteRoleAction.java | 12 ++-- .../rest/action/role/RestGetRolesAction.java | 11 ++-- .../rest/action/role/RestPutRoleAction.java | 12 ++-- .../RestDeleteRoleMappingAction.java | 12 ++-- .../RestGetRoleMappingsAction.java | 14 ++--- .../rolemapping/RestPutRoleMappingAction.java | 14 ++--- .../action/user/RestChangePasswordAction.java | 18 +++--- .../action/user/RestDeleteUserAction.java | 12 ++-- .../rest/action/user/RestGetUsersAction.java | 12 ++-- .../action/user/RestHasPrivilegesAction.java | 12 ++-- .../rest/action/user/RestPutUserAction.java | 11 ++-- .../action/user/RestSetEnabledAction.java | 11 ++-- .../action/SecurityBaseRestHandlerTests.java | 60 ++++++++++++++++++ 20 files changed, 251 insertions(+), 145 deletions(-) create mode 100644 plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/SecurityBaseRestHandler.java create mode 100644 plugin/src/test/java/org/elasticsearch/xpack/security/rest/action/SecurityBaseRestHandlerTests.java diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/Security.java b/plugin/src/main/java/org/elasticsearch/xpack/security/Security.java index 1ad4aada617..20e892e07f0 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/Security.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/Security.java @@ -586,22 +586,22 @@ public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin { } return Arrays.asList( new RestAuthenticateAction(settings, restController, securityContext.get(), licenseState), - new RestClearRealmCacheAction(settings, restController), - new RestClearRolesCacheAction(settings, restController), - new RestGetUsersAction(settings, restController), - new RestPutUserAction(settings, restController), - new RestDeleteUserAction(settings, restController), - new RestGetRolesAction(settings, restController), - new RestPutRoleAction(settings, restController), - new RestDeleteRoleAction(settings, restController), - new RestChangePasswordAction(settings, restController, securityContext.get()), - new RestSetEnabledAction(settings, restController), - new RestHasPrivilegesAction(settings, restController, securityContext.get()), - new RestGetRoleMappingsAction(settings, restController), - new RestPutRoleMappingAction(settings, restController), - new RestDeleteRoleMappingAction(settings, restController), - new RestGetTokenAction(settings, licenseState, restController), - new RestInvalidateTokenAction(settings, licenseState, restController) + new RestClearRealmCacheAction(settings, restController, licenseState), + new RestClearRolesCacheAction(settings, restController, licenseState), + new RestGetUsersAction(settings, restController, licenseState), + new RestPutUserAction(settings, restController, licenseState), + new RestDeleteUserAction(settings, restController, licenseState), + new RestGetRolesAction(settings, restController, licenseState), + new RestPutRoleAction(settings, restController, licenseState), + new RestDeleteRoleAction(settings, restController, licenseState), + new RestChangePasswordAction(settings, restController, securityContext.get(), licenseState), + new RestSetEnabledAction(settings, restController, licenseState), + new RestHasPrivilegesAction(settings, restController, securityContext.get(), licenseState), + new RestGetRoleMappingsAction(settings, restController, licenseState), + new RestPutRoleMappingAction(settings, restController, licenseState), + new RestDeleteRoleMappingAction(settings, restController, licenseState), + new RestGetTokenAction(settings, restController, licenseState), + new RestInvalidateTokenAction(settings, restController, licenseState) ); } diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/RestAuthenticateAction.java b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/RestAuthenticateAction.java index 4a453813dfb..4fa2e5b1b17 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/RestAuthenticateAction.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/RestAuthenticateAction.java @@ -9,16 +9,13 @@ import org.elasticsearch.client.node.NodeClient; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.license.LicenseUtils; import org.elasticsearch.license.XPackLicenseState; -import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.BytesRestResponse; import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.RestResponse; import org.elasticsearch.rest.RestStatus; import org.elasticsearch.rest.action.RestBuilderListener; -import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.security.SecurityContext; import org.elasticsearch.xpack.security.action.user.AuthenticateAction; import org.elasticsearch.xpack.security.action.user.AuthenticateRequest; @@ -29,16 +26,14 @@ import java.io.IOException; import static org.elasticsearch.rest.RestRequest.Method.GET; -public class RestAuthenticateAction extends BaseRestHandler { +public class RestAuthenticateAction extends SecurityBaseRestHandler { private final SecurityContext securityContext; - private final XPackLicenseState licenseState; public RestAuthenticateAction(Settings settings, RestController controller, SecurityContext securityContext, XPackLicenseState licenseState) { - super(settings); + super(settings, licenseState); this.securityContext = securityContext; - this.licenseState = licenseState; controller.registerHandler(GET, "/_xpack/security/_authenticate", this); // @deprecated: Remove in 6.0 @@ -49,15 +44,11 @@ public class RestAuthenticateAction extends BaseRestHandler { } @Override - public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { - // this API is a special case since we access the user here and we want it to fail with the proper error instead of a request - // validation error - if (licenseState.isAuthAllowed() == false) { - throw LicenseUtils.newComplianceException(XPackPlugin.SECURITY); - } - + public RestChannelConsumer innerPrepareRequest(RestRequest request, NodeClient client) throws IOException { final User user = securityContext.getUser(); - assert user != null; + if (user == null) { + return restChannel -> { throw new IllegalStateException("we should never have a null user and invoke this consumer"); }; + } final String username = user.runAs() == null ? user.principal() : user.runAs().principal(); return channel -> client.execute(AuthenticateAction.INSTANCE, new AuthenticateRequest(username), diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/SecurityBaseRestHandler.java b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/SecurityBaseRestHandler.java new file mode 100644 index 00000000000..ee2670d9935 --- /dev/null +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/SecurityBaseRestHandler.java @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.security.rest.action; + +import org.elasticsearch.client.node.NodeClient; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.license.LicenseUtils; +import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.rest.BaseRestHandler; +import org.elasticsearch.rest.BytesRestResponse; +import org.elasticsearch.rest.RestRequest; + +import java.io.IOException; + +import static org.elasticsearch.xpack.XPackPlugin.SECURITY; + +/** + * Base class for security rest handlers. This handler takes care of ensuring that the license + * level is valid so that security can be used! + */ +public abstract class SecurityBaseRestHandler extends BaseRestHandler { + + protected final XPackLicenseState licenseState; + + /** + * @param settings the node's settings + * @param licenseState the license state that will be used to determine if security is licensed + */ + protected SecurityBaseRestHandler(Settings settings, XPackLicenseState licenseState) { + super(settings); + this.licenseState = licenseState; + } + + /** + * Calls the {@link #innerPrepareRequest(RestRequest, NodeClient)} method and then checks the + * license state. If the license state allows auth, the result from + * {@link #innerPrepareRequest(RestRequest, NodeClient)} is returned, otherwise a default error + * response will be returned indicating that security is not licensed. + * + * Note: the implementing rest handler is called before the license is checked so that we do not + * trip the unused parameters check + */ + protected final RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { + RestChannelConsumer consumer = innerPrepareRequest(request, client); + if (licenseState.isAuthAllowed()) { + return consumer; + } else { + return channel -> channel.sendResponse(new BytesRestResponse(channel, LicenseUtils.newComplianceException(SECURITY))); + } + } + + /** + * Implementers should implement this method as they normally would for + * {@link BaseRestHandler#prepareRequest(RestRequest, NodeClient)} and ensure that all request + * parameters are consumed prior to returning a value. The returned value is not guaranteed to + * be executed unless security is licensed and all request parameters are known + */ + protected abstract RestChannelConsumer innerPrepareRequest(RestRequest request, NodeClient client) throws IOException; +} diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/oauth2/RestGetTokenAction.java b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/oauth2/RestGetTokenAction.java index b756fe208fa..dffd2c34749 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/oauth2/RestGetTokenAction.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/oauth2/RestGetTokenAction.java @@ -16,18 +16,16 @@ import org.elasticsearch.common.xcontent.ConstructingObjectParser; import org.elasticsearch.common.xcontent.ObjectParser.ValueType; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.license.LicenseUtils; import org.elasticsearch.license.XPackLicenseState; -import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.BytesRestResponse; import org.elasticsearch.rest.RestChannel; import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.RestStatus; -import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.security.action.token.CreateTokenAction; import org.elasticsearch.xpack.security.action.token.CreateTokenRequest; import org.elasticsearch.xpack.security.action.token.CreateTokenResponse; +import org.elasticsearch.xpack.security.rest.action.SecurityBaseRestHandler; import java.io.IOException; import java.util.Arrays; @@ -42,7 +40,7 @@ import static org.elasticsearch.rest.RestRequest.Method.POST; * specification as this aspect does not make the most sense since the response body is * expected to be JSON */ -public final class RestGetTokenAction extends BaseRestHandler { +public final class RestGetTokenAction extends SecurityBaseRestHandler { static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>("token_request", a -> new CreateTokenRequest((String) a[0], (String) a[1], (SecureString) a[2], (String) a[3])); @@ -55,22 +53,13 @@ public final class RestGetTokenAction extends BaseRestHandler { PARSER.declareString(ConstructingObjectParser.optionalConstructorArg(), new ParseField("scope")); } - private final XPackLicenseState licenseState; - - public RestGetTokenAction(Settings settings, XPackLicenseState xPackLicenseState, RestController controller) { - super(settings); - this.licenseState = xPackLicenseState; + public RestGetTokenAction(Settings settings, RestController controller, XPackLicenseState xPackLicenseState) { + super(settings, xPackLicenseState); controller.registerHandler(POST, "/_xpack/security/oauth2/token", this); } @Override - protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client)throws IOException { - // this API shouldn't be available if security is disabled by license - if (licenseState.isAuthAllowed() == false) { - return channel -> - channel.sendResponse(new BytesRestResponse(channel, LicenseUtils.newComplianceException(XPackPlugin.SECURITY))); - } - + protected RestChannelConsumer innerPrepareRequest(RestRequest request, NodeClient client)throws IOException { try (XContentParser parser = request.contentParser()) { final CreateTokenRequest tokenRequest = PARSER.parse(parser, null); return channel -> client.execute(CreateTokenAction.INSTANCE, tokenRequest, diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/oauth2/RestInvalidateTokenAction.java b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/oauth2/RestInvalidateTokenAction.java index 318ab902f25..e6a1199d372 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/oauth2/RestInvalidateTokenAction.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/oauth2/RestInvalidateTokenAction.java @@ -11,19 +11,17 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.ConstructingObjectParser; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.license.LicenseUtils; import org.elasticsearch.license.XPackLicenseState; -import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.BytesRestResponse; import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.RestResponse; import org.elasticsearch.rest.RestStatus; import org.elasticsearch.rest.action.RestBuilderListener; -import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.security.action.token.InvalidateTokenAction; import org.elasticsearch.xpack.security.action.token.InvalidateTokenRequest; import org.elasticsearch.xpack.security.action.token.InvalidateTokenResponse; +import org.elasticsearch.xpack.security.rest.action.SecurityBaseRestHandler; import java.io.IOException; @@ -32,7 +30,7 @@ import static org.elasticsearch.rest.RestRequest.Method.DELETE; /** * Rest handler for handling access token invalidation requests */ -public final class RestInvalidateTokenAction extends BaseRestHandler { +public final class RestInvalidateTokenAction extends SecurityBaseRestHandler { static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>("invalidate_token", a -> ((String) a[0])); @@ -40,24 +38,13 @@ public final class RestInvalidateTokenAction extends BaseRestHandler { PARSER.declareString(ConstructingObjectParser.constructorArg(), new ParseField("token")); } - private final XPackLicenseState licenseState; - - public RestInvalidateTokenAction(Settings settings, XPackLicenseState xPackLicenseState, - RestController controller) { - super(settings); - this.licenseState = xPackLicenseState; + public RestInvalidateTokenAction(Settings settings, RestController controller, XPackLicenseState xPackLicenseState) { + super(settings, xPackLicenseState); controller.registerHandler(DELETE, "/_xpack/security/oauth2/token", this); } @Override - protected RestChannelConsumer prepareRequest(RestRequest request, - NodeClient client)throws IOException { - // this API shouldn't be available if security is disabled by license - if (licenseState.isAuthAllowed() == false) { - return channel -> - channel.sendResponse(new BytesRestResponse(channel, LicenseUtils.newComplianceException(XPackPlugin.SECURITY))); - } - + protected RestChannelConsumer innerPrepareRequest(RestRequest request, NodeClient client) throws IOException { try (XContentParser parser = request.contentParser()) { final String token = PARSER.parse(parser, null); final InvalidateTokenRequest tokenRequest = new InvalidateTokenRequest(token); diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/realm/RestClearRealmCacheAction.java b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/realm/RestClearRealmCacheAction.java index ecd94e40f8b..7b488cd0d36 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/realm/RestClearRealmCacheAction.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/realm/RestClearRealmCacheAction.java @@ -7,20 +7,22 @@ package org.elasticsearch.xpack.security.rest.action.realm; import org.elasticsearch.client.node.NodeClient; import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.rest.BaseRestHandler; +import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.action.RestActions.NodesResponseRestListener; import org.elasticsearch.xpack.security.action.realm.ClearRealmCacheRequest; import org.elasticsearch.xpack.security.client.SecurityClient; +import org.elasticsearch.xpack.security.rest.action.SecurityBaseRestHandler; import java.io.IOException; import static org.elasticsearch.rest.RestRequest.Method.POST; -public class RestClearRealmCacheAction extends BaseRestHandler { - public RestClearRealmCacheAction(Settings settings, RestController controller) { - super(settings); +public final class RestClearRealmCacheAction extends SecurityBaseRestHandler { + + public RestClearRealmCacheAction(Settings settings, RestController controller, XPackLicenseState licenseState) { + super(settings, licenseState); controller.registerHandler(POST, "/_xpack/security/realm/{realms}/_clear_cache", this); // @deprecated: Remove in 6.0 @@ -35,8 +37,7 @@ public class RestClearRealmCacheAction extends BaseRestHandler { } @Override - public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { - + public RestChannelConsumer innerPrepareRequest(RestRequest request, NodeClient client) throws IOException { String[] realms = request.paramAsStringArrayOrEmptyIfAll("realms"); String[] usernames = request.paramAsStringArrayOrEmptyIfAll("usernames"); diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/role/RestClearRolesCacheAction.java b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/role/RestClearRolesCacheAction.java index 827becffd84..100b8587354 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/role/RestClearRolesCacheAction.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/role/RestClearRolesCacheAction.java @@ -7,20 +7,22 @@ package org.elasticsearch.xpack.security.rest.action.role; import org.elasticsearch.client.node.NodeClient; import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.rest.BaseRestHandler; +import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.action.RestActions.NodesResponseRestListener; import org.elasticsearch.xpack.security.action.role.ClearRolesCacheRequest; import org.elasticsearch.xpack.security.client.SecurityClient; +import org.elasticsearch.xpack.security.rest.action.SecurityBaseRestHandler; import java.io.IOException; import static org.elasticsearch.rest.RestRequest.Method.POST; -public class RestClearRolesCacheAction extends BaseRestHandler { - public RestClearRolesCacheAction(Settings settings, RestController controller) { - super(settings); +public final class RestClearRolesCacheAction extends SecurityBaseRestHandler { + + public RestClearRolesCacheAction(Settings settings, RestController controller, XPackLicenseState licenseState) { + super(settings, licenseState); controller.registerHandler(POST, "/_xpack/security/role/{name}/_clear_cache", this); // @deprecated: Remove in 6.0 @@ -31,8 +33,7 @@ public class RestClearRolesCacheAction extends BaseRestHandler { } @Override - public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { - + public RestChannelConsumer innerPrepareRequest(RestRequest request, NodeClient client) throws IOException { String[] roles = request.paramAsStringArrayOrEmptyIfAll("name"); ClearRolesCacheRequest req = new ClearRolesCacheRequest().names(roles); diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/role/RestDeleteRoleAction.java b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/role/RestDeleteRoleAction.java index 8968a8da015..37f0598c280 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/role/RestDeleteRoleAction.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/role/RestDeleteRoleAction.java @@ -8,7 +8,7 @@ package org.elasticsearch.xpack.security.rest.action.role; import org.elasticsearch.client.node.NodeClient; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.rest.BaseRestHandler; +import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.rest.BytesRestResponse; import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestRequest; @@ -17,6 +17,7 @@ import org.elasticsearch.rest.RestStatus; import org.elasticsearch.rest.action.RestBuilderListener; import org.elasticsearch.xpack.security.action.role.DeleteRoleResponse; import org.elasticsearch.xpack.security.client.SecurityClient; +import org.elasticsearch.xpack.security.rest.action.SecurityBaseRestHandler; import java.io.IOException; @@ -25,9 +26,10 @@ import static org.elasticsearch.rest.RestRequest.Method.DELETE; /** * Rest endpoint to delete a Role from the security index */ -public class RestDeleteRoleAction extends BaseRestHandler { - public RestDeleteRoleAction(Settings settings, RestController controller) { - super(settings); +public class RestDeleteRoleAction extends SecurityBaseRestHandler { + + public RestDeleteRoleAction(Settings settings, RestController controller, XPackLicenseState licenseState) { + super(settings, licenseState); controller.registerHandler(DELETE, "/_xpack/security/role/{name}", this); // @deprecated: Remove in 6.0 @@ -38,7 +40,7 @@ public class RestDeleteRoleAction extends BaseRestHandler { } @Override - public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { + public RestChannelConsumer innerPrepareRequest(RestRequest request, NodeClient client) throws IOException { final String name = request.param("name"); final String refresh = request.param("refresh"); diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/role/RestGetRolesAction.java b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/role/RestGetRolesAction.java index aff141540ad..9673896174a 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/role/RestGetRolesAction.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/role/RestGetRolesAction.java @@ -9,7 +9,7 @@ import org.elasticsearch.client.node.NodeClient; import org.elasticsearch.common.Strings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.rest.BaseRestHandler; +import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.rest.BytesRestResponse; import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestRequest; @@ -19,6 +19,7 @@ import org.elasticsearch.rest.action.RestBuilderListener; import org.elasticsearch.xpack.security.action.role.GetRolesResponse; import org.elasticsearch.xpack.security.authz.RoleDescriptor; import org.elasticsearch.xpack.security.client.SecurityClient; +import org.elasticsearch.xpack.security.rest.action.SecurityBaseRestHandler; import java.io.IOException; @@ -27,9 +28,9 @@ import static org.elasticsearch.rest.RestRequest.Method.GET; /** * Rest endpoint to retrieve a Role from the security index */ -public class RestGetRolesAction extends BaseRestHandler { - public RestGetRolesAction(Settings settings, RestController controller) { - super(settings); +public class RestGetRolesAction extends SecurityBaseRestHandler { + public RestGetRolesAction(Settings settings, RestController controller, XPackLicenseState licenseState) { + super(settings, licenseState); controller.registerHandler(GET, "/_xpack/security/role/", this); controller.registerHandler(GET, "/_xpack/security/role/{name}", this); @@ -45,7 +46,7 @@ public class RestGetRolesAction extends BaseRestHandler { } @Override - public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { + public RestChannelConsumer innerPrepareRequest(RestRequest request, NodeClient client) throws IOException { final String[] roles = request.paramAsStringArray("name", Strings.EMPTY_ARRAY); return channel -> new SecurityClient(client).prepareGetRoles(roles).execute(new RestBuilderListener(channel) { @Override diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/role/RestPutRoleAction.java b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/role/RestPutRoleAction.java index 8c6f063964a..18007c15020 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/role/RestPutRoleAction.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/role/RestPutRoleAction.java @@ -8,7 +8,7 @@ package org.elasticsearch.xpack.security.rest.action.role; import org.elasticsearch.client.node.NodeClient; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.rest.BaseRestHandler; +import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.rest.BytesRestResponse; import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestRequest; @@ -18,6 +18,7 @@ import org.elasticsearch.rest.action.RestBuilderListener; import org.elasticsearch.xpack.security.action.role.PutRoleRequestBuilder; import org.elasticsearch.xpack.security.action.role.PutRoleResponse; import org.elasticsearch.xpack.security.client.SecurityClient; +import org.elasticsearch.xpack.security.rest.action.SecurityBaseRestHandler; import java.io.IOException; @@ -27,9 +28,10 @@ import static org.elasticsearch.rest.RestRequest.Method.PUT; /** * Rest endpoint to add a Role to the security index */ -public class RestPutRoleAction extends BaseRestHandler { - public RestPutRoleAction(Settings settings, RestController controller) { - super(settings); +public class RestPutRoleAction extends SecurityBaseRestHandler { + + public RestPutRoleAction(Settings settings, RestController controller, XPackLicenseState licenseState) { + super(settings, licenseState); controller.registerHandler(POST, "/_xpack/security/role/{name}", this); controller.registerHandler(PUT, "/_xpack/security/role/{name}", this); @@ -45,7 +47,7 @@ public class RestPutRoleAction extends BaseRestHandler { } @Override - public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { + public RestChannelConsumer innerPrepareRequest(RestRequest request, NodeClient client) throws IOException { PutRoleRequestBuilder requestBuilder = new SecurityClient(client) .preparePutRole(request.param("name"), request.content(), request.getXContentType()) .setRefreshPolicy(request.param("refresh")); diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/rolemapping/RestDeleteRoleMappingAction.java b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/rolemapping/RestDeleteRoleMappingAction.java index 5ecebedff14..d9175131bb0 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/rolemapping/RestDeleteRoleMappingAction.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/rolemapping/RestDeleteRoleMappingAction.java @@ -10,7 +10,7 @@ import java.io.IOException; import org.elasticsearch.client.node.NodeClient; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.rest.BaseRestHandler; +import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.rest.BytesRestResponse; import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestRequest; @@ -19,22 +19,22 @@ import org.elasticsearch.rest.RestStatus; import org.elasticsearch.rest.action.RestBuilderListener; import org.elasticsearch.xpack.security.action.rolemapping.DeleteRoleMappingResponse; import org.elasticsearch.xpack.security.client.SecurityClient; +import org.elasticsearch.xpack.security.rest.action.SecurityBaseRestHandler; import static org.elasticsearch.rest.RestRequest.Method.DELETE; /** * Rest endpoint to delete a role-mapping from the {@link org.elasticsearch.xpack.security.authc.support.mapper.NativeRoleMappingStore} */ -public class RestDeleteRoleMappingAction extends BaseRestHandler { +public class RestDeleteRoleMappingAction extends SecurityBaseRestHandler { - public RestDeleteRoleMappingAction(Settings settings, RestController controller) { - super(settings); + public RestDeleteRoleMappingAction(Settings settings, RestController controller, XPackLicenseState licenseState) { + super(settings, licenseState); controller.registerHandler(DELETE, "/_xpack/security/role_mapping/{name}", this); } @Override - public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) - throws IOException { + public RestChannelConsumer innerPrepareRequest(RestRequest request, NodeClient client) throws IOException { final String name = request.param("name"); final String refresh = request.param("refresh"); diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/rolemapping/RestGetRoleMappingsAction.java b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/rolemapping/RestGetRoleMappingsAction.java index 6d01b1600da..ac999ac84d0 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/rolemapping/RestGetRoleMappingsAction.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/rolemapping/RestGetRoleMappingsAction.java @@ -8,10 +8,9 @@ package org.elasticsearch.xpack.security.rest.action.rolemapping; import java.io.IOException; import org.elasticsearch.client.node.NodeClient; -import org.elasticsearch.common.Strings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.rest.BaseRestHandler; +import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.rest.BytesRestResponse; import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestRequest; @@ -21,22 +20,23 @@ import org.elasticsearch.rest.action.RestBuilderListener; import org.elasticsearch.xpack.security.action.rolemapping.GetRoleMappingsResponse; import org.elasticsearch.xpack.security.authc.support.mapper.ExpressionRoleMapping; import org.elasticsearch.xpack.security.client.SecurityClient; +import org.elasticsearch.xpack.security.rest.action.SecurityBaseRestHandler; import static org.elasticsearch.rest.RestRequest.Method.GET; /** * Rest endpoint to retrieve a role-mapping from the {@link org.elasticsearch.xpack.security.authc.support.mapper.NativeRoleMappingStore} */ -public class RestGetRoleMappingsAction extends BaseRestHandler { - public RestGetRoleMappingsAction(Settings settings, RestController controller) { - super(settings); +public class RestGetRoleMappingsAction extends SecurityBaseRestHandler { + + public RestGetRoleMappingsAction(Settings settings, RestController controller, XPackLicenseState licenseState) { + super(settings, licenseState); controller.registerHandler(GET, "/_xpack/security/role_mapping/", this); controller.registerHandler(GET, "/_xpack/security/role_mapping/{name}", this); } @Override - public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) - throws IOException { + public RestChannelConsumer innerPrepareRequest(RestRequest request, NodeClient client) throws IOException { final String[] names = request.paramAsStringArrayOrEmptyIfAll("name"); return channel -> new SecurityClient(client).prepareGetRoleMappings(names) .execute(new RestBuilderListener(channel) { diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/rolemapping/RestPutRoleMappingAction.java b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/rolemapping/RestPutRoleMappingAction.java index a369cec2a82..6ef896b3b98 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/rolemapping/RestPutRoleMappingAction.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/rolemapping/RestPutRoleMappingAction.java @@ -10,7 +10,7 @@ import java.io.IOException; import org.elasticsearch.client.node.NodeClient; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.rest.BaseRestHandler; +import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.rest.BytesRestResponse; import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestRequest; @@ -20,6 +20,7 @@ import org.elasticsearch.rest.action.RestBuilderListener; import org.elasticsearch.xpack.security.action.rolemapping.PutRoleMappingRequestBuilder; import org.elasticsearch.xpack.security.action.rolemapping.PutRoleMappingResponse; import org.elasticsearch.xpack.security.client.SecurityClient; +import org.elasticsearch.xpack.security.rest.action.SecurityBaseRestHandler; import static org.elasticsearch.rest.RestRequest.Method.POST; import static org.elasticsearch.rest.RestRequest.Method.PUT; @@ -29,17 +30,16 @@ import static org.elasticsearch.rest.RestRequest.Method.PUT; * * @see org.elasticsearch.xpack.security.authc.support.mapper.NativeRoleMappingStore */ -public class RestPutRoleMappingAction extends BaseRestHandler { - public RestPutRoleMappingAction(Settings settings, RestController controller) { - super(settings); +public class RestPutRoleMappingAction extends SecurityBaseRestHandler { + + public RestPutRoleMappingAction(Settings settings, RestController controller, XPackLicenseState licenseState) { + super(settings, licenseState); controller.registerHandler(POST, "/_xpack/security/role_mapping/{name}", this); controller.registerHandler(PUT, "/_xpack/security/role_mapping/{name}", this); } @Override - public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) - throws IOException { - + public RestChannelConsumer innerPrepareRequest(RestRequest request, NodeClient client) throws IOException { final String name = request.param("name"); PutRoleMappingRequestBuilder requestBuilder = new SecurityClient(client) .preparePutRoleMapping(name, request.content(), request.getXContentType()) diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/user/RestChangePasswordAction.java b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/user/RestChangePasswordAction.java index cd6f86d2e0a..c8ac73afcf2 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/user/RestChangePasswordAction.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/user/RestChangePasswordAction.java @@ -8,7 +8,7 @@ package org.elasticsearch.xpack.security.rest.action.user; import org.elasticsearch.client.node.NodeClient; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.rest.BaseRestHandler; +import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.rest.BytesRestResponse; import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestRequest; @@ -19,6 +19,7 @@ import org.elasticsearch.xpack.security.SecurityContext; import org.elasticsearch.xpack.security.action.user.ChangePasswordResponse; import org.elasticsearch.xpack.security.client.SecurityClient; import org.elasticsearch.xpack.security.rest.RestRequestFilter; +import org.elasticsearch.xpack.security.rest.action.SecurityBaseRestHandler; import org.elasticsearch.xpack.security.user.User; import java.io.IOException; @@ -28,12 +29,13 @@ import java.util.Set; import static org.elasticsearch.rest.RestRequest.Method.POST; import static org.elasticsearch.rest.RestRequest.Method.PUT; -public class RestChangePasswordAction extends BaseRestHandler implements RestRequestFilter { +public class RestChangePasswordAction extends SecurityBaseRestHandler implements RestRequestFilter { private final SecurityContext securityContext; - public RestChangePasswordAction(Settings settings, RestController controller, SecurityContext securityContext) { - super(settings); + public RestChangePasswordAction(Settings settings, RestController controller, SecurityContext securityContext, + XPackLicenseState licenseState) { + super(settings, licenseState); this.securityContext = securityContext; controller.registerHandler(POST, "/_xpack/security/user/{username}/_password", this); controller.registerHandler(PUT, "/_xpack/security/user/{username}/_password", this); @@ -42,7 +44,7 @@ public class RestChangePasswordAction extends BaseRestHandler implements RestReq } @Override - public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { + public RestChannelConsumer innerPrepareRequest(RestRequest request, NodeClient client) throws IOException { final User user = securityContext.getUser(); final String username; if (request.param("username") == null) { @@ -58,10 +60,8 @@ public class RestChangePasswordAction extends BaseRestHandler implements RestReq .setRefreshPolicy(refresh) .execute(new RestBuilderListener(channel) { @Override - public RestResponse buildResponse( - ChangePasswordResponse changePasswordResponse, - XContentBuilder builder) - throws Exception { + public RestResponse buildResponse(ChangePasswordResponse changePasswordResponse, + XContentBuilder builder) throws Exception { return new BytesRestResponse(RestStatus.OK, builder.startObject().endObject()); } }); diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/user/RestDeleteUserAction.java b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/user/RestDeleteUserAction.java index e0ecf501326..a70c7ad9f4d 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/user/RestDeleteUserAction.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/user/RestDeleteUserAction.java @@ -8,7 +8,7 @@ package org.elasticsearch.xpack.security.rest.action.user; import org.elasticsearch.client.node.NodeClient; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.rest.BaseRestHandler; +import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.rest.BytesRestResponse; import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestRequest; @@ -17,6 +17,7 @@ import org.elasticsearch.rest.RestStatus; import org.elasticsearch.rest.action.RestBuilderListener; import org.elasticsearch.xpack.security.action.user.DeleteUserResponse; import org.elasticsearch.xpack.security.client.SecurityClient; +import org.elasticsearch.xpack.security.rest.action.SecurityBaseRestHandler; import java.io.IOException; @@ -25,9 +26,10 @@ import static org.elasticsearch.rest.RestRequest.Method.DELETE; /** * Rest action to delete a user from the security index */ -public class RestDeleteUserAction extends BaseRestHandler { - public RestDeleteUserAction(Settings settings, RestController controller) { - super(settings); +public class RestDeleteUserAction extends SecurityBaseRestHandler { + + public RestDeleteUserAction(Settings settings, RestController controller, XPackLicenseState licenseState) { + super(settings, licenseState); controller.registerHandler(DELETE, "/_xpack/security/user/{username}", this); // @deprecated: Remove in 6.0 @@ -38,7 +40,7 @@ public class RestDeleteUserAction extends BaseRestHandler { } @Override - public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { + public RestChannelConsumer innerPrepareRequest(RestRequest request, NodeClient client) throws IOException { final String username = request.param("username"); final String refresh = request.param("refresh"); return channel -> new SecurityClient(client).prepareDeleteUser(username) diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/user/RestGetUsersAction.java b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/user/RestGetUsersAction.java index 47194db8d5e..de48618e8c6 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/user/RestGetUsersAction.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/user/RestGetUsersAction.java @@ -9,7 +9,7 @@ import org.elasticsearch.client.node.NodeClient; import org.elasticsearch.common.Strings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.rest.BaseRestHandler; +import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.rest.BytesRestResponse; import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestRequest; @@ -18,6 +18,7 @@ import org.elasticsearch.rest.RestStatus; import org.elasticsearch.rest.action.RestBuilderListener; import org.elasticsearch.xpack.security.action.user.GetUsersResponse; import org.elasticsearch.xpack.security.client.SecurityClient; +import org.elasticsearch.xpack.security.rest.action.SecurityBaseRestHandler; import org.elasticsearch.xpack.security.user.User; import java.io.IOException; @@ -27,9 +28,10 @@ import static org.elasticsearch.rest.RestRequest.Method.GET; /** * Rest action to retrieve a user from the security index */ -public class RestGetUsersAction extends BaseRestHandler { - public RestGetUsersAction(Settings settings, RestController controller) { - super(settings); +public class RestGetUsersAction extends SecurityBaseRestHandler { + + public RestGetUsersAction(Settings settings, RestController controller, XPackLicenseState licenseState) { + super(settings, licenseState); controller.registerHandler(GET, "/_xpack/security/user/", this); controller.registerHandler(GET, "/_xpack/security/user/{username}", this); @@ -45,7 +47,7 @@ public class RestGetUsersAction extends BaseRestHandler { } @Override - public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { + public RestChannelConsumer innerPrepareRequest(RestRequest request, NodeClient client) throws IOException { String[] usernames = request.paramAsStringArray("username", Strings.EMPTY_ARRAY); return channel -> new SecurityClient(client).prepareGetUsers(usernames).execute(new RestBuilderListener(channel) { diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/user/RestHasPrivilegesAction.java b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/user/RestHasPrivilegesAction.java index ef4bd3f3c4a..25be18e398e 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/user/RestHasPrivilegesAction.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/user/RestHasPrivilegesAction.java @@ -10,7 +10,7 @@ import java.io.IOException; import org.elasticsearch.client.node.NodeClient; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.rest.BaseRestHandler; +import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.rest.BytesRestResponse; import org.elasticsearch.rest.RestChannel; import org.elasticsearch.rest.RestController; @@ -22,6 +22,7 @@ import org.elasticsearch.xpack.security.SecurityContext; import org.elasticsearch.xpack.security.action.user.HasPrivilegesRequestBuilder; import org.elasticsearch.xpack.security.action.user.HasPrivilegesResponse; import org.elasticsearch.xpack.security.client.SecurityClient; +import org.elasticsearch.xpack.security.rest.action.SecurityBaseRestHandler; import org.elasticsearch.xpack.security.user.User; import static org.elasticsearch.rest.RestRequest.Method.GET; @@ -31,12 +32,13 @@ import static org.elasticsearch.rest.RestRequest.Method.POST; * REST handler that tests whether a user has the specified * {@link org.elasticsearch.xpack.security.authz.RoleDescriptor.IndicesPrivileges privileges} */ -public class RestHasPrivilegesAction extends BaseRestHandler { +public class RestHasPrivilegesAction extends SecurityBaseRestHandler { private final SecurityContext securityContext; - public RestHasPrivilegesAction(Settings settings, RestController controller, SecurityContext securityContext) { - super(settings); + public RestHasPrivilegesAction(Settings settings, RestController controller, SecurityContext securityContext, + XPackLicenseState licenseState) { + super(settings, licenseState); this.securityContext = securityContext; controller.registerHandler(GET, "/_xpack/security/user/{username}/_has_privileges", this); controller.registerHandler(POST, "/_xpack/security/user/{username}/_has_privileges", this); @@ -45,7 +47,7 @@ public class RestHasPrivilegesAction extends BaseRestHandler { } @Override - public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { + public RestChannelConsumer innerPrepareRequest(RestRequest request, NodeClient client) throws IOException { final String username = getUsername(request); HasPrivilegesRequestBuilder requestBuilder = new SecurityClient(client) .prepareHasPrivileges(username, request.content(), request.getXContentType()); diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/user/RestPutUserAction.java b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/user/RestPutUserAction.java index be2f146570d..f095735dfa6 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/user/RestPutUserAction.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/user/RestPutUserAction.java @@ -9,7 +9,7 @@ import org.elasticsearch.client.node.NodeClient; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.set.Sets; import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.rest.BaseRestHandler; +import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.rest.BytesRestResponse; import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestRequest; @@ -20,6 +20,7 @@ import org.elasticsearch.xpack.security.action.user.PutUserRequestBuilder; import org.elasticsearch.xpack.security.action.user.PutUserResponse; import org.elasticsearch.xpack.security.client.SecurityClient; import org.elasticsearch.xpack.security.rest.RestRequestFilter; +import org.elasticsearch.xpack.security.rest.action.SecurityBaseRestHandler; import java.io.IOException; import java.util.Collections; @@ -31,10 +32,10 @@ import static org.elasticsearch.rest.RestRequest.Method.PUT; /** * Rest endpoint to add a User to the security index */ -public class RestPutUserAction extends BaseRestHandler implements RestRequestFilter { +public class RestPutUserAction extends SecurityBaseRestHandler implements RestRequestFilter { - public RestPutUserAction(Settings settings, RestController controller) { - super(settings); + public RestPutUserAction(Settings settings, RestController controller, XPackLicenseState licenseState) { + super(settings, licenseState); controller.registerHandler(POST, "/_xpack/security/user/{username}", this); controller.registerHandler(PUT, "/_xpack/security/user/{username}", this); @@ -50,7 +51,7 @@ public class RestPutUserAction extends BaseRestHandler implements RestRequestFil } @Override - public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { + public RestChannelConsumer innerPrepareRequest(RestRequest request, NodeClient client) throws IOException { PutUserRequestBuilder requestBuilder = new SecurityClient(client) .preparePutUser(request.param("username"), request.content(), request.getXContentType()) .setRefreshPolicy(request.param("refresh")); diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/user/RestSetEnabledAction.java b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/user/RestSetEnabledAction.java index fad50a2bab2..0956af9fb17 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/user/RestSetEnabledAction.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/rest/action/user/RestSetEnabledAction.java @@ -8,6 +8,7 @@ package org.elasticsearch.xpack.security.rest.action.user; import org.elasticsearch.client.node.NodeClient; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.BytesRestResponse; import org.elasticsearch.rest.RestController; @@ -17,6 +18,7 @@ import org.elasticsearch.rest.RestStatus; import org.elasticsearch.rest.action.RestBuilderListener; import org.elasticsearch.xpack.security.action.user.SetEnabledResponse; import org.elasticsearch.xpack.security.client.SecurityClient; +import org.elasticsearch.xpack.security.rest.action.SecurityBaseRestHandler; import java.io.IOException; @@ -27,9 +29,10 @@ import static org.elasticsearch.rest.RestRequest.Method.PUT; * REST handler for enabling and disabling users. The username is required and we use the path to determine if the user is being * enabled or disabled. */ -public class RestSetEnabledAction extends BaseRestHandler { - public RestSetEnabledAction(Settings settings, RestController controller) { - super(settings); +public class RestSetEnabledAction extends SecurityBaseRestHandler { + + public RestSetEnabledAction(Settings settings, RestController controller, XPackLicenseState licenseState) { + super(settings, licenseState); controller.registerHandler(POST, "/_xpack/security/user/{username}/_enable", this); controller.registerHandler(PUT, "/_xpack/security/user/{username}/_enable", this); controller.registerHandler(POST, "/_xpack/security/user/{username}/_disable", this); @@ -37,7 +40,7 @@ public class RestSetEnabledAction extends BaseRestHandler { } @Override - public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { + public RestChannelConsumer innerPrepareRequest(RestRequest request, NodeClient client) throws IOException { final boolean enabled = request.path().endsWith("_enable"); assert enabled || request.path().endsWith("_disable"); final String username = request.param("username"); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/rest/action/SecurityBaseRestHandlerTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/rest/action/SecurityBaseRestHandlerTests.java new file mode 100644 index 00000000000..6c5307ccb35 --- /dev/null +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/rest/action/SecurityBaseRestHandlerTests.java @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.security.rest.action; + +import org.elasticsearch.client.node.NodeClient; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.test.rest.FakeRestChannel; +import org.elasticsearch.test.rest.FakeRestRequest; + +import java.io.IOException; +import java.util.concurrent.atomic.AtomicBoolean; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; + +public class SecurityBaseRestHandlerTests extends ESTestCase { + + public void testSecurityBaseRestHandlerChecksLicenseState() throws Exception { + final boolean securityEnabled = randomBoolean(); + final AtomicBoolean consumerCalled = new AtomicBoolean(false); + final XPackLicenseState licenseState = mock(XPackLicenseState.class); + when(licenseState.isAuthAllowed()).thenReturn(securityEnabled); + SecurityBaseRestHandler handler = new SecurityBaseRestHandler(Settings.EMPTY, licenseState) { + @Override + protected RestChannelConsumer innerPrepareRequest(RestRequest request, NodeClient client) throws IOException { + return channel -> { + if (consumerCalled.compareAndSet(false, true) == false) { + fail("consumerCalled was not false"); + } + }; + } + }; + FakeRestRequest fakeRestRequest = new FakeRestRequest(); + FakeRestChannel fakeRestChannel = new FakeRestChannel(fakeRestRequest, randomBoolean(), securityEnabled ? 0 : 1); + NodeClient client = mock(NodeClient.class); + + assertFalse(consumerCalled.get()); + verifyZeroInteractions(licenseState); + handler.handleRequest(fakeRestRequest, fakeRestChannel, client); + + verify(licenseState).isAuthAllowed(); + if (securityEnabled) { + assertTrue(consumerCalled.get()); + assertEquals(0, fakeRestChannel.responses().get()); + assertEquals(0, fakeRestChannel.errors().get()); + } else { + assertFalse(consumerCalled.get()); + assertEquals(0, fakeRestChannel.responses().get()); + assertEquals(1, fakeRestChannel.errors().get()); + } + } +}