1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.owasp.dependencycheck.xml.suppression;
19
20 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
21 import java.io.File;
22 import java.io.FileInputStream;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.io.InputStreamReader;
26 import java.io.Reader;
27 import java.nio.charset.StandardCharsets;
28 import java.util.List;
29 import javax.annotation.concurrent.ThreadSafe;
30 import javax.xml.parsers.ParserConfigurationException;
31 import javax.xml.parsers.SAXParser;
32 import org.apache.commons.io.ByteOrderMark;
33 import org.apache.commons.io.input.BOMInputStream;
34
35 import org.owasp.dependencycheck.utils.FileUtils;
36 import org.owasp.dependencycheck.utils.XmlUtils;
37
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40 import org.xml.sax.EntityResolver;
41 import org.xml.sax.InputSource;
42 import org.xml.sax.SAXException;
43 import org.xml.sax.XMLReader;
44
45
46
47
48
49
50 @ThreadSafe
51 public class SuppressionParser {
52
53
54
55
56 private static final Logger LOGGER = LoggerFactory.getLogger(SuppressionParser.class);
57
58
59
60 public static final String SUPPRESSION_SCHEMA_1_3 = "schema/dependency-suppression.1.3.xsd";
61
62
63
64 public static final String SUPPRESSION_SCHEMA_1_2 = "schema/dependency-suppression.1.2.xsd";
65
66
67
68 public static final String SUPPRESSION_SCHEMA_1_1 = "schema/dependency-suppression.1.1.xsd";
69
70
71
72 private static final String SUPPRESSION_SCHEMA_1_0 = "schema/suppression.xsd";
73
74
75
76
77
78
79
80
81
82 @SuppressFBWarnings(justification = "try with resource will clenaup the resources", value = {"OBL_UNSATISFIED_OBLIGATION"})
83 public List<SuppressionRule> parseSuppressionRules(File file) throws SuppressionParseException {
84 try (FileInputStream fis = new FileInputStream(file)) {
85 return parseSuppressionRules(fis);
86 } catch (SAXException | IOException ex) {
87 LOGGER.debug("", ex);
88 throw new SuppressionParseException(ex);
89 }
90 }
91
92
93
94
95
96
97
98
99
100
101 public List<SuppressionRule> parseSuppressionRules(InputStream inputStream)
102 throws SuppressionParseException, SAXException {
103 try (
104 InputStream schemaStream13 = FileUtils.getResourceAsStream(SUPPRESSION_SCHEMA_1_3);
105 InputStream schemaStream12 = FileUtils.getResourceAsStream(SUPPRESSION_SCHEMA_1_2);
106 InputStream schemaStream11 = FileUtils.getResourceAsStream(SUPPRESSION_SCHEMA_1_1);
107 InputStream schemaStream10 = FileUtils.getResourceAsStream(SUPPRESSION_SCHEMA_1_0)) {
108
109 final BOMInputStream bomStream = BOMInputStream.builder().setInputStream(inputStream).get();
110 final ByteOrderMark bom = bomStream.getBOM();
111 final String defaultEncoding = StandardCharsets.UTF_8.name();
112 final String charsetName = bom == null ? defaultEncoding : bom.getCharsetName();
113
114 final SuppressionHandler handler = new SuppressionHandler();
115 final SAXParser saxParser = XmlUtils.buildSecureSaxParser(schemaStream13, schemaStream12, schemaStream11, schemaStream10);
116 final XMLReader xmlReader = saxParser.getXMLReader();
117 xmlReader.setErrorHandler(new SuppressionErrorHandler());
118 xmlReader.setContentHandler(handler);
119 xmlReader.setEntityResolver(new ClassloaderResolver());
120 try (Reader reader = new InputStreamReader(bomStream, charsetName)) {
121 final InputSource in = new InputSource(reader);
122 xmlReader.parse(in);
123 return handler.getSuppressionRules();
124 }
125 } catch (ParserConfigurationException | IOException ex) {
126 LOGGER.debug("", ex);
127 throw new SuppressionParseException(ex);
128 } catch (SAXException ex) {
129 if (ex.getMessage().contains("Cannot find the declaration of element 'suppressions'.")) {
130 throw ex;
131 } else {
132 LOGGER.debug("", ex);
133 throw new SuppressionParseException(ex);
134 }
135 }
136 }
137
138
139
140
141 private static class ClassloaderResolver implements EntityResolver {
142
143 @Override
144 public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
145
146 if (systemId != null && systemId.startsWith("https://jeremylong.github.io/DependencyCheck/")) {
147 final String resource = "schema/" + systemId.substring(45);
148 final InputStream in = SuppressionParser.class.getClassLoader().getResourceAsStream(resource);
149 if (in != null) {
150 final InputSource source = new InputSource(in);
151 source.setSystemId(systemId);
152 return source;
153 }
154 }
155 return null;
156 }
157 }
158 }