diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/AbstractSuppressionAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/AbstractSuppressionAnalyzer.java index 28ea42e91e..ad8244eba0 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/AbstractSuppressionAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/AbstractSuppressionAnalyzer.java @@ -148,7 +148,7 @@ protected void analyzeDependency(Dependency dependency, Engine engine) throws An */ private void loadSuppressionData(Engine engine) throws SuppressionParseException { final List ruleList = new ArrayList<>(); - final SuppressionParser parser = new SuppressionParser(); + final SuppressionParser parser = SuppressionParser.newInstance(); final String[] suppressionFilePaths = getSettings().getArray(Settings.KEYS.SUPPRESSION_FILE); final List failedLoadingFiles = new ArrayList<>(); if (suppressionFilePaths != null && suppressionFilePaths.length > 0) { @@ -188,7 +188,7 @@ private void loadSuppressionData(Engine engine) throws SuppressionParseException * @throws SuppressionParseException thrown if the XML cannot be parsed. */ private void loadSuppressionBaseData(final Engine engine) throws SuppressionParseException { - final SuppressionParser parser = new SuppressionParser(); + final SuppressionParser parser = SuppressionParser.newInstance(); loadPackagedSuppressionBaseData(parser, engine); loadHostedSuppressionBaseData(parser, engine); } diff --git a/core/src/main/java/org/owasp/dependencycheck/xml/suppression/SuppressionHandler.java b/core/src/main/java/org/owasp/dependencycheck/xml/suppression/SuppressionHandler.java index 76cd4911b5..28a63f83d3 100644 --- a/core/src/main/java/org/owasp/dependencycheck/xml/suppression/SuppressionHandler.java +++ b/core/src/main/java/org/owasp/dependencycheck/xml/suppression/SuppressionHandler.java @@ -125,7 +125,26 @@ public class SuppressionHandler extends DefaultHandler { private Boolean groupBase = null; private Calendar groupUntil = null; + private final Calendar now; + /** + * Constructs a new suppression handler. + * + * @deprecated use {@link SuppressionHandler#SuppressionHandler(Calendar)} + */ + @Deprecated(forRemoval = true) + public SuppressionHandler() { + this(Calendar.getInstance()); + } + + /** + * Constructs a new suppression handler. + * + * @param now represents current time. Used to compare suppression expiration dates set within the 'until' attribute. + */ + SuppressionHandler(Calendar now) { + this.now = now; + } /** * Get the value of suppressionRules. @@ -199,7 +218,7 @@ public void endElement(String uri, String localName, String qName) throws SAXExc if (null != qName) { switch (qName) { case SUPPRESS: - if (rule.getUntil() != null && rule.getUntil().before(Calendar.getInstance())) { + if (rule.getUntil() != null && rule.getUntil().before(now)) { LOGGER.info("Suppression is expired for rule: {}", rule); } else { suppressionRules.add(rule); diff --git a/core/src/main/java/org/owasp/dependencycheck/xml/suppression/SuppressionParser.java b/core/src/main/java/org/owasp/dependencycheck/xml/suppression/SuppressionParser.java index ed823bc672..ac55c28225 100644 --- a/core/src/main/java/org/owasp/dependencycheck/xml/suppression/SuppressionParser.java +++ b/core/src/main/java/org/owasp/dependencycheck/xml/suppression/SuppressionParser.java @@ -25,6 +25,7 @@ import java.io.InputStreamReader; import java.io.Reader; import java.nio.charset.StandardCharsets; +import java.util.Calendar; import java.util.List; import javax.annotation.concurrent.ThreadSafe; import javax.xml.parsers.ParserConfigurationException; @@ -76,6 +77,31 @@ public class SuppressionParser { */ private static final String SUPPRESSION_SCHEMA_1_0 = "schema/suppression.xsd"; + private final Calendar now; + + public static SuppressionParser newInstance() { + return new SuppressionParser(Calendar.getInstance()); + } + + /** + * Constructs a new SuppressionParser. + * + * @deprecated use {@link SuppressionParser#newInstance()} + */ + @Deprecated(forRemoval = true) + public SuppressionParser() { + this(Calendar.getInstance()); + } + + /** + * Constructs a new SuppressionParser. + * + * @param now represents current time. Used to compare suppression expiration dates set within the 'until' attribute. + */ + SuppressionParser(Calendar now) { + this.now = now; + } + /** * Parses the given XML file and returns a list of the suppression rules * contained. @@ -117,7 +143,7 @@ public List parseSuppressionRules(InputStream inputStream) final String defaultEncoding = StandardCharsets.UTF_8.name(); final String charsetName = bom == null ? defaultEncoding : bom.getCharsetName(); - final SuppressionHandler handler = new SuppressionHandler(); + final SuppressionHandler handler = new SuppressionHandler(now); final SAXParser saxParser = XmlUtils.buildSecureSaxParser(schemaStream14, schemaStream13, schemaStream12, schemaStream11, schemaStream10); final XMLReader xmlReader = saxParser.getXMLReader(); xmlReader.setErrorHandler(new SuppressionErrorHandler()); diff --git a/core/src/test/java/org/owasp/dependencycheck/xml/suppression/SuppressionHandlerTest.java b/core/src/test/java/org/owasp/dependencycheck/xml/suppression/SuppressionHandlerTest.java index 0177ea12fa..c268d8158d 100644 --- a/core/src/test/java/org/owasp/dependencycheck/xml/suppression/SuppressionHandlerTest.java +++ b/core/src/test/java/org/owasp/dependencycheck/xml/suppression/SuppressionHandlerTest.java @@ -30,6 +30,7 @@ import java.io.InputStreamReader; import java.io.Reader; import java.nio.charset.StandardCharsets; +import java.util.Calendar; import java.util.List; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -50,7 +51,7 @@ void testHandler() throws Exception { File file = BaseTest.getResourceAsFile(this, "suppressions.xml"); InputStream schemaStream = BaseTest.getResourceAsStream(this, "schema/suppression.xsd"); - SuppressionHandler handler = new SuppressionHandler(); + SuppressionHandler handler = new SuppressionHandler(Calendar.getInstance()); SAXParser saxParser = XmlUtils.buildSecureSaxParser(schemaStream); XMLReader xmlReader = saxParser.getXMLReader(); xmlReader.setErrorHandler(new SuppressionErrorHandler()); diff --git a/core/src/test/java/org/owasp/dependencycheck/xml/suppression/SuppressionParserTest.java b/core/src/test/java/org/owasp/dependencycheck/xml/suppression/SuppressionParserTest.java index 8bcc0e9e83..1ec0c77609 100644 --- a/core/src/test/java/org/owasp/dependencycheck/xml/suppression/SuppressionParserTest.java +++ b/core/src/test/java/org/owasp/dependencycheck/xml/suppression/SuppressionParserTest.java @@ -24,6 +24,7 @@ import java.time.Instant; import java.time.LocalDate; import java.time.ZoneOffset; +import java.util.Calendar; import java.util.List; import java.util.stream.Collectors; @@ -36,6 +37,23 @@ */ class SuppressionParserTest extends BaseTest { + + private static final Calendar NOW_AS_OF_2013_11_13 = new Calendar.Builder() + .setDate(2013, 10, 13) + .build(); + + private static final Calendar NOW_AS_OF_2018_04_08 = new Calendar.Builder() + .setDate(2018, 3, 8) + .build(); + + private static final Calendar NOW_AS_OF_2019_07_21 = new Calendar.Builder() + .setDate(2019, 6, 21) + .build(); + + private static final Calendar NOW_AS_OF_2025_11_13 = new Calendar.Builder() + .setDate(2025, 10, 13) + .build(); + /** * Test of parseSuppressionRules method, of class SuppressionParser for the * v1.0 suppression XML Schema. @@ -44,7 +62,7 @@ class SuppressionParserTest extends BaseTest { void testParseSuppressionRulesV1dot0() throws Exception { //File file = new File(this.getClass().getClassLoader().getResource("suppressions.xml").getPath()); File file = BaseTest.getResourceAsFile(this, "suppressions.xml"); - SuppressionParser instance = new SuppressionParser(); + SuppressionParser instance = new SuppressionParser(NOW_AS_OF_2013_11_13); List result = instance.parseSuppressionRules(file); assertEquals(5, result.size()); } @@ -57,7 +75,7 @@ void testParseSuppressionRulesV1dot0() throws Exception { void testParseSuppressionRulesV1dot1() throws Exception { //File file = new File(this.getClass().getClassLoader().getResource("suppressions.xml").getPath()); File file = BaseTest.getResourceAsFile(this, "suppressions_1_1.xml"); - SuppressionParser instance = new SuppressionParser(); + SuppressionParser instance = new SuppressionParser(NOW_AS_OF_2018_04_08); List result = instance.parseSuppressionRules(file); assertEquals(5, result.size()); } @@ -70,7 +88,7 @@ void testParseSuppressionRulesV1dot1() throws Exception { void testParseSuppressionRulesV1dot2() throws Exception { //File file = new File(this.getClass().getClassLoader().getResource("suppressions.xml").getPath()); File file = BaseTest.getResourceAsFile(this, "suppressions_1_2.xml"); - SuppressionParser instance = new SuppressionParser(); + SuppressionParser instance = new SuppressionParser(NOW_AS_OF_2018_04_08); List result = instance.parseSuppressionRules(file); assertEquals(4, result.size()); } @@ -83,7 +101,7 @@ void testParseSuppressionRulesV1dot2() throws Exception { void testParseSuppressionRulesV1dot3() throws Exception { //File file = new File(this.getClass().getClassLoader().getResource("suppressions.xml").getPath()); File file = BaseTest.getResourceAsFile(this, "suppressions_1_3.xml"); - SuppressionParser instance = new SuppressionParser(); + SuppressionParser instance = new SuppressionParser(NOW_AS_OF_2019_07_21); List result = instance.parseSuppressionRules(file); assertEquals(4, result.size()); } @@ -95,7 +113,7 @@ void testParseSuppressionRulesV1dot3() throws Exception { @Test void testParseSuppressionRulesV1dot4() throws SuppressionParseException { File file = BaseTest.getResourceAsFile(this, "suppressions_1_4.xml"); - SuppressionParser instance = new SuppressionParser(); + SuppressionParser instance = new SuppressionParser(NOW_AS_OF_2025_11_13); List suppressionRules = instance.parseSuppressionRules(file); assertEquals(7, suppressionRules.size()); @@ -108,7 +126,7 @@ void testParseSuppressionRulesV1dot4() throws SuppressionParseException { void testParseSuppressionRulesV1dot4BackwardsCompability() throws SuppressionParseException { // 'suppressions_1_4_no_groups.xml' has the same content as 'suppressions_1_3.xml'. But follows schema 1.4 File file = BaseTest.getResourceAsFile(this, "suppressions_1_4_no_groups.xml"); - SuppressionParser instance = new SuppressionParser(); + SuppressionParser instance = new SuppressionParser(NOW_AS_OF_2025_11_13); List suppressionRules = instance.parseSuppressionRules(file); assertEquals(4, suppressionRules.size()); @@ -121,7 +139,7 @@ void testParseSuppressionRulesV1dot4BackwardsCompability() throws SuppressionPar @Test void testParseSuppressionV1dot4Inherits() throws SuppressionParseException { File file = BaseTest.getResourceAsFile(this, "suppressions_1_4.xml"); - SuppressionParser instance = new SuppressionParser(); + SuppressionParser instance = new SuppressionParser(NOW_AS_OF_2025_11_13); List suppressionRules = instance.parseSuppressionRules(file); // CVE-2013-1338 in test xml has no attributes and should inherit the ones set on group level. @@ -144,7 +162,7 @@ void testParseSuppressionV1dot4Inherits() throws SuppressionParseException { @Test void testParseSuppressionV1dot4AttributeOverrides() throws SuppressionParseException { File file = BaseTest.getResourceAsFile(this, "suppressions_1_4.xml"); - SuppressionParser instance = new SuppressionParser(); + SuppressionParser instance = new SuppressionParser(NOW_AS_OF_2025_11_13); List suppressionRules = instance.parseSuppressionRules(file); // CVE-2013-1339 in test xml has attribute {code (until="2027-01-01Z")} set and is present in suppressionGroup.