Reputation: 5052
I have 2 TransformerFactory
instances: one default, one with secure processing feature set true
. Each generates a Templates
for the same XSL file. When I apply a transformation to XML data for each, I receive different results.
The output generated from the secure TransformerFactory
stripped the attributes from my elements.
The console output identified: SystemId Unknown; Line #xx; Column #yy; "zzzz" attribute is not allowed on the vvvv element!
What is going on here, and how do I prevent this?
I am required to set secure processing to true, going forward. Note that if I apply the attribute using the xsl:attribute
tag (<xsl:attribute name="variable">value</xsl:attribute>
), then it is not ignored by the transformation, however I have many XSL files that are much larger than the sample and changing this would require a massive effort.
There must be a setting to allow for secure processing, but also allow for the strict attributes.
RESEARCH SECTION
Similar question unanswered because it got conflated with a focus on Apache-FO instead of the actual problem, which is the secure transformer.
According to this question, this may be an issue with xalan-2.7.1/xalan-2.7.2 library; I will research and update dependencies.
DATA SECTION
Sample Code
package test;
import java.io.File;
import java.io.StringReader;
import java.io.StringWriter;
import java.nio.charset.Charset;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.commons.io.FileUtils;
public class XformTest {
public static void main(String[] args) {
try {
File BASE_FOLDER = new File("C:\\path-to-work-folder\\");
File outFolder = new File(BASE_FOLDER, "out_" + System.currentTimeMillis());
outFolder.mkdirs();
String xmlData = FileUtils.readFileToString(new File(BASE_FOLDER, "data.xml"), Charset.defaultCharset());
File xslFile = new File(BASE_FOLDER, "format.xsl");
StreamSource dataSource = null;
StreamSource xslSource = null;
TransformerFactory factory = null;
Templates template = null;
Transformer transformer = null;
StringWriter writer = null;
File outFile = null;
String result = null;
// DEFAULT
System.out.println("DEFAULT");
outFile = new File(outFolder, "default.html");
dataSource = new StreamSource(new StringReader(xmlData));
xslSource = new StreamSource(FileUtils.openInputStream(xslFile));
factory = TransformerFactory.newInstance();
template = factory.newTemplates(xslSource);
transformer = template.newTransformer();
writer = new StringWriter();
transformer.transform(dataSource, new StreamResult(writer));
result = writer.toString();
FileUtils.writeStringToFile(outFile, result, Charset.defaultCharset());
// SECURE
System.out.println("SECURE");
outFile = new File(outFolder, "secure.html");
dataSource = new StreamSource(new StringReader(xmlData));
xslSource = new StreamSource(FileUtils.openInputStream(xslFile));
factory = TransformerFactory.newInstance();
factory.setFeature("http://javax.xml.XMLConstants/feature/secure-processing", true);
template = factory.newTemplates(xslSource);
transformer = template.newTransformer();
writer = new StringWriter();
transformer.transform(dataSource, new StreamResult(writer));
result = writer.toString();
FileUtils.writeStringToFile(outFile, result, Charset.defaultCharset());
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Data File "data.xml"
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<page>
<record>
<data>0</data>
<moredata>888.88</moredata>
<info>12345</info>
<name>foo</name>
</record>
<Address1>123 ANY STREET</Address1>
<Address2>SUITE 100</Address2>
<City>ALBUQUERQUE</City>
<Country>USA</Country>
<Fax>1-(888)-686-8281</Fax>
<Name>MISC 000000AA000CDDE</Name>
<State>NM</State>
<Zip>99999-999</Zip>
</page>
XSL File format.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
<xsl:template match="/">
<xsl:variable name="record" select="page/record"/>
<html>
<body>
<form>
<input type="hidden" name="hiddenInputName" value="SpecialValue"/>
<table width="100%" border="0">
<tr><td width="100%"><center><span class="Heading">HELP ME FIGURE THIS OUT</span></center><br/>DATA: <xsl:value-of select="page/City"/></td></tr>
<tr><td width="100%"><span class="BodyNormal"><b><i>The span should have said BodyNormal 100% and the hidden input should have a name and value of hiddenInputName and SpecialValue respectively</i></b></span></td></tr>
</table>
</form>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Default (expected) Output: "default.html"
<?xml version="1.0" encoding="UTF-8"?><html>
<body>
<form>
<input value="SpecialValue" name="hiddenInputName" type="hidden"/>
<table border="0" width="100%">
<tr>
<td width="100%">
<center>
<span class="Heading">HELP ME FIGURE THIS OUT</span>
</center>
<br/>DATA: ALBUQUERQUE</td>
</tr>
<tr>
<td width="100%">
<span class="BodyNormal">
<b>
<i>The span should have said BodyNormal 100% and the hidden input should have a name and value of hiddenInputName and SpecialValue respectively</i>
</b>
</span>
</td>
</tr>
</table>
</form>
</body>
</html>
Secure (truncated) Output: "secure.html"
<?xml version="1.0" encoding="UTF-8"?><html>
<body>
<form>
<input/>
<table>
<tr>
<td>
<center>
<span>HELP ME FIGURE THIS OUT</span>
</center>
<br/>DATA: ALBUQUERQUE</td>
</tr>
<tr>
<td>
<span>
<b>
<i>The span should have said BodyNormal 100% and the hidden input should have a name and value of hiddenInputName and SpecialValue respectively</i>
</b>
</span>
</td>
</tr>
</table>
</form>
</body>
</html>
Console Output
DEFAULT
SECURE
SystemId Unknown; Line #9; Column #67; "type" attribute is not allowed on the input element!
SystemId Unknown; Line #9; Column #67; "name" attribute is not allowed on the input element!
SystemId Unknown; Line #9; Column #67; "value" attribute is not allowed on the input element!
SystemId Unknown; Line #10; Column #32; "width" attribute is not allowed on the table element!
SystemId Unknown; Line #10; Column #32; "border" attribute is not allowed on the table element!
SystemId Unknown; Line #11; Column #22; "width" attribute is not allowed on the td element!
SystemId Unknown; Line #11; Column #52; "class" attribute is not allowed on the span element!
SystemId Unknown; Line #12; Column #22; "width" attribute is not allowed on the td element!
SystemId Unknown; Line #12; Column #47; "class" attribute is not allowed on the span element!
Upvotes: 1
Views: 1257
Reputation: 5052
Solved.
This is due to xalan-2.7.2. Here is the JIRA bug for Xalan-J, XALANJ-2591.
Reverting to xalan-2.7.1 solved the problem, but I ended up temporarily moving to the Apache ServiceMix xalan build 2.7.2_3, which had an embedded patch for the bug and resolved other security vulnerabilities.
This patch was not migrated to the subsequent Apache xalan-2.7.3 release; the bug persisted. Additionally, early releases of ServiceMix for xalan-2.7.3 were inconsistent with prior ServiceMix verions, until ServiceMix xalan-2.7.3_3, which I am currently using and resolves all concerns.
This is the maven include for Apache ServiceMix for Xalan 2.7.3_3
<!-- https://mvnrepository.com/artifact/org.apache.servicemix.bundles/org.apache.servicemix.bundles.xalan -->
<dependency>
<groupId>org.apache.servicemix.bundles</groupId>
<artifactId>org.apache.servicemix.bundles.xalan</artifactId>
<version>2.7.3_3</version>
</dependency>
Upvotes: 1