From 60bbd2c5c56ee06c4a0c14d95dd3beb2229cf11b Mon Sep 17 00:00:00 2001 From: MdTanwer Date: Sat, 27 Jun 2026 07:04:15 +0000 Subject: [PATCH 1/2] Skip FLS salt warning when field masking unused Only validate compliance salt after roles reload when masked_fields are configured, instead of warning on every Salt construction at startup. Fixes #6105 Signed-off-by: MdTanwer --- .../security/OpenSearchSecurityPlugin.java | 4 +- .../ConfigurationRepository.java | 11 ++ .../security/configuration/Salt.java | 60 ++++++--- .../security/configuration/SaltTest.java | 125 ++++++++++++++++-- 4 files changed, 172 insertions(+), 28 deletions(-) diff --git a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java index f64516c74e..b123b5b587 100644 --- a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java +++ b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java @@ -544,8 +544,8 @@ public OpenSearchSecurityPlugin(final Settings settings, final Path configPath) } - // TODO: Uncomment for 4.0 - enforce that the default compliance salt is not used outside of demo configuration - // Salt.validateSaltSettings(settings); + // TODO: Uncomment for 4.0 - enforce that the default compliance salt is not used when field masking is configured + // Salt.validateSaltSettings(settings, Salt.isFieldMaskingConfigured(rolesConfig)); } private void verifyTLSVersion(final String settings, final List configuredProtocols) { diff --git a/src/main/java/org/opensearch/security/configuration/ConfigurationRepository.java b/src/main/java/org/opensearch/security/configuration/ConfigurationRepository.java index 7eafcf1cb7..17d46c4f80 100644 --- a/src/main/java/org/opensearch/security/configuration/ConfigurationRepository.java +++ b/src/main/java/org/opensearch/security/configuration/ConfigurationRepository.java @@ -88,6 +88,7 @@ import org.opensearch.security.securityconf.DynamicConfigFactory; import org.opensearch.security.securityconf.impl.CType; import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; +import org.opensearch.security.securityconf.impl.v7.RoleV7; import org.opensearch.security.ssl.util.ExceptionUtils; import org.opensearch.security.state.SecurityMetadata; import org.opensearch.security.support.ConfigConstants; @@ -553,9 +554,19 @@ private void doReload(Set> configTypes) { private void notifyConfigurationListeners(ConfigurationMap configuration) { configCache.putAll(configuration.rawMap()); + validateComplianceSaltIfNeeded(configuration); notifyAboutChanges(configuration); } + private void validateComplianceSaltIfNeeded(ConfigurationMap configuration) { + if (!configuration.containsKey(CType.ROLES)) { + return; + } + + final SecurityDynamicConfiguration rolesConfig = configuration.get(CType.ROLES); + Salt.validateSaltSettings(settings, Salt.isFieldMaskingConfigured(rolesConfig)); + } + public synchronized void subscribeOnChange(ConfigurationChangeListener listener) { configurationChangedListener.add(listener); } diff --git a/src/main/java/org/opensearch/security/configuration/Salt.java b/src/main/java/org/opensearch/security/configuration/Salt.java index 3882e20ecd..ac4f6989c9 100644 --- a/src/main/java/org/opensearch/security/configuration/Salt.java +++ b/src/main/java/org/opensearch/security/configuration/Salt.java @@ -21,6 +21,8 @@ import org.opensearch.OpenSearchException; import org.opensearch.common.settings.Settings; +import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; +import org.opensearch.security.securityconf.impl.v7.RoleV7; import org.opensearch.security.support.ConfigConstants; /** @@ -44,12 +46,6 @@ public Salt(final byte[] salt) { private Salt(final String saltAsString) { this.salt16 = new byte[SALT_SIZE]; - if (saltAsString.equals(ConfigConstants.SECURITY_COMPLIANCE_SALT_DEFAULT)) { - log.warn( - "If you plan to use field masking pls configure compliance salt {} to be a random string of 16 chars length identical on all nodes", - saltAsString - ); - } try { ByteBuffer byteBuffer = StandardCharsets.UTF_8.encode(saltAsString); byteBuffer.get(salt16); @@ -87,25 +83,53 @@ public static Salt from(final Settings settings) { } /** - * Validates that the default compliance salt is not used unless allow_unsafe_democertificates is enabled. - * Must be called after node settings are fully loaded (e.g. during plugin startup). + * Returns whether any loaded role defines field masking via {@code masked_fields}. + */ + public static boolean isFieldMaskingConfigured(final SecurityDynamicConfiguration rolesConfig) { + if (rolesConfig == null) { + return false; + } + + return rolesConfig.getCEntries() + .values() + .stream() + .flatMap(role -> role.getIndex_permissions().stream()) + .anyMatch(index -> !index.getMasked_fields().isEmpty()); + } + + /** + * Validates compliance salt when field masking is in use. + * Must be called after roles configuration is loaded or reloaded. * @param settings fully loaded node settings - * @throws OpenSearchException if the default salt is used without the demo flag + * @param fieldMaskingConfigured whether any role defines {@code masked_fields} + * @throws OpenSearchException if the default salt is used with field masking in production */ - public static void validateSaltSettings(final Settings settings) { + public static void validateSaltSettings(final Settings settings, final boolean fieldMaskingConfigured) { + if (!fieldMaskingConfigured) { + return; + } + final String saltAsString = settings.get( ConfigConstants.SECURITY_COMPLIANCE_SALT, ConfigConstants.SECURITY_COMPLIANCE_SALT_DEFAULT ); final boolean allowUnsafeDemoCertificates = settings.getAsBoolean(ConfigConstants.SECURITY_ALLOW_UNSAFE_DEMOCERTIFICATES, false); - if (ConfigConstants.SECURITY_COMPLIANCE_SALT_DEFAULT.equals(saltAsString) && !allowUnsafeDemoCertificates) { - throw new OpenSearchException( - "Default compliance salt is not allowed in production. Please configure " - + ConfigConstants.SECURITY_COMPLIANCE_SALT - + " to a random 16-character string, or set " - + ConfigConstants.SECURITY_ALLOW_UNSAFE_DEMOCERTIFICATES - + " to true for demo/test environments." - ); + if (ConfigConstants.SECURITY_COMPLIANCE_SALT_DEFAULT.equals(saltAsString)) { + if (allowUnsafeDemoCertificates) { + log.warn( + "Field masking is configured but compliance salt {} is still the default. Configure {} to a random 16-character string identical on all nodes", + saltAsString, + ConfigConstants.SECURITY_COMPLIANCE_SALT + ); + } else { + throw new OpenSearchException( + "Default compliance salt is not allowed in production when field masking is configured. Please configure " + + ConfigConstants.SECURITY_COMPLIANCE_SALT + + " to a random 16-character string, or set " + + ConfigConstants.SECURITY_ALLOW_UNSAFE_DEMOCERTIFICATES + + " to true for demo/test environments." + ); + } } } } diff --git a/src/test/java/org/opensearch/security/configuration/SaltTest.java b/src/test/java/org/opensearch/security/configuration/SaltTest.java index d5716718f0..1950cd8fb3 100644 --- a/src/test/java/org/opensearch/security/configuration/SaltTest.java +++ b/src/test/java/org/opensearch/security/configuration/SaltTest.java @@ -12,7 +12,15 @@ package org.opensearch.security.configuration; import java.nio.charset.StandardCharsets; - +import java.util.List; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.Logger; +import org.apache.logging.log4j.core.appender.AbstractAppender; +import org.apache.logging.log4j.core.config.Property; +import org.apache.logging.log4j.core.layout.PatternLayout; import org.apache.lucene.tests.util.LuceneTestCase; import org.junit.Rule; import org.junit.Test; @@ -20,12 +28,18 @@ import org.opensearch.OpenSearchException; import org.opensearch.common.settings.Settings; +import org.opensearch.security.securityconf.impl.CType; +import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; +import org.opensearch.security.securityconf.impl.v7.RoleV7; import org.opensearch.security.support.ConfigConstants; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.is; import static org.opensearch.security.configuration.Salt.SALT_SIZE; import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; public class SaltTest extends LuceneTestCase { @@ -43,19 +57,78 @@ public void testDefault() { } @Test - public void testDefaultSaltRejectedInProduction() { + public void testDefaultSaltDoesNotLogWarningWithoutFieldMasking() { + final List warnings = captureWarnLogs(() -> { + Salt.from(Settings.EMPTY); + Salt.from(Settings.EMPTY); + Salt.from(Settings.EMPTY); + }); + + assertThat(warnings, empty()); + } + + @Test + public void testDefaultSaltRejectedInProductionWhenFieldMaskingConfigured() { // assert thrown.expect(OpenSearchException.class); - thrown.expectMessage("Default compliance salt is not allowed in production"); + thrown.expectMessage("Default compliance salt is not allowed in production when field masking is configured"); - // act - validation rejects default salt when allow_unsafe_democertificates is false - Salt.validateSaltSettings(Settings.EMPTY); + // act + Salt.validateSaltSettings(Settings.EMPTY, true); } @Test - public void testDefaultSaltAllowedWithDemoFlag() { - // should not throw - Salt.validateSaltSettings(Settings.builder().put(ConfigConstants.SECURITY_ALLOW_UNSAFE_DEMOCERTIFICATES, true).build()); + public void testDefaultSaltAllowedWhenFieldMaskingNotConfigured() { + Salt.validateSaltSettings(Settings.EMPTY, false); + Salt.validateSaltSettings(Settings.builder().put(ConfigConstants.SECURITY_ALLOW_UNSAFE_DEMOCERTIFICATES, true).build(), false); + } + + @Test + public void testDefaultSaltAllowedWithDemoFlagWhenFieldMaskingConfigured() { + final List warnings = captureWarnLogs( + () -> Salt.validateSaltSettings( + Settings.builder().put(ConfigConstants.SECURITY_ALLOW_UNSAFE_DEMOCERTIFICATES, true).build(), + true + ) + ); + + assertThat(warnings.size(), is(1)); + assertTrue(warnings.get(0).contains("Field masking is configured")); + assertTrue(warnings.get(0).contains(ConfigConstants.SECURITY_COMPLIANCE_SALT_DEFAULT)); + } + + @Test + public void testIsFieldMaskingConfigured() throws Exception { + final RoleV7 roleWithoutMasking = RoleV7.fromYamlString( + "cluster_permissions:\n" + + " - 'cluster:monitor/health'\n" + + "index_permissions:\n" + + " - index_patterns:\n" + + " - '*'\n" + + " allowed_actions:\n" + + " - 'read'" + ); + final RoleV7 roleWithMasking = RoleV7.fromYamlString( + "cluster_permissions:\n" + + " - 'cluster:monitor/health'\n" + + "index_permissions:\n" + + " - index_patterns:\n" + + " - '*'\n" + + " masked_fields:\n" + + " - 'secret'\n" + + " allowed_actions:\n" + + " - 'read'" + ); + + final SecurityDynamicConfiguration withoutMasking = SecurityDynamicConfiguration.empty(CType.ROLES); + withoutMasking.putCEntry("role_a", roleWithoutMasking); + + final SecurityDynamicConfiguration withMasking = SecurityDynamicConfiguration.empty(CType.ROLES); + withMasking.putCEntry("role_b", roleWithMasking); + + assertFalse(Salt.isFieldMaskingConfigured(null)); + assertFalse(Salt.isFieldMaskingConfigured(withoutMasking)); + assertTrue(Salt.isFieldMaskingConfigured(withMasking)); } @Test @@ -123,4 +196,40 @@ public void testSaltThrowsNoExceptionWhenCorrectBytesArrayProvided() { // act new Salt(new byte[] { 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1 }); } + + private static List captureWarnLogs(Runnable action) { + final Logger logger = (Logger) LogManager.getLogger(Salt.class); + final var appender = new AbstractAppender( + "SaltWarningCapture", + null, + PatternLayout.createDefaultLayout(), + false, + Property.EMPTY_ARRAY + ) { + private final java.util.List events = new java.util.ArrayList<>(); + + @Override + public void append(LogEvent event) { + events.add(event.toImmutable()); + } + + java.util.List getEvents() { + return events; + } + }; + appender.start(); + logger.addAppender(appender); + logger.setLevel(Level.WARN); + try { + action.run(); + return appender.getEvents() + .stream() + .filter(e -> e.getLevel() == Level.WARN) + .map(e -> e.getMessage().getFormattedMessage()) + .toList(); + } finally { + logger.removeAppender(appender); + appender.stop(); + } + } } From fecf36a28e1c701c17079691460a38a08a95b19a Mon Sep 17 00:00:00 2001 From: MdTanwer Date: Mon, 29 Jun 2026 05:11:37 +0000 Subject: [PATCH 2/2] Log default compliance salt warning once at startup Move the default-salt warning out of Salt construction and log it once during plugin startup. Keeps unconditional warning per maintainer direction and leaves 4.0 bootstrap enforcement as a TODO. Fixes #6105 Signed-off-by: MdTanwer Co-authored-by: Cursor --- .../security/OpenSearchSecurityPlugin.java | 7 +- .../ConfigurationRepository.java | 11 --- .../security/configuration/Salt.java | 64 +++++++-------- .../security/configuration/SaltTest.java | 77 ++++++------------- 4 files changed, 54 insertions(+), 105 deletions(-) diff --git a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java index b123b5b587..572f57fd3a 100644 --- a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java +++ b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java @@ -159,6 +159,7 @@ import org.opensearch.security.configuration.DlsFlsRequestValve; import org.opensearch.security.configuration.DlsFlsValveImpl; import org.opensearch.security.configuration.SecurityConfigVersionHandler; +import org.opensearch.security.configuration.Salt; import org.opensearch.security.configuration.SecurityFlsDlsIndexSearcherWrapper; import org.opensearch.security.dlic.rest.api.Endpoint; import org.opensearch.security.dlic.rest.api.SecurityRestApiActions; @@ -544,8 +545,10 @@ public OpenSearchSecurityPlugin(final Settings settings, final Path configPath) } - // TODO: Uncomment for 4.0 - enforce that the default compliance salt is not used when field masking is configured - // Salt.validateSaltSettings(settings, Salt.isFieldMaskingConfigured(rolesConfig)); + Salt.warnIfDefaultComplianceSalt(settings); + + // TODO: Uncomment for 4.0 - enforce that the default compliance salt is not used outside of demo configuration + // Salt.validateSaltSettings(settings); } private void verifyTLSVersion(final String settings, final List configuredProtocols) { diff --git a/src/main/java/org/opensearch/security/configuration/ConfigurationRepository.java b/src/main/java/org/opensearch/security/configuration/ConfigurationRepository.java index 17d46c4f80..7eafcf1cb7 100644 --- a/src/main/java/org/opensearch/security/configuration/ConfigurationRepository.java +++ b/src/main/java/org/opensearch/security/configuration/ConfigurationRepository.java @@ -88,7 +88,6 @@ import org.opensearch.security.securityconf.DynamicConfigFactory; import org.opensearch.security.securityconf.impl.CType; import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; -import org.opensearch.security.securityconf.impl.v7.RoleV7; import org.opensearch.security.ssl.util.ExceptionUtils; import org.opensearch.security.state.SecurityMetadata; import org.opensearch.security.support.ConfigConstants; @@ -554,19 +553,9 @@ private void doReload(Set> configTypes) { private void notifyConfigurationListeners(ConfigurationMap configuration) { configCache.putAll(configuration.rawMap()); - validateComplianceSaltIfNeeded(configuration); notifyAboutChanges(configuration); } - private void validateComplianceSaltIfNeeded(ConfigurationMap configuration) { - if (!configuration.containsKey(CType.ROLES)) { - return; - } - - final SecurityDynamicConfiguration rolesConfig = configuration.get(CType.ROLES); - Salt.validateSaltSettings(settings, Salt.isFieldMaskingConfigured(rolesConfig)); - } - public synchronized void subscribeOnChange(ConfigurationChangeListener listener) { configurationChangedListener.add(listener); } diff --git a/src/main/java/org/opensearch/security/configuration/Salt.java b/src/main/java/org/opensearch/security/configuration/Salt.java index ac4f6989c9..59a5ca0d73 100644 --- a/src/main/java/org/opensearch/security/configuration/Salt.java +++ b/src/main/java/org/opensearch/security/configuration/Salt.java @@ -21,8 +21,6 @@ import org.opensearch.OpenSearchException; import org.opensearch.common.settings.Settings; -import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; -import org.opensearch.security.securityconf.impl.v7.RoleV7; import org.opensearch.security.support.ConfigConstants; /** @@ -83,53 +81,45 @@ public static Salt from(final Settings settings) { } /** - * Returns whether any loaded role defines field masking via {@code masked_fields}. + * Logs a warning when the default compliance salt is in use. + * Must be called once during plugin startup. + * @param settings fully loaded node settings */ - public static boolean isFieldMaskingConfigured(final SecurityDynamicConfiguration rolesConfig) { - if (rolesConfig == null) { - return false; + public static void warnIfDefaultComplianceSalt(final Settings settings) { + final String saltAsString = settings.get( + ConfigConstants.SECURITY_COMPLIANCE_SALT, + ConfigConstants.SECURITY_COMPLIANCE_SALT_DEFAULT + ); + if (ConfigConstants.SECURITY_COMPLIANCE_SALT_DEFAULT.equals(saltAsString)) { + log.warn( + "Default compliance salt is in use. Configure {} to a random 16-character string identical on all nodes, " + + "or set {} to true for demo/test environments.", + ConfigConstants.SECURITY_COMPLIANCE_SALT, + ConfigConstants.SECURITY_ALLOW_UNSAFE_DEMOCERTIFICATES + ); } - - return rolesConfig.getCEntries() - .values() - .stream() - .flatMap(role -> role.getIndex_permissions().stream()) - .anyMatch(index -> !index.getMasked_fields().isEmpty()); } /** - * Validates compliance salt when field masking is in use. - * Must be called after roles configuration is loaded or reloaded. + * Validates that the default compliance salt is not used unless allow_unsafe_democertificates is enabled. + * Must be called after node settings are fully loaded (e.g. during plugin startup). * @param settings fully loaded node settings - * @param fieldMaskingConfigured whether any role defines {@code masked_fields} - * @throws OpenSearchException if the default salt is used with field masking in production + * @throws OpenSearchException if the default salt is used without the demo flag */ - public static void validateSaltSettings(final Settings settings, final boolean fieldMaskingConfigured) { - if (!fieldMaskingConfigured) { - return; - } - + public static void validateSaltSettings(final Settings settings) { final String saltAsString = settings.get( ConfigConstants.SECURITY_COMPLIANCE_SALT, ConfigConstants.SECURITY_COMPLIANCE_SALT_DEFAULT ); final boolean allowUnsafeDemoCertificates = settings.getAsBoolean(ConfigConstants.SECURITY_ALLOW_UNSAFE_DEMOCERTIFICATES, false); - if (ConfigConstants.SECURITY_COMPLIANCE_SALT_DEFAULT.equals(saltAsString)) { - if (allowUnsafeDemoCertificates) { - log.warn( - "Field masking is configured but compliance salt {} is still the default. Configure {} to a random 16-character string identical on all nodes", - saltAsString, - ConfigConstants.SECURITY_COMPLIANCE_SALT - ); - } else { - throw new OpenSearchException( - "Default compliance salt is not allowed in production when field masking is configured. Please configure " - + ConfigConstants.SECURITY_COMPLIANCE_SALT - + " to a random 16-character string, or set " - + ConfigConstants.SECURITY_ALLOW_UNSAFE_DEMOCERTIFICATES - + " to true for demo/test environments." - ); - } + if (ConfigConstants.SECURITY_COMPLIANCE_SALT_DEFAULT.equals(saltAsString) && !allowUnsafeDemoCertificates) { + throw new OpenSearchException( + "Default compliance salt is not allowed in production. Please configure " + + ConfigConstants.SECURITY_COMPLIANCE_SALT + + " to a random 16-character string, or set " + + ConfigConstants.SECURITY_ALLOW_UNSAFE_DEMOCERTIFICATES + + " to true for demo/test environments." + ); } } } diff --git a/src/test/java/org/opensearch/security/configuration/SaltTest.java b/src/test/java/org/opensearch/security/configuration/SaltTest.java index 1950cd8fb3..d3a3a04c05 100644 --- a/src/test/java/org/opensearch/security/configuration/SaltTest.java +++ b/src/test/java/org/opensearch/security/configuration/SaltTest.java @@ -28,9 +28,6 @@ import org.opensearch.OpenSearchException; import org.opensearch.common.settings.Settings; -import org.opensearch.security.securityconf.impl.CType; -import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; -import org.opensearch.security.securityconf.impl.v7.RoleV7; import org.opensearch.security.support.ConfigConstants; import static org.hamcrest.MatcherAssert.assertThat; @@ -38,7 +35,6 @@ import static org.hamcrest.Matchers.is; import static org.opensearch.security.configuration.Salt.SALT_SIZE; import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; public class SaltTest extends LuceneTestCase { @@ -57,7 +53,7 @@ public void testDefault() { } @Test - public void testDefaultSaltDoesNotLogWarningWithoutFieldMasking() { + public void testSaltFromDoesNotLogDefaultSaltWarning() { final List warnings = captureWarnLogs(() -> { Salt.from(Settings.EMPTY); Salt.from(Settings.EMPTY); @@ -68,67 +64,38 @@ public void testDefaultSaltDoesNotLogWarningWithoutFieldMasking() { } @Test - public void testDefaultSaltRejectedInProductionWhenFieldMaskingConfigured() { - // assert - thrown.expect(OpenSearchException.class); - thrown.expectMessage("Default compliance salt is not allowed in production when field masking is configured"); + public void testWarnIfDefaultComplianceSaltLogsOnce() { + final List warnings = captureWarnLogs(() -> Salt.warnIfDefaultComplianceSalt(Settings.EMPTY)); - // act - Salt.validateSaltSettings(Settings.EMPTY, true); + assertThat(warnings.size(), is(1)); + assertTrue(warnings.get(0).contains("Default compliance salt is in use")); + assertTrue(warnings.get(0).contains(ConfigConstants.SECURITY_COMPLIANCE_SALT)); + assertTrue(warnings.get(0).contains(ConfigConstants.SECURITY_ALLOW_UNSAFE_DEMOCERTIFICATES)); } @Test - public void testDefaultSaltAllowedWhenFieldMaskingNotConfigured() { - Salt.validateSaltSettings(Settings.EMPTY, false); - Salt.validateSaltSettings(Settings.builder().put(ConfigConstants.SECURITY_ALLOW_UNSAFE_DEMOCERTIFICATES, true).build(), false); + public void testWarnIfDefaultComplianceSaltSkipsCustomSalt() { + final Settings settings = Settings.builder().put(ConfigConstants.SECURITY_COMPLIANCE_SALT, "abcdefghijklmnop").build(); + + final List warnings = captureWarnLogs(() -> Salt.warnIfDefaultComplianceSalt(settings)); + + assertThat(warnings, empty()); } @Test - public void testDefaultSaltAllowedWithDemoFlagWhenFieldMaskingConfigured() { - final List warnings = captureWarnLogs( - () -> Salt.validateSaltSettings( - Settings.builder().put(ConfigConstants.SECURITY_ALLOW_UNSAFE_DEMOCERTIFICATES, true).build(), - true - ) - ); + public void testDefaultSaltRejectedInProduction() { + // assert + thrown.expect(OpenSearchException.class); + thrown.expectMessage("Default compliance salt is not allowed in production"); - assertThat(warnings.size(), is(1)); - assertTrue(warnings.get(0).contains("Field masking is configured")); - assertTrue(warnings.get(0).contains(ConfigConstants.SECURITY_COMPLIANCE_SALT_DEFAULT)); + // act - validation rejects default salt when allow_unsafe_democertificates is false + Salt.validateSaltSettings(Settings.EMPTY); } @Test - public void testIsFieldMaskingConfigured() throws Exception { - final RoleV7 roleWithoutMasking = RoleV7.fromYamlString( - "cluster_permissions:\n" - + " - 'cluster:monitor/health'\n" - + "index_permissions:\n" - + " - index_patterns:\n" - + " - '*'\n" - + " allowed_actions:\n" - + " - 'read'" - ); - final RoleV7 roleWithMasking = RoleV7.fromYamlString( - "cluster_permissions:\n" - + " - 'cluster:monitor/health'\n" - + "index_permissions:\n" - + " - index_patterns:\n" - + " - '*'\n" - + " masked_fields:\n" - + " - 'secret'\n" - + " allowed_actions:\n" - + " - 'read'" - ); - - final SecurityDynamicConfiguration withoutMasking = SecurityDynamicConfiguration.empty(CType.ROLES); - withoutMasking.putCEntry("role_a", roleWithoutMasking); - - final SecurityDynamicConfiguration withMasking = SecurityDynamicConfiguration.empty(CType.ROLES); - withMasking.putCEntry("role_b", roleWithMasking); - - assertFalse(Salt.isFieldMaskingConfigured(null)); - assertFalse(Salt.isFieldMaskingConfigured(withoutMasking)); - assertTrue(Salt.isFieldMaskingConfigured(withMasking)); + public void testDefaultSaltAllowedWithDemoFlag() { + // should not throw + Salt.validateSaltSettings(Settings.builder().put(ConfigConstants.SECURITY_ALLOW_UNSAFE_DEMOCERTIFICATES, true).build()); } @Test