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.util.Objects; 023import java.util.function.Supplier; 024 025import javax.xml.XMLConstants; 026import javax.xml.parsers.DocumentBuilderFactory; 027import javax.xml.parsers.FactoryConfigurationError; 028import javax.xml.parsers.ParserConfigurationException; 029import javax.xml.transform.ErrorListener; 030import javax.xml.transform.Source; 031import javax.xml.transform.Templates; 032import javax.xml.transform.Transformer; 033import javax.xml.transform.TransformerConfigurationException; 034import javax.xml.transform.TransformerException; 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 055 * resolved. 056 * </p> 057 * <p> 058 * The guarantees govern what the transform reads, not what it writes: an output instruction like {@code xsl:result-document} still writes wherever the 059 * stylesheet directs, so an untrusted stylesheet's output destinations must be restricted outside the library. 060 * </p> 061 * <p> 062 * The guarantees apply to every parser the factory creates internally for the standard {@link TransformerFactory} entry points: stylesheet compilation 063 * ({@link TransformerFactory#newTemplates(javax.xml.transform.Source) newTemplates(Source)}, 064 * {@link TransformerFactory#newTransformer(javax.xml.transform.Source) newTransformer(Source)}) and source-document reading at 065 * {@code Transformer.transform(Source, Result)} time. 066 * </p> 067 * <p> 068 * The {@code href} an {@code xml-stylesheet} processing instruction names is content of the document being scanned, so 069 * {@link TransformerFactory#getAssociatedStylesheet(Source, String, String, String) getAssociatedStylesheet} treats it as any other content-named reference: 070 * install a {@link URIResolver} resolving that href to compile the stylesheet it points at. Without one, the returned {@link Source} carries empty content 071 * rather than naming the URI, so compiling it cannot fetch a stylesheet the parsed document chose. 072 * </p> 073 * <p> 074 * The {@link javax.xml.transform.sax.SAXTransformerFactory} extension methods ({@code newTransformerHandler(..)}, {@code newTemplatesHandler()}, 075 * {@code newXMLFilter(..)}), if reachable by casting the returned factory, produce objects carrying the same guarantees. 076 * </p> 077 * <p> 078 * This class is not itself a {@link TransformerFactory}, so it inherits none of the static JAXP factory methods. A caller therefore cannot obtain an unsecured 079 * factory through this class by calling a method such as {@code newDefaultInstance()}. The secure factories are instances of a nested, non-public wrapper 080 * class. 081 * </p> 082 * 083 * @see org.apache.commons.xml.secure 084 */ 085public final class SecureTransformerFactory { 086 087 /** 088 * {@link TransformerFactory} wrapper that rewrites every Source-taking entry point through {@link SecureSAXParserFactory#secure(Source, boolean)} before 089 * delegating. 090 * 091 * <p> 092 * Used by providers whose underlying TrAX implementation pulls a new {@code SAXParserFactory.newInstance()} for any Source that is not already a 093 * {@link SAXSource} carrying its own {@link XMLReader}, and only sets {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING FSP} on the resulting reader. 094 * Wrapping the factory and rewriting the Source upstream guarantees the parse runs through an {@link org.apache.commons.xml.secure}-secured reader instead. 095 * </p> 096 * <p> 097 * Three layers cooperate: 098 * </p> 099 * <ol> 100 * <li>{@link SecureTransformerFactory} rewrites the Source on every entry point that compiles a stylesheet or transforms a one-shot input.</li> 101 * <li>{@link SecureTemplates} returns a {@link SecureTransformer} from {@link Templates#newTransformer()} so runtime source parsing is also covered, and 102 * restores the factory's URIResolver onto the produced Transformer (which the underlying implementation typically does not propagate through 103 * {@code Templates}).</li> 104 * <li>{@link SecureTransformer} rewrites the Source on every {@link Transformer#transform(Source, javax.xml.transform.Result)} call.</li> 105 * </ol> 106 * <p> 107 * The {@link SAXTransformerFactory} extension products ride the same wrappers: {@code newTransformerHandler}/{@code newTemplatesHandler} products are 108 * wrapped ({@link SecureTransformerHandler}, {@link SecureTemplatesHandler}) so the {@link Transformer}/{@link Templates} they expose carry the resolver 109 * floor, and {@code newXMLFilter} returns a {@link SecureXMLFilter} composed from these wrappers instead of the implementation's filter, which would 110 * self-provision an unsecured input reader. 111 * </p> 112 * 113 * <h2>Caveats</h2> 114 * <ul> 115 * <li>A {@link SAXSource} that carries its own {@link XMLReader} is trusted as-is: the caller is expected to supply a secure reader (via 116 * {@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 117 * caller sets on a returned {@link XMLFilter}. The exception is {@code getAssociatedStylesheet} on an engine that drops the reader (Apache Xalan, and 118 * the JDK's XSLTC on Java 8): there the document is pre-parsed into a DOM instead, since the reader would otherwise be replaced by the engine's own.</li> 119 * </ul> 120 */ 121 private static final class Wrapper extends SAXTransformerFactory { 122 123 /** 124 * Tests whether the delegate is Apache Xalan (either its interpretive or its XSLTC factory), whose {@code getAssociatedStylesheet} ignores a SAXSource 125 * reader. 126 * 127 * @param factory The delegate factory. 128 * @return Whether the delegate is an {@code org.apache.xalan.} implementation. 129 */ 130 private static boolean isXalan(final SAXTransformerFactory factory) { 131 return factory.getClass().getName().startsWith("org.apache.xalan."); 132 } 133 134 /** 135 * Whether the delegate recognizes {@value SecureSAXParserFactory#OVERRIDE_DEFAULT_PARSER}, probed with a same-value {@code setFeature}: 136 * {@code TransformerFactory.getFeature} cannot signal an unrecognized name (it returns {@code false}), while every implementation rejects a 137 * {@code setFeature} for a name it does not support (Xalan with {@link TransformerConfigurationException}, Saxon with its own unchecked exception). 138 * 139 * @param factory The delegate factory. 140 * @return Whether the delegate recognizes the feature. 141 */ 142 private static boolean probeOverrideDefaultParser(final SAXTransformerFactory factory) { 143 try { 144 factory.setFeature(SecureSAXParserFactory.OVERRIDE_DEFAULT_PARSER, 145 factory.getFeature(SecureSAXParserFactory.OVERRIDE_DEFAULT_PARSER)); 146 return true; 147 } catch (final Exception e) { 148 return false; 149 } 150 } 151 152 /** 153 * Returns the value, or reports its absence in the TrAX shape. 154 * 155 * @param <T> The type of the product. 156 * @param value The value an implementation produced. 157 * @param what Name of the missing product, for the message. 158 * @return The value, never {@code null}. 159 * @throws TransformerConfigurationException Thrown if {@code value} is {@code null}. 160 */ 161 private static <T> T required(final T value, final String what) throws TransformerConfigurationException { 162 // Xalan hands back null instead of throwing when the stylesheet failed to compile: XALANJ-2410. 163 if (value == null) { 164 throw new TransformerConfigurationException("Underlying implementation returned a null " + what + "."); 165 } 166 return value; 167 } 168 169 private static Templates unwrap(final Templates templates) { 170 return templates instanceof SecureTemplates ? ((SecureTemplates) templates).getDelegate() : templates; 171 } 172 173 private final SAXTransformerFactory delegate; 174 175 /** 176 * Empty-{@link Source} supplier for the resolver floor, threaded onto every produced Templates/Transformer; {@code null} means the default empty DOM. 177 */ 178 private final Supplier<Source> emptySource; 179 180 private final FallbackIgnoreURIResolver floor; 181 182 /** 183 * Whether the delegate recognizes {@value SecureSAXParserFactory#OVERRIDE_DEFAULT_PARSER}; its value is read for each created product, as in the JDK. 184 */ 185 private final boolean supportsOverrideDefaultParser; 186 187 /** 188 * Constructs a new instance. 189 * 190 * @param delegate The delegate to wrap; must not be {@code null}. 191 * @throws NullPointerException Thrown if {@code delegate} is {@code null}. 192 */ 193 private Wrapper(final SAXTransformerFactory delegate) { 194 this(delegate, null); 195 } 196 197 /** 198 * Constructs a new instance. 199 * 200 * @param delegate The delegate to wrap; must not be {@code null}. 201 * @param emptySource The empty-{@link Source} supplier for the resolver floor, threaded onto every produced Templates/Transformer; {@code null} means 202 * the default empty DOM. 203 * @throws NullPointerException Thrown if {@code delegate} is {@code null}. 204 */ 205 private Wrapper(final SAXTransformerFactory delegate, final Supplier<Source> emptySource) { 206 this.delegate = Objects.requireNonNull(delegate, "delegate"); 207 this.emptySource = emptySource; 208 this.supportsOverrideDefaultParser = probeOverrideDefaultParser(delegate); 209 this.floor = new FallbackIgnoreURIResolver(null, emptySource, this::overrideDefaultParser); 210 // Compile-time block for xsl:import/xsl:include and document(); a caller-set resolver is routed through the floor rather than replacing it. 211 delegate.setURIResolver(floor); 212 } 213 214 /** 215 * Routes the href an {@code xml-stylesheet} PI yielded through the floor, so a URI distilled from untrusted content is opted in by the caller's 216 * resolver or resolved to empty like any other content-named reference. 217 * 218 * <p> 219 * XSLTC-lineage engines resolve the href during the scan, before they install the factory's {@link URIResolver}, and hand back a live 220 * {@link SAXSource} naming the absolutized URI; compiling it, the one documented use of this method, would then fetch it. Saxon already floors the href 221 * itself and returns an empty source, so flooring here is also what makes the engines agree. 222 * </p> 223 * 224 * @param associated The delegate's result; {@code null} when no PI matched. 225 * @param base The system ID of the scanned document, the base the href was resolved against. 226 * @return The caller resolver's source for an opted-in href, an empty source otherwise, or {@code null} when no PI matched. 227 * @throws TransformerConfigurationException Thrown if the floor rejects the href, which it does when {@value SecureException#THROW_ON_UNRESOLVED} is 228 * set. 229 */ 230 private Source floorAssociated(final Source associated, final String base) throws TransformerConfigurationException { 231 if (associated == null || associated.getSystemId() == null) { 232 // No PI matched, or the engine already floored the href to a source that names no URI. 233 return associated; 234 } 235 try { 236 return floor.resolve(associated.getSystemId(), base); 237 } catch (final TransformerException e) { 238 throw new TransformerConfigurationException("Failed to resolve the associated stylesheet " + associated.getSystemId(), e); 239 } 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 Source getAssociatedStylesheet(final Source source, final String media, final String title, final String charset) 250 throws TransformerConfigurationException { 251 // Xalan's getAssociatedStylesheet drops a SAXSource's reader and self-provisions its own to scan for xml-stylesheet PIs (XALANJ-2849), and the 252 // JDK's XSLTC did the same before 8u162; hand those a DOM so no parser but ours ever sees the document. 253 final Source secure = isXalan(delegate) || JAVA_8 ? secureSourceToDom(source) : SecureSAXParserFactory.secure(source, overrideDefaultParser()); 254 return floorAssociated(delegate.getAssociatedStylesheet(secure, media, title, charset), secure.getSystemId()); 255 } 256 257 @Override 258 public Object getAttribute(final String name) { 259 return delegate.getAttribute(name); 260 } 261 262 @Override 263 public ErrorListener getErrorListener() { 264 return delegate.getErrorListener(); 265 } 266 267 @Override 268 public boolean getFeature(final String name) { 269 return delegate.getFeature(name); 270 } 271 272 @Override 273 public URIResolver getURIResolver() { 274 return floor.getDelegate(); 275 } 276 277 /** 278 * {@inheritDoc} 279 * 280 * @throws FactoryConfigurationError Thrown from a factory in case of a {@link java.util.ServiceConfigurationError service 281 * configuration error} or if the implementation is not available or cannot be instantiated. 282 */ 283 @Override 284 public Templates newTemplates(final Source source) throws TransformerConfigurationException { 285 // newTemplates() should never return null for a specification-compliant factory. 286 final Templates templates = delegate.newTemplates(SecureSAXParserFactory.secure(source, overrideDefaultParser())); 287 return templates == null ? null : new SecureTemplates(templates, getURIResolver(), emptySource, overrideDefaultParser()); 288 } 289 290 @Override 291 public TemplatesHandler newTemplatesHandler() throws TransformerConfigurationException { 292 // newTemplatesHandler() should never return null for a specification-compliant factory. 293 final TemplatesHandler handler = delegate.newTemplatesHandler(); 294 return handler == null ? null : new SecureTemplatesHandler(handler, getURIResolver(), emptySource, overrideDefaultParser()); 295 } 296 297 @Override 298 public Transformer newTransformer() throws TransformerConfigurationException { 299 // Identity transformer: still parses runtime sources, so wrap it to secure Transformer.transform(Source, Result). 300 // newTransformer() should never return null for a specification-compliant factory. 301 final Transformer transformer = delegate.newTransformer(); 302 return transformer == null ? null : new SecureTransformer(transformer, getURIResolver(), emptySource, overrideDefaultParser()); 303 } 304 305 /** 306 * {@inheritDoc} 307 * 308 * @throws FactoryConfigurationError Thrown from a factory in case of a {@link java.util.ServiceConfigurationError service 309 * configuration error} or if the implementation is not available or cannot be instantiated. 310 */ 311 @Override 312 public Transformer newTransformer(final Source source) throws TransformerConfigurationException { 313 // newTransformer() should never return null for a specification-compliant factory. 314 final Transformer transformer = delegate.newTransformer(SecureSAXParserFactory.secure(source, overrideDefaultParser())); 315 return transformer == null ? null : new SecureTransformer(transformer, getURIResolver(), emptySource, overrideDefaultParser()); 316 } 317 318 @Override 319 public TransformerHandler newTransformerHandler() throws TransformerConfigurationException { 320 return secure(delegate.newTransformerHandler()); 321 } 322 323 /** 324 * {@inheritDoc} 325 * 326 * @throws FactoryConfigurationError Thrown from a factory in case of a {@link java.util.ServiceConfigurationError service 327 * configuration error} or if the implementation is not available or cannot be instantiated. 328 */ 329 @Override 330 public TransformerHandler newTransformerHandler(final Source source) throws TransformerConfigurationException { 331 return secure(delegate.newTransformerHandler(SecureSAXParserFactory.secure(source, overrideDefaultParser()))); 332 } 333 334 /** 335 * {@inheritDoc} 336 * 337 * <p> 338 * Most implementations reject a {@link Templates} they did not compile, some in the TrAX shape, others by casting it or its Transformer to their 339 * own type. Both reach the caller as a {@link TransformerConfigurationException}. 340 * </p> 341 */ 342 @Override 343 public TransformerHandler newTransformerHandler(final Templates templates) throws TransformerConfigurationException { 344 // Implementations: 345 // - cast templates.newTransformer() to their own Transformer type, so hand them the wrapped implementation Templates, not the wrapper; 346 // - raise NullPointerException for a null argument, except Saxon; rejecting it here keeps that uniform, as on the other methods. 347 final Templates unwrapped = unwrap(Objects.requireNonNull(templates, "templates")); 348 try { 349 return secure(delegate.newTransformerHandler(unwrapped)); 350 } catch (final ClassCastException e) { 351 throw new TransformerConfigurationException("Failed to create a TransformerHandler from a Templates of type " 352 + unwrapped.getClass().getName(), e); 353 } 354 } 355 356 /** 357 * {@inheritDoc} 358 * 359 * @throws FactoryConfigurationError Thrown from a factory in case of a {@link java.util.ServiceConfigurationError service 360 * configuration error} or if the implementation is not available or cannot be instantiated. 361 */ 362 @Override 363 public XMLFilter newXMLFilter(final Source source) throws TransformerConfigurationException { 364 return newXMLFilter(required(newTemplates(source), "Templates")); 365 } 366 367 @Override 368 public XMLFilter newXMLFilter(final Templates templates) throws TransformerConfigurationException { 369 final Transformer transformer = required(templates.newTransformer(), "Transformer"); 370 return new SecureXMLFilter(transformer instanceof SecureTransformer 371 ? (SecureTransformer) transformer 372 : new SecureTransformer(transformer, getURIResolver(), emptySource, overrideDefaultParser())); 373 } 374 375 /** 376 * Tests whether parsers should be instantiated via {@code newInstance()} instead of {@code newDefaultInstance()}. 377 * 378 * <p> 379 * The JDK implementation of {@link TransformerFactory} uses the JDK parsers while {@value SecureSAXParserFactory#OVERRIDE_DEFAULT_PARSER} is unset 380 * or {@code false}. 381 * </p> 382 * 383 * @return {@code true} if parsers should be created via {@code newInstance()}. 384 */ 385 private boolean overrideDefaultParser() { 386 return !supportsOverrideDefaultParser || delegate.getFeature(SecureSAXParserFactory.OVERRIDE_DEFAULT_PARSER); 387 } 388 389 private TransformerHandler secure(final TransformerHandler handler) { 390 return handler == null ? null : new SecureTransformerHandler(handler, getURIResolver(), emptySource, overrideDefaultParser()); 391 } 392 393 /** 394 * Parses a stream or SAX source into a DOM through a secure, namespace-aware {@link javax.xml.parsers.DocumentBuilder} and returns a {@link DOMSource} 395 * carrying its system ID, so the consumer walks the tree instead of provisioning its own reader. Any other source is left to 396 * {@link SecureSAXParserFactory#secure(Source, boolean)}. 397 * 398 * <p> 399 * A {@link SAXSource} carrying the caller's own reader is pre-parsed here too, unlike everywhere else in this class: an engine that reaches this 400 * method drops that reader anyway, so honoring it is not among the options; the choice is only between this parse and the engine's unsecured one. 401 * </p> 402 * 403 * @param source The source to scan for an associated stylesheet. 404 * @return A {@link DOMSource} for a stream or SAX source, otherwise the result of {@link SecureSAXParserFactory#secure(Source, boolean)}. 405 * @throws TransformerConfigurationException Thrown if the source cannot be parsed. 406 * @throws FactoryConfigurationError Thrown from a factory in case of a {@link java.util.ServiceConfigurationError service 407 * configuration error} or if the implementation is not available or cannot be instantiated. 408 * @throws SecureException Thrown if a (non-Android) factory cannot support the secure processing feature 409 * {@link XMLConstants#FEATURE_SECURE_PROCESSING}. 410 */ 411 private Source secureSourceToDom(final Source source) throws TransformerConfigurationException { 412 if (source instanceof StreamSource || source instanceof SAXSource) { 413 final InputSource inputSource = SAXSource.sourceToInputSource(source); 414 if (inputSource != null) { 415 try { 416 final DocumentBuilderFactory factory = SecureDocumentBuilderFactory.newNSInstance(overrideDefaultParser()); 417 final Document document = factory.newDocumentBuilder().parse(inputSource); 418 return new DOMSource(document, inputSource.getSystemId()); 419 } catch (final ParserConfigurationException | SAXException | IOException e) { 420 throw new TransformerConfigurationException("Failed to parse the source for associated-stylesheet lookup", e); 421 } 422 } 423 } 424 return SecureSAXParserFactory.secure(source, overrideDefaultParser()); 425 } 426 427 @Override 428 public void setAttribute(final String name, final Object value) { 429 delegate.setAttribute(name, value); 430 } 431 432 @Override 433 public void setErrorListener(final ErrorListener listener) { 434 delegate.setErrorListener(listener); 435 } 436 437 438 @Override 439 public void setFeature(final String name, final boolean value) throws TransformerConfigurationException { 440 delegate.setFeature(name, value); 441 } 442 443 @Override 444 public void setURIResolver(final URIResolver resolver) { 445 floor.setDelegate(resolver); 446 } 447 } 448 449 /** 450 * Class name of the JDK's built-in default implementation, the Java 8 fallback for {@link #newDefaultInstance()}. 451 */ 452 private static final String JDK_TRANSFORMER_FACTORY = "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl"; 453 454 private static final MethodHandle MH_newDefaultInstance = MethodHandleFactory.findStatic(TransformerFactory.class, "newDefaultInstance"); 455 456 /** 457 * {@code true} on Java 8, detected by the absence of {@code TransformerFactory.newDefaultInstance()}, which arrived in Java 9. 458 * <p> 459 * The JDK's XSLTC only began honoring the {@link XMLReader} carried by a {@link SAXSource} in {@code getAssociatedStylesheet} in 8u162; through 8u152 it 460 * provisions its own parser, exactly as Apache Xalan does. Java 8 as a whole is used as the boundary rather than the patch level: the two are 461 * indistinguishable through any API, and such an old runtime has already chosen correctness of configuration over the cost of a DOM pre-parse. 462 * </p> 463 */ 464 private static final boolean JAVA_8 = MH_newDefaultInstance == null; 465 466 /** 467 * Returns a new, secure {@link TransformerFactory} of the system-default implementation. 468 * <p> 469 * Obtained from {@code TransformerFactory.newDefaultInstance()} where the platform provides it (Java 9 or later), and by instantiating the JDK's built-in 470 * implementation directly on Java 8. 471 * </p> 472 * 473 * @return A secure factory. 474 * @throws IllegalStateException Thrown if a required secure setting cannot be applied to the underlying implementation. 475 * @throws TransformerFactoryConfigurationError Thrown if the running platform provides neither {@code newDefaultInstance()} nor the JDK's built-in 476 * implementation (for example, Android). 477 */ 478 public static TransformerFactory newDefaultInstance() { 479 if (MH_newDefaultInstance != null) { 480 return secure(MethodHandleFactory.invokeExact(() -> (TransformerFactory) MH_newDefaultInstance.invokeExact(), TransformerFactoryConfigurationError.class)); 481 } 482 // 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 483 // example Android), the lookup miss surfaces as TransformerFactoryConfigurationError, like any newInstance miss. 484 return newInstance(JDK_TRANSFORMER_FACTORY, null); 485 } 486 487 /** 488 * Returns a new, secure {@link TransformerFactory}. 489 * 490 * @return A secure factory. 491 * @throws IllegalStateException Thrown if a required secure setting cannot be applied to the underlying implementation. 492 */ 493 public static TransformerFactory newInstance() { 494 return secure(TransformerFactory.newInstance()); 495 } 496 497 /** 498 * Returns a new, secure {@link TransformerFactory} of the given implementation class. 499 * 500 * @param factoryClassName The fully qualified class name of the {@link TransformerFactory} implementation. 501 * @param classLoader The class loader used to load the factory class; {@code null} means the current thread's context class loader. 502 * @return A secure factory. 503 * @throws IllegalStateException Thrown if a required secure setting cannot be applied to the underlying implementation. 504 * @throws TransformerFactoryConfigurationError Thrown if {@code factoryClassName} is {@code null} or the factory class cannot be loaded or instantiated. 505 */ 506 public static TransformerFactory newInstance(final String factoryClassName, final ClassLoader classLoader) { 507 return secure(TransformerFactory.newInstance(factoryClassName, classLoader)); 508 } 509 510 /** 511 * Applies capability-driven secure settings to any {@link TransformerFactory} on the classpath. 512 * 513 * <p> 514 * Rather than branching on the implementation class, this method probes what the factory supports and adapts: 515 * </p> 516 * <ul> 517 * <li><strong>Saxon</strong> ({@code net.sf.saxon}): recognized by package prefix and handed to {@link SaxonProvider#configure(TransformerFactory)} for the 518 * channels the standard JAXP knobs cannot close (reflection-based extension functions, the collection finder, the internal SAX parser). It is then 519 * wrapped like every other implementation to install the {@link FallbackIgnoreURIResolver} floor; the only 520 * difference is the empty-{@link Source} shape the floor returns, {@code EmptySource} for Saxon rather than the default empty DOM document.</li> 521 * <li><strong>FSP</strong> ({@link XMLConstants#FEATURE_SECURE_PROCESSING}): required. On XSLTC it enables the runtime evaluator limits; on Xalan it 522 * disables reflection-based extension functions.</li> 523 * <li><strong>{@link FallbackIgnoreURIResolver} floor</strong>: required. An ignore-all {@link URIResolver} floor, installed by 524 * the nested wrapper and carried onto every produced {@link Transformer}, resolves {@code xsl:import}/{@code xsl:include} at compile 525 * 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 526 * routed through the floor rather than replacing it, so a caller can opt a specific URI in but cannot reopen the fetch.</li> 527 * <li><strong>The nested wrapper</strong>: required. Both implementations fall back to {@code SAXParserFactory.newInstance()} to parse a 528 * 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 529 * {@link org.apache.commons.xml.secure}-secured reader instead.</li> 530 * </ul> 531 * 532 * @param factory The factory to secure; never {@code null}. 533 * @return a secure factory. 534 */ 535 static TransformerFactory secure(final TransformerFactory factory) { 536 // Required: enables secure processing (XSLTC runtime limits; Xalan's extension-function block). 537 setFeature(factory, XMLConstants.FEATURE_SECURE_PROCESSING, true); 538 if (SaxonProvider.isSaxon(factory.getClass())) { 539 // Saxon keeps its vendor Configuration for the channels JAXP cannot close, 540 // then goes through the same wrapper as every other implementation for the URIResolver floor; 541 // EmptySource is the empty-source shape Saxon's consumers expect. 542 return new Wrapper((SAXTransformerFactory) SaxonProvider.configure(factory), SaxonProvider.emptySourceSupplier()); 543 } 544 // Required: source/stylesheet parsing provisions its own SAX reader otherwise; the wrapper routes every Source through a secure one and installs the 545 // ignore-all URIResolver floor (blocking xsl:import/include at compile time and document() at runtime) that a caller-set resolver cannot remove. 546 return new Wrapper((SAXTransformerFactory) factory); 547 } 548 549 private static void setFeature(final TransformerFactory factory, final String feature, final boolean value) { 550 try { 551 factory.setFeature(feature, value); 552 } catch (final Exception e) { 553 throw SecureException.featureFailed(feature, factory, e); 554 } 555 } 556 557 private SecureTransformerFactory() { 558 // static only 559 } 560}