diff --git a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java index cfb18b3df6..9591667f10 100644 --- a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java +++ b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java @@ -917,6 +917,7 @@ public List> getSettings() { settings.add(Setting.boolSetting(ConfigConstants.SECURITY_ALLOW_UNSAFE_DEMOCERTIFICATES, false, Property.NodeScope, Property.Filtered)); settings.add(Setting.boolSetting(ConfigConstants.SECURITY_ALLOW_DEFAULT_INIT_SECURITYINDEX, false, Property.NodeScope, Property.Filtered)); settings.add(Setting.boolSetting(ConfigConstants.SECURITY_BACKGROUND_INIT_IF_SECURITYINDEX_NOT_EXIST, true, Property.NodeScope, Property.Filtered)); + settings.add(Setting.boolSetting(ConfigConstants.SECURITY_DFM_EMPTY_OVERRIDES_ALL, false, Property.NodeScope, Property.Filtered)); settings.add(Setting.groupSetting(ConfigConstants.SECURITY_AUTHCZ_REST_IMPERSONATION_USERS+".", Property.NodeScope)); //not filtered here settings.add(Setting.simpleString(ConfigConstants.SECURITY_ROLES_MAPPING_RESOLUTION, Property.NodeScope, Property.Filtered)); diff --git a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java index d822b2fdab..e57a7176b6 100644 --- a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java +++ b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java @@ -136,6 +136,7 @@ public class PrivilegesEvaluator { private final ProtectedIndexAccessEvaluator protectedIndexAccessEvaluator; private final TermsAggregationEvaluator termsAggregationEvaluator; private final boolean dlsFlsEnabled; + private final boolean dfmEmptyOverwritesAll; private DynamicConfigModel dcm; private final NamedXContentRegistry namedXContentRegistry; @@ -164,6 +165,7 @@ public PrivilegesEvaluator(final ClusterService clusterService, final ThreadPool termsAggregationEvaluator = new TermsAggregationEvaluator(); this.namedXContentRegistry = namedXContentRegistry; this.dlsFlsEnabled = dlsFlsEnabled; + this.dfmEmptyOverwritesAll = settings.getAsBoolean(ConfigConstants.SECURITY_DFM_EMPTY_OVERRIDES_ALL, false); } @Subscribe @@ -292,7 +294,7 @@ public PrivilegesEvaluatorResponse evaluate(final User user, String action0, fin log.trace("dnfof enabled? {}", dnfofEnabled); } - presponse.evaluatedDlsFlsConfig = getSecurityRoles(mappedRoles).getDlsFls(user, resolver, clusterService, namedXContentRegistry); + presponse.evaluatedDlsFlsConfig = getSecurityRoles(mappedRoles).getDlsFls(user, dfmEmptyOverwritesAll, resolver, clusterService, namedXContentRegistry); if (isClusterPerm(action0)) { diff --git a/src/main/java/org/opensearch/security/securityconf/ConfigModelV6.java b/src/main/java/org/opensearch/security/securityconf/ConfigModelV6.java index 10828f85e7..a7af70f77a 100644 --- a/src/main/java/org/opensearch/security/securityconf/ConfigModelV6.java +++ b/src/main/java/org/opensearch/security/securityconf/ConfigModelV6.java @@ -364,7 +364,7 @@ public SecurityRoles filter(Set keep) { @Override - public EvaluatedDlsFlsConfig getDlsFls(User user, IndexNameExpressionResolver resolver, ClusterService cs, + public EvaluatedDlsFlsConfig getDlsFls(User user, boolean dfmEmptyOverwritesAll, IndexNameExpressionResolver resolver, ClusterService cs, NamedXContentRegistry namedXContentRegistry) { final Map> dlsQueries = new HashMap>(); diff --git a/src/main/java/org/opensearch/security/securityconf/ConfigModelV7.java b/src/main/java/org/opensearch/security/securityconf/ConfigModelV7.java index 6c1898eb95..a496f520cc 100644 --- a/src/main/java/org/opensearch/security/securityconf/ConfigModelV7.java +++ b/src/main/java/org/opensearch/security/securityconf/ConfigModelV7.java @@ -351,7 +351,7 @@ public SecurityRoles filter(Set keep) { @Override - public EvaluatedDlsFlsConfig getDlsFls(User user, IndexNameExpressionResolver resolver, ClusterService cs, + public EvaluatedDlsFlsConfig getDlsFls(User user, boolean dfmEmptyOverwritesAll, IndexNameExpressionResolver resolver, ClusterService cs, NamedXContentRegistry namedXContentRegistry) { @@ -366,11 +366,19 @@ public EvaluatedDlsFlsConfig getDlsFls(User user, IndexNameExpressionResolver re Map> dlsQueriesByIndex = new HashMap>(); Map> flsFields = new HashMap>(); Map> maskedFieldsMap = new HashMap>(); + + // we capture all concrete indices that do not have any + // DLS/FLS/Masked Fields restrictions. If the dfm_empty_overwrites_all + // switch is enabled, this trumps any restrictions on those indices + // that may be imposed by other roles. + Set noDlsConcreteIndices = new HashSet<>(); + Set noFlsConcreteIndices = new HashSet<>(); + Set noMaskedFieldConcreteIndices = new HashSet<>(); for (SecurityRole role : roles) { for (IndexPattern ip : role.getIpatterns()) { Set concreteIndices; - concreteIndices = ip.getResolvedIndexPattern(user, resolver, cs); + concreteIndices = ip.getResolvedIndexPattern(user, resolver, cs, false); String dls = ip.getDlsQuery(user); if (dls != null && dls.length() > 0) { @@ -378,6 +386,8 @@ public EvaluatedDlsFlsConfig getDlsFls(User user, IndexNameExpressionResolver re for (String concreteIndex : concreteIndices) { dlsQueriesByIndex.computeIfAbsent(concreteIndex, (key) -> new HashSet()).add(dls); } + } else if (dfmEmptyOverwritesAll) { + noDlsConcreteIndices.addAll(concreteIndices); } Set fls = ip.getFls(); @@ -392,6 +402,8 @@ public EvaluatedDlsFlsConfig getDlsFls(User user, IndexNameExpressionResolver re flsFields.get(concreteIndex).addAll(Sets.newHashSet(fls)); } } + } else if (dfmEmptyOverwritesAll) { + noFlsConcreteIndices.addAll(concreteIndices); } Set maskedFields = ip.getMaskedFields(); @@ -406,8 +418,25 @@ public EvaluatedDlsFlsConfig getDlsFls(User user, IndexNameExpressionResolver re maskedFieldsMap.get(concreteIndex).addAll(Sets.newHashSet(maskedFields)); } } - } + } else if (dfmEmptyOverwritesAll) { + noMaskedFieldConcreteIndices.addAll(concreteIndices); + } + } + } + if (dfmEmptyOverwritesAll) { + if (log.isDebugEnabled()) { + log.debug("Index patterns with no dls queries attached: {} - They will be removed from {}", noDlsConcreteIndices, + dlsQueriesByIndex.keySet()); + log.debug("Index patterns with no fls fields attached: {} - They will be removed from {}", noFlsConcreteIndices, + flsFields.keySet()); + log.debug("Index patterns with no masked fields attached: {} - They will be removed from {}", noMaskedFieldConcreteIndices, + maskedFieldsMap.keySet()); } + // removing the indices that do not have D/M/F restrictions + // from the keySet will also modify the underlying map + dlsQueriesByIndex.keySet().removeAll(noDlsConcreteIndices); + flsFields.keySet().removeAll(noFlsConcreteIndices); + maskedFieldsMap.keySet().removeAll(noMaskedFieldConcreteIndices); } return new EvaluatedDlsFlsConfig(dlsQueriesByIndex, flsFields, maskedFieldsMap); @@ -530,7 +559,7 @@ private Set getAllResolvedPermittedIndices(Resolved resolved, User user, // } if (patternMatch) { //resolved but can contain patterns for nonexistent indices - final WildcardMatcher permitted = WildcardMatcher.from(p.getResolvedIndexPattern(user, resolver, cs)); //maybe they do not exist + final WildcardMatcher permitted = WildcardMatcher.from(p.getResolvedIndexPattern(user, resolver, cs, true)); //maybe they do not exist final Set res = new HashSet<>(); if (!resolved.isLocalAll() && !resolved.getAllIndices().contains("*") && !resolved.getAllIndices().contains("_all")) { //resolved but can contain patterns for nonexistent indices @@ -722,7 +751,7 @@ public String getUnresolvedIndexPattern(User user) { return replaceProperties(indexPattern, user); } - public Set getResolvedIndexPattern(User user, IndexNameExpressionResolver resolver, ClusterService cs) { + public Set getResolvedIndexPattern(User user, IndexNameExpressionResolver resolver, ClusterService cs, boolean appendUnresolved) { String unresolved = getUnresolvedIndexPattern(user); WildcardMatcher matcher = WildcardMatcher.from(unresolved); String[] resolved = null; @@ -744,10 +773,12 @@ public Set getResolvedIndexPattern(User user, IndexNameExpressionResolve if (resolved == null || resolved.length == 0) { return ImmutableSet.of(unresolved); } else { - return ImmutableSet.builder() - .addAll(Arrays.asList(resolved)) - .add(unresolved) - .build(); + ImmutableSet.Builder builder = ImmutableSet.builder() + .addAll(Arrays.asList(resolved)); + if (appendUnresolved) { + builder.add(unresolved); + } + return builder.build(); } } @@ -963,12 +994,12 @@ private static boolean impliesTypePerm(Set ipatterns, Resolved res indexMatcherAndPermissions = ipatterns .stream() .filter(indexPattern -> "*".equals(indexPattern.getUnresolvedIndexPattern(user))) - .map(p -> new IndexMatcherAndPermissions(p.getResolvedIndexPattern(user, resolver, cs), p.perms)) + .map(p -> new IndexMatcherAndPermissions(p.getResolvedIndexPattern(user, resolver, cs, true), p.perms)) .toArray(IndexMatcherAndPermissions[]::new); } else { indexMatcherAndPermissions = ipatterns .stream() - .map(p -> new IndexMatcherAndPermissions(p.getResolvedIndexPattern(user, resolver, cs), p.perms)) + .map(p -> new IndexMatcherAndPermissions(p.getResolvedIndexPattern(user, resolver, cs, true), p.perms)) .toArray(IndexMatcherAndPermissions[]::new); } return resolvedRequestedIndices diff --git a/src/main/java/org/opensearch/security/securityconf/SecurityRoles.java b/src/main/java/org/opensearch/security/securityconf/SecurityRoles.java index 0ad849d51f..d5ce799cb2 100644 --- a/src/main/java/org/opensearch/security/securityconf/SecurityRoles.java +++ b/src/main/java/org/opensearch/security/securityconf/SecurityRoles.java @@ -51,7 +51,7 @@ public interface SecurityRoles { boolean get(Resolved requestedResolved, User user, String[] allIndexPermsRequiredA, IndexNameExpressionResolver resolver, ClusterService clusterService); - EvaluatedDlsFlsConfig getDlsFls(User user, IndexNameExpressionResolver resolver, ClusterService clusterService, NamedXContentRegistry namedXContentRegistry); + EvaluatedDlsFlsConfig getDlsFls(User user, boolean dfmEmptyOverwritesAll, IndexNameExpressionResolver resolver, ClusterService clusterService, NamedXContentRegistry namedXContentRegistry); Set getAllPermittedIndicesForDashboards(Resolved resolved, User user, String[] actions, IndexNameExpressionResolver resolver, ClusterService cs); diff --git a/src/main/java/org/opensearch/security/support/ConfigConstants.java b/src/main/java/org/opensearch/security/support/ConfigConstants.java index 93e0f328be..587f0f1ff7 100644 --- a/src/main/java/org/opensearch/security/support/ConfigConstants.java +++ b/src/main/java/org/opensearch/security/support/ConfigConstants.java @@ -240,6 +240,7 @@ public class ConfigConstants { public static final String LEGACY_OPENDISTRO_SECURITY_CONFIG_SSL_DUAL_MODE_ENABLED = "opendistro_security_config.ssl_dual_mode_enabled"; public static final String SECURITY_SSL_CERT_RELOAD_ENABLED = "plugins.security.ssl_cert_reload_enabled"; public static final String SECURITY_DISABLE_ENVVAR_REPLACEMENT = "plugins.security.disable_envvar_replacement"; + public static final String SECURITY_DFM_EMPTY_OVERRIDES_ALL = "plugins.security.dfm_empty_overrides_all"; public enum RolesMappingResolution { MAPPING_ONLY, diff --git a/src/test/java/org/opensearch/security/dlic/dlsfls/DfmOverwritesAllTest.java b/src/test/java/org/opensearch/security/dlic/dlsfls/DfmOverwritesAllTest.java new file mode 100644 index 0000000000..18e2f68695 --- /dev/null +++ b/src/test/java/org/opensearch/security/dlic/dlsfls/DfmOverwritesAllTest.java @@ -0,0 +1,237 @@ +/* + * Copyright OpenSearch Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package org.opensearch.security.dlic.dlsfls; + +import org.junit.Assert; +import org.junit.Test; +import org.opensearch.action.index.IndexRequest; +import org.opensearch.action.support.WriteRequest.RefreshPolicy; +import org.opensearch.client.Client; +import org.opensearch.common.settings.Settings; +import org.opensearch.common.xcontent.XContentType; +import org.opensearch.security.support.ConfigConstants; +import org.opensearch.security.test.DynamicSecurityConfig; +import org.opensearch.security.test.helper.rest.RestHelper.HttpResponse; + +/** + * Tests that the dfm_empty_overwrites_all flag works correctly. + * Per default, if a user has a role that adds restrictions to an index + * regarding DLS, FLS or masked fields (DFM), and another role that has no restrictions + * on the same index, the restrictions from the first role still applies. + * + * If the dfm_empty_overwrites_all flag is set to true, the logic is reversed: + * If a user has a role that places no restrictions on an index, this trumps + * all other role that eventually do place restrictions on this index. + */ +public class DfmOverwritesAllTest extends AbstractDlsFlsTest { + + protected void populateData(Client tc) { + + tc.index(new IndexRequest("index1-1").id("0").setRefreshPolicy(RefreshPolicy.IMMEDIATE) + .source("{\"field1\": 1, \"field2\": \"value-2-1\", \"field3\": \"value-3-1\", \"field4\": \"value-4-1\" }", XContentType.JSON)).actionGet(); + + tc.index(new IndexRequest("index1-2").id("0").setRefreshPolicy(RefreshPolicy.IMMEDIATE) + .source("{\"field1\": 2, \"field2\": \"value-2-2\", \"field3\": \"value-3-2\", \"field4\": \"value-4-2\" }", XContentType.JSON)).actionGet(); + + tc.index(new IndexRequest("index1-3").id("0").setRefreshPolicy(RefreshPolicy.IMMEDIATE) + .source("{\"field1\": 3, \"field2\": \"value-2-3\", \"field3\": \"value-3-3\", \"field4\": \"value-4-3\" }", XContentType.JSON)).actionGet(); + + tc.index(new IndexRequest("index1-4").id("0").setRefreshPolicy(RefreshPolicy.IMMEDIATE) + .source("{\"field1\": 4, \"field2\": \"value-2-4\", \"field3\": \"value-3-4\", \"field4\": \"value-4-4\" }", XContentType.JSON)).actionGet(); + + } + + /** + * Admin user sees all, no dfm restrictions apply. + * @throws Exception + */ + @Test + public void testDFMUnrestrictedUser() throws Exception { + final Settings settings = Settings.builder().put(ConfigConstants.SECURITY_DFM_EMPTY_OVERRIDES_ALL, true).build(); + + setup(settings, new DynamicSecurityConfig().setConfig("securityconfig_dfm_empty_overwrites_all.yml") + .setSecurityInternalUsers("internal_users_dfm_empty_overwrites_all.yml") + .setSecurityRoles("roles_dfm_empty_overwrites_all.yml") + .setSecurityRolesMapping("rolesmapping_dfm_empty_overwrites_all.yml")); + + HttpResponse response; + + response = rh.executeGetRequest("/index1-*/_search?pretty", + encodeBasicHeader("admin", "password")); + Assert.assertEquals(200, response.getStatusCode()); + + // the only document in index1-1 is filtered by DLS query, so normally no hit in index-1-1 + Assert.assertTrue(response.getBody().contains("index1-1")); + + // field3 and field4 - normally filtered out by FLS + Assert.assertTrue(response.getBody().contains("value-3-1")); + Assert.assertTrue(response.getBody().contains("value-4-1")); + Assert.assertTrue(response.getBody().contains("value-3-2")); + Assert.assertTrue(response.getBody().contains("value-4-2")); + Assert.assertTrue(response.getBody().contains("value-3-3")); + Assert.assertTrue(response.getBody().contains("value-4-3")); + Assert.assertTrue(response.getBody().contains("value-3-4")); + Assert.assertTrue(response.getBody().contains("value-4-4")); + + // field2 - normally masked + Assert.assertTrue(response.getBody().contains("value-2-1")); + Assert.assertTrue(response.getBody().contains("value-2-2")); + Assert.assertTrue(response.getBody().contains("value-2-3")); + Assert.assertTrue(response.getBody().contains("value-2-4")); + } + + /** + * Tests that the DFM settings are applied. User has only one role + * with D/F/M all enabled, so restrictions must kick in. + * @throws Exception + */ + @Test + public void testDFMRestrictedUser() throws Exception { + final Settings settings = Settings.builder().put(ConfigConstants.SECURITY_DFM_EMPTY_OVERRIDES_ALL, true).build(); + + setup(settings, new DynamicSecurityConfig().setConfig("securityconfig_dfm_empty_overwrites_all.yml") + .setSecurityInternalUsers("internal_users_dfm_empty_overwrites_all.yml") + .setSecurityRoles("roles_dfm_empty_overwrites_all.yml") + .setSecurityRolesMapping("rolesmapping_dfm_empty_overwrites_all.yml")); + + HttpResponse response; + + response = rh.executeGetRequest("/index1-*/_search?pretty", + encodeBasicHeader("dfm_restricted_role", "password")); + Assert.assertEquals(200, response.getStatusCode()); + + // the only document in index1-1 is filtered by DLS query, so no hit in index-1-1 + Assert.assertFalse(response.getBody().contains("index1-1")); + + // field3 and field4 - filtered out by FLS + Assert.assertFalse(response.getBody().contains("value-3-1")); + Assert.assertFalse(response.getBody().contains("value-4-1")); + Assert.assertFalse(response.getBody().contains("value-3-2")); + Assert.assertFalse(response.getBody().contains("value-4-2")); + Assert.assertFalse(response.getBody().contains("value-3-3")); + Assert.assertFalse(response.getBody().contains("value-4-3")); + Assert.assertFalse(response.getBody().contains("value-3-4")); + Assert.assertFalse(response.getBody().contains("value-4-4")); + + // field2 - masked + Assert.assertFalse(response.getBody().contains("value-2-1")); + Assert.assertFalse(response.getBody().contains("value-2-2")); + Assert.assertFalse(response.getBody().contains("value-2-3")); + Assert.assertFalse(response.getBody().contains("value-2-4")); + + // field2 - check also some masked values + Assert.assertTrue(response.getBody().contains("514b27191e2322b0f7cd6afc3a5d657ff438fd0cc8dc229bd1a589804fdffd99")); + Assert.assertTrue(response.getBody().contains("3090f7e867f390fb96b20ba30ee518b09a927b857393ebd1262f31191a385efa")); + } + + /** + * User has the restricted role as in test testDFMRestrictedUser(). In addition, user has + * another role with the same index pattern as the restricted role but no DFM settings. In that + * case the unrestricted role should trump the restricted one, so basically user has + * full access again. + * @throws Exception + */ + @Test + public void testDFMRestrictedAndUnrestrictedAllIndices() throws Exception { + + final Settings settings = Settings.builder().put(ConfigConstants.SECURITY_DFM_EMPTY_OVERRIDES_ALL, true).build(); + + setup(settings, new DynamicSecurityConfig().setConfig("securityconfig_dfm_empty_overwrites_all.yml") + .setSecurityInternalUsers("internal_users_dfm_empty_overwrites_all.yml") + .setSecurityRoles("roles_dfm_empty_overwrites_all.yml") + .setSecurityRolesMapping("rolesmapping_dfm_empty_overwrites_all.yml")); + + HttpResponse response; + + response = rh.executeGetRequest("/index1-*/_search?pretty", + encodeBasicHeader("dfm_restricted_and_unrestricted_all_indices_role", "password")); + Assert.assertEquals(200, response.getStatusCode()); + + // the only document in index1-1 is filtered by DLS query, so normally no hit in index-1-1 + Assert.assertTrue(response.getBody().contains("index1-1")); + + // field3 and field4 - normally filtered out by FLS + Assert.assertTrue(response.getBody().contains("value-3-1")); + Assert.assertTrue(response.getBody().contains("value-4-1")); + Assert.assertTrue(response.getBody().contains("value-3-2")); + Assert.assertTrue(response.getBody().contains("value-4-2")); + Assert.assertTrue(response.getBody().contains("value-3-3")); + Assert.assertTrue(response.getBody().contains("value-4-3")); + Assert.assertTrue(response.getBody().contains("value-3-4")); + Assert.assertTrue(response.getBody().contains("value-4-4")); + + // field2 - normally masked + Assert.assertTrue(response.getBody().contains("value-2-1")); + Assert.assertTrue(response.getBody().contains("value-2-2")); + Assert.assertTrue(response.getBody().contains("value-2-3")); + Assert.assertTrue(response.getBody().contains("value-2-4")); + } + + /** + * User has the restricted role as in test testDFMRestrictedUser(). In addition, user has + * another role where the index pattern matches two specific index ("index1-2", "index-1-1"), means this role has two indices + * which are more specific than the index pattern in the restricted role ("index1-*"), So the second role should + * remove the DMF restrictions from exactly two indices. Otherwise, restrictions still apply. + * @throws Exception + */ + @Test + public void testDFMRestrictedAndUnrestrictedOneIndex() throws Exception { + final Settings settings = Settings.builder().put(ConfigConstants.SECURITY_DFM_EMPTY_OVERRIDES_ALL, true).build(); + setup(settings, new DynamicSecurityConfig().setConfig("securityconfig_dfm_empty_overwrites_all.yml") + .setSecurityInternalUsers("internal_users_dfm_empty_overwrites_all.yml") + .setSecurityRoles("roles_dfm_empty_overwrites_all.yml") + .setSecurityRolesMapping("rolesmapping_dfm_empty_overwrites_all.yml")); + + HttpResponse response; + + response = rh.executeGetRequest("/_plugins/_security/authinfo?pretty", + encodeBasicHeader("dfm_restricted_and_unrestricted_one_index_role", "password")); + + response = rh.executeGetRequest("/index1-*/_search?pretty", + encodeBasicHeader("dfm_restricted_and_unrestricted_one_index_role", "password")); + Assert.assertEquals(200, response.getStatusCode()); + + // we have a role that places no restrictions on index-1-1, lifting the DLS from the restricted role + Assert.assertTrue(response.getBody().contains("index1-1")); + Assert.assertTrue(response.getBody().contains("value-2-1")); + Assert.assertTrue(response.getBody().contains("value-3-1")); + Assert.assertTrue(response.getBody().contains("value-4-1")); + + // field3 and field4 - normally filtered out by FLS. The second role + // lifts restrictions for index1-1 and index1-4, so only those + // values should be visible for index1-1 and index1-4 + Assert.assertTrue(response.getBody().contains("value-3-1")); + Assert.assertTrue(response.getBody().contains("value-4-1")); + Assert.assertTrue(response.getBody().contains("value-3-4")); + Assert.assertTrue(response.getBody().contains("value-4-4")); + + // FLS restrictions still in place for index1-2 and index1-3, those + // fields must not be present + Assert.assertFalse(response.getBody().contains("value-3-2")); + Assert.assertFalse(response.getBody().contains("value-4-2")); + Assert.assertFalse(response.getBody().contains("value-3-3")); + Assert.assertFalse(response.getBody().contains("value-4-3")); + + // field2 - normally masked, but for index1-1 and index1-4 restrictions are + // lifted by second role, so we have cleartext in index1-1 and index1-4 + Assert.assertTrue(response.getBody().contains("value-2-1")); + Assert.assertTrue(response.getBody().contains("value-2-4")); + + // but we still have masked values for index1-2 and index1-3 + Assert.assertTrue(response.getBody().contains("514b27191e2322b0f7cd6afc3a5d657ff438fd0cc8dc229bd1a589804fdffd99")); + Assert.assertTrue(response.getBody().contains("3090f7e867f390fb96b20ba30ee518b09a927b857393ebd1262f31191a385efa")); + } +} diff --git a/src/test/resources/dlsfls/internal_users_dfm_empty_overwrites_all.yml b/src/test/resources/dlsfls/internal_users_dfm_empty_overwrites_all.yml new file mode 100644 index 0000000000..1030469e77 --- /dev/null +++ b/src/test/resources/dlsfls/internal_users_dfm_empty_overwrites_all.yml @@ -0,0 +1,24 @@ +--- +_meta: + type: "internalusers" + config_version: 2 + +admin: + #password + hash: $2a$12$YCBrpxYyFusK609FurY5Ee3BlmuzWw0qHwpwqEyNhM2.XnQY3Bxpe + +dfm_user: + #password + hash: $2a$12$YCBrpxYyFusK609FurY5Ee3BlmuzWw0qHwpwqEyNhM2.XnQY3Bxpe + +dfm_restricted_and_unrestricted_all_indices_role: + #password + hash: $2a$12$YCBrpxYyFusK609FurY5Ee3BlmuzWw0qHwpwqEyNhM2.XnQY3Bxpe + +dfm_restricted_and_unrestricted_one_index_role: + #password + hash: $2a$12$YCBrpxYyFusK609FurY5Ee3BlmuzWw0qHwpwqEyNhM2.XnQY3Bxpe + +dfm_restricted_role: + #password + hash: $2a$12$YCBrpxYyFusK609FurY5Ee3BlmuzWw0qHwpwqEyNhM2.XnQY3Bxpe diff --git a/src/test/resources/dlsfls/roles_dfm_empty_overwrites_all.yml b/src/test/resources/dlsfls/roles_dfm_empty_overwrites_all.yml new file mode 100644 index 0000000000..89b09d3abb --- /dev/null +++ b/src/test/resources/dlsfls/roles_dfm_empty_overwrites_all.yml @@ -0,0 +1,50 @@ +--- +_meta: + type: "roles" + config_version: 2 + +os_admin: + cluster_permissions: + - '*' + index_permissions: + - index_patterns: + - '*' + allowed_actions: + - '*' + +os_dfm_restricted_all_indices: + cluster_permissions: + - "*" + index_permissions: + - index_patterns: + - "index1-*" + allowed_actions: + - "*" + dls: '{ "bool": { "must_not": { "term": { "field1": 1 }}}}' + masked_fields: + - "field2" + fls: + - "~field3" + - "~field4" + +os_dfm_not_restricted_all_indices: + cluster_permissions: + - "*" + index_permissions: + - index_patterns: + - "index1-*" + allowed_actions: + - "*" + +os_dfm_not_restricted_one_index: + cluster_permissions: + - "*" + index_permissions: + - index_patterns: + - "index1-4" + allowed_actions: + - "*" + - index_patterns: + - "index1-1" + allowed_actions: + - "*" diff --git a/src/test/resources/dlsfls/rolesmapping_dfm_empty_overwrites_all.yml b/src/test/resources/dlsfls/rolesmapping_dfm_empty_overwrites_all.yml new file mode 100644 index 0000000000..d31c4a8995 --- /dev/null +++ b/src/test/resources/dlsfls/rolesmapping_dfm_empty_overwrites_all.yml @@ -0,0 +1,22 @@ +--- +_meta: + type: "rolesmapping" + config_version: 2 + +os_admin: + users: + - admin + +os_dfm_restricted_all_indices: + users: + - dfm_restricted_role + - dfm_restricted_and_unrestricted_one_index_role + - dfm_restricted_and_unrestricted_all_indices_role + +os_dfm_not_restricted_all_indices: + users: + - dfm_restricted_and_unrestricted_all_indices_role + +os_dfm_not_restricted_one_index: + users: + - dfm_restricted_and_unrestricted_one_index_role diff --git a/src/test/resources/dlsfls/securityconfig_dfm_empty_overwrites_all.yml b/src/test/resources/dlsfls/securityconfig_dfm_empty_overwrites_all.yml new file mode 100644 index 0000000000..02c78087ce --- /dev/null +++ b/src/test/resources/dlsfls/securityconfig_dfm_empty_overwrites_all.yml @@ -0,0 +1,16 @@ +--- +_meta: + type: "config" + config_version: 2 +config: + dynamic: + do_not_fail_on_forbidden: true + authc: + authentication_domain_basic_internal: + http_enabled: true + transport_enabled: true + order: 0 + http_authenticator: + type: "basic" + authentication_backend: + type: "intern"