View Javadoc
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.function.Supplier;
22  
23  import javax.xml.transform.Result;
24  import javax.xml.transform.Source;
25  import javax.xml.transform.Transformer;
26  import javax.xml.transform.URIResolver;
27  import javax.xml.transform.sax.TransformerHandler;
28  
29  import org.xml.sax.Attributes;
30  import org.xml.sax.Locator;
31  import org.xml.sax.SAXException;
32  
33  /**
34   * {@link TransformerHandler} wrapper that keeps an ignore-all {@link URIResolver} floor on the live transformer the handler transforms with.
35   *
36   * <p>The handler's input is SAX events the caller drives, so it has no inner source-parsing path of its own. What needs the floor is its transformer: the
37   * handler runs the transformation on the object {@link TransformerHandler#getTransformer()} exposes, and not every implementation seeds that transformer with
38   * the factory's resolver (the stock JDK's {@code newTransformerHandler(Templates)} does not). Wrapping that transformer in a {@link SecureTransformer} at
39   * construction installs the floor on the live instance, so runtime {@code document()} during the handler's transform is covered, and so is a caller who pulls
40   * the transformer out through {@code getTransformer()}.</p>
41   */
42  final class SecureTransformerHandler implements TransformerHandler {
43  
44      private final TransformerHandler delegate;
45  
46      /**
47       * Wraps the handler's LIVE transformer; constructing it installs the resolver floor that the handler's own transform then runs under.
48       */
49      private final SecureTransformer transformer;
50  
51      /**
52       * Constructs a new instance.
53       *
54       * @param delegate the delegate to wrap; must not be {@code null}.
55       * @param uriResolver the compile-time URIResolver snapshot to restore onto the live transformer; may be {@code null}.
56       * @param emptySource the empty-{@link Source} supplier for the produced Transformer's floor; {@code null} means the default empty DOM.
57       * @param overrideDefaultParser whether the live transformer's source rewrites should use the pluggable parser lookup instead of the platform's built-in parser.
58       * @throws NullPointerException if {@code delegate} is {@code null}.
59       */
60      SecureTransformerHandler(final TransformerHandler delegate, final URIResolver uriResolver, final Supplier<Source> emptySource,
61              final boolean overrideDefaultParser) {
62          this.delegate = Objects.requireNonNull(delegate, "delegate");
63          this.transformer = new SecureTransformer(delegate.getTransformer(), uriResolver, emptySource, overrideDefaultParser);
64      }
65  
66      @Override
67      public void characters(final char[] ch, final int start, final int length) throws SAXException {
68          delegate.characters(ch, start, length);
69      }
70  
71      @Override
72      public void comment(final char[] ch, final int start, final int length) throws SAXException {
73          delegate.comment(ch, start, length);
74      }
75  
76  
77      @Override
78      public void endCDATA() throws SAXException {
79          delegate.endCDATA();
80      }
81  
82      @Override
83      public void endDocument() throws SAXException {
84          delegate.endDocument();
85      }
86  
87      @Override
88      public void endDTD() throws SAXException {
89          delegate.endDTD();
90      }
91  
92      @Override
93      public void endElement(final String uri, final String localName, final String qName) throws SAXException {
94          delegate.endElement(uri, localName, qName);
95      }
96  
97      @Override
98      public void endEntity(final String name) throws SAXException {
99          delegate.endEntity(name);
100     }
101 
102     @Override
103     public void endPrefixMapping(final String prefix) throws SAXException {
104         delegate.endPrefixMapping(prefix);
105     }
106 
107     @Override
108     public String getSystemId() {
109         return delegate.getSystemId();
110     }
111 
112     @Override
113     public Transformer getTransformer() {
114         return transformer;
115     }
116 
117     @Override
118     public void ignorableWhitespace(final char[] ch, final int start, final int length) throws SAXException {
119         delegate.ignorableWhitespace(ch, start, length);
120     }
121 
122     @Override
123     public void notationDecl(final String name, final String publicId, final String systemId) throws SAXException {
124         delegate.notationDecl(name, publicId, systemId);
125     }
126 
127     @Override
128     public void processingInstruction(final String target, final String data) throws SAXException {
129         delegate.processingInstruction(target, data);
130     }
131 
132     @Override
133     public void setDocumentLocator(final Locator locator) {
134         delegate.setDocumentLocator(locator);
135     }
136 
137     @Override
138     public void setResult(final Result result) {
139         delegate.setResult(result);
140     }
141 
142     @Override
143     public void setSystemId(final String systemID) {
144         delegate.setSystemId(systemID);
145     }
146 
147     @Override
148     public void skippedEntity(final String name) throws SAXException {
149         delegate.skippedEntity(name);
150     }
151 
152     @Override
153     public void startCDATA() throws SAXException {
154         delegate.startCDATA();
155     }
156 
157     @Override
158     public void startDocument() throws SAXException {
159         delegate.startDocument();
160     }
161 
162     @Override
163     public void startDTD(final String name, final String publicId, final String systemId) throws SAXException {
164         delegate.startDTD(name, publicId, systemId);
165     }
166 
167     @Override
168     public void startElement(final String uri, final String localName, final String qName, final Attributes atts) throws SAXException {
169         delegate.startElement(uri, localName, qName, atts);
170     }
171 
172     @Override
173     public void startEntity(final String name) throws SAXException {
174         delegate.startEntity(name);
175     }
176 
177     @Override
178     public void startPrefixMapping(final String prefix, final String uri) throws SAXException {
179         delegate.startPrefixMapping(prefix, uri);
180     }
181 
182     @Override
183     public void unparsedEntityDecl(final String name, final String publicId, final String systemId, final String notationName) throws SAXException {
184         delegate.unparsedEntityDecl(name, publicId, systemId, notationName);
185     }
186 }