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}