From b3406e0a9778b766da651ea4fbf67572f02d90c6 Mon Sep 17 00:00:00 2001 From: Rupert Griffin Date: Mon, 22 Jul 2024 12:21:39 -0400 Subject: [PATCH] Added denylist formatting validation --- .../output/filter/AbstractFilter.java | 37 +++++++++++++++++++ .../output/filter/AbstractFilterTest.java | 32 ++++++++-------- 2 files changed, 53 insertions(+), 16 deletions(-) diff --git a/src/main/java/emissary/output/filter/AbstractFilter.java b/src/main/java/emissary/output/filter/AbstractFilter.java index 240c2b1dd2..5f71416c7b 100755 --- a/src/main/java/emissary/output/filter/AbstractFilter.java +++ b/src/main/java/emissary/output/filter/AbstractFilter.java @@ -2,6 +2,7 @@ import emissary.config.ConfigUtil; import emissary.config.Configurator; +import emissary.core.EmissaryRuntimeException; import emissary.core.IBaseDataObject; import emissary.output.DropOffUtil; import emissary.util.JavaCharSet; @@ -20,6 +21,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.regex.Pattern; import java.util.stream.Collectors; import javax.annotation.Nullable; @@ -171,6 +173,7 @@ protected void initializeOutputTypes(@Nullable final Configurator config) { this.outputTypes = config.findEntriesAsSet("OUTPUT_TYPE"); this.logger.debug("Loaded {} output types for filter {}", this.outputTypes.size(), this.outputTypes); this.denylist = config.findEntriesAsSet("DENYLIST"); + this.validateDenylist(); this.wildCardDenylist = this.denylist.stream() .filter(i -> i.endsWith("*")) .map(i -> i.substring(0, i.length() - 1)) @@ -183,6 +186,40 @@ protected void initializeOutputTypes(@Nullable final Configurator config) { } } + protected void validateDenylist() { + Pattern charSet = Pattern.compile("^[\\w*]+[\\w*.]*[\\w*]+$"); // Match if acceptable characters are in correct order + Pattern repeatedPeriods = Pattern.compile("\\.\\."); // Match if any sequential `.` characters + Pattern typeWildcardFormat = Pattern.compile("^(\\*|\\w+)$"); // Match if String is `*` or word sequence + Pattern viewWildcardFormat = Pattern.compile("^[\\w.]*\\*?$"); // Match if String is word sequence with optional `*` suffix + final String errorPrefix = "Invalid filter configuration: `DENYLIST = %s` "; + + for (String entry : this.denylist) { + if (charSet.matcher(entry).matches() && !repeatedPeriods.matcher(entry).matches()) { + String[] names = entry.split("\\.", 2); + String filetype = names[0]; + if (!typeWildcardFormat.matcher(filetype).matches()) { + throw new EmissaryRuntimeException(String.format(errorPrefix + + "filetype `%s` must be wildcard `*` only or sequence of [A-Z, a-z, 0-9, _].", + entry, filetype)); + } + if (names.length > 1) { + String viewName = names[1]; + if (viewName.chars().filter(ch -> ch == '.').count() > 0) { + logger.warn("`DENYLIST = {}` viewName `{}` should not contain any `.` characters", entry, viewName); + } + if (!viewWildcardFormat.matcher(viewName).matches()) { + throw new EmissaryRuntimeException(String.format(errorPrefix + + "viewName `%s` must be sequence of [A-Z, a-z, 0-9, _] with optional wildcard `*` suffix.", + entry, viewName)); + } + } + } else { + throw new EmissaryRuntimeException(String.format(errorPrefix + + "must be one sequence of [A-Z, a-z, 0-9, _] or two sequences separated with `.` delimiter.", entry)); + } + } + } + /** * Return the name of this filter * diff --git a/src/test/java/emissary/output/filter/AbstractFilterTest.java b/src/test/java/emissary/output/filter/AbstractFilterTest.java index 416686d8b0..c5a61a2453 100644 --- a/src/test/java/emissary/output/filter/AbstractFilterTest.java +++ b/src/test/java/emissary/output/filter/AbstractFilterTest.java @@ -3,6 +3,7 @@ import emissary.config.Configurator; import emissary.config.ServiceConfigGuide; import emissary.core.DataObjectFactory; +import emissary.core.EmissaryRuntimeException; import emissary.core.IBaseDataObject; import emissary.test.core.junit5.UnitTest; @@ -13,6 +14,7 @@ import java.util.Set; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; public class AbstractFilterTest extends UnitTest { @@ -43,22 +45,20 @@ AbstractFilter getDenyFilter(final String outputType) { @Test void testIncorrectConfigs() { - /* TODO - AbstractFilter f = getAbstractFilterInstance(); - Configurator config = new ServiceConfigGuide(); - config.addEntry("DENYLIST", "J*"); - EmissaryRuntimeException e = assertThrows( - EmissaryRuntimeException.class, - () -> f.initialize(new ServiceConfigGuide(), "FOO", config)); - assertTrue(e.getMessage().contains("Invalid filter configuration: DENYLIST = J*")); - - config = new ServiceConfigGuide(); - config.addEntry("DENYLIST", "*filetype.J*"); - e = assertThrows( - EmissaryRuntimeException.class, - () -> f.initialize(new ServiceConfigGuide(), "FOO", config)); - assertTrue(e.getMessage().contains("Invalid filter configuration: DENYLIST = *filetype.J*")); - */ + AbstractFilter f = getAbstractFilterInstance(); + String[] invalidEntries = { + "type*", "*type", "ty*pe", "type*.view", "*type.view", "ty*pe.view", + "type*.view*", "*type.view*", "ty*pe.view*", "type*.*", "*type.*", "ty*pe.*", + "type.*view", "type.vi*ew", "*.*view", "*.vi*ew", + "type.", ".view", "."}; + for (String entry : invalidEntries) { + final Configurator config = new ServiceConfigGuide(); + config.addEntry("DENYLIST", entry); + EmissaryRuntimeException e = assertThrows( + EmissaryRuntimeException.class, + () -> f.initialize(new ServiceConfigGuide(), "FOO", config)); + assertTrue(e.getMessage().contains(String.format("Invalid filter configuration: `DENYLIST = %s`", entry))); + } } @Test