shield: disable document and field level security by default

This change disables document and field level security by default so that we are able to maintain
bulk update functionality. Users that enable DLS/FLS will not have this functionality. Additionally,
if a user tries to configure DLS/FLS in a role without enabling it, the role will be skipped during
parsing and a log message will be logged at the error level.

See elastic/elasticsearch#938

Original commit: elastic/x-pack-elasticsearch@60c7519092
This commit is contained in:
jaymode 2015-11-17 16:28:45 -05:00
parent cc2096b4f9
commit 16848c6043
11 changed files with 185 additions and 19 deletions

View File

@ -309,7 +309,7 @@ public class ShieldPlugin extends Plugin {
} }
public static boolean flsDlsEnabled(Settings settings) { public static boolean flsDlsEnabled(Settings settings) {
return settings.getAsBoolean(DLS_FLS_ENABLED_SETTING, true); return settings.getAsBoolean(DLS_FLS_ENABLED_SETTING, false);
} }
private void failIfShieldQueryCacheIsNotActive(Settings settings, boolean nodeSettings) { private void failIfShieldQueryCacheIsNotActive(Settings settings, boolean nodeSettings) {

View File

@ -90,7 +90,7 @@ public class FileRolesStore extends AbstractLifecycleComponent<RolesStore> imple
} catch (IOException e) { } catch (IOException e) {
throw new ElasticsearchException("failed to setup roles file watcher", e); throw new ElasticsearchException("failed to setup roles file watcher", e);
} }
permissions = parseFile(file, reservedRoles, logger); permissions = parseFile(file, reservedRoles, logger, settings);
} }
@Override @Override
@ -116,18 +116,18 @@ public class FileRolesStore extends AbstractLifecycleComponent<RolesStore> imple
} }
public static Set<String> parseFileForRoleNames(Path path, ESLogger logger) { public static Set<String> parseFileForRoleNames(Path path, ESLogger logger) {
Map<String, Permission.Global.Role> roleMap = parseFile(path, Collections.<Permission.Global.Role>emptySet(), logger, false); Map<String, Permission.Global.Role> roleMap = parseFile(path, Collections.<Permission.Global.Role>emptySet(), logger, false, Settings.EMPTY);
if (roleMap == null) { if (roleMap == null) {
return emptySet(); return emptySet();
} }
return roleMap.keySet(); return roleMap.keySet();
} }
public static Map<String, Permission.Global.Role> parseFile(Path path, Set<Permission.Global.Role> reservedRoles, ESLogger logger) { public static Map<String, Permission.Global.Role> parseFile(Path path, Set<Permission.Global.Role> reservedRoles, ESLogger logger, Settings settings) {
return parseFile(path, reservedRoles, logger, true); return parseFile(path, reservedRoles, logger, true, settings);
} }
public static Map<String, Permission.Global.Role> parseFile(Path path, Set<Permission.Global.Role> reservedRoles, ESLogger logger, boolean resolvePermission) { public static Map<String, Permission.Global.Role> parseFile(Path path, Set<Permission.Global.Role> reservedRoles, ESLogger logger, boolean resolvePermission, Settings settings) {
if (logger == null) { if (logger == null) {
logger = NoOpLogger.INSTANCE; logger = NoOpLogger.INSTANCE;
} }
@ -138,7 +138,7 @@ public class FileRolesStore extends AbstractLifecycleComponent<RolesStore> imple
try { try {
List<String> roleSegments = roleSegments(path); List<String> roleSegments = roleSegments(path);
for (String segment : roleSegments) { for (String segment : roleSegments) {
Permission.Global.Role role = parseRole(segment, path, logger, resolvePermission); Permission.Global.Role role = parseRole(segment, path, logger, resolvePermission, settings);
if (role != null) { if (role != null) {
if (SystemRole.NAME.equals(role.name())) { if (SystemRole.NAME.equals(role.name())) {
logger.warn("role [{}] is reserved to the system. the relevant role definition in the mapping file will be ignored", SystemRole.NAME); logger.warn("role [{}] is reserved to the system. the relevant role definition in the mapping file will be ignored", SystemRole.NAME);
@ -164,7 +164,7 @@ public class FileRolesStore extends AbstractLifecycleComponent<RolesStore> imple
return unmodifiableMap(roles); return unmodifiableMap(roles);
} }
private static Permission.Global.Role parseRole(String segment, Path path, ESLogger logger, boolean resolvePermissions) { private static Permission.Global.Role parseRole(String segment, Path path, ESLogger logger, boolean resolvePermissions, Settings settings) {
String roleName = null; String roleName = null;
try { try {
XContentParser parser = YamlXContent.yamlXContent.createParser(segment); XContentParser parser = YamlXContent.yamlXContent.createParser(segment);
@ -301,6 +301,11 @@ public class FileRolesStore extends AbstractLifecycleComponent<RolesStore> imple
} }
} }
if (name != null) { if (name != null) {
if ((query != null || (fields != null && fields.isEmpty() == false)) && ShieldPlugin.flsDlsEnabled(settings) == false) {
logger.error("invalid role definition [{}] in roles file [{}]. document and field level security is not enabled. set [{}] to [true] in the configuration file. skipping role...", roleName, path.toAbsolutePath(), ShieldPlugin.DLS_FLS_ENABLED_SETTING);
return null;
}
try { try {
permission.add(fields, query, Privilege.Index.get(name), indices); permission.add(fields, query, Privilege.Index.get(name), indices);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
@ -417,7 +422,7 @@ public class FileRolesStore extends AbstractLifecycleComponent<RolesStore> imple
public void onFileChanged(Path file) { public void onFileChanged(Path file) {
if (file.equals(FileRolesStore.this.file)) { if (file.equals(FileRolesStore.this.file)) {
try { try {
permissions = parseFile(file, reservedRoles, logger); permissions = parseFile(file, reservedRoles, logger, settings);
logger.info("updated roles (roles file [{}] changed)", file.toAbsolutePath()); logger.info("updated roles (roles file [{}] changed)", file.toAbsolutePath());
} catch (Throwable t) { } catch (Throwable t) {
logger.error("could not reload roles file [{}]. Current roles remain unmodified", t, file.toAbsolutePath()); logger.error("could not reload roles file [{}]. Current roles remain unmodified", t, file.toAbsolutePath());

View File

@ -10,7 +10,6 @@ import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.update.UpdateResponse; import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.node.Node; import org.elasticsearch.node.Node;
import org.elasticsearch.shield.ShieldPlugin;
import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.shield.authc.support.UsernamePasswordToken; import org.elasticsearch.shield.authc.support.UsernamePasswordToken;
import org.elasticsearch.test.ShieldIntegTestCase; import org.elasticsearch.test.ShieldIntegTestCase;
@ -30,7 +29,7 @@ public class BulkUpdateTests extends ShieldIntegTestCase {
return Settings.builder() return Settings.builder()
.put(super.nodeSettings(nodeOrdinal)) .put(super.nodeSettings(nodeOrdinal))
.put(Node.HTTP_ENABLED, true) .put(Node.HTTP_ENABLED, true)
.put(ShieldPlugin.DLS_FLS_ENABLED_SETTING, false) //FIXME randomize once DLS/FLS works with Bulk updates... //.put(ShieldPlugin.DLS_FLS_ENABLED_SETTING, false) //FIXME randomize once DLS/FLS works with Bulk updates...
.build(); .build();
} }

View File

@ -8,6 +8,7 @@ package org.elasticsearch.integration;
import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.IndexModule; import org.elasticsearch.index.IndexModule;
import org.elasticsearch.shield.ShieldPlugin;
import org.elasticsearch.shield.authc.support.Hasher; import org.elasticsearch.shield.authc.support.Hasher;
import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.test.ShieldIntegTestCase; import org.elasticsearch.test.ShieldIntegTestCase;
@ -39,6 +40,7 @@ public class DocumentAndFieldLevelSecurityTests extends ShieldIntegTestCase {
"role2:user2\n" + "role2:user2\n" +
"role3:user3\n"; "role3:user3\n";
} }
@Override @Override
protected String configRoles() { protected String configRoles() {
return super.configRoles() + return super.configRoles() +
@ -65,6 +67,14 @@ public class DocumentAndFieldLevelSecurityTests extends ShieldIntegTestCase {
" query: '{\"term\" : {\"field2\" : \"value2\"}}'\n"; " query: '{\"term\" : {\"field2\" : \"value2\"}}'\n";
} }
@Override
public Settings nodeSettings(int nodeOrdinal) {
return Settings.builder()
.put(super.nodeSettings(nodeOrdinal))
.put(ShieldPlugin.DLS_FLS_ENABLED_SETTING, true)
.build();
}
public void testSimpleQuery() throws Exception { public void testSimpleQuery() throws Exception {
assertAcked(client().admin().indices().prepareCreate("test") assertAcked(client().admin().indices().prepareCreate("test")
.addMapping("type1", "field1", "type=string", "field2", "type=string") .addMapping("type1", "field1", "type=string", "field2", "type=string")

View File

@ -8,7 +8,9 @@ package org.elasticsearch.integration;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequestBuilder; import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequestBuilder;
import org.elasticsearch.action.index.IndexRequestBuilder; import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.shield.ShieldPlugin;
import org.elasticsearch.shield.authc.support.Hasher; import org.elasticsearch.shield.authc.support.Hasher;
import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.test.ShieldIntegTestCase; import org.elasticsearch.test.ShieldIntegTestCase;
@ -49,6 +51,7 @@ public class DocumentLevelSecurityRandomTests extends ShieldIntegTestCase {
} }
return builder.toString(); return builder.toString();
} }
@Override @Override
protected String configRoles() { protected String configRoles() {
StringBuilder builder = new StringBuilder(super.configRoles()); StringBuilder builder = new StringBuilder(super.configRoles());
@ -66,6 +69,14 @@ public class DocumentLevelSecurityRandomTests extends ShieldIntegTestCase {
return builder.toString(); return builder.toString();
} }
@Override
public Settings nodeSettings(int nodeOrdinal) {
return Settings.builder()
.put(super.nodeSettings(nodeOrdinal))
.put(ShieldPlugin.DLS_FLS_ENABLED_SETTING, true)
.build();
}
public void testDuelWithAliasFilters() throws Exception { public void testDuelWithAliasFilters() throws Exception {
assertAcked(client().admin().indices().prepareCreate("test") assertAcked(client().admin().indices().prepareCreate("test")
.addMapping("type1", "field1", "type=string", "field2", "type=string") .addMapping("type1", "field1", "type=string", "field2", "type=string")

View File

@ -13,12 +13,14 @@ import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.termvectors.MultiTermVectorsResponse; import org.elasticsearch.action.termvectors.MultiTermVectorsResponse;
import org.elasticsearch.action.termvectors.TermVectorsRequest; import org.elasticsearch.action.termvectors.TermVectorsRequest;
import org.elasticsearch.action.termvectors.TermVectorsResponse; import org.elasticsearch.action.termvectors.TermVectorsResponse;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilders; import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.children.Children; import org.elasticsearch.search.aggregations.bucket.children.Children;
import org.elasticsearch.search.aggregations.bucket.global.Global; import org.elasticsearch.search.aggregations.bucket.global.Global;
import org.elasticsearch.search.aggregations.bucket.terms.Terms; import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.sort.SortOrder; import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.shield.ShieldPlugin;
import org.elasticsearch.shield.authc.support.Hasher; import org.elasticsearch.shield.authc.support.Hasher;
import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.test.ShieldIntegTestCase; import org.elasticsearch.test.ShieldIntegTestCase;
@ -69,6 +71,14 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
" query: '{\"term\" : {\"field2\" : \"value2\"}}'"; // <-- query defined as json in a string " query: '{\"term\" : {\"field2\" : \"value2\"}}'"; // <-- query defined as json in a string
} }
@Override
public Settings nodeSettings(int nodeOrdinal) {
return Settings.builder()
.put(super.nodeSettings(nodeOrdinal))
.put(ShieldPlugin.DLS_FLS_ENABLED_SETTING, true)
.build();
}
public void testSimpleQuery() throws Exception { public void testSimpleQuery() throws Exception {
assertAcked(client().admin().indices().prepareCreate("test") assertAcked(client().admin().indices().prepareCreate("test")
.addMapping("type1", "field1", "type=string", "field2", "type=string") .addMapping("type1", "field1", "type=string", "field2", "type=string")

View File

@ -7,8 +7,10 @@ package org.elasticsearch.integration;
import org.elasticsearch.action.index.IndexRequestBuilder; import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortOrder; import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.shield.ShieldPlugin;
import org.elasticsearch.shield.authc.support.Hasher; import org.elasticsearch.shield.authc.support.Hasher;
import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.test.ShieldIntegTestCase; import org.elasticsearch.test.ShieldIntegTestCase;
@ -47,6 +49,7 @@ public class FieldLevelSecurityRandomTests extends ShieldIntegTestCase {
"role3:user3\n" + "role3:user3\n" +
"role4:user4\n"; "role4:user4\n";
} }
@Override @Override
protected String configRoles() { protected String configRoles() {
if (allowedFields == null) { if (allowedFields == null) {
@ -98,6 +101,14 @@ public class FieldLevelSecurityRandomTests extends ShieldIntegTestCase {
" - field3\n"; " - field3\n";
} }
@Override
public Settings nodeSettings(int nodeOrdinal) {
return Settings.builder()
.put(super.nodeSettings(nodeOrdinal))
.put(ShieldPlugin.DLS_FLS_ENABLED_SETTING, true)
.build();
}
public void testRandom() throws Exception { public void testRandom() throws Exception {
int j = 0; int j = 0;
Map<String, Object> doc = new HashMap<>(); Map<String, Object> doc = new HashMap<>();

View File

@ -23,6 +23,7 @@ import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.aggregations.AggregationBuilders; import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms; import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.sort.SortOrder; import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.shield.ShieldPlugin;
import org.elasticsearch.shield.authc.support.Hasher; import org.elasticsearch.shield.authc.support.Hasher;
import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ESIntegTestCase;
@ -102,6 +103,14 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
" fields: 'field*'\n"; " fields: 'field*'\n";
} }
@Override
public Settings nodeSettings(int nodeOrdinal) {
return Settings.builder()
.put(super.nodeSettings(nodeOrdinal))
.put(ShieldPlugin.DLS_FLS_ENABLED_SETTING, true)
.build();
}
public void testQuery() throws Exception { public void testQuery() throws Exception {
assertAcked(client().admin().indices().prepareCreate("test") assertAcked(client().admin().indices().prepareCreate("test")
.addMapping("type1", "field1", "type=string", "field2", "type=string") .addMapping("type1", "field1", "type=string", "field2", "type=string")

View File

@ -7,6 +7,8 @@ package org.elasticsearch.integration;
import org.elasticsearch.action.admin.indices.alias.Alias; import org.elasticsearch.action.admin.indices.alias.Alias;
import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.shield.ShieldPlugin;
import org.elasticsearch.shield.authc.support.Hasher; import org.elasticsearch.shield.authc.support.Hasher;
import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.shield.authc.support.SecuredString;
import org.elasticsearch.test.ShieldIntegTestCase; import org.elasticsearch.test.ShieldIntegTestCase;
@ -34,6 +36,7 @@ public class IndicesPermissionsWithAliasesWildcardsAndRegexsTests extends Shield
return super.configUsersRoles() + return super.configUsersRoles() +
"role1:user1\n"; "role1:user1\n";
} }
@Override @Override
protected String configRoles() { protected String configRoles() {
return super.configRoles() + return super.configRoles() +
@ -51,6 +54,14 @@ public class IndicesPermissionsWithAliasesWildcardsAndRegexsTests extends Shield
" fields: field3\n"; " fields: field3\n";
} }
@Override
public Settings nodeSettings(int nodeOrdinal) {
return Settings.builder()
.put(super.nodeSettings(nodeOrdinal))
.put(ShieldPlugin.DLS_FLS_ENABLED_SETTING, true)
.build();
}
public void testResolveWildcardsRegexs() throws Exception { public void testResolveWildcardsRegexs() throws Exception {
assertAcked(client().admin().indices().prepareCreate("test") assertAcked(client().admin().indices().prepareCreate("test")
.addMapping("type1", "field1", "type=string", "field2", "type=string") .addMapping("type1", "field1", "type=string", "field2", "type=string")

View File

@ -7,6 +7,7 @@ package org.elasticsearch.shield.authz.store;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment; import org.elasticsearch.env.Environment;
import org.elasticsearch.shield.ShieldPlugin;
import org.elasticsearch.shield.audit.logfile.CapturingLogger; import org.elasticsearch.shield.audit.logfile.CapturingLogger;
import org.elasticsearch.shield.authc.support.RefreshListener; import org.elasticsearch.shield.authc.support.RefreshListener;
import org.elasticsearch.shield.authz.Permission; import org.elasticsearch.shield.authz.Permission;
@ -29,6 +30,7 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static java.util.Collections.singleton; import static java.util.Collections.singleton;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.empty;
@ -46,9 +48,10 @@ import static org.hamcrest.Matchers.startsWith;
public class FileRolesStoreTests extends ESTestCase { public class FileRolesStoreTests extends ESTestCase {
public void testParseFile() throws Exception { public void testParseFile() throws Exception {
Path path = getDataPath("roles.yml"); Path path = getDataPath("roles.yml");
Map<String, Permission.Global.Role> roles = FileRolesStore.parseFile(path, Collections.<Permission.Global.Role>emptySet(), logger); Map<String, Permission.Global.Role> roles = FileRolesStore.parseFile(path, Collections.<Permission.Global.Role>emptySet(),
logger, Settings.builder().put(ShieldPlugin.DLS_FLS_ENABLED_SETTING, true).build());
assertThat(roles, notNullValue()); assertThat(roles, notNullValue());
assertThat(roles.size(), is(7)); assertThat(roles.size(), is(10));
Permission.Global.Role role = roles.get("role1"); Permission.Global.Role role = roles.get("role1");
assertThat(role, notNullValue()); assertThat(role, notNullValue());
@ -140,6 +143,80 @@ public class FileRolesStoreTests extends ESTestCase {
assertThat(role.runAs().check("user1"), is(true)); assertThat(role.runAs().check("user1"), is(true));
assertThat(role.runAs().check("user2"), is(true)); assertThat(role.runAs().check("user2"), is(true));
assertThat(role.runAs().check("user" + randomIntBetween(3, 9)), is(false)); assertThat(role.runAs().check("user" + randomIntBetween(3, 9)), is(false));
role = roles.get("role_fields");
assertThat(role, notNullValue());
assertThat(role.name(), equalTo("role_fields"));
assertThat(role.cluster(), notNullValue());
assertThat(role.cluster(), is(Permission.Cluster.Core.NONE));
assertThat(role.runAs(), is(Permission.RunAs.Core.NONE));
assertThat(role.indices(), notNullValue());
assertThat(role.indices().groups(), notNullValue());
assertThat(role.indices().groups().length, is(1));
group = role.indices().groups()[0];
assertThat(group.indices(), notNullValue());
assertThat(group.indices().length, is(1));
assertThat(group.indices()[0], equalTo("field_idx"));
assertThat(group.privilege(), notNullValue());
assertThat(group.privilege().isAlias(Privilege.Index.READ), is(true));
assertThat(group.getFields(), contains("foo", "boo"));
role = roles.get("role_query");
assertThat(role, notNullValue());
assertThat(role.name(), equalTo("role_query"));
assertThat(role.cluster(), notNullValue());
assertThat(role.cluster(), is(Permission.Cluster.Core.NONE));
assertThat(role.runAs(), is(Permission.RunAs.Core.NONE));
assertThat(role.indices(), notNullValue());
assertThat(role.indices().groups(), notNullValue());
assertThat(role.indices().groups().length, is(1));
group = role.indices().groups()[0];
assertThat(group.indices(), notNullValue());
assertThat(group.indices().length, is(1));
assertThat(group.indices()[0], equalTo("query_idx"));
assertThat(group.privilege(), notNullValue());
assertThat(group.privilege().isAlias(Privilege.Index.READ), is(true));
assertThat(group.getFields(), nullValue());
assertThat(group.getQuery(), notNullValue());
role = roles.get("role_query_fields");
assertThat(role, notNullValue());
assertThat(role.name(), equalTo("role_query_fields"));
assertThat(role.cluster(), notNullValue());
assertThat(role.cluster(), is(Permission.Cluster.Core.NONE));
assertThat(role.runAs(), is(Permission.RunAs.Core.NONE));
assertThat(role.indices(), notNullValue());
assertThat(role.indices().groups(), notNullValue());
assertThat(role.indices().groups().length, is(1));
group = role.indices().groups()[0];
assertThat(group.indices(), notNullValue());
assertThat(group.indices().length, is(1));
assertThat(group.indices()[0], equalTo("query_fields_idx"));
assertThat(group.privilege(), notNullValue());
assertThat(group.privilege().isAlias(Privilege.Index.READ), is(true));
assertThat(group.getFields(), contains("foo", "boo"));
assertThat(group.getQuery(), notNullValue());
}
public void testParseFileWithFLSAndDLSDisabled() throws Exception {
Path path = getDataPath("roles.yml");
CapturingLogger logger = new CapturingLogger(CapturingLogger.Level.ERROR);
Map<String, Permission.Global.Role> roles = FileRolesStore.parseFile(path, Collections.<Permission.Global.Role>emptySet(),
logger, randomBoolean() ? Settings.builder().put(ShieldPlugin.DLS_FLS_ENABLED_SETTING, false).build() : Settings.EMPTY);
assertThat(roles, notNullValue());
assertThat(roles.size(), is(7));
assertThat(roles.get("role_fields"), nullValue());
assertThat(roles.get("role_query"), nullValue());
assertThat(roles.get("role_query_fields"), nullValue());
List<CapturingLogger.Msg> entries = logger.output(CapturingLogger.Level.ERROR);
assertThat(entries, hasSize(3));
assertThat(entries.get(0).text, startsWith("invalid role definition [role_fields] in roles file [" + path.toAbsolutePath() + "]. document and field level security is not enabled."));
assertThat(entries.get(1).text, startsWith("invalid role definition [role_query] in roles file [" + path.toAbsolutePath() + "]. document and field level security is not enabled."));
assertThat(entries.get(2).text, startsWith("invalid role definition [role_query_fields] in roles file [" + path.toAbsolutePath() + "]. document and field level security is not enabled."));
} }
/** /**
@ -147,7 +224,7 @@ public class FileRolesStoreTests extends ESTestCase {
*/ */
public void testDefaultRolesFile() throws Exception { public void testDefaultRolesFile() throws Exception {
Path path = getDataPath("default_roles.yml"); Path path = getDataPath("default_roles.yml");
Map<String, Permission.Global.Role> roles = FileRolesStore.parseFile(path, Collections.<Permission.Global.Role>emptySet(), logger); Map<String, Permission.Global.Role> roles = FileRolesStore.parseFile(path, Collections.<Permission.Global.Role>emptySet(), logger, Settings.EMPTY);
assertThat(roles, notNullValue()); assertThat(roles, notNullValue());
assertThat(roles.size(), is(8)); assertThat(roles.size(), is(8));
@ -225,14 +302,14 @@ public class FileRolesStoreTests extends ESTestCase {
public void testThatEmptyFileDoesNotResultInLoop() throws Exception { public void testThatEmptyFileDoesNotResultInLoop() throws Exception {
Path file = createTempFile(); Path file = createTempFile();
Files.write(file, Collections.singletonList("#"), StandardCharsets.UTF_8); Files.write(file, Collections.singletonList("#"), StandardCharsets.UTF_8);
Map<String, Permission.Global.Role> roles = FileRolesStore.parseFile(file, Collections.<Permission.Global.Role>emptySet(), logger); Map<String, Permission.Global.Role> roles = FileRolesStore.parseFile(file, Collections.<Permission.Global.Role>emptySet(), logger, Settings.EMPTY);
assertThat(roles.keySet(), is(empty())); assertThat(roles.keySet(), is(empty()));
} }
public void testThatInvalidRoleDefinitions() throws Exception { public void testThatInvalidRoleDefinitions() throws Exception {
Path path = getDataPath("invalid_roles.yml"); Path path = getDataPath("invalid_roles.yml");
CapturingLogger logger = new CapturingLogger(CapturingLogger.Level.ERROR); CapturingLogger logger = new CapturingLogger(CapturingLogger.Level.ERROR);
Map<String, Permission.Global.Role> roles = FileRolesStore.parseFile(path, Collections.<Permission.Global.Role>emptySet(), logger); Map<String, Permission.Global.Role> roles = FileRolesStore.parseFile(path, Collections.<Permission.Global.Role>emptySet(), logger, Settings.EMPTY);
assertThat(roles.size(), is(1)); assertThat(roles.size(), is(1));
assertThat(roles, hasKey("valid_role")); assertThat(roles, hasKey("valid_role"));
Permission.Global.Role role = roles.get("valid_role"); Permission.Global.Role role = roles.get("valid_role");
@ -268,7 +345,7 @@ public class FileRolesStoreTests extends ESTestCase {
CapturingLogger logger = new CapturingLogger(CapturingLogger.Level.INFO); CapturingLogger logger = new CapturingLogger(CapturingLogger.Level.INFO);
Path path = getDataPath("reserved_roles.yml"); Path path = getDataPath("reserved_roles.yml");
Map<String, Permission.Global.Role> roles = FileRolesStore.parseFile(path, reservedRoles, logger); Map<String, Permission.Global.Role> roles = FileRolesStore.parseFile(path, reservedRoles, logger, Settings.EMPTY);
assertThat(roles, notNullValue()); assertThat(roles, notNullValue());
assertThat(roles.size(), is(2)); assertThat(roles.size(), is(2));
@ -300,7 +377,7 @@ public class FileRolesStoreTests extends ESTestCase {
Path path = createTempFile(); Path path = createTempFile();
Files.delete(path); Files.delete(path);
assertThat(Files.exists(path), is(false)); assertThat(Files.exists(path), is(false));
Map<String, Permission.Global.Role> roles = FileRolesStore.parseFile(path, reservedRoles, logger); Map<String, Permission.Global.Role> roles = FileRolesStore.parseFile(path, reservedRoles, logger, Settings.EMPTY);
assertThat(roles, notNullValue()); assertThat(roles, notNullValue());
assertThat(roles.size(), is(1)); assertThat(roles.size(), is(1));

View File

@ -29,4 +29,27 @@ role_run_as:
# role with more than run_as # role with more than run_as
role_run_as1: role_run_as1:
run_as: [user1, user2] run_as: [user1, user2]
role_fields:
indices:
'field_idx':
privileges: READ
fields:
- foo
- boo
role_query:
indices:
'query_idx':
privileges: READ
query: '{ "match_all": {} }'
role_query_fields:
indices:
'query_fields_idx':
privileges: READ
query: '{ "match_all": {} }'
fields:
- foo
- boo