diff --git a/libs/x-content/src/main/java/org/elasticsearch/common/xcontent/XContent.java b/libs/x-content/src/main/java/org/elasticsearch/common/xcontent/XContent.java index b448a613065ad..f9150d201b071 100644 --- a/libs/x-content/src/main/java/org/elasticsearch/common/xcontent/XContent.java +++ b/libs/x-content/src/main/java/org/elasticsearch/common/xcontent/XContent.java @@ -88,4 +88,8 @@ XContentParser createParserForCompatibility(NamedXContentRegistry xContentRegist DeprecationHandler deprecationHandler, byte[] data, int offset, int length, RestApiVersion restApiVersion) throws IOException; + XContentParser createParserForCompatibility(NamedXContentRegistry xContentRegistry, + DeprecationHandler deprecationHandler, String content, + RestApiVersion restApiVersion) throws IOException; + } diff --git a/libs/x-content/src/main/java/org/elasticsearch/common/xcontent/cbor/CborXContent.java b/libs/x-content/src/main/java/org/elasticsearch/common/xcontent/cbor/CborXContent.java index 0fd9e85fa48e3..8c00ab8f8b544 100644 --- a/libs/x-content/src/main/java/org/elasticsearch/common/xcontent/cbor/CborXContent.java +++ b/libs/x-content/src/main/java/org/elasticsearch/common/xcontent/cbor/CborXContent.java @@ -112,4 +112,9 @@ public XContentParser createParserForCompatibility(NamedXContentRegistry xConten return new CborXContentParser(xContentRegistry, deprecationHandler, cborFactory.createParser(data, offset, length), restApiVersion); } + @Override + public XContentParser createParserForCompatibility(NamedXContentRegistry xContentRegistry, DeprecationHandler deprecationHandler, + String content, RestApiVersion restApiVersion) throws IOException { + return new CborXContentParser(xContentRegistry, deprecationHandler, cborFactory.createParser(content), restApiVersion); + } } diff --git a/libs/x-content/src/main/java/org/elasticsearch/common/xcontent/json/JsonXContent.java b/libs/x-content/src/main/java/org/elasticsearch/common/xcontent/json/JsonXContent.java index f7f4c098c772c..96d554cae1a3a 100644 --- a/libs/x-content/src/main/java/org/elasticsearch/common/xcontent/json/JsonXContent.java +++ b/libs/x-content/src/main/java/org/elasticsearch/common/xcontent/json/JsonXContent.java @@ -112,4 +112,9 @@ public XContentParser createParserForCompatibility(NamedXContentRegistry xConten return new JsonXContentParser(xContentRegistry, deprecationHandler, jsonFactory.createParser(data, offset, length), restApiVersion); } + @Override + public XContentParser createParserForCompatibility(NamedXContentRegistry xContentRegistry, DeprecationHandler deprecationHandler, + String content, RestApiVersion restApiVersion) throws IOException { + return new JsonXContentParser(xContentRegistry, deprecationHandler, jsonFactory.createParser(content), restApiVersion); + } } diff --git a/libs/x-content/src/main/java/org/elasticsearch/common/xcontent/smile/SmileXContent.java b/libs/x-content/src/main/java/org/elasticsearch/common/xcontent/smile/SmileXContent.java index 0faa82f002b20..5fba079d90a44 100644 --- a/libs/x-content/src/main/java/org/elasticsearch/common/xcontent/smile/SmileXContent.java +++ b/libs/x-content/src/main/java/org/elasticsearch/common/xcontent/smile/SmileXContent.java @@ -113,4 +113,11 @@ public XContentParser createParserForCompatibility(NamedXContentRegistry xConten return new SmileXContentParser(xContentRegistry, deprecationHandler, smileFactory.createParser(data, offset, length), restApiVersion); } + + @Override + public XContentParser createParserForCompatibility(NamedXContentRegistry xContentRegistry, DeprecationHandler deprecationHandler, + String content, RestApiVersion restApiVersion) throws IOException { + return new SmileXContentParser(xContentRegistry, deprecationHandler, smileFactory.createParser(content), + restApiVersion); + } } diff --git a/libs/x-content/src/main/java/org/elasticsearch/common/xcontent/yaml/YamlXContent.java b/libs/x-content/src/main/java/org/elasticsearch/common/xcontent/yaml/YamlXContent.java index 92fdbfcd43967..66f7921b9e7fd 100644 --- a/libs/x-content/src/main/java/org/elasticsearch/common/xcontent/yaml/YamlXContent.java +++ b/libs/x-content/src/main/java/org/elasticsearch/common/xcontent/yaml/YamlXContent.java @@ -107,5 +107,10 @@ public XContentParser createParserForCompatibility(NamedXContentRegistry xConten restApiVersion); } - + @Override + public XContentParser createParserForCompatibility(NamedXContentRegistry xContentRegistry, DeprecationHandler deprecationHandler, + String content, RestApiVersion restApiVersion) throws IOException { + return new YamlXContentParser(xContentRegistry, deprecationHandler, yamlFactory.createParser(content), + restApiVersion); + } } diff --git a/rest-api-spec/build.gradle b/rest-api-spec/build.gradle index 722ef7f0f4fcc..989e77134cf18 100644 --- a/rest-api-spec/build.gradle +++ b/rest-api-spec/build.gradle @@ -106,8 +106,6 @@ tasks.named("yamlRestCompatTest").configure { 'mtermvectors/11_basic_with_types/Basic tests for multi termvector get', 'mtermvectors/21_deprecated_with_types/Deprecated camel case and _ parameters should fail in Term Vectors query', 'mtermvectors/30_mix_typeless_typeful/mtermvectors without types on an index that has types', - 'search/150_rewrite_on_coordinator/Ensure that we fetch the document only once', //terms_lookup - 'search/171_terms_query_with_types/Terms Query with No.of terms exceeding index.max_terms_count should FAIL', //bulk 'search/260_parameter_validation/test size=-1 is deprecated', //size=-1 change 'search/310_match_bool_prefix/multi_match multiple fields with cutoff_frequency throws exception', //cutoff_frequency 'search/340_type_query/type query', // type_query - probably should behave like match_all diff --git a/server/src/main/java/org/elasticsearch/indices/TermsLookup.java b/server/src/main/java/org/elasticsearch/indices/TermsLookup.java index 53964d11b0d6e..1e2a090f5c2d9 100644 --- a/server/src/main/java/org/elasticsearch/indices/TermsLookup.java +++ b/server/src/main/java/org/elasticsearch/indices/TermsLookup.java @@ -17,6 +17,7 @@ import org.elasticsearch.common.xcontent.ToXContentFragment; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.core.RestApiVersion; import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.query.TermsQueryBuilder; @@ -24,6 +25,7 @@ import java.util.Objects; import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg; +import static org.elasticsearch.core.RestApiVersion.equalTo; /** * Encapsulates the parameters needed to fetch terms. @@ -107,6 +109,8 @@ public TermsLookup routing(String routing) { PARSER.declareString(constructorArg(), new ParseField("id")); PARSER.declareString(constructorArg(), new ParseField("path")); PARSER.declareString(TermsLookup::routing, new ParseField("routing")); + PARSER.declareString((termLookup,type)-> {}, new ParseField("type") + .forRestApiVersion(equalTo(RestApiVersion.V_7))); } public static TermsLookup parseTermsLookup(XContentParser parser) throws IOException { diff --git a/test/framework/src/main/java/org/elasticsearch/test/rest/RestActionTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/rest/RestActionTestCase.java index a4d759242dcde..56cee804180b8 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/rest/RestActionTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/rest/RestActionTestCase.java @@ -64,6 +64,10 @@ protected RestController controller() { */ protected void dispatchRequest(RestRequest request) { FakeRestChannel channel = new FakeRestChannel(request, false, 1); + dispatchRequest(request, channel); + } + + protected void dispatchRequest(RestRequest request, FakeRestChannel channel) { ThreadContext threadContext = verifyingClient.threadPool().getThreadContext(); try(ThreadContext.StoredContext ignore = threadContext.stashContext()) { controller.dispatchRequest(request, channel, threadContext); diff --git a/x-pack/plugin/build.gradle b/x-pack/plugin/build.gradle index 109e9ab62ff1a..749da2fd39c05 100644 --- a/x-pack/plugin/build.gradle +++ b/x-pack/plugin/build.gradle @@ -149,7 +149,6 @@ tasks.named("yamlRestCompatTest").configure { 'ml/set_upgrade_mode/Test setting upgrade_mode to false when it is already false', 'ml/trained_model_cat_apis/Test cat trained models', 'roles/11_idx_arrays/Test put role api using as array of index names', - 'roles/30_prohibited_role_query/Test use prohibited query inside role query', 'rollup/delete_job/Test basic delete_job', 'rollup/delete_job/Test delete job twice', 'rollup/delete_job/Test delete running job', diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/role/PutRoleRequestBuilder.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/role/PutRoleRequestBuilder.java index 8d48f792c74f2..90dfd16d5bb31 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/role/PutRoleRequestBuilder.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/role/PutRoleRequestBuilder.java @@ -9,9 +9,9 @@ import org.elasticsearch.action.ActionRequestBuilder; import org.elasticsearch.action.support.WriteRequestBuilder; import org.elasticsearch.client.ElasticsearchClient; -import org.elasticsearch.core.Nullable; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.core.Nullable; import org.elasticsearch.xpack.core.security.authz.RoleDescriptor; import java.io.IOException; @@ -38,6 +38,7 @@ public PutRoleRequestBuilder source(String name, BytesReference source, XContent // we pass false as last parameter because we want to reject the request if field permissions // are given in 2.x syntax RoleDescriptor descriptor = RoleDescriptor.parse(name, source, false, xContentType); + assert name.equals(descriptor.getName()); request.name(name); request.cluster(descriptor.getClusterPrivileges()); diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/permission/DocumentPermissions.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/permission/DocumentPermissions.java index 6ac06ee9b1a40..69ceff9cd403b 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/permission/DocumentPermissions.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/permission/DocumentPermissions.java @@ -13,6 +13,7 @@ import org.apache.lucene.search.join.ToChildBlockJoinQuery; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.lucene.search.Queries; +import org.elasticsearch.core.RestApiVersion; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryRewriteContext; import org.elasticsearch.index.query.SearchExecutionContext; @@ -119,7 +120,7 @@ private static void buildRoleQuery(User user, ScriptService scriptService, Shard for (BytesReference bytesReference : queries) { SearchExecutionContext context = searchExecutionContextProvider.apply(shardId); QueryBuilder queryBuilder = DLSRoleQueryValidator.evaluateAndVerifyRoleQuery(bytesReference, scriptService, - context.getXContentRegistry(), user); + context.getXContentRegistry(), user, RestApiVersion.current()); if (queryBuilder != null) { failIfQueryUsesClient(queryBuilder, context); Query roleQuery = context.toQuery(queryBuilder).query(); diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/support/DLSRoleQueryValidator.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/support/DLSRoleQueryValidator.java index 17552b6b98fb0..4cb818fd8b3ed 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/support/DLSRoleQueryValidator.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/support/DLSRoleQueryValidator.java @@ -17,6 +17,7 @@ import org.elasticsearch.common.xcontent.XContentParseException; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.core.RestApiVersion; import org.elasticsearch.index.query.AbstractQueryBuilder; import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.BoostingQueryBuilder; @@ -45,23 +46,23 @@ private DLSRoleQueryValidator() { /** * Validates the query field in the {@link RoleDescriptor.IndicesPrivileges} only if it is not a template query.
* It parses the query and builds the {@link QueryBuilder}, also checks if the query type is supported in DLS role query. - * - * @param indicesPrivileges {@link RoleDescriptor.IndicesPrivileges} + * @param indicesPrivileges {@link RoleDescriptor.IndicesPrivileges} * @param xContentRegistry {@link NamedXContentRegistry} for finding named queries + * @param restApiVersion */ public static void validateQueryField(RoleDescriptor.IndicesPrivileges[] indicesPrivileges, - NamedXContentRegistry xContentRegistry) { + NamedXContentRegistry xContentRegistry, RestApiVersion restApiVersion) { if (indicesPrivileges != null) { for (int i = 0; i < indicesPrivileges.length; i++) { BytesReference query = indicesPrivileges[i].getQuery(); try { if (query != null) { - if (isTemplateQuery(query, xContentRegistry)) { + if (isTemplateQuery(query, xContentRegistry, restApiVersion)) { // skip template query, this requires runtime information like 'User' information. continue; } - evaluateAndVerifyRoleQuery(query.utf8ToString(), xContentRegistry); + evaluateAndVerifyRoleQuery(query.utf8ToString(), xContentRegistry, restApiVersion); } } catch (ParsingException | IllegalArgumentException | IOException e) { throw new ElasticsearchParseException("failed to parse field 'query' for indices [" + @@ -72,9 +73,10 @@ public static void validateQueryField(RoleDescriptor.IndicesPrivileges[] indices } } - private static boolean isTemplateQuery(BytesReference query, NamedXContentRegistry xContentRegistry) throws IOException { - try (XContentParser parser = XContentType.JSON.xContent().createParser(xContentRegistry, - LoggingDeprecationHandler.INSTANCE, query.utf8ToString())) { + private static boolean isTemplateQuery(BytesReference query, NamedXContentRegistry xContentRegistry, RestApiVersion restApiVersion) + throws IOException { + try (XContentParser parser = XContentType.JSON.xContent().createParserForCompatibility(xContentRegistry, + LoggingDeprecationHandler.INSTANCE, query.streamInput(), restApiVersion)) { XContentParser.Token token = parser.nextToken(); if (token != XContentParser.Token.START_OBJECT) { throw new XContentParseException(parser.getTokenLocation(), "expected [" + XContentParser.Token.START_OBJECT + "] but " + @@ -103,17 +105,19 @@ private static boolean isTemplateQuery(BytesReference query, NamedXContentRegist * @param scriptService {@link ScriptService} used for evaluation of a template query * @param xContentRegistry {@link NamedXContentRegistry} for finding named queries * @param user {@link User} used when evaluation a template query + * @param restApiVersion * @return {@link QueryBuilder} if the query is valid and allowed, in case {@link RoleDescriptor.IndicesPrivileges} * * does not have a query field then it returns {@code null}. */ @Nullable public static QueryBuilder evaluateAndVerifyRoleQuery(BytesReference query, ScriptService scriptService, - NamedXContentRegistry xContentRegistry, User user) { + NamedXContentRegistry xContentRegistry, User user, + RestApiVersion restApiVersion) { if (query != null) { String templateResult = SecurityQueryTemplateEvaluator.evaluateTemplate(query.utf8ToString(), scriptService, user); try { - return evaluateAndVerifyRoleQuery(templateResult, xContentRegistry); + return evaluateAndVerifyRoleQuery(templateResult, xContentRegistry, restApiVersion); } catch (ElasticsearchParseException | ParsingException | XContentParseException | IOException e) { throw new ElasticsearchParseException("failed to parse field 'query' from the role descriptor", e); } @@ -122,10 +126,11 @@ public static QueryBuilder evaluateAndVerifyRoleQuery(BytesReference query, Scri } @Nullable - private static QueryBuilder evaluateAndVerifyRoleQuery(String query, NamedXContentRegistry xContentRegistry) throws IOException { + private static QueryBuilder evaluateAndVerifyRoleQuery(String query, NamedXContentRegistry xContentRegistry, + RestApiVersion restApiVersion) throws IOException { if (query != null) { - try (XContentParser parser = XContentFactory.xContent(query).createParser(xContentRegistry, - LoggingDeprecationHandler.INSTANCE, query)) { + try (XContentParser parser = XContentFactory.xContent(query).createParserForCompatibility(xContentRegistry, + LoggingDeprecationHandler.INSTANCE, query, restApiVersion)) { QueryBuilder queryBuilder = AbstractQueryBuilder.parseInnerQueryBuilder(parser); verifyRoleQuery(queryBuilder); return queryBuilder; diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/termsenum/action/TransportTermsEnumAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/termsenum/action/TransportTermsEnumAction.java index 45b116c41dd4d..1bd948585e07f 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/termsenum/action/TransportTermsEnumAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/termsenum/action/TransportTermsEnumAction.java @@ -36,6 +36,7 @@ import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.util.concurrent.EsThreadPoolExecutor; import org.elasticsearch.common.util.concurrent.ThreadContext; +import org.elasticsearch.core.RestApiVersion; import org.elasticsearch.core.internal.io.IOUtils; import org.elasticsearch.index.IndexService; import org.elasticsearch.index.engine.Engine; @@ -435,8 +436,8 @@ private boolean canAccess( querySource, scriptService, queryShardContext.getXContentRegistry(), - securityContext.getUser() - ); + securityContext.getUser(), + RestApiVersion.current()); QueryBuilder rewrittenQueryBuilder = Rewriteable.rewrite(queryBuilder, queryShardContext); if (rewrittenQueryBuilder instanceof MatchAllQueryBuilder) { // One of the roles assigned has "all" permissions - allow unfettered access to termsDict diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/role/TransportPutRoleAction.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/role/TransportPutRoleAction.java index fcb0ddc8f278d..affbe735a8a11 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/role/TransportPutRoleAction.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/action/role/TransportPutRoleAction.java @@ -6,7 +6,6 @@ */ package org.elasticsearch.xpack.security.action.role; -import org.elasticsearch.ElasticsearchException; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.support.ActionFilters; import org.elasticsearch.action.support.HandledTransportAction; @@ -18,7 +17,6 @@ import org.elasticsearch.xpack.core.security.action.role.PutRoleRequest; import org.elasticsearch.xpack.core.security.action.role.PutRoleResponse; import org.elasticsearch.xpack.core.security.authz.store.ReservedRolesStore; -import org.elasticsearch.xpack.core.security.authz.support.DLSRoleQueryValidator; import org.elasticsearch.xpack.security.authz.store.NativeRolesStore; public class TransportPutRoleAction extends HandledTransportAction { @@ -42,13 +40,6 @@ protected void doExecute(Task task, final PutRoleRequest request, final ActionLi return; } - try { - DLSRoleQueryValidator.validateQueryField(request.roleDescriptor().getIndicesPrivileges(), xContentRegistry); - } catch (ElasticsearchException | IllegalArgumentException e) { - listener.onFailure(e); - return; - } - rolesStore.putRole(request, request.roleDescriptor(), listener.delegateFailure((l, created) -> { if (created) { logger.info("added role [{}]", request.name()); diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/ApiKeyGenerator.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/ApiKeyGenerator.java index 71afd11c21696..089544a835ac2 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/ApiKeyGenerator.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/ApiKeyGenerator.java @@ -11,6 +11,7 @@ import org.elasticsearch.ElasticsearchSecurityException; import org.elasticsearch.action.ActionListener; import org.elasticsearch.common.xcontent.NamedXContentRegistry; +import org.elasticsearch.core.RestApiVersion; import org.elasticsearch.xpack.core.security.action.CreateApiKeyRequest; import org.elasticsearch.xpack.core.security.action.CreateApiKeyResponse; import org.elasticsearch.xpack.core.security.authc.Authentication; @@ -44,7 +45,7 @@ public void generateApiKey(Authentication authentication, CreateApiKeyRequest re ActionListener.wrap(roleDescriptors -> { for (RoleDescriptor rd : roleDescriptors) { try { - DLSRoleQueryValidator.validateQueryField(rd.getIndicesPrivileges(), xContentRegistry); + DLSRoleQueryValidator.validateQueryField(rd.getIndicesPrivileges(), xContentRegistry, RestApiVersion.current()); } catch (ElasticsearchException | IllegalArgumentException e) { listener.onFailure(e); return; diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/FileRolesStore.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/FileRolesStore.java index f36f0127f866d..51425ab44cfc1 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/FileRolesStore.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/FileRolesStore.java @@ -21,6 +21,7 @@ import org.elasticsearch.common.xcontent.NamedXContentRegistry; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.yaml.YamlXContent; +import org.elasticsearch.core.RestApiVersion; import org.elasticsearch.env.Environment; import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.license.XPackLicenseState.Feature; @@ -318,7 +319,7 @@ private static RoleDescriptor checkDescriptor(RoleDescriptor descriptor, Path pa return null; } else { try { - DLSRoleQueryValidator.validateQueryField(descriptor.getIndicesPrivileges(), xContentRegistry); + DLSRoleQueryValidator.validateQueryField(descriptor.getIndicesPrivileges(), xContentRegistry, RestApiVersion.current()); } catch (ElasticsearchException | IllegalArgumentException e) { logger.error((Supplier) () -> new ParameterizedMessage( "invalid role definition [{}] in roles file [{}]. failed to validate query field. skipping role...", roleName, diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/rest/action/role/RestPutRoleAction.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/rest/action/role/RestPutRoleAction.java index 70d50ea3d974a..d65090368ae42 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/rest/action/role/RestPutRoleAction.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/rest/action/role/RestPutRoleAction.java @@ -7,9 +7,9 @@ package org.elasticsearch.xpack.security.rest.action.role; import org.elasticsearch.client.node.NodeClient; -import org.elasticsearch.core.RestApiVersion; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.core.RestApiVersion; import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.rest.BytesRestResponse; import org.elasticsearch.rest.RestRequest; @@ -18,6 +18,7 @@ import org.elasticsearch.rest.action.RestBuilderListener; import org.elasticsearch.xpack.core.security.action.role.PutRoleRequestBuilder; import org.elasticsearch.xpack.core.security.action.role.PutRoleResponse; +import org.elasticsearch.xpack.core.security.authz.support.DLSRoleQueryValidator; import org.elasticsearch.xpack.security.rest.action.SecurityBaseRestHandler; import java.io.IOException; @@ -55,6 +56,11 @@ public RestChannelConsumer innerPrepareRequest(RestRequest request, NodeClient c PutRoleRequestBuilder requestBuilder = new PutRoleRequestBuilder(client) .source(request.param("name"), request.requiredContent(), request.getXContentType()) .setRefreshPolicy(request.param("refresh")); + + DLSRoleQueryValidator.validateQueryField(requestBuilder.request().indices(), request.getXContentRegistry(), + request.getRestApiVersion()); + + return channel -> requestBuilder.execute(new RestBuilderListener<>(channel) { @Override public RestResponse buildResponse(PutRoleResponse putRoleResponse, XContentBuilder builder) throws Exception { diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/rest/action/role/RestPutRoleActionTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/rest/action/role/RestPutRoleActionTests.java new file mode 100644 index 0000000000000..14785c5dd3b47 --- /dev/null +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/rest/action/role/RestPutRoleActionTests.java @@ -0,0 +1,86 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.security.rest.action.role; + +import org.elasticsearch.common.bytes.BytesArray; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.core.RestApiVersion; +import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.rest.RestStatus; +import org.elasticsearch.test.rest.FakeRestChannel; +import org.elasticsearch.test.rest.FakeRestRequest; +import org.elasticsearch.test.rest.RestActionTestCase; +import org.elasticsearch.xpack.core.security.action.role.PutRoleRequest; +import org.elasticsearch.xpack.core.security.action.role.PutRoleResponse; +import org.junit.Before; +import org.mockito.Mockito; + +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.instanceOf; + +public class RestPutRoleActionTests extends RestActionTestCase { + + final List contentTypeHeader = Collections.singletonList(randomCompatibleMediaType(RestApiVersion.V_7)); + final List jsonContentType = Collections.singletonList(XContentType.JSON.toParsedMediaType().responseContentTypeHeader()); + + @Before + public void setUpAction() { + controller().registerHandler(new RestPutRoleAction(Settings.EMPTY, new XPackLicenseState(Settings.EMPTY, () -> 0))); + verifyingClient.setExecuteVerifier((actionType, request) -> { + assertThat(request, instanceOf(PutRoleRequest.class)); + return Mockito.mock(PutRoleResponse.class); + }); + } + + + public void testCreationOfRoleWithMalformedQueryJsonFails() { + + String[] malformedQueries = new String[]{"{ \"match_all\": { \"unknown_field\": \"\" } }", + "{ malformed JSON }", + "{ \"unknown\": {\"\"} }", + "{}"}; + + String queryPattern = "{" + + "\"indices\": [\n" + + " {\n" + + " \"names\": \"index\",\n" + + " \"privileges\": [\n" + + " \"all\"\n" + + " ],\n" + + " \"query\": %s" + + " }\n" + + " }\n" + + " ]" + + "}"; + for (String malformedQuery : malformedQueries) { + + final String query = String.format(Locale.ROOT, queryPattern, malformedQuery); + FakeRestRequest.Builder deprecatedRequest = new FakeRestRequest.Builder(xContentRegistry()) + .withHeaders(Map.of("Content-Type", jsonContentType, "Accept", jsonContentType)) + .withPath("_security/role/rolename") + .withMethod(RestRequest.Method.POST) + .withContent(new BytesArray(query), null); + + RestRequest request = deprecatedRequest.build(); + FakeRestChannel channel = new FakeRestChannel(request, true, 1); + + dispatchRequest(request, channel); + + assertThat(channel.errors().get(), equalTo(1)); + assertThat(channel.responses().get(), equalTo(0)); + assertThat(channel.capturedResponse().status(), equalTo(RestStatus.BAD_REQUEST)); + } + } +}