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
61 public static final String SUPPRESSION_SCHEMA_1_4 = "schema/dependency-suppression.1.4.xsd";
62
63
64
65 public static final String SUPPRESSION_SCHEMA_1_3 = "schema/dependency-suppression.1.3.xsd";
66
67
68
69 public static final String SUPPRESSION_SCHEMA_1_2 = "schema/dependency-suppression.1.2.xsd";
70
71
72
73 public static final String SUPPRESSION_SCHEMA_1_1 = "schema/dependency-suppression.1.1.xsd";
74
75
76
77 private static final String SUPPRESSION_SCHEMA_1_0 = "schema/suppression.xsd";
78
79
80
81
82
83
84
85
86
87 @SuppressFBWarnings(justification = "try with resource will clenaup the resources", value = {"OBL_UNSATISFIED_OBLIGATION"})
88 public List<SuppressionRule> parseSuppressionRules(File file) throws SuppressionParseException {
89 try (FileInputStream fis = new FileInputStream(file)) {
90 return parseSuppressionRules(fis);
91 } catch (SAXException | IOException ex) {
92 LOGGER.debug("", ex);
93 throw new SuppressionParseException(ex);
94 }
95 }
96
97
98
99
100
101
102
103
104
105
106 public List<SuppressionRule> parseSuppressionRules(InputStream inputStream)
107 throws SuppressionParseException, SAXException {
108 try (
109 InputStream schemaStream14 = FileUtils.getResourceAsStream(SUPPRESSION_SCHEMA_1_4);
110 InputStream schemaStream13 = FileUtils.getResourceAsStream(SUPPRESSION_SCHEMA_1_3);
111 InputStream schemaStream12 = FileUtils.getResourceAsStream(SUPPRESSION_SCHEMA_1_2);
112 InputStream schemaStream11 = FileUtils.getResourceAsStream(SUPPRESSION_SCHEMA_1_1);
113 InputStream schemaStream10 = FileUtils.getResourceAsStream(SUPPRESSION_SCHEMA_1_0)) {
114
115 final BOMInputStream bomStream = BOMInputStream.builder().setInputStream(inputStream).get();
116 final ByteOrderMark bom = bomStream.getBOM();
117 final String defaultEncoding = StandardCharsets.UTF_8.name();
118 final String charsetName = bom == null ? defaultEncoding : bom.getCharsetName();
119
120 final SuppressionHandler handler = new SuppressionHandler();
121 final SAXParser saxParser = XmlUtils.buildSecureSaxParser(schemaStream14, schemaStream13, schemaStream12, schemaStream11, schemaStream10);
122 final XMLReader xmlReader = saxParser.getXMLReader();
123 xmlReader.setErrorHandler(new SuppressionErrorHandler());
124 xmlReader.setContentHandler(handler);
125 xmlReader.setEntityResolver(new ClassloaderResolver());
126 try (Reader reader = new InputStreamReader(bomStream, charsetName)) {
127 final InputSource in = new InputSource(reader);
128 xmlReader.parse(in);
129 return handler.getSuppressionRules();
130 }
131 } catch (ParserConfigurationException | IOException ex) {
132 LOGGER.debug("", ex);
133 throw new SuppressionParseException(ex);
134 } catch (SAXException ex) {
135 if (ex.getMessage().contains("Cannot find the declaration of element 'suppressions'.")) {
136 throw ex;
137 } else {
138 LOGGER.debug("", ex);
139 throw new SuppressionParseException(ex);
140 }
141 }
142 }
143
144
145
146
147 private static class ClassloaderResolver implements EntityResolver {
148
149 @Override
150 public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
151
152 if (systemId != null && systemId.startsWith("https://jeremylong.github.io/DependencyCheck/")) {
153 final String resource = "schema/" + systemId.substring(45);
154 final InputStream in = SuppressionParser.class.getClassLoader().getResourceAsStream(resource);
155 if (in != null) {
156 final InputSource source = new InputSource(in);
157 source.setSystemId(systemId);
158 return source;
159 }
160 }
161 return null;
162 }
163 }
164 }