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:
parent
cc2096b4f9
commit
16848c6043
|
@ -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) {
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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<>();
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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));
|
||||||
|
|
||||||
|
|
|
@ -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
|
Loading…
Reference in New Issue