1212import org .elasticsearch .SpecialPermission ;
1313import org .elasticsearch .common .hash .MessageDigests ;
1414import org .elasticsearch .core .IOUtils ;
15- import org .elasticsearch .core .SuppressForbidden ;
15+ import org .elasticsearch .core .XmlUtils ;
1616import org .elasticsearch .xpack .core .security .support .RestorableContextClassLoader ;
1717import org .opensaml .core .config .InitializationService ;
1818import org .opensaml .core .xml .XMLObject ;
3030import org .w3c .dom .ls .DOMImplementationLS ;
3131import org .w3c .dom .ls .LSInput ;
3232import org .w3c .dom .ls .LSResourceResolver ;
33- import org .xml .sax .SAXException ;
34- import org .xml .sax .SAXParseException ;
3533
3634import java .io .IOException ;
3735import java .io .InputStream ;
5149import javax .xml .XMLConstants ;
5250import javax .xml .namespace .QName ;
5351import javax .xml .parsers .DocumentBuilder ;
54- import javax .xml .parsers .DocumentBuilderFactory ;
5552import javax .xml .parsers .ParserConfigurationException ;
5653import javax .xml .transform .OutputKeys ;
5754import javax .xml .transform .Transformer ;
58- import javax .xml .transform .TransformerConfigurationException ;
5955import javax .xml .transform .TransformerException ;
60- import javax .xml .transform .TransformerFactory ;
6156import javax .xml .transform .dom .DOMSource ;
6257import javax .xml .transform .stream .StreamResult ;
6358import javax .xml .transform .stream .StreamSource ;
@@ -161,7 +156,7 @@ static String toString(Element element) {
161156 }
162157
163158 static void print (Element element , Writer writer , boolean pretty ) throws TransformerException {
164- final Transformer serializer = getHardenedXMLTransformer ();
159+ final Transformer serializer = XmlUtils . getHardenedXMLTransformer ();
165160 if (pretty ) {
166161 serializer .setOutputProperty (OutputKeys .INDENT , "yes" );
167162 }
@@ -211,18 +206,6 @@ static String describeSamlObject(SAMLObject object) {
211206 return getXmlContent (object , true );
212207 }
213208
214- @ SuppressForbidden (reason = "This is the only allowed way to construct a Transformer" )
215- public static Transformer getHardenedXMLTransformer () throws TransformerConfigurationException {
216- final TransformerFactory tfactory = TransformerFactory .newInstance ();
217- tfactory .setFeature (XMLConstants .FEATURE_SECURE_PROCESSING , true );
218- tfactory .setAttribute (XMLConstants .ACCESS_EXTERNAL_DTD , "" );
219- tfactory .setAttribute (XMLConstants .ACCESS_EXTERNAL_STYLESHEET , "" );
220- tfactory .setAttribute ("indent-number" , 2 );
221- Transformer transformer = tfactory .newTransformer ();
222- transformer .setErrorListener (new ErrorListener ());
223- return transformer ;
224- }
225-
226209 static void validate (InputStream xml , String xsdName ) throws Exception {
227210 SchemaFactory schemaFactory = SchemaFactory .newInstance (XMLConstants .W3C_XML_SCHEMA_NS_URI );
228211 try (InputStream xsdStream = loadSchema (xsdName ); ResourceResolver resolver = new ResourceResolver ()) {
@@ -277,40 +260,8 @@ public void close() throws IOException {
277260 *
278261 * @throws ParserConfigurationException if one of the features can't be set on the DocumentBuilderFactory
279262 */
280- @ SuppressForbidden (reason = "This is the only allowed way to construct a DocumentBuilder" )
281263 public static DocumentBuilder getHardenedBuilder (String [] schemaFiles ) throws ParserConfigurationException {
282- final DocumentBuilderFactory dbf = DocumentBuilderFactory .newInstance ();
283- dbf .setNamespaceAware (true );
284- // Ensure that Schema Validation is enabled for the factory
285- dbf .setValidating (true );
286- // Disallow internal and external entity expansion
287- dbf .setFeature ("http://apache.org/xml/features/disallow-doctype-decl" , true );
288- dbf .setFeature ("http://xml.org/sax/features/external-general-entities" , false );
289- dbf .setFeature ("http://xml.org/sax/features/external-parameter-entities" , false );
290- dbf .setFeature ("http://apache.org/xml/features/nonvalidating/load-external-dtd" , false );
291- dbf .setFeature ("http://xml.org/sax/features/validation" , true );
292- dbf .setFeature ("http://apache.org/xml/features/nonvalidating/load-dtd-grammar" , false );
293- dbf .setIgnoringComments (true );
294- // This is required, otherwise schema validation causes signature invalidation
295- dbf .setFeature ("http://apache.org/xml/features/validation/schema/normalized-value" , false );
296- // Make sure that URL schema namespaces are not resolved/downloaded from URLs we do not control
297- dbf .setAttribute (XMLConstants .ACCESS_EXTERNAL_DTD , "file,jar" );
298- dbf .setAttribute (XMLConstants .ACCESS_EXTERNAL_SCHEMA , "file,jar" );
299- dbf .setFeature ("http://apache.org/xml/features/honour-all-schemaLocations" , true );
300- // Ensure we do not resolve XIncludes. Defaults to false, but set it explicitly to be future-proof
301- dbf .setXIncludeAware (false );
302- // Ensure we do not expand entity reference nodes
303- dbf .setExpandEntityReferences (false );
304- // Further limit danger from denial of service attacks
305- dbf .setFeature (XMLConstants .FEATURE_SECURE_PROCESSING , true );
306- dbf .setAttribute ("http://apache.org/xml/features/validation/schema" , true );
307- dbf .setAttribute ("http://apache.org/xml/features/validation/schema-full-checking" , true );
308- dbf .setAttribute ("http://java.sun.com/xml/jaxp/properties/schemaLanguage" , XMLConstants .W3C_XML_SCHEMA_NS_URI );
309- // We ship our own xsd files for schema validation since we do not trust anyone else.
310- dbf .setAttribute ("http://java.sun.com/xml/jaxp/properties/schemaSource" , resolveSchemaFilePaths (schemaFiles ));
311- DocumentBuilder documentBuilder = dbf .newDocumentBuilder ();
312- documentBuilder .setErrorHandler (new ErrorHandler ());
313- return documentBuilder ;
264+ return XmlUtils .getHardenedBuilder (resolveSchemaFilePaths (schemaFiles ));
314265 }
315266
316267 private static String [] resolveSchemaFilePaths (String [] relativePaths ) {
@@ -324,52 +275,4 @@ private static String[] resolveSchemaFilePaths(String[] relativePaths) {
324275 }
325276 }).filter (Objects ::nonNull ).toArray (String []::new );
326277 }
327-
328- private static class ErrorListener implements javax .xml .transform .ErrorListener {
329-
330- @ Override
331- public void warning (TransformerException e ) throws TransformerException {
332- LOGGER .debug ("XML transformation error" , e );
333- throw e ;
334- }
335-
336- @ Override
337- public void error (TransformerException e ) throws TransformerException {
338- LOGGER .debug ("XML transformation error" , e );
339- throw e ;
340- }
341-
342- @ Override
343- public void fatalError (TransformerException e ) throws TransformerException {
344- LOGGER .debug ("XML transformation error" , e );
345- throw e ;
346- }
347- }
348-
349- private static class ErrorHandler implements org .xml .sax .ErrorHandler {
350- /**
351- * Enabling schema validation with `setValidating(true)` in our
352- * DocumentBuilderFactory requires that we provide our own
353- * ErrorHandler implementation
354- *
355- * @throws SAXException If the document we attempt to parse is not valid according to the specified schema.
356- */
357- @ Override
358- public void warning (SAXParseException e ) throws SAXException {
359- LOGGER .debug ("XML Parser error " , e );
360- throw e ;
361- }
362-
363- @ Override
364- public void error (SAXParseException e ) throws SAXException {
365- LOGGER .debug ("XML Parser error " , e );
366- throw e ;
367- }
368-
369- @ Override
370- public void fatalError (SAXParseException e ) throws SAXException {
371- LOGGER .debug ("XML Parser error " , e );
372- throw e ;
373- }
374- }
375278}
0 commit comments