001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      https://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.xml.secure;
019
020import java.io.IOException;
021import java.lang.invoke.MethodHandle;
022import java.lang.invoke.MethodType;
023import java.util.Objects;
024import java.util.function.Supplier;
025
026import javax.xml.XMLConstants;
027import javax.xml.parsers.DocumentBuilderFactory;
028import javax.xml.parsers.FactoryConfigurationError;
029import javax.xml.parsers.ParserConfigurationException;
030import javax.xml.transform.ErrorListener;
031import javax.xml.transform.Source;
032import javax.xml.transform.Templates;
033import javax.xml.transform.Transformer;
034import javax.xml.transform.TransformerConfigurationException;
035import javax.xml.transform.TransformerFactory;
036import javax.xml.transform.TransformerFactoryConfigurationError;
037import javax.xml.transform.URIResolver;
038import javax.xml.transform.dom.DOMSource;
039import javax.xml.transform.sax.SAXSource;
040import javax.xml.transform.sax.SAXTransformerFactory;
041import javax.xml.transform.sax.TemplatesHandler;
042import javax.xml.transform.sax.TransformerHandler;
043import javax.xml.transform.stream.StreamSource;
044
045import org.w3c.dom.Document;
046import org.xml.sax.InputSource;
047import org.xml.sax.SAXException;
048import org.xml.sax.XMLFilter;
049import org.xml.sax.XMLReader;
050
051/**
052 * Creates new, secure {@link TransformerFactory} instances.
053 * <p>
054 * Beyond the three universal guarantees on {@link org.apache.commons.xml.secure}: {@code xsl:import}, {@code xsl:include} and {@code document()} URIs are not resolved.
055 * </p>
056 * <p>
057 * The guarantees govern what the transform reads, not what it writes: an output instruction like {@code xsl:result-document} still writes wherever the
058 * stylesheet directs, so an untrusted stylesheet's output destinations must be restricted outside the library.
059 * </p>
060 * <p>
061 * The guarantees apply to every parser the factory creates internally for the standard {@link TransformerFactory} entry points: stylesheet compilation
062 * ({@link TransformerFactory#newTemplates(javax.xml.transform.Source) newTemplates(Source)},
063 * {@link TransformerFactory#newTransformer(javax.xml.transform.Source) newTransformer(Source)}) and source-document reading at
064 * {@code Transformer.transform(Source, Result)} time.
065 * </p>
066 * <p>
067 * The {@link javax.xml.transform.sax.SAXTransformerFactory} extension methods ({@code newTransformerHandler(..)}, {@code newTemplatesHandler()},
068 * {@code newXMLFilter(..)}), if reachable by casting the returned factory, produce objects carrying the same guarantees.
069 * </p>
070 * <p>
071 * Not a {@link TransformerFactory} itself, so none of the JAXP static factory methods is inherited: a caller cannot reach a non-secured factory through this class
072 * by calling an inherited method such as {@code newDefaultInstance()}. The secure factories are instances of a nested, non-public wrapper class.
073 * </p>
074 *
075 * @see org.apache.commons.xml.secure
076 */
077public final class SecureTransformerFactory {
078
079    /**
080     * {@link TransformerFactory} wrapper that rewrites every Source-taking entry point through {@link SecureSAXParserFactory#secure(Source, boolean)} before
081     * delegating.
082     *
083     * <p>Used by providers whose underlying TrAX implementation pulls a new {@code SAXParserFactory.newInstance()} for any Source that is not already a
084     * {@link SAXSource} carrying its own {@link XMLReader}, and only sets {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING FSP} on the resulting reader.
085     * Wrapping the factory and rewriting the Source upstream guarantees the parse runs through an {@link org.apache.commons.xml.secure}-secured reader instead.</p>
086     *
087     * <p>Three layers cooperate:</p>
088     * <ol>
089     *   <li>{@link SecureTransformerFactory} rewrites the Source on every entry point that compiles a stylesheet or transforms a one-shot input.</li>
090     *   <li>{@link SecureTemplates} returns a {@link SecureTransformer} from {@link Templates#newTransformer()} so runtime source parsing is also covered, and
091     *       restores the factory's URIResolver onto the produced Transformer (which the underlying implementation typically does not propagate through
092     *       {@code Templates}).</li>
093     *   <li>{@link SecureTransformer} rewrites the Source on every {@link Transformer#transform(Source, javax.xml.transform.Result)} call.</li>
094     * </ol>
095     *
096     * <p>The {@link SAXTransformerFactory} extension products ride the same wrappers: {@code newTransformerHandler}/{@code newTemplatesHandler} products are
097     * wrapped ({@link SecureTransformerHandler}, {@link SecureTemplatesHandler}) so the {@link Transformer}/{@link Templates} they expose carry the resolver
098     * floor, and {@code newXMLFilter} returns a {@link SecureXMLFilter} composed from these wrappers instead of the implementation's filter, which would
099     * self-provision an unsecured input reader.</p>
100     *
101     * <h2>Caveats</h2>
102     * <ul>
103     *   <li>A {@link SAXSource} that carries its own {@link XMLReader} is trusted as-is: the caller is expected to supply a secure reader (via
104     *       {@link SecureSAXParserFactory#newInstance()}) in that case. The same applies to the SAX events a caller feeds into a handler, and to a parent reader a
105     *       caller sets on a returned {@link XMLFilter}.</li>
106     * </ul>
107     *
108     * @see org.apache.commons.xml.secure
109     */
110    private static final class Wrapper extends SAXTransformerFactory {
111
112        /**
113         * Whether the delegate is Apache Xalan (either its interpretive or its XSLTC factory), whose {@code getAssociatedStylesheet} ignores a SAXSource reader.
114         *
115         * @param factory The delegate factory.
116         * @return Whether the delegate is an {@code org.apache.xalan.} implementation.
117         */
118        private static boolean isXalan(final SAXTransformerFactory factory) {
119            return factory.getClass().getName().startsWith("org.apache.xalan.");
120        }
121
122        /**
123         * Whether the delegate recognizes {@value SecureSAXParserFactory#OVERRIDE_DEFAULT_PARSER}, probed with a same-value {@code setFeature}:
124         * {@code TransformerFactory.getFeature} cannot signal an unrecognized name (it returns {@code false}), while every implementation rejects a
125         * {@code setFeature} for a name it does not support (Xalan with {@link TransformerConfigurationException}, Saxon with its own unchecked exception).
126         *
127         * @param factory The delegate factory.
128         * @return Whether the delegate recognizes the feature.
129         */
130        private static boolean probeOverrideDefaultParser(final SAXTransformerFactory factory) {
131            try {
132                factory.setFeature(SecureSAXParserFactory.OVERRIDE_DEFAULT_PARSER,
133                        factory.getFeature(SecureSAXParserFactory.OVERRIDE_DEFAULT_PARSER));
134                return true;
135            } catch (final Exception e) {
136                return false;
137            }
138        }
139
140        private static Templates unwrap(final Templates templates) {
141            return templates instanceof SecureTemplates ? ((SecureTemplates) templates).getDelegate() : templates;
142        }
143
144        private final SAXTransformerFactory delegate;
145
146        /**
147         * Empty-{@link Source} supplier for the resolver floor, threaded onto every produced Templates/Transformer; {@code null} means the default empty DOM.
148         */
149        private final Supplier<Source> emptySource;
150
151        private final FallbackIgnoreURIResolver floor;
152
153        /** Whether the delegate recognizes {@value SecureSAXParserFactory#OVERRIDE_DEFAULT_PARSER}; its value is read per created product, like the JDK. */
154        private final boolean supportsOverrideDefaultParser;
155
156        /**
157         * Constructs a new instance.
158         *
159         * @param delegate the delegate to wrap; must not be {@code null}.
160         * @throws NullPointerException if {@code delegate} is {@code null}.
161         */
162        private Wrapper(final SAXTransformerFactory delegate) {
163            this(delegate, null);
164        }
165
166        /**
167         * Constructs a new instance.
168         *
169         * @param delegate    the delegate to wrap; must not be {@code null}.
170         * @param emptySource the empty-{@link Source} supplier for the resolver floor, threaded onto every produced Templates/Transformer; {@code null} means the
171         *                    default empty DOM.
172         * @throws NullPointerException if {@code delegate} is {@code null}.
173         */
174        private Wrapper(final SAXTransformerFactory delegate, final Supplier<Source> emptySource) {
175            this.delegate = Objects.requireNonNull(delegate, "delegate");
176            this.emptySource = emptySource;
177            this.supportsOverrideDefaultParser = probeOverrideDefaultParser(delegate);
178            this.floor = new FallbackIgnoreURIResolver(null, emptySource, this::overrideDefaultParser);
179            // Compile-time block for xsl:import/xsl:include and document(); a caller-set resolver is routed through the floor rather than replacing it.
180            delegate.setURIResolver(floor);
181        }
182
183        /**
184         * {@inheritDoc}
185         *
186         * @throws FactoryConfigurationError Thrown from a factory in case of a {@link java.util.ServiceConfigurationError service
187         *                                   configuration error} or if the implementation is not available or cannot be instantiated.
188         */
189        @Override
190        public Source getAssociatedStylesheet(final Source source, final String media, final String title, final String charset)
191                throws TransformerConfigurationException {
192            // Xalan's getAssociatedStylesheet drops a SAXSource's reader and self-provisions its own to scan for xml-stylesheet PIs (XALANJ-2849).
193            final Source secure = isXalan(delegate) ? secureSourceToDom(source) : SecureSAXParserFactory.secure(source, overrideDefaultParser());
194            return delegate.getAssociatedStylesheet(secure, media, title, charset);
195        }
196
197        @Override
198        public Object getAttribute(final String name) {
199            return delegate.getAttribute(name);
200        }
201
202        @Override
203        public ErrorListener getErrorListener() {
204            return delegate.getErrorListener();
205        }
206
207        @Override
208        public boolean getFeature(final String name) {
209            return delegate.getFeature(name);
210        }
211
212        @Override
213        public URIResolver getURIResolver() {
214            return floor.getDelegate();
215        }
216
217        /**
218         * {@inheritDoc}
219         *
220         * @throws FactoryConfigurationError Thrown from a factory in case of a {@link java.util.ServiceConfigurationError service
221         *                                   configuration error} or if the implementation is not available or cannot be instantiated.
222         */
223        @Override
224        public Templates newTemplates(final Source source) throws TransformerConfigurationException {
225            final Templates templates = delegate.newTemplates(SecureSAXParserFactory.secure(source, overrideDefaultParser()));
226            return templates == null ? null : new SecureTemplates(templates, getURIResolver(), emptySource, overrideDefaultParser());
227        }
228
229        @Override
230        public TemplatesHandler newTemplatesHandler() throws TransformerConfigurationException {
231            final TemplatesHandler handler = delegate.newTemplatesHandler();
232            return handler == null ? null : new SecureTemplatesHandler(handler, getURIResolver(), emptySource, overrideDefaultParser());
233        }
234
235        @Override
236        public Transformer newTransformer() throws TransformerConfigurationException {
237            // Identity transformer: still parses runtime sources, so wrap it to secure Transformer.transform(Source, Result).
238            final Transformer transformer = delegate.newTransformer();
239            return transformer == null ? null : new SecureTransformer(transformer, getURIResolver(), emptySource, overrideDefaultParser());
240        }
241
242        /**
243         * {@inheritDoc}
244         *
245         * @throws FactoryConfigurationError Thrown from a factory in case of a {@link java.util.ServiceConfigurationError service
246         *                                   configuration error} or if the implementation is not available or cannot be instantiated.
247         */
248        @Override
249        public Transformer newTransformer(final Source source) throws TransformerConfigurationException {
250            final Transformer transformer = delegate.newTransformer(SecureSAXParserFactory.secure(source, overrideDefaultParser()));
251            return transformer == null ? null : new SecureTransformer(transformer, getURIResolver(), emptySource, overrideDefaultParser());
252        }
253
254        @Override
255        public TransformerHandler newTransformerHandler() throws TransformerConfigurationException {
256            return secure(delegate.newTransformerHandler());
257        }
258
259        /**
260         * {@inheritDoc}
261         *
262         * @throws FactoryConfigurationError Thrown from a factory in case of a {@link java.util.ServiceConfigurationError service
263         *                                   configuration error} or if the implementation is not available or cannot be instantiated.
264         */
265        @Override
266        public TransformerHandler newTransformerHandler(final Source source) throws TransformerConfigurationException {
267            return secure(delegate.newTransformerHandler(SecureSAXParserFactory.secure(source, overrideDefaultParser())));
268        }
269
270        @Override
271        public TransformerHandler newTransformerHandler(final Templates templates) throws TransformerConfigurationException {
272            // Implementations cast templates.newTransformer() to their own Transformer type, so hand them the wrapped implementation Templates, not the wrapper.
273            return secure(delegate.newTransformerHandler(unwrap(templates)));
274        }
275
276        /**
277         * {@inheritDoc}
278         *
279         * @throws FactoryConfigurationError Thrown from a factory in case of a {@link java.util.ServiceConfigurationError service
280         *                                   configuration error} or if the implementation is not available or cannot be instantiated.
281         */
282        @Override
283        public XMLFilter newXMLFilter(final Source source) throws TransformerConfigurationException {
284            final Templates templates = newTemplates(source);
285            return templates == null ? null : new SecureXMLFilter((SecureTemplates) templates);
286        }
287
288        @Override
289        public XMLFilter newXMLFilter(final Templates templates) throws TransformerConfigurationException {
290            return new SecureXMLFilter(templates instanceof SecureTemplates ? (SecureTemplates) templates
291                    : new SecureTemplates(templates, getURIResolver(), emptySource, overrideDefaultParser()));
292        }
293
294        /**
295         * Checks whether parsers should be instantiated via {@code newInstance()} instead of {@code newDefaultInstance()}.
296         *
297         * <p>The JDK implementation of {@link TransformerFactory} uses the JDK parsers while {@value SecureSAXParserFactory#OVERRIDE_DEFAULT_PARSER} is unset
298         * or {@code false}.</p>
299         *
300         * @return {@code true} if parsers should be created via {@code newInstance()}.
301         */
302        private boolean overrideDefaultParser() {
303            return !supportsOverrideDefaultParser || delegate.getFeature(SecureSAXParserFactory.OVERRIDE_DEFAULT_PARSER);
304        }
305
306        private TransformerHandler secure(final TransformerHandler handler) {
307            return handler == null ? null : new SecureTransformerHandler(handler, getURIResolver(), emptySource, overrideDefaultParser());
308        }
309
310        /**
311         * Parses a reader-less source into a DOM through a secure, namespace-aware {@link javax.xml.parsers.DocumentBuilder} and returns a {@link DOMSource}
312         * carrying its system id, so the consumer walks the tree instead of provisioning its own reader. Any other source is left to
313         * {@link SecureSAXParserFactory#secure(Source, boolean)}.
314         *
315         * @param source The source to scan for an associated stylesheet.
316         * @return A {@link DOMSource} for a reader-less source, otherwise the result of {@link SecureSAXParserFactory#secure(Source, boolean)}.
317         * @throws TransformerConfigurationException if the source cannot be parsed.
318         * @throws FactoryConfigurationError Thrown from a factory in case of a {@link java.util.ServiceConfigurationError service
319         *                                   configuration error} or if the implementation is not available or cannot be instantiated.
320         * @throws SecureException Thrown if a (non-Android) factory cannot support the secure processing feature {@link XMLConstants#FEATURE_SECURE_PROCESSING}.
321         */
322        private Source secureSourceToDom(final Source source) throws TransformerConfigurationException {
323            if (source instanceof StreamSource || source instanceof SAXSource && ((SAXSource) source).getXMLReader() == null) {
324                final InputSource inputSource = SAXSource.sourceToInputSource(source);
325                if (inputSource != null) {
326                    try {
327                        final DocumentBuilderFactory factory = SecureDocumentBuilderFactory.newNSInstance(overrideDefaultParser());
328                        final Document document = factory.newDocumentBuilder().parse(inputSource);
329                        return new DOMSource(document, inputSource.getSystemId());
330                    } catch (final ParserConfigurationException | SAXException | IOException e) {
331                        throw new TransformerConfigurationException("Failed to parse the source for associated-stylesheet lookup", e);
332                    }
333                }
334            }
335            return SecureSAXParserFactory.secure(source, overrideDefaultParser());
336        }
337
338        @Override
339        public void setAttribute(final String name, final Object value) {
340            delegate.setAttribute(name, value);
341        }
342
343        @Override
344        public void setErrorListener(final ErrorListener listener) {
345            delegate.setErrorListener(listener);
346        }
347
348
349        @Override
350        public void setFeature(final String name, final boolean value) throws TransformerConfigurationException {
351            delegate.setFeature(name, value);
352        }
353
354        @Override
355        public void setURIResolver(final URIResolver resolver) {
356            floor.setDelegate(resolver);
357        }
358    }
359
360    /** Class name of the JDK's built-in default implementation, the Java 8 fallback for {@link #newDefaultInstance()}. */
361    private static final String JDK_TRANSFORMER_FACTORY = "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl";
362
363    private static final MethodHandle MH_newDefaultInstance = MethodHandleFactory.findStatic(TransformerFactory.class, "newDefaultInstance",
364            MethodType.methodType(TransformerFactory.class));
365
366    /**
367     * Returns a new, secure {@link TransformerFactory} of the system-default implementation.
368     * <p>
369     * Obtained as by {@code TransformerFactory.newDefaultInstance()} where the platform provides it (Java 9 or later), and by instantiating the JDK's built-in
370     * implementation directly on Java 8.
371     * </p>
372     *
373     * @return A secure factory.
374     * @throws IllegalStateException                Thrown if a required secure setting cannot be applied to the underlying implementation.
375     * @throws TransformerFactoryConfigurationError Thrown if the running platform provides neither {@code newDefaultInstance()} nor the JDK's built-in
376     *                                                implementation (for example Android).
377     */
378    public static TransformerFactory newDefaultInstance() {
379        if (MH_newDefaultInstance != null) {
380            return secure(MethodHandleFactory.invokeExact(() -> (TransformerFactory) MH_newDefaultInstance.invokeExact(), TransformerFactoryConfigurationError.class));
381        }
382        // Java 8: the method does not exist; instantiate the JDK's built-in default by its class name instead. Where that class does not exist either (for
383        // example Android), the lookup miss surfaces as TransformerFactoryConfigurationError, like any newInstance miss.
384        return newInstance(JDK_TRANSFORMER_FACTORY, null);
385    }
386
387    /**
388     * Returns a new, secure {@link TransformerFactory}.
389     *
390     * @return A secure factory.
391     * @throws IllegalStateException if a required secure setting cannot be applied to the underlying implementation.
392     */
393    public static TransformerFactory newInstance() {
394        return secure(TransformerFactory.newInstance());
395    }
396
397    /**
398     * Returns a new, secure {@link TransformerFactory} of the given implementation class.
399     *
400     * @param factoryClassName The fully qualified class name of the {@link TransformerFactory} implementation.
401     * @param classLoader      The class loader used to load the factory class; {@code null} means the current thread's context class loader.
402     * @return A secure factory.
403     * @throws IllegalStateException                Thrown if a required secure setting cannot be applied to the underlying implementation.
404     * @throws TransformerFactoryConfigurationError Thrown if {@code factoryClassName} is {@code null} or the factory class cannot be loaded or instantiated.
405     */
406    public static TransformerFactory newInstance(final String factoryClassName, final ClassLoader classLoader) {
407        return secure(TransformerFactory.newInstance(factoryClassName, classLoader));
408    }
409
410    /**
411     * Capability-driven secure for any {@link TransformerFactory} on the classpath.
412     *
413     * <p>Rather than branching on the implementation class, this method probes what the factory supports and adapts:</p>
414     * <ul>
415     *     <li><strong>Saxon</strong> ({@code net.sf.saxon}): recognized by package prefix and handed to {@link SaxonProvider#configure(TransformerFactory)} for the
416     *         channels the standard JAXP knobs cannot close (reflection-based extension functions, the collection finder, the internal SAX parser). It is then
417     *         wrapped like every other implementation to install the {@link FallbackIgnoreURIResolver} floor; the only
418     *         difference is the empty-{@link Source} shape the floor returns, {@code EmptySource} for Saxon rather than the default empty DOM document.</li>
419     *     <li><strong>FSP</strong> ({@link XMLConstants#FEATURE_SECURE_PROCESSING}): required. On XSLTC it enables the runtime evaluator limits; on Xalan it disables
420     *         reflection-based extension functions.</li>
421     *     <li><strong>{@link FallbackIgnoreURIResolver} floor</strong>: required. An ignore-all {@link URIResolver} floor, installed by
422     *         the nested wrapper and carried onto every produced {@link Transformer}, resolves {@code xsl:import}/{@code xsl:include} at compile
423     *         time and {@code document()} at runtime to an empty document, the one channel both XSLTC and Xalan route through. A caller-set {@link URIResolver} is
424     *         routed through the floor rather than replacing it, so a caller can opt a specific URI in but cannot reopen the fetch.</li>
425     *     <li><strong>The nested wrapper</strong>: required. Both implementations fall back to {@code SAXParserFactory.newInstance()} to parse a
426     *         stylesheet or source document that does not carry its own reader, and only set FSP on it; wrapping the factory rewrites every {@link Source} through an
427     *         {@link org.apache.commons.xml.secure}-secured reader instead.</li>
428     * </ul>
429     *
430     * @param factory the factory to secure; never {@code null}.
431     * @return a secure factory.
432     */
433    static TransformerFactory secure(final TransformerFactory factory) {
434        // Required: enables secure processing (XSLTC runtime limits; Xalan's extension-function block).
435        setFeature(factory, XMLConstants.FEATURE_SECURE_PROCESSING, true);
436        if (SaxonProvider.isSaxon(factory.getClass())) {
437            // Saxon keeps its vendor Configuration for the channels JAXP cannot close,
438            // then goes through the same wrapper as every other implementation for the URIResolver floor;
439            // EmptySource is the empty-source shape Saxon's consumers expect.
440            return new Wrapper((SAXTransformerFactory) SaxonProvider.configure(factory), SaxonProvider.emptySourceSupplier());
441        }
442        // Required: source/stylesheet parsing provisions its own SAX reader otherwise; the wrapper routes every Source through a secure one and installs the
443        // ignore-all URIResolver floor (blocking xsl:import/include at compile time and document() at runtime) that a caller-set resolver cannot remove.
444        return new Wrapper((SAXTransformerFactory) factory);
445    }
446
447    private static void setFeature(final TransformerFactory factory, final String feature, final boolean value) {
448        try {
449            factory.setFeature(feature, value);
450        } catch (final Exception e) {
451            throw SecureException.featureFailed(feature, factory, e);
452        }
453    }
454
455    private SecureTransformerFactory() {
456        // static only
457    }
458}