diff --git a/elasticsearch/build.gradle b/elasticsearch/build.gradle index c0d83f4e83e..b83ecb35ba4 100644 --- a/elasticsearch/build.gradle +++ b/elasticsearch/build.gradle @@ -1,3 +1,5 @@ +import org.elasticsearch.gradle.precommit.LicenseHeadersTask + File checkstyleSuppressions = file('checkstyle_suppressions.xml') subprojects { tasks.withType(Checkstyle) { @@ -7,4 +9,9 @@ subprojects { suppressions: checkstyleSuppressions ] } + + tasks.withType(LicenseHeadersTask.class) { + approvedLicenses = ['Elasticsearch Confidential'] + additionalLicense 'ESCON', 'Elasticsearch Confidential', 'ELASTICSEARCH CONFIDENTIAL' + } } diff --git a/elasticsearch/license/build.gradle b/elasticsearch/license/build.gradle index f4f03e52e7a..b4e221e7884 100644 --- a/elasticsearch/license/build.gradle +++ b/elasticsearch/license/build.gradle @@ -3,7 +3,5 @@ subprojects { project.forbiddenPatterns { exclude '**/*.key' } - // someone figure out what the x-plugins logic should be - project.licenseHeaders.enabled = false } } diff --git a/elasticsearch/qa/build.gradle b/elasticsearch/qa/build.gradle index 3c9541e6178..e69de29bb2d 100644 --- a/elasticsearch/qa/build.gradle +++ b/elasticsearch/qa/build.gradle @@ -1,6 +0,0 @@ -subprojects { - tasks.withType(org.elasticsearch.gradle.precommit.LicenseHeadersTask) { - // someone figure out what the x-plugins logic should be - project.licenseHeaders.enabled = false - } -} diff --git a/elasticsearch/qa/core-rest-tests-with-security/src/test/java/org/elasticsearch/xpack/security/RestIT.java b/elasticsearch/qa/core-rest-tests-with-security/src/test/java/org/elasticsearch/xpack/security/RestIT.java index 184b21989d9..106b6864938 100644 --- a/elasticsearch/qa/core-rest-tests-with-security/src/test/java/org/elasticsearch/xpack/security/RestIT.java +++ b/elasticsearch/qa/core-rest-tests-with-security/src/test/java/org/elasticsearch/xpack/security/RestIT.java @@ -7,18 +7,19 @@ package org.elasticsearch.xpack.security; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; + import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.ThreadContext; -import org.elasticsearch.xpack.security.authc.support.SecuredString; -import org.elasticsearch.test.rest.ESRestTestCase; +import org.elasticsearch.test.rest.ESClientYamlSuiteTestCase; import org.elasticsearch.test.rest.RestTestCandidate; import org.elasticsearch.test.rest.parser.RestTestParseException; +import org.elasticsearch.xpack.security.authc.support.SecuredString; import java.io.IOException; import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; -public class RestIT extends ESRestTestCase { +public class RestIT extends ESClientYamlSuiteTestCase { private static final String USER = "test_user"; private static final String PASS = "changeme"; @@ -29,7 +30,7 @@ public class RestIT extends ESRestTestCase { @ParametersFactory public static Iterable parameters() throws IOException, RestTestParseException { - return ESRestTestCase.createParameters(0, 1); + return ESClientYamlSuiteTestCase.createParameters(0, 1); } @Override diff --git a/elasticsearch/qa/reindex-tests-with-security/src/test/java/org/elasticsearch/xpack/security/RestIT.java b/elasticsearch/qa/reindex-tests-with-security/src/test/java/org/elasticsearch/xpack/security/RestIT.java index 1b726fa386a..527c0188299 100644 --- a/elasticsearch/qa/reindex-tests-with-security/src/test/java/org/elasticsearch/xpack/security/RestIT.java +++ b/elasticsearch/qa/reindex-tests-with-security/src/test/java/org/elasticsearch/xpack/security/RestIT.java @@ -7,18 +7,19 @@ package org.elasticsearch.xpack.security; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; + import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.ThreadContext; -import org.elasticsearch.xpack.security.authc.support.SecuredString; -import org.elasticsearch.test.rest.ESRestTestCase; +import org.elasticsearch.test.rest.ESClientYamlSuiteTestCase; import org.elasticsearch.test.rest.RestTestCandidate; import org.elasticsearch.test.rest.parser.RestTestParseException; +import org.elasticsearch.xpack.security.authc.support.SecuredString; import java.io.IOException; import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; -public class RestIT extends ESRestTestCase { +public class RestIT extends ESClientYamlSuiteTestCase { private static final String USER = "test_admin"; private static final String PASS = "changeme"; @@ -28,7 +29,7 @@ public class RestIT extends ESRestTestCase { @ParametersFactory public static Iterable parameters() throws IOException, RestTestParseException { - return ESRestTestCase.createParameters(0, 1); + return ESClientYamlSuiteTestCase.createParameters(0, 1); } /** diff --git a/elasticsearch/qa/smoke-test-graph-with-security/src/test/java/org/elasticsearch/smoketest/GraphWithSecurityIT.java b/elasticsearch/qa/smoke-test-graph-with-security/src/test/java/org/elasticsearch/smoketest/GraphWithSecurityIT.java index 01556a37fde..3ddcdee9774 100644 --- a/elasticsearch/qa/smoke-test-graph-with-security/src/test/java/org/elasticsearch/smoketest/GraphWithSecurityIT.java +++ b/elasticsearch/qa/smoke-test-graph-with-security/src/test/java/org/elasticsearch/smoketest/GraphWithSecurityIT.java @@ -7,20 +7,20 @@ package org.elasticsearch.smoketest; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; + import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.ThreadContext; - -import org.elasticsearch.xpack.security.authc.support.SecuredString; -import org.elasticsearch.test.rest.ESRestTestCase; +import org.elasticsearch.test.rest.ESClientYamlSuiteTestCase; import org.elasticsearch.test.rest.RestTestCandidate; import org.elasticsearch.test.rest.parser.RestTestParseException; +import org.elasticsearch.xpack.security.authc.support.SecuredString; import java.io.IOException; import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; -public class GraphWithSecurityIT extends ESRestTestCase { +public class GraphWithSecurityIT extends ESClientYamlSuiteTestCase { private static final String TEST_ADMIN_USERNAME = "test_admin"; private static final String TEST_ADMIN_PASSWORD = "changeme"; @@ -31,7 +31,7 @@ public class GraphWithSecurityIT extends ESRestTestCase { @ParametersFactory public static Iterable parameters() throws IOException, RestTestParseException { - return ESRestTestCase.createParameters(0, 1); + return ESClientYamlSuiteTestCase.createParameters(0, 1); } protected String[] getCredentials() { diff --git a/elasticsearch/qa/smoke-test-monitoring-with-security/insufficient-rights/src/test/java/org/elasticsearch/smoketest/MonitoringWithSecurityInsufficientRoleIT.java b/elasticsearch/qa/smoke-test-monitoring-with-security/insufficient-rights/src/test/java/org/elasticsearch/smoketest/MonitoringWithSecurityInsufficientRoleIT.java index 037941611bf..7e443043ebe 100644 --- a/elasticsearch/qa/smoke-test-monitoring-with-security/insufficient-rights/src/test/java/org/elasticsearch/smoketest/MonitoringWithSecurityInsufficientRoleIT.java +++ b/elasticsearch/qa/smoke-test-monitoring-with-security/insufficient-rights/src/test/java/org/elasticsearch/smoketest/MonitoringWithSecurityInsufficientRoleIT.java @@ -7,19 +7,20 @@ package org.elasticsearch.smoketest; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; + import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.ThreadContext; -import org.elasticsearch.xpack.security.authc.support.SecuredString; -import org.elasticsearch.test.rest.ESRestTestCase; +import org.elasticsearch.test.rest.ESClientYamlSuiteTestCase; import org.elasticsearch.test.rest.RestTestCandidate; import org.elasticsearch.test.rest.parser.RestTestParseException; +import org.elasticsearch.xpack.security.authc.support.SecuredString; import java.io.IOException; import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.hamcrest.Matchers.containsString; -public class MonitoringWithSecurityInsufficientRoleIT extends ESRestTestCase { +public class MonitoringWithSecurityInsufficientRoleIT extends ESClientYamlSuiteTestCase { public MonitoringWithSecurityInsufficientRoleIT(@Name("yaml") RestTestCandidate testCandidate) { super(testCandidate); @@ -27,7 +28,7 @@ public class MonitoringWithSecurityInsufficientRoleIT extends ESRestTestCase { @ParametersFactory public static Iterable parameters() throws IOException, RestTestParseException { - return ESRestTestCase.createParameters(0, 1); + return ESClientYamlSuiteTestCase.createParameters(0, 1); } @Override diff --git a/elasticsearch/qa/smoke-test-monitoring-with-security/sufficient-rights/src/test/java/org/elasticsearch/smoketest/MonitoringWithSecurityIT.java b/elasticsearch/qa/smoke-test-monitoring-with-security/sufficient-rights/src/test/java/org/elasticsearch/smoketest/MonitoringWithSecurityIT.java index c98a6d01c38..be7bb1cc216 100644 --- a/elasticsearch/qa/smoke-test-monitoring-with-security/sufficient-rights/src/test/java/org/elasticsearch/smoketest/MonitoringWithSecurityIT.java +++ b/elasticsearch/qa/smoke-test-monitoring-with-security/sufficient-rights/src/test/java/org/elasticsearch/smoketest/MonitoringWithSecurityIT.java @@ -7,18 +7,19 @@ package org.elasticsearch.smoketest; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; + import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.ThreadContext; -import org.elasticsearch.xpack.security.authc.support.SecuredString; -import org.elasticsearch.test.rest.ESRestTestCase; +import org.elasticsearch.test.rest.ESClientYamlSuiteTestCase; import org.elasticsearch.test.rest.RestTestCandidate; import org.elasticsearch.test.rest.parser.RestTestParseException; +import org.elasticsearch.xpack.security.authc.support.SecuredString; import java.io.IOException; import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; -public class MonitoringWithSecurityIT extends ESRestTestCase { +public class MonitoringWithSecurityIT extends ESClientYamlSuiteTestCase { public MonitoringWithSecurityIT(@Name("yaml") RestTestCandidate testCandidate) { super(testCandidate); @@ -26,7 +27,7 @@ public class MonitoringWithSecurityIT extends ESRestTestCase { @ParametersFactory public static Iterable parameters() throws IOException, RestTestParseException { - return ESRestTestCase.createParameters(0, 1); + return ESClientYamlSuiteTestCase.createParameters(0, 1); } @Override diff --git a/elasticsearch/qa/smoke-test-plugins-ssl/src/test/java/org/elasticsearch/smoketest/SmokeTestPluginsSslIT.java b/elasticsearch/qa/smoke-test-plugins-ssl/src/test/java/org/elasticsearch/smoketest/SmokeTestPluginsSslIT.java index 5741fb72acc..ddd6100f60e 100644 --- a/elasticsearch/qa/smoke-test-plugins-ssl/src/test/java/org/elasticsearch/smoketest/SmokeTestPluginsSslIT.java +++ b/elasticsearch/qa/smoke-test-plugins-ssl/src/test/java/org/elasticsearch/smoketest/SmokeTestPluginsSslIT.java @@ -7,15 +7,16 @@ package org.elasticsearch.smoketest; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; + import org.elasticsearch.ElasticsearchException; import org.elasticsearch.common.io.PathUtils; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.ThreadContext; -import org.elasticsearch.xpack.security.authc.support.SecuredString; +import org.elasticsearch.test.rest.ESClientYamlSuiteTestCase; import org.elasticsearch.test.rest.ESRestTestCase; import org.elasticsearch.test.rest.RestTestCandidate; -import org.elasticsearch.test.rest.client.RestTestClient; import org.elasticsearch.test.rest.parser.RestTestParseException; +import org.elasticsearch.xpack.security.authc.support.SecuredString; import org.junit.AfterClass; import org.junit.BeforeClass; @@ -26,7 +27,7 @@ import java.nio.file.Path; import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; -public class SmokeTestPluginsSslIT extends ESRestTestCase { +public class SmokeTestPluginsSslIT extends ESClientYamlSuiteTestCase { private static final String USER = "test_user"; private static final String PASS = "changeme"; @@ -38,7 +39,7 @@ public class SmokeTestPluginsSslIT extends ESRestTestCase { @ParametersFactory public static Iterable parameters() throws IOException, RestTestParseException { - return ESRestTestCase.createParameters(0, 1); + return ESClientYamlSuiteTestCase.createParameters(0, 1); } static Path keyStore; @@ -65,9 +66,13 @@ public class SmokeTestPluginsSslIT extends ESRestTestCase { String token = basicAuthHeaderValue(USER, new SecuredString(PASS.toCharArray())); return Settings.builder() .put(ThreadContext.PREFIX + ".Authorization", token) - .put(RestTestClient.PROTOCOL, "https") - .put(RestTestClient.TRUSTSTORE_PATH, keyStore) - .put(RestTestClient.TRUSTSTORE_PASSWORD, KEYSTORE_PASS) + .put(ESRestTestCase.TRUSTSTORE_PATH, keyStore) + .put(ESRestTestCase.TRUSTSTORE_PASSWORD, KEYSTORE_PASS) .build(); } + + @Override + protected String getProtocol() { + return "https"; + } } diff --git a/elasticsearch/qa/smoke-test-plugins/src/test/java/org/elasticsearch/smoketest/SmokeTestPluginsIT.java b/elasticsearch/qa/smoke-test-plugins/src/test/java/org/elasticsearch/smoketest/SmokeTestPluginsIT.java index 4555cc858d2..09f23a0939a 100644 --- a/elasticsearch/qa/smoke-test-plugins/src/test/java/org/elasticsearch/smoketest/SmokeTestPluginsIT.java +++ b/elasticsearch/qa/smoke-test-plugins/src/test/java/org/elasticsearch/smoketest/SmokeTestPluginsIT.java @@ -7,18 +7,19 @@ package org.elasticsearch.smoketest; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; + import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.ThreadContext; -import org.elasticsearch.xpack.security.authc.support.SecuredString; -import org.elasticsearch.test.rest.ESRestTestCase; +import org.elasticsearch.test.rest.ESClientYamlSuiteTestCase; import org.elasticsearch.test.rest.RestTestCandidate; import org.elasticsearch.test.rest.parser.RestTestParseException; +import org.elasticsearch.xpack.security.authc.support.SecuredString; import java.io.IOException; import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; -public class SmokeTestPluginsIT extends ESRestTestCase { +public class SmokeTestPluginsIT extends ESClientYamlSuiteTestCase { private static final String USER = "test_user"; private static final String PASS = "changeme"; @@ -29,7 +30,7 @@ public class SmokeTestPluginsIT extends ESRestTestCase { @ParametersFactory public static Iterable parameters() throws IOException, RestTestParseException { - return ESRestTestCase.createParameters(0, 1); + return ESClientYamlSuiteTestCase.createParameters(0, 1); } @Override diff --git a/elasticsearch/qa/smoke-test-security-with-mustache/build.gradle b/elasticsearch/qa/smoke-test-security-with-mustache/build.gradle new file mode 100644 index 00000000000..05ea5357e3e --- /dev/null +++ b/elasticsearch/qa/smoke-test-security-with-mustache/build.gradle @@ -0,0 +1,27 @@ +apply plugin: 'elasticsearch.rest-test' + +dependencies { + testCompile project(path: ':x-plugins:elasticsearch:x-pack', configuration: 'runtime') + testCompile project(path: ':modules:lang-mustache', configuration: 'runtime') +} + +integTest { + cluster { + plugin ':x-plugins:elasticsearch:x-pack' + setting 'xpack.watcher.enabled', 'false' + setting 'xpack.monitoring.enabled', 'false' + setting 'path.scripts', "${project.buildDir}/resources/test/templates" + setupCommand 'setupDummyUser', + 'bin/x-pack/users', 'useradd', 'test_admin', '-p', 'changeme', '-r', 'superuser' + waitCondition = { node, ant -> + File tmpFile = new File(node.cwd, 'wait.success') + ant.get(src: "http://${node.httpUri()}", + dest: tmpFile.toString(), + username: 'test_admin', + password: 'changeme', + ignoreerrors: true, + retries: 10) + return tmpFile.exists() + } + } +} diff --git a/elasticsearch/qa/smoke-test-security-with-mustache/src/test/java/org/elasticsearch/smoketest/RestIT.java b/elasticsearch/qa/smoke-test-security-with-mustache/src/test/java/org/elasticsearch/smoketest/RestIT.java new file mode 100644 index 00000000000..15469da78bf --- /dev/null +++ b/elasticsearch/qa/smoke-test-security-with-mustache/src/test/java/org/elasticsearch/smoketest/RestIT.java @@ -0,0 +1,41 @@ +/* + * 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.smoketest; + +import com.carrotsearch.randomizedtesting.annotations.Name; +import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; + +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; +import org.elasticsearch.test.rest.ESClientYamlSuiteTestCase; +import org.elasticsearch.test.rest.RestTestCandidate; +import org.elasticsearch.test.rest.parser.RestTestParseException; +import org.elasticsearch.xpack.security.authc.support.SecuredString; + +import java.io.IOException; + +import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; + +public class RestIT extends ESClientYamlSuiteTestCase { + + private static final String BASIC_AUTH_VALUE = basicAuthHeaderValue("test_admin", new SecuredString("changeme".toCharArray())); + + public RestIT(@Name("yaml") RestTestCandidate testCandidate) { + super(testCandidate); + } + + @ParametersFactory + public static Iterable parameters() throws IOException, RestTestParseException { + return ESClientYamlSuiteTestCase.createParameters(0, 1); + } + + @Override + protected Settings restClientSettings() { + return Settings.builder() + .put(ThreadContext.PREFIX + ".Authorization", BASIC_AUTH_VALUE) + .build(); + } +} diff --git a/elasticsearch/qa/smoke-test-security-with-mustache/src/test/resources/rest-api-spec/test/templated_role_query/10_templated_role_query.yaml b/elasticsearch/qa/smoke-test-security-with-mustache/src/test/resources/rest-api-spec/test/templated_role_query/10_templated_role_query.yaml new file mode 100644 index 00000000000..a1e016aca5c --- /dev/null +++ b/elasticsearch/qa/smoke-test-security-with-mustache/src/test/resources/rest-api-spec/test/templated_role_query/10_templated_role_query.yaml @@ -0,0 +1,191 @@ +--- +setup: + - skip: + features: headers + + - do: + cluster.health: + wait_for_status: yellow + + - do: + xpack.security.put_user: + username: "inline_template_user" + body: > + { + "password": "changeme", + "roles" : [ "inline_template_role" ] + } + - do: + xpack.security.put_user: + username: "stored_template_user" + body: > + { + "password": "changeme", + "roles" : [ "stored_template_role" ] + } + + - do: + xpack.security.put_user: + username: "file_template_user" + body: > + { + "password": "changeme", + "roles" : [ "file_template_role" ] + } + + - do: + xpack.security.put_role: + name: "inline_template_role" + body: > + { + "indices": [ + { + "names": "foobar", + "privileges": ["all"], + "query" : { + "template" : { + "inline" : { + "term" : { "username" : "{{_user.username}}" } + } + } + } + } + ] + } + + - do: + xpack.security.put_role: + name: "stored_template_role" + body: > + { + "indices": [ + { + "names": "foobar", + "privileges": ["all"], + "query" : { + "template" : { + "id" : "1" + } + } + } + ] + } + + - do: + xpack.security.put_role: + name: "file_template_role" + body: > + { + "indices": [ + { + "names": "foobar", + "privileges": ["all"], + "query" : { + "template" : { + "file" : "query" + } + } + } + ] + } + + - do: + put_template: + id: "1" + body: > + { + "term" : { + "username" : "{{_user.username}}" + } + } + + - do: + index: + index: foobar + type: type + id: 1 + body: > + { + "username": "inline_template_user" + } + - do: + index: + index: foobar + type: type + id: 2 + body: > + { + "username": "stored_template_user" + } + - do: + index: + index: foobar + type: type + id: 3 + body: > + { + "username": "file_template_user" + } + + - do: + indices.refresh: {} + +--- +teardown: + - do: + xpack.security.delete_user: + username: "inline_template_user" + ignore: 404 + - do: + xpack.security.delete_user: + username: "stored_template_user" + ignore: 404 + - do: + xpack.security.delete_user: + username: "file_template_user" + ignore: 404 + - do: + xpack.security.delete_role: + name: "inline_template_role" + ignore: 404 + - do: + xpack.security.delete_role: + name: "stored_template_role" + ignore: 404 + - do: + xpack.security.delete_role: + name: "file_template_role" + ignore: 404 + +--- +"Test inline template": + - do: + headers: + Authorization: "Basic aW5saW5lX3RlbXBsYXRlX3VzZXI6Y2hhbmdlbWU=" + search: + index: foobar + body: { "query" : { "match_all" : {} } } + - match: { hits.total: 1} + - match: { hits.hits.0._source.username: inline_template_user} + +--- +"Test stored template": + - do: + headers: + Authorization: "Basic c3RvcmVkX3RlbXBsYXRlX3VzZXI6Y2hhbmdlbWU=" + search: + index: foobar + body: { "query" : { "match_all" : {} } } + - match: { hits.total: 1} + - match: { hits.hits.0._source.username: stored_template_user} + +--- +"Test file template": + - do: + headers: + Authorization: "Basic ZmlsZV90ZW1wbGF0ZV91c2VyOmNoYW5nZW1l" + search: + index: foobar + body: { "query" : { "match_all" : {} } } + - match: { hits.total: 1} + - match: { hits.hits.0._source.username: file_template_user} diff --git a/elasticsearch/qa/smoke-test-security-with-mustache/src/test/resources/rest-api-spec/test/templated_role_query/20_small_users_one_index.yaml b/elasticsearch/qa/smoke-test-security-with-mustache/src/test/resources/rest-api-spec/test/templated_role_query/20_small_users_one_index.yaml new file mode 100644 index 00000000000..c04ae085fdd --- /dev/null +++ b/elasticsearch/qa/smoke-test-security-with-mustache/src/test/resources/rest-api-spec/test/templated_role_query/20_small_users_one_index.yaml @@ -0,0 +1,198 @@ +--- +setup: + - skip: + features: headers + + - do: + indices.create: + index: shared_logs + + - do: + cluster.health: + wait_for_status: yellow + - do: + ingest.put_pipeline: + id: "my_pipeline" + body: > + { + "processors": [ + { + "set_security_user" : { + "field" : "user" + } + } + ] + } + - do: + xpack.security.put_user: + username: "joe" + body: > + { + "password": "changeme", + "roles" : [ "small_companies_role" ], + "metadata" : { + "customer_id" : "1" + } + } + - do: + xpack.security.put_user: + username: "john" + body: > + { + "password": "changeme", + "roles" : [ "small_companies_role" ], + "metadata" : { + "customer_id" : "2" + } + } + +--- +teardown: + - do: + xpack.security.delete_user: + username: "joe" + ignore: 404 + - do: + xpack.security.delete_user: + username: "john" + ignore: 404 + - do: + xpack.security.delete_role: + name: "small_companies_role" + ignore: 404 + +--- +"Test shared index seperating user by using DLS role query with user's username": + - do: + xpack.security.put_role: + name: "small_companies_role" + body: > + { + "indices": [ + { + "names": "shared_logs", + "privileges": ["read", "create"], + "query" : { + "template" : { + "inline" : { + "term" : { "user.username" : "{{_user.username}}" } + } + } + } + } + ] + } + + - do: + headers: + Authorization: "Basic am9lOmNoYW5nZW1l" + index: + index: shared_logs + type: type + pipeline: "my_pipeline" + body: > + { + "log": "Joe's first log entry" + } + - do: + headers: + Authorization: "Basic am9objpjaGFuZ2VtZQ==" + index: + index: shared_logs + type: type + pipeline: "my_pipeline" + body: > + { + "log": "John's first log entry" + } + + - do: + indices.refresh: {} + + # Joe searches: + - do: + headers: + Authorization: "Basic am9lOmNoYW5nZW1l" + search: + index: shared_logs + body: { "query" : { "match_all" : {} } } + - match: { hits.total: 1} + - match: { hits.hits.0._source.user.username: joe} + + # John searches: + - do: + headers: + Authorization: "Basic am9objpjaGFuZ2VtZQ==" + search: + index: shared_logs + body: { "query" : { "match_all" : {} } } + - match: { hits.total: 1} + - match: { hits.hits.0._source.user.username: john} + +--- +"Test shared index seperating user by using DLS role query with user's metadata": + - do: + xpack.security.put_role: + name: "small_companies_role" + body: > + { + "indices": [ + { + "names": "shared_logs", + "privileges": ["read", "create"], + "query" : { + "template" : { + "inline" : { + "term" : { "user.metadata.customer_id" : "{{_user.metadata.customer_id}}" } + } + } + } + } + ] + } + + - do: + headers: + Authorization: "Basic am9lOmNoYW5nZW1l" + index: + index: shared_logs + type: type + pipeline: "my_pipeline" + body: > + { + "log": "Joe's first log entry" + } + - do: + headers: + Authorization: "Basic am9objpjaGFuZ2VtZQ==" + index: + index: shared_logs + type: type + pipeline: "my_pipeline" + body: > + { + "log": "John's first log entry" + } + + - do: + indices.refresh: {} + + # Joe searches: + - do: + headers: + Authorization: "Basic am9lOmNoYW5nZW1l" + search: + index: shared_logs + body: { "query" : { "match_all" : {} } } + - match: { hits.total: 1} + - match: { hits.hits.0._source.user.username: joe} + + # John searches: + - do: + headers: + Authorization: "Basic am9objpjaGFuZ2VtZQ==" + search: + index: shared_logs + body: { "query" : { "match_all" : {} } } + - match: { hits.total: 1} + - match: { hits.hits.0._source.user.username: john} diff --git a/elasticsearch/qa/smoke-test-security-with-mustache/src/test/resources/templates/query.mustache b/elasticsearch/qa/smoke-test-security-with-mustache/src/test/resources/templates/query.mustache new file mode 100644 index 00000000000..34a93aa2cd7 --- /dev/null +++ b/elasticsearch/qa/smoke-test-security-with-mustache/src/test/resources/templates/query.mustache @@ -0,0 +1,5 @@ +{ + "term" : { + "username" : "{{_user.username}}" + } +} \ No newline at end of file diff --git a/elasticsearch/qa/smoke-test-watcher-with-groovy/src/test/java/org/elasticsearch/smoketest/WatcherRestTestCase.java b/elasticsearch/qa/smoke-test-watcher-with-groovy/src/test/java/org/elasticsearch/smoketest/WatcherRestTestCase.java index af80d098c1c..a1842d3a8ee 100644 --- a/elasticsearch/qa/smoke-test-watcher-with-groovy/src/test/java/org/elasticsearch/smoketest/WatcherRestTestCase.java +++ b/elasticsearch/qa/smoke-test-watcher-with-groovy/src/test/java/org/elasticsearch/smoketest/WatcherRestTestCase.java @@ -7,7 +7,8 @@ package org.elasticsearch.smoketest; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; -import org.elasticsearch.test.rest.ESRestTestCase; + +import org.elasticsearch.test.rest.ESClientYamlSuiteTestCase; import org.elasticsearch.test.rest.RestTestCandidate; import org.elasticsearch.test.rest.parser.RestTestParseException; import org.junit.After; @@ -18,7 +19,7 @@ import java.io.IOException; import static java.util.Collections.emptyList; import static java.util.Collections.emptyMap; -public abstract class WatcherRestTestCase extends ESRestTestCase { +public abstract class WatcherRestTestCase extends ESClientYamlSuiteTestCase { public WatcherRestTestCase(@Name("yaml") RestTestCandidate testCandidate) { super(testCandidate); @@ -26,7 +27,7 @@ public abstract class WatcherRestTestCase extends ESRestTestCase { @ParametersFactory public static Iterable parameters() throws IOException, RestTestParseException { - return ESRestTestCase.createParameters(0, 1); + return ESClientYamlSuiteTestCase.createParameters(0, 1); } @Before diff --git a/elasticsearch/qa/smoke-test-watcher-with-mustache/src/test/java/org/elasticsearch/smoketest/WatcherRestTestCase.java b/elasticsearch/qa/smoke-test-watcher-with-mustache/src/test/java/org/elasticsearch/smoketest/WatcherRestTestCase.java index af80d098c1c..a1842d3a8ee 100644 --- a/elasticsearch/qa/smoke-test-watcher-with-mustache/src/test/java/org/elasticsearch/smoketest/WatcherRestTestCase.java +++ b/elasticsearch/qa/smoke-test-watcher-with-mustache/src/test/java/org/elasticsearch/smoketest/WatcherRestTestCase.java @@ -7,7 +7,8 @@ package org.elasticsearch.smoketest; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; -import org.elasticsearch.test.rest.ESRestTestCase; + +import org.elasticsearch.test.rest.ESClientYamlSuiteTestCase; import org.elasticsearch.test.rest.RestTestCandidate; import org.elasticsearch.test.rest.parser.RestTestParseException; import org.junit.After; @@ -18,7 +19,7 @@ import java.io.IOException; import static java.util.Collections.emptyList; import static java.util.Collections.emptyMap; -public abstract class WatcherRestTestCase extends ESRestTestCase { +public abstract class WatcherRestTestCase extends ESClientYamlSuiteTestCase { public WatcherRestTestCase(@Name("yaml") RestTestCandidate testCandidate) { super(testCandidate); @@ -26,7 +27,7 @@ public abstract class WatcherRestTestCase extends ESRestTestCase { @ParametersFactory public static Iterable parameters() throws IOException, RestTestParseException { - return ESRestTestCase.createParameters(0, 1); + return ESClientYamlSuiteTestCase.createParameters(0, 1); } @Before diff --git a/elasticsearch/qa/smoke-test-watcher-with-mustache/src/test/java/org/elasticsearch/smoketest/WatcherWithMustacheIT.java b/elasticsearch/qa/smoke-test-watcher-with-mustache/src/test/java/org/elasticsearch/smoketest/WatcherWithMustacheIT.java index 4865aa483ad..299341a4fba 100644 --- a/elasticsearch/qa/smoke-test-watcher-with-mustache/src/test/java/org/elasticsearch/smoketest/WatcherWithMustacheIT.java +++ b/elasticsearch/qa/smoke-test-watcher-with-mustache/src/test/java/org/elasticsearch/smoketest/WatcherWithMustacheIT.java @@ -7,14 +7,15 @@ package org.elasticsearch.smoketest; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; -import org.elasticsearch.test.rest.ESRestTestCase; + +import org.elasticsearch.test.rest.ESClientYamlSuiteTestCase; import org.elasticsearch.test.rest.RestTestCandidate; import org.elasticsearch.test.rest.parser.RestTestParseException; import java.io.IOException; /** Runs rest tests against external cluster */ -public class WatcherWithMustacheIT extends WatcherRestTestCase { +public class WatcherWithMustacheIT extends ESClientYamlSuiteTestCase { public WatcherWithMustacheIT(@Name("yaml") RestTestCandidate testCandidate) { super(testCandidate); @@ -22,7 +23,7 @@ public class WatcherWithMustacheIT extends WatcherRestTestCase { @ParametersFactory public static Iterable parameters() throws IOException, RestTestParseException { - return ESRestTestCase.createParameters(0, 1); + return ESClientYamlSuiteTestCase.createParameters(0, 1); } } diff --git a/elasticsearch/qa/smoke-test-watcher-with-painless/src/test/java/org/elasticsearch/smoketest/WatcherRestTestCase.java b/elasticsearch/qa/smoke-test-watcher-with-painless/src/test/java/org/elasticsearch/smoketest/WatcherRestTestCase.java index af80d098c1c..a1842d3a8ee 100644 --- a/elasticsearch/qa/smoke-test-watcher-with-painless/src/test/java/org/elasticsearch/smoketest/WatcherRestTestCase.java +++ b/elasticsearch/qa/smoke-test-watcher-with-painless/src/test/java/org/elasticsearch/smoketest/WatcherRestTestCase.java @@ -7,7 +7,8 @@ package org.elasticsearch.smoketest; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; -import org.elasticsearch.test.rest.ESRestTestCase; + +import org.elasticsearch.test.rest.ESClientYamlSuiteTestCase; import org.elasticsearch.test.rest.RestTestCandidate; import org.elasticsearch.test.rest.parser.RestTestParseException; import org.junit.After; @@ -18,7 +19,7 @@ import java.io.IOException; import static java.util.Collections.emptyList; import static java.util.Collections.emptyMap; -public abstract class WatcherRestTestCase extends ESRestTestCase { +public abstract class WatcherRestTestCase extends ESClientYamlSuiteTestCase { public WatcherRestTestCase(@Name("yaml") RestTestCandidate testCandidate) { super(testCandidate); @@ -26,7 +27,7 @@ public abstract class WatcherRestTestCase extends ESRestTestCase { @ParametersFactory public static Iterable parameters() throws IOException, RestTestParseException { - return ESRestTestCase.createParameters(0, 1); + return ESClientYamlSuiteTestCase.createParameters(0, 1); } @Before diff --git a/elasticsearch/qa/smoke-test-watcher-with-security/src/test/java/org/elasticsearch/smoketest/WatcherWithSecurityIT.java b/elasticsearch/qa/smoke-test-watcher-with-security/src/test/java/org/elasticsearch/smoketest/WatcherWithSecurityIT.java index 7c449e251b0..cfaa001f174 100644 --- a/elasticsearch/qa/smoke-test-watcher-with-security/src/test/java/org/elasticsearch/smoketest/WatcherWithSecurityIT.java +++ b/elasticsearch/qa/smoke-test-watcher-with-security/src/test/java/org/elasticsearch/smoketest/WatcherWithSecurityIT.java @@ -7,25 +7,24 @@ package org.elasticsearch.smoketest; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; + import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.ThreadContext; -import org.elasticsearch.xpack.security.authc.support.SecuredString; -import org.elasticsearch.test.rest.ESRestTestCase; +import org.elasticsearch.test.rest.ESClientYamlSuiteTestCase; import org.elasticsearch.test.rest.RestTestCandidate; import org.elasticsearch.test.rest.parser.RestTestParseException; +import org.elasticsearch.xpack.security.authc.support.SecuredString; import org.junit.After; import org.junit.Before; - import java.io.IOException; import static java.util.Collections.emptyList; import static java.util.Collections.emptyMap; - import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; -public class WatcherWithSecurityIT extends ESRestTestCase { +public class WatcherWithSecurityIT extends ESClientYamlSuiteTestCase { private static final String TEST_ADMIN_USERNAME = "test_admin"; private static final String TEST_ADMIN_PASSWORD = "changeme"; @@ -36,7 +35,7 @@ public class WatcherWithSecurityIT extends ESRestTestCase { @ParametersFactory public static Iterable parameters() throws IOException, RestTestParseException { - return ESRestTestCase.createParameters(0, 1); + return ESClientYamlSuiteTestCase.createParameters(0, 1); } @Before diff --git a/elasticsearch/qa/smoke-test-watcher/src/test/java/org/elasticsearch/smoketest/WatcherGettingStartedIT.java b/elasticsearch/qa/smoke-test-watcher/src/test/java/org/elasticsearch/smoketest/WatcherGettingStartedIT.java index bb9a09d6dbf..d4b58ffcf86 100644 --- a/elasticsearch/qa/smoke-test-watcher/src/test/java/org/elasticsearch/smoketest/WatcherGettingStartedIT.java +++ b/elasticsearch/qa/smoke-test-watcher/src/test/java/org/elasticsearch/smoketest/WatcherGettingStartedIT.java @@ -7,7 +7,8 @@ package org.elasticsearch.smoketest; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; -import org.elasticsearch.test.rest.ESRestTestCase; + +import org.elasticsearch.test.rest.ESClientYamlSuiteTestCase; import org.elasticsearch.test.rest.RestTestCandidate; import org.elasticsearch.test.rest.parser.RestTestParseException; import org.junit.After; @@ -19,7 +20,7 @@ import static java.util.Collections.emptyList; import static java.util.Collections.emptyMap; /** Runs rest tests against external cluster */ -public class WatcherGettingStartedIT extends ESRestTestCase { +public class WatcherGettingStartedIT extends ESClientYamlSuiteTestCase { public WatcherGettingStartedIT(@Name("yaml") RestTestCandidate testCandidate) { super(testCandidate); @@ -27,7 +28,7 @@ public class WatcherGettingStartedIT extends ESRestTestCase { @ParametersFactory public static Iterable parameters() throws IOException, RestTestParseException { - return ESRestTestCase.createParameters(0, 1); + return ESClientYamlSuiteTestCase.createParameters(0, 1); } @Before diff --git a/elasticsearch/x-pack/build.gradle b/elasticsearch/x-pack/build.gradle index 9fd6a295b0d..a83e22824c7 100644 --- a/elasticsearch/x-pack/build.gradle +++ b/elasticsearch/x-pack/build.gradle @@ -19,7 +19,10 @@ ext.versions = [ // TODO: fix this! https://github.com/elastic/x-plugins/issues/1066 ext.compactProfile = 'full' -dependencyLicenses.enabled = false +licenseHeaders { + approvedLicenses << 'BCrypt (BSD-like)' + additionalLicense 'BCRYP', 'BCrypt (BSD-like)', 'Copyright (c) 2006 Damien Miller ' +} dependencies { // license deps @@ -232,9 +235,6 @@ thirdPartyAudit.excludes = [ 'javax.activation.UnsupportedDataTypeException' ] -// someone figure out what the x-plugins logic should be -licenseHeaders.enabled = false - modifyPom { MavenPom pom -> pom.withXml { XmlProvider xml -> // first find if we have dependencies at all, and grab the node diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/Security.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/Security.java index 3b1d74ab544..e9ef647a048 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/Security.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/Security.java @@ -427,7 +427,8 @@ public class Security implements ActionPlugin, IngestPlugin { module.setSearcherWrapper(indexService -> new SecurityIndexSearcherWrapper(indexService.getIndexSettings(), indexService.newQueryShardContext(), indexService.mapperService(), indexService.cache().bitsetFilterCache(), - indexService.getIndexServices().getThreadPool().getThreadContext(), licenseState)); + indexService.getIndexServices().getThreadPool().getThreadContext(), licenseState, + indexService.getIndexServices().getScriptService())); } if (transportClientMode == false) { /* We need to forcefully overwrite the query cache implementation to use security's opt out query cache implementation. diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/accesscontrol/SecurityIndexSearcherWrapper.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/accesscontrol/SecurityIndexSearcherWrapper.java index 55133a7fe5a..4e0c25db6cc 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/accesscontrol/SecurityIndexSearcherWrapper.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/accesscontrol/SecurityIndexSearcherWrapper.java @@ -22,7 +22,9 @@ import org.apache.lucene.util.BitSet; import org.apache.lucene.util.BitSetIterator; import org.apache.lucene.util.Bits; import org.apache.lucene.util.SparseFixedBitSet; +import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.ExceptionsHelper; +import org.elasticsearch.common.ParseFieldMatcher; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.logging.ESLogger; import org.elasticsearch.common.logging.LoggerMessageFormat; @@ -44,15 +46,23 @@ import org.elasticsearch.index.shard.IndexSearcherWrapper; import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.index.shard.ShardUtils; import org.elasticsearch.license.plugin.core.XPackLicenseState; +import org.elasticsearch.script.ExecutableScript; +import org.elasticsearch.script.Script; +import org.elasticsearch.script.ScriptContext; +import org.elasticsearch.script.ScriptService; +import org.elasticsearch.xpack.security.authc.Authentication; import org.elasticsearch.xpack.security.authz.AuthorizationService; import org.elasticsearch.xpack.security.authz.accesscontrol.DocumentSubsetReader.DocumentSubsetDirectoryReader; import org.elasticsearch.xpack.security.support.Exceptions; +import org.elasticsearch.xpack.security.user.User; import java.io.IOException; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; @@ -78,10 +88,13 @@ public class SecurityIndexSearcherWrapper extends IndexSearcherWrapper { private final XPackLicenseState licenseState; private final ThreadContext threadContext; private final ESLogger logger; + private final ScriptService scriptService; public SecurityIndexSearcherWrapper(IndexSettings indexSettings, QueryShardContext queryShardContext, MapperService mapperService, BitsetFilterCache bitsetFilterCache, - ThreadContext threadContext, XPackLicenseState licenseState) { + ThreadContext threadContext, XPackLicenseState licenseState, + ScriptService scriptService) { + this.scriptService = scriptService; this.logger = Loggers.getLogger(getClass(), indexSettings.getSettings()); this.mapperService = mapperService; this.queryShardContext = queryShardContext; @@ -124,6 +137,7 @@ public class SecurityIndexSearcherWrapper extends IndexSearcherWrapper { BooleanQuery.Builder filter = new BooleanQuery.Builder(); for (BytesReference bytesReference : permissions.getQueries()) { QueryShardContext queryShardContext = copyQueryShardContext(this.queryShardContext); + bytesReference = evaluateTemplate(bytesReference); try (XContentParser parser = XContentFactory.xContent(bytesReference).createParser(bytesReference)) { Optional queryBuilder = queryShardContext.newParseContext(parser).parseInnerQueryBuilder(); if (queryBuilder.isPresent()) { @@ -262,6 +276,45 @@ public class SecurityIndexSearcherWrapper extends IndexSearcherWrapper { } } + BytesReference evaluateTemplate(BytesReference querySource) throws IOException { + try (XContentParser parser = XContentFactory.xContent(querySource).createParser(querySource)) { + XContentParser.Token token = parser.nextToken(); + if (token != XContentParser.Token.START_OBJECT) { + throw new ElasticsearchParseException("Unexpected token [" + token + "]"); + } + token = parser.nextToken(); + if (token != XContentParser.Token.FIELD_NAME) { + throw new ElasticsearchParseException("Unexpected token [" + token + "]"); + } + if ("template".equals(parser.currentName())) { + token = parser.nextToken(); + if (token != XContentParser.Token.START_OBJECT) { + throw new ElasticsearchParseException("Unexpected token [" + token + "]"); + } + Script script = Script.parse(parser, ParseFieldMatcher.EMPTY); + // Add the user details to the params + Map params = new HashMap<>(); + if (script.getParams() != null) { + params.putAll(script.getParams()); + } + User user = getUser(); + Map userModel = new HashMap<>(); + userModel.put("username", user.principal()); + userModel.put("full_name", user.fullName()); + userModel.put("email", user.email()); + userModel.put("roles", Arrays.asList(user.roles())); + userModel.put("metadata", Collections.unmodifiableMap(user.metadata())); + params.put("_user", userModel); + // Always enforce mustache script lang: + script = new Script(script.getScript(), script.getType(), "mustache", params, script.getContentType()); + ExecutableScript executable = scriptService.executable(script, ScriptContext.Standard.SEARCH, Collections.emptyMap()); + return (BytesReference) executable.run(); + } else { + return querySource; + } + } + } + protected IndicesAccessControl getIndicesAccessControl() { IndicesAccessControl indicesAccessControl = threadContext.getTransient(AuthorizationService.INDICES_PERMISSIONS_KEY); if (indicesAccessControl == null) { @@ -269,4 +322,9 @@ public class SecurityIndexSearcherWrapper extends IndexSearcherWrapper { } return indicesAccessControl; } + + protected User getUser(){ + Authentication authentication = Authentication.getAuthentication(threadContext); + return authentication.getUser(); + } } diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/accesscontrol/SecurityIndexSearcherWrapperIntegrationTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/accesscontrol/SecurityIndexSearcherWrapperIntegrationTests.java index efa74e30a28..51a836dad05 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/accesscontrol/SecurityIndexSearcherWrapperIntegrationTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/accesscontrol/SecurityIndexSearcherWrapperIntegrationTests.java @@ -35,6 +35,7 @@ import org.elasticsearch.index.query.QueryShardContext; import org.elasticsearch.index.query.TermQueryBuilder; import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.license.plugin.core.XPackLicenseState; +import org.elasticsearch.script.ScriptService; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.IndexSettingsModule; @@ -55,13 +56,14 @@ public class SecurityIndexSearcherWrapperIntegrationTests extends ESTestCase { public void testDLS() throws Exception { ShardId shardId = new ShardId("_index", "_na_", 0); MapperService mapperService = mock(MapperService.class); + ScriptService scriptService = mock(ScriptService.class); when(mapperService.docMappers(anyBoolean())).thenReturn(Collections.emptyList()); when(mapperService.simpleMatchToIndexNames(anyString())) .then(invocationOnMock -> Collections.singletonList((String) invocationOnMock.getArguments()[0])); ThreadContext threadContext = new ThreadContext(Settings.EMPTY); IndicesAccessControl.IndexAccessControl indexAccessControl = new IndicesAccessControl.IndexAccessControl(true, null, - singleton(new BytesArray("{}"))); + singleton(new BytesArray("{\"match_all\" : {}}"))); IndexSettings indexSettings = IndexSettingsModule.newIndexSettings(shardId.getIndex(), Settings.EMPTY); QueryShardContext queryShardContext = mock(QueryShardContext.class); QueryParseContext queryParseContext = mock(QueryParseContext.class); @@ -79,7 +81,7 @@ public class SecurityIndexSearcherWrapperIntegrationTests extends ESTestCase { XPackLicenseState licenseState = mock(XPackLicenseState.class); when(licenseState.isDocumentAndFieldLevelSecurityAllowed()).thenReturn(true); SecurityIndexSearcherWrapper wrapper = new SecurityIndexSearcherWrapper(indexSettings, queryShardContext, mapperService, - bitsetFilterCache, threadContext, licenseState) { + bitsetFilterCache, threadContext, licenseState, scriptService) { @Override protected QueryShardContext copyQueryShardContext(QueryShardContext context) { @@ -140,7 +142,7 @@ public class SecurityIndexSearcherWrapperIntegrationTests extends ESTestCase { ParsedQuery parsedQuery = new ParsedQuery(new TermQuery(new Term("field", values[i]))); when(queryShardContext.newParseContext(any(XContentParser.class))).thenReturn(queryParseContext); when(queryParseContext.parseInnerQueryBuilder()) - .thenReturn(Optional.of((QueryBuilder) new TermQueryBuilder("field", values[i]))); + .thenReturn(Optional.of(new TermQueryBuilder("field", values[i]))); when(queryShardContext.toQuery(any(QueryBuilder.class))).thenReturn(parsedQuery); DirectoryReader wrappedDirectoryReader = wrapper.wrap(directoryReader); IndexSearcher indexSearcher = wrapper.wrap(new IndexSearcher(wrappedDirectoryReader)); diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/accesscontrol/SecurityIndexSearcherWrapperUnitTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/accesscontrol/SecurityIndexSearcherWrapperUnitTests.java index fc71f66142b..3e029b98141 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/accesscontrol/SecurityIndexSearcherWrapperUnitTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/accesscontrol/SecurityIndexSearcherWrapperUnitTests.java @@ -35,33 +35,48 @@ import org.apache.lucene.util.BitSet; import org.apache.lucene.util.FixedBitSet; import org.apache.lucene.util.IOUtils; import org.apache.lucene.util.SparseFixedBitSet; +import org.elasticsearch.common.bytes.BytesArray; +import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.compress.CompressedXContent; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.lucene.index.ElasticsearchDirectoryReader; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.ThreadContext; +import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.env.Environment; import org.elasticsearch.index.Index; import org.elasticsearch.index.IndexSettings; import org.elasticsearch.index.analysis.AnalysisService; import org.elasticsearch.index.cache.bitset.BitsetFilterCache; import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.mapper.internal.ParentFieldMapper; +import org.elasticsearch.index.query.TermQueryBuilder; import org.elasticsearch.index.shard.IndexShard; import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.index.similarity.SimilarityService; import org.elasticsearch.indices.IndicesModule; +import org.elasticsearch.script.ExecutableScript; +import org.elasticsearch.script.Script; +import org.elasticsearch.script.ScriptContext; +import org.elasticsearch.script.ScriptService; import org.elasticsearch.search.aggregations.LeafBucketCollector; +import org.elasticsearch.watcher.ResourceWatcherService; import org.elasticsearch.xpack.security.authz.accesscontrol.DocumentSubsetReader.DocumentSubsetDirectoryReader; import org.elasticsearch.license.plugin.core.XPackLicenseState; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.IndexSettingsModule; +import org.elasticsearch.xpack.security.user.User; import org.junit.After; import org.junit.Before; +import org.mockito.ArgumentCaptor; import java.io.IOException; +import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.IdentityHashMap; +import java.util.Map; import java.util.Set; import static java.util.Collections.emptyList; @@ -75,13 +90,18 @@ import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.sameInstance; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; 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 SecurityIndexSearcherWrapperUnitTests extends ESTestCase { private ThreadContext threadContext; private MapperService mapperService; + private ScriptService scriptService; private SecurityIndexSearcherWrapper securityIndexSearcherWrapper; private ElasticsearchDirectoryReader esIn; private XPackLicenseState licenseState; @@ -90,6 +110,7 @@ public class SecurityIndexSearcherWrapperUnitTests extends ESTestCase { @Before public void before() throws Exception { Index index = new Index("_index", "testUUID"); + scriptService = mock(ScriptService.class); indexSettings = IndexSettingsModule.newIndexSettings(index, Settings.EMPTY); AnalysisService analysisService = new AnalysisService(indexSettings, Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap()); @@ -125,7 +146,7 @@ public class SecurityIndexSearcherWrapperUnitTests extends ESTestCase { mapperService.merge("type", new CompressedXContent(mappingSource.string()), MapperService.MergeReason.MAPPING_UPDATE, false); securityIndexSearcherWrapper = - new SecurityIndexSearcherWrapper(indexSettings, null, mapperService, null, threadContext, licenseState) { + new SecurityIndexSearcherWrapper(indexSettings, null, mapperService, null, threadContext, licenseState, scriptService) { @Override protected IndicesAccessControl getIndicesAccessControl() { IndicesAccessControl.IndexAccessControl indexAccessControl = new IndicesAccessControl.IndexAccessControl(true, @@ -156,14 +177,14 @@ public class SecurityIndexSearcherWrapperUnitTests extends ESTestCase { public void testWrapReaderWhenFeatureDisabled() throws Exception { when(licenseState.isDocumentAndFieldLevelSecurityAllowed()).thenReturn(false); securityIndexSearcherWrapper = - new SecurityIndexSearcherWrapper(indexSettings, null, mapperService, null, threadContext, licenseState); + new SecurityIndexSearcherWrapper(indexSettings, null, mapperService, null, threadContext, licenseState, scriptService); DirectoryReader reader = securityIndexSearcherWrapper.wrap(esIn); assertThat(reader, sameInstance(esIn)); } public void testWrapSearcherWhenFeatureDisabled() throws Exception { securityIndexSearcherWrapper = - new SecurityIndexSearcherWrapper(indexSettings, null, mapperService, null, threadContext, licenseState); + new SecurityIndexSearcherWrapper(indexSettings, null, mapperService, null, threadContext, licenseState, scriptService); IndexSearcher indexSearcher = new IndexSearcher(esIn); IndexSearcher result = securityIndexSearcherWrapper.wrap(indexSearcher); assertThat(result, sameInstance(indexSearcher)); @@ -275,7 +296,7 @@ public class SecurityIndexSearcherWrapperUnitTests extends ESTestCase { DirectoryReader directoryReader = DocumentSubsetReader.wrap(esIn, bitsetFilterCache, new MatchAllDocsQuery()); IndexSearcher indexSearcher = new IndexSearcher(directoryReader); securityIndexSearcherWrapper = - new SecurityIndexSearcherWrapper(indexSettings, null, mapperService, null, threadContext, licenseState); + new SecurityIndexSearcherWrapper(indexSettings, null, mapperService, null, threadContext, licenseState, scriptService); IndexSearcher result = securityIndexSearcherWrapper.wrap(indexSearcher); assertThat(result, not(sameInstance(indexSearcher))); assertThat(result.getSimilarity(true), sameInstance(indexSearcher.getSimilarity(true))); @@ -284,7 +305,7 @@ public class SecurityIndexSearcherWrapperUnitTests extends ESTestCase { public void testIntersectScorerAndRoleBits() throws Exception { securityIndexSearcherWrapper = - new SecurityIndexSearcherWrapper(indexSettings, null, mapperService, null, threadContext, licenseState); + new SecurityIndexSearcherWrapper(indexSettings, null, mapperService, null, threadContext, licenseState, scriptService); final Directory directory = newDirectory(); IndexWriter iw = new IndexWriter( directory, @@ -373,7 +394,7 @@ public class SecurityIndexSearcherWrapperUnitTests extends ESTestCase { private void assertResolvedFields(String expression, String... expectedFields) { securityIndexSearcherWrapper = - new SecurityIndexSearcherWrapper(indexSettings, null, mapperService, null, threadContext, licenseState) { + new SecurityIndexSearcherWrapper(indexSettings, null, mapperService, null, threadContext, licenseState, scriptService) { @Override protected IndicesAccessControl getIndicesAccessControl() { IndicesAccessControl.IndexAccessControl indexAccessControl = new IndicesAccessControl.IndexAccessControl(true, @@ -407,6 +428,60 @@ public class SecurityIndexSearcherWrapperUnitTests extends ESTestCase { doTestIndexSearcherWrapper(false, true); } + public void testTemplating() throws Exception { + User user = new User("_username", new String[]{"role1", "role2"}, "_full_name", "_email", + Collections.singletonMap("key", "value")); + securityIndexSearcherWrapper = + new SecurityIndexSearcherWrapper(indexSettings, null, mapperService, null, threadContext, licenseState, scriptService) { + + @Override + protected User getUser() { + return user; + } + }; + + ExecutableScript executableScript = mock(ExecutableScript.class); + when(scriptService.executable(any(Script.class), eq(ScriptContext.Standard.SEARCH), eq(Collections.emptyMap()))) + .thenReturn(executableScript); + + XContentBuilder builder = jsonBuilder(); + String query = new TermQueryBuilder("field", "{{_user.username}}").toXContent(builder, ToXContent.EMPTY_PARAMS).string(); + Script script = new Script(query, ScriptService.ScriptType.INLINE, null, Collections.singletonMap("custom", "value")); + builder = jsonBuilder().startObject().field("template"); + script.toXContent(builder, ToXContent.EMPTY_PARAMS); + BytesReference querySource = builder.endObject().bytes(); + + securityIndexSearcherWrapper.evaluateTemplate(querySource); + ArgumentCaptor