XalanProvider.java
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.xml;
import static org.apache.commons.xml.JaxpSetters.setFeature;
import javax.xml.XMLConstants;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.xpath.XPathFactory;
/**
* Hardening recipes for the external Apache Xalan distribution (the {@code xalan:xalan} artifact).
*
* <p>Factory classes live under the {@code org.apache.xalan.*} and {@code org.apache.xpath.*} packages. Xalan ships only TrAX and XPath; its DOM, SAX, StAX and
* Schema needs are served by whatever JDK or external Xerces is on the classpath.</p>
*
* <p>Hardening recipe applied to every factory below uses the same building blocks:</p>
* <ul>
* <li><strong>FSP</strong> ({@link XMLConstants#FEATURE_SECURE_PROCESSING}, set to {@code true}): enables Xalan's secure-processing mode, which disables
* reflection-based extension functions. Required.</li>
* <li><strong>{@link Resolvers.DenyAll#URI}</strong>: required. Xalan does not implement the JAXP 1.5 {@code ACCESS_EXTERNAL_*} attributes; a deny-all
* {@link javax.xml.transform.URIResolver} blocks {@code xsl:include}, {@code xsl:import}, {@code xsl:source-document} during stylesheet compilation
* and {@code document()}, {@code unparsed-text()}, {@code collection()} at runtime.</li>
* <li><strong>{@link HardeningTransformerFactory} + {@link HardeningTemplates} + {@link HardeningTransformer}</strong>: required. Xalan's source-document
* parsing path falls back to {@code SAXParserFactory.newInstance()} whenever the input is not a {@link javax.xml.transform.dom.DOMSource} or a
* {@link javax.xml.transform.sax.SAXSource} carrying its own {@link org.xml.sax.XMLReader}; it only sets FSP on the resulting reader. The wrappers
* rewrite every Source through an {@link XmlFactories}-hardened reader so the Xalan internals never get to provision their own.</li>
* </ul>
*
* <h2>Caveats</h2>
* <ul>
* <li>Replacing the {@code URIResolver} on the factory or transformer cancels the deny-all hardening for XSLT URI fetches; Xalan exposes no
* tamper-resistant equivalent of JAXP 1.5 {@code ACCESS_EXTERNAL_STYLESHEET}.</li>
* </ul>
*/
final class XalanProvider {
static TransformerFactory configure(final TransformerFactory factory) {
// Required: enables Xalan's secure-processing mode (extension-function block)
setFeature(factory, XMLConstants.FEATURE_SECURE_PROCESSING, true);
// Required: Xalan does not honour JAXP 1.5 ACCESS_EXTERNAL_*; the deny-all URIResolver blocks:
// xsl:import/xsl:include at compile time and document()/unparsed-text() at runtime.
factory.setURIResolver(Resolvers.DenyAll.URI);
// Required: Xalan's internal SAX reader is sourced from SAXParserFactory.newInstance() and only carries FSP.
// We replace it with our hardened factory
return new HardeningTransformerFactory((SAXTransformerFactory) factory);
}
static XPathFactory configure(final XPathFactory factory) {
// Required: enables Xalan's secure-processing mode; XPathFactory has no property API for finer control.
setFeature(factory, XMLConstants.FEATURE_SECURE_PROCESSING, true);
return factory;
}
private XalanProvider() {
}
}