1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.xml.secure;
19
20 import static org.junit.jupiter.api.Assertions.assertFalse;
21 import static org.junit.jupiter.api.Assertions.assertTrue;
22
23 import java.io.StringWriter;
24
25 import javax.xml.transform.TransformerException;
26 import javax.xml.transform.TransformerFactory;
27 import javax.xml.transform.stream.StreamResult;
28
29 import org.junit.jupiter.api.Assumptions;
30 import org.junit.jupiter.api.Tag;
31 import org.junit.jupiter.api.Test;
32
33
34
35
36
37
38
39
40
41
42
43
44
45 @Tag("trax")
46 class SaxonAlternateFactoryTest {
47
48 private static final String BASIC_FACTORY_CLASS = "net.sf.saxon.BasicTransformerFactory";
49
50 private static void assumeSaxonPresent() {
51 boolean present;
52 try {
53 Class.forName(BASIC_FACTORY_CLASS);
54 present = true;
55 } catch (final ClassNotFoundException e) {
56 present = false;
57 }
58 Assumptions.assumeTrue(present, "Saxon is not on the classpath");
59 }
60
61
62
63
64 private static TransformerFactory basicSaxonFactory() {
65 try {
66 return (TransformerFactory) Class.forName(BASIC_FACTORY_CLASS).getDeclaredConstructor().newInstance();
67 } catch (final ReflectiveOperationException e) {
68 throw new AssertionError("Cannot instantiate " + BASIC_FACTORY_CLASS, e);
69 }
70 }
71
72
73
74
75 private static String collectionStylesheet() {
76 final String collection = AttackTestSupport.resourceUrl("referenced.xml").toString().replaceFirst("referenced\\.xml$", "?select=referenced.xml");
77 return "<?xml version=\"1.0\"?>\n"
78 + "<xsl:stylesheet version=\"3.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n"
79 + " <xsl:template match=\"/\">\n"
80 + " <leaked><xsl:value-of select=\"string(collection('" + collection + "')/leaked)\"/></leaked>\n"
81 + " </xsl:template>\n"
82 + "</xsl:stylesheet>\n";
83 }
84
85 private static String transform(final TransformerFactory factory) throws TransformerException {
86 final StringWriter sink = new StringWriter();
87 factory.newTemplates(AttackTestSupport.streamSource(collectionStylesheet())).newTransformer()
88 .transform(AttackTestSupport.streamSource("<root/>"), new StreamResult(sink));
89 return sink.toString();
90 }
91
92 @Test
93 void secureBasicFactoryDoesNotLeakCollection() {
94 assumeSaxonPresent();
95 try {
96 final String result = transform(SecureTransformerFactory.secure(basicSaxonFactory()));
97 assertFalse(result.contains(AttackTestSupport.LEAKED_MARKER), "collection() leaked through the alternate Saxon factory:\n" + result);
98 } catch (final TransformerException blocked) {
99
100 }
101 }
102
103 @Test
104 void unconfiguredBasicFactoryLeaksCollection() throws TransformerException {
105 assumeSaxonPresent();
106
107 final String result = transform(basicSaxonFactory());
108 assertTrue(result.contains(AttackTestSupport.LEAKED_MARKER), "bare alternate Saxon factory was expected to resolve collection(), got: " + result);
109 }
110 }