1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.xml.secure;
19
20 import java.util.Objects;
21 import java.util.Properties;
22 import java.util.function.Supplier;
23
24 import javax.xml.transform.Source;
25 import javax.xml.transform.Templates;
26 import javax.xml.transform.Transformer;
27 import javax.xml.transform.TransformerConfigurationException;
28 import javax.xml.transform.URIResolver;
29
30 /**
31 * {@link Templates} wrapper whose only purpose is to return a {@link SecureTransformer} from {@link Templates#newTransformer()}, with the factory's
32 * compile-time {@link URIResolver} pre-installed.
33 * <p>
34 * Both Apache Xalan 2.7 and stock-JDK XSLTC fail to propagate the factory's URIResolver through {@code Templates.newTransformer()}: the produced runtime
35 * Transformer has a null URIResolver unless the caller sets one, leaving runtime {@code document()} calls unguarded. Snapshotting the resolver at compile time
36 * and restoring it onto the runtime Transformer matches the JAXP-conformant expectation that the factory's resolver is the default for any Transformer the
37 * factory ultimately produces.
38 * </p>
39 */
40 final class SecureTemplates implements Templates {
41
42 private final Templates delegate;
43
44 /**
45 * Compile-time URIResolver snapshot; the underlying implementation does not propagate the factory's resolver onto Transformers obtained from Templates.
46 */
47 private final URIResolver factoryUriResolver;
48
49 /**
50 * Empty-{@link Source} supplier for the produced Transformer's floor; {@code null} means the default empty DOM.
51 */
52 private final Supplier<Source> emptySource;
53
54 /**
55 * Snapshot of the factory's {@value SecureSAXParserFactory#OVERRIDE_DEFAULT_PARSER} outcome, carried onto every produced Transformer and self-provisioned
56 * filter reader.
57 */
58 final boolean overrideDefaultParser;
59
60 /**
61 * Constructs a new instance.
62 *
63 * @param delegate The delegate to wrap; must not be {@code null}.
64 * @param factoryUriResolver The factory's compile-time URIResolver snapshot to restore onto Transformers produced from the compiled Templates; may be
65 * {@code null}.
66 * @param emptySource The empty-{@link Source} supplier for the produced Transformers.
67 * @param overrideDefaultParser whether the produced Transformers' source rewrites should use the pluggable parser lookup instead of the platform's built-in
68 * parser.
69 * @throws NullPointerException Thrown if {@code delegate} is {@code null}.
70 */
71 SecureTemplates(final Templates delegate, final URIResolver factoryUriResolver, final Supplier<Source> emptySource, final boolean overrideDefaultParser) {
72 this.delegate = Objects.requireNonNull(delegate, "delegate");
73 this.factoryUriResolver = factoryUriResolver;
74 this.emptySource = emptySource;
75 this.overrideDefaultParser = overrideDefaultParser;
76 }
77
78 /**
79 * Gets the wrapped {@link Templates} implementation for factory methods whose implementations cast {@code newTransformer()} to their own type.
80 *
81 * @return the wrapped {@link Templates} implementation, never {@code null}.
82 */
83 Templates getDelegate() {
84 return delegate;
85 }
86
87 @Override
88 public Properties getOutputProperties() {
89 return delegate.getOutputProperties();
90 }
91
92 @Override
93 public Transformer newTransformer() throws TransformerConfigurationException {
94 final Transformer transformer = delegate.newTransformer();
95 // Some implementations return null rather than throw, so preserve the delegate's behavior instead of enforcing the contract.
96 // For example, https://issues.apache.org/jira/browse/XALANJ-2410
97 return transformer != null ? new SecureTransformer(transformer, factoryUriResolver, emptySource, overrideDefaultParser) : null;
98 }
99 }