View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /**
6    * Licensed to the Apache Software Foundation (ASF) under one
7    * or more contributor license agreements. See the NOTICE file
8    * distributed with this work for additional information
9    * regarding copyright ownership. The ASF licenses this file
10   * to you under the Apache License, Version 2.0 (the
11   * "License"); you may not use this file except in compliance
12   * with the License. You may obtain a copy of the License at
13   *
14   * http://www.apache.org/licenses/LICENSE-2.0
15   *
16   * Unless required by applicable law or agreed to in writing,
17   * software distributed under the License is distributed on an
18   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
19   * KIND, either express or implied. See the License for the
20   * specific language governing permissions and limitations
21   * under the License.
22   */
23  package com.sun.org.apache.xml.internal.security.c14n.implementations;
24  
25  import java.io.IOException;
26  import java.util.Iterator;
27  import java.util.Set;
28  import java.util.SortedSet;
29  import java.util.TreeSet;
30  import javax.xml.parsers.ParserConfigurationException;
31  
32  import com.sun.org.apache.xml.internal.security.c14n.CanonicalizationException;
33  import com.sun.org.apache.xml.internal.security.c14n.helper.C14nHelper;
34  import com.sun.org.apache.xml.internal.security.signature.XMLSignatureInput;
35  import com.sun.org.apache.xml.internal.security.transforms.params.InclusiveNamespaces;
36  import com.sun.org.apache.xml.internal.security.utils.Constants;
37  import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
38  import org.w3c.dom.Attr;
39  import org.w3c.dom.Document;
40  import org.w3c.dom.Element;
41  import org.w3c.dom.NamedNodeMap;
42  import org.w3c.dom.Node;
43  import org.xml.sax.SAXException;
44  
45  /**
46   * Implements &quot; <A
47   * HREF="http://www.w3.org/TR/2002/REC-xml-exc-c14n-20020718/">Exclusive XML
48   * Canonicalization, Version 1.0 </A>&quot; <BR />
49   * Credits: During restructuring of the Canonicalizer framework, Ren??
50   * Kollmorgen from Software AG submitted an implementation of ExclC14n which
51   * fitted into the old architecture and which based heavily on my old (and slow)
52   * implementation of "Canonical XML". A big "thank you" to Ren?? for this.
53   * <BR />
54   * <i>THIS </i> implementation is a complete rewrite of the algorithm.
55   *
56   * @author Christian Geuer-Pollmann <geuerp@apache.org>
57   * @version $Revision: 1147448 $
58   * @see <a href="http://www.w3.org/TR/2002/REC-xml-exc-c14n-20020718/ Exclusive#">
59   *          XML Canonicalization, Version 1.0</a>
60   */
61  public abstract class Canonicalizer20010315Excl extends CanonicalizerBase {
62  
63      private static final String XML_LANG_URI = Constants.XML_LANG_SPACE_SpecNS;
64      private static final String XMLNS_URI = Constants.NamespaceSpecNS;
65  
66      /**
67        * This Set contains the names (Strings like "xmlns" or "xmlns:foo") of
68        * the inclusive namespaces.
69        */
70      private SortedSet<String> inclusiveNSSet;
71  
72      private final SortedSet<Attr> result = new TreeSet<Attr>(COMPARE);
73  
74      /**
75       * Constructor Canonicalizer20010315Excl
76       *
77       * @param includeComments
78       */
79      public Canonicalizer20010315Excl(boolean includeComments) {
80          super(includeComments);
81      }
82  
83      /**
84       * Method engineCanonicalizeSubTree
85       * @inheritDoc
86       * @param rootNode
87       *
88       * @throws CanonicalizationException
89       */
90      public byte[] engineCanonicalizeSubTree(Node rootNode)
91          throws CanonicalizationException {
92          return engineCanonicalizeSubTree(rootNode, "", null);
93      }
94  
95      /**
96       * Method engineCanonicalizeSubTree
97       *  @inheritDoc
98       * @param rootNode
99       * @param inclusiveNamespaces
100      *
101      * @throws CanonicalizationException
102      */
103     public byte[] engineCanonicalizeSubTree(
104         Node rootNode, String inclusiveNamespaces
105     ) throws CanonicalizationException {
106         return engineCanonicalizeSubTree(rootNode, inclusiveNamespaces, null);
107     }
108 
109     /**
110      * Method engineCanonicalizeSubTree
111      * @param rootNode
112      * @param inclusiveNamespaces
113      * @param excl A element to exclude from the c14n process.
114      * @return the rootNode c14n.
115      * @throws CanonicalizationException
116      */
117     public byte[] engineCanonicalizeSubTree(
118         Node rootNode, String inclusiveNamespaces, Node excl
119     ) throws CanonicalizationException{
120         inclusiveNSSet = InclusiveNamespaces.prefixStr2Set(inclusiveNamespaces);
121         return super.engineCanonicalizeSubTree(rootNode, excl);
122     }
123 
124     /**
125      *
126      * @param rootNode
127      * @param inclusiveNamespaces
128      * @return the rootNode c14n.
129      * @throws CanonicalizationException
130      */
131     public byte[] engineCanonicalize(
132         XMLSignatureInput rootNode, String inclusiveNamespaces
133     ) throws CanonicalizationException {
134         inclusiveNSSet = InclusiveNamespaces.prefixStr2Set(inclusiveNamespaces);
135         return super.engineCanonicalize(rootNode);
136     }
137 
138     /**
139      * Method engineCanonicalizeXPathNodeSet
140      * @inheritDoc
141      * @param xpathNodeSet
142      * @param inclusiveNamespaces
143      * @throws CanonicalizationException
144      */
145     public byte[] engineCanonicalizeXPathNodeSet(
146         Set<Node> xpathNodeSet, String inclusiveNamespaces
147     ) throws CanonicalizationException {
148         inclusiveNSSet = InclusiveNamespaces.prefixStr2Set(inclusiveNamespaces);
149         return super.engineCanonicalizeXPathNodeSet(xpathNodeSet);
150     }
151 
152     @Override
153     protected Iterator<Attr> handleAttributesSubtree(Element element, NameSpaceSymbTable ns)
154         throws CanonicalizationException {
155         // result will contain the attrs which have to be output
156         final SortedSet<Attr> result = this.result;
157         result.clear();
158 
159         // The prefix visibly utilized (in the attribute or in the name) in
160         // the element
161         SortedSet<String> visiblyUtilized = new TreeSet<String>();
162         if (inclusiveNSSet != null && !inclusiveNSSet.isEmpty()) {
163             visiblyUtilized.addAll(inclusiveNSSet);
164         }
165 
166         if (element.hasAttributes()) {
167             NamedNodeMap attrs = element.getAttributes();
168             int attrsLength = attrs.getLength();
169             for (int i = 0; i < attrsLength; i++) {
170                 Attr attribute = (Attr) attrs.item(i);
171                 String NName = attribute.getLocalName();
172                 String NNodeValue = attribute.getNodeValue();
173 
174                 if (!XMLNS_URI.equals(attribute.getNamespaceURI())) {
175                     // Not a namespace definition.
176                     // The Element is output element, add the prefix (if used) to
177                     // visiblyUtilized
178                     String prefix = attribute.getPrefix();
179                     if (prefix != null && !(prefix.equals(XML) || prefix.equals(XMLNS))) {
180                         visiblyUtilized.add(prefix);
181                     }
182                     // Add to the result.
183                     result.add(attribute);
184                 } else if (!(XML.equals(NName) && XML_LANG_URI.equals(NNodeValue))
185                     && ns.addMapping(NName, NNodeValue, attribute)
186                     && C14nHelper.namespaceIsRelative(NNodeValue)) {
187                     // The default mapping for xml must not be output.
188                     // New definition check if it is relative.
189                     Object exArgs[] = {element.getTagName(), NName, attribute.getNodeValue()};
190                     throw new CanonicalizationException(
191                         "c14n.Canonicalizer.RelativeNamespace", exArgs
192                     );
193                 }
194             }
195         }
196         String prefix = null;
197         if (element.getNamespaceURI() != null
198             && !(element.getPrefix() == null || element.getPrefix().length() == 0)) {
199             prefix = element.getPrefix();
200         } else {
201             prefix = XMLNS;
202         }
203         visiblyUtilized.add(prefix);
204 
205         for (String s : visiblyUtilized) {
206             Attr key = ns.getMapping(s);
207             if (key != null) {
208                 result.add(key);
209             }
210         }
211 
212         return result.iterator();
213     }
214 
215     /**
216      * @inheritDoc
217      * @param element
218      * @throws CanonicalizationException
219      */
220     @Override
221     protected final Iterator<Attr> handleAttributes(Element element, NameSpaceSymbTable ns)
222         throws CanonicalizationException {
223         // result will contain the attrs which have to be output
224         final SortedSet<Attr> result = this.result;
225         result.clear();
226 
227         // The prefix visibly utilized (in the attribute or in the name) in
228         // the element
229         Set<String> visiblyUtilized = null;
230         // It's the output selected.
231         boolean isOutputElement = isVisibleDO(element, ns.getLevel()) == 1;
232         if (isOutputElement) {
233             visiblyUtilized = new TreeSet<String>();
234             if (inclusiveNSSet != null && !inclusiveNSSet.isEmpty()) {
235                 visiblyUtilized.addAll(inclusiveNSSet);
236             }
237         }
238 
239         if (element.hasAttributes()) {
240             NamedNodeMap attrs = element.getAttributes();
241             int attrsLength = attrs.getLength();
242             for (int i = 0; i < attrsLength; i++) {
243                 Attr attribute = (Attr) attrs.item(i);
244 
245                 String NName = attribute.getLocalName();
246                 String NNodeValue = attribute.getNodeValue();
247 
248                 if (!XMLNS_URI.equals(attribute.getNamespaceURI())) {
249                     if (isVisible(attribute) && isOutputElement) {
250                         // The Element is output element, add the prefix (if used)
251                         // to visibyUtilized
252                         String prefix = attribute.getPrefix();
253                         if (prefix != null && !(prefix.equals(XML) || prefix.equals(XMLNS))) {
254                             visiblyUtilized.add(prefix);
255                         }
256                         // Add to the result.
257                         result.add(attribute);
258                     }
259                 } else if (isOutputElement && !isVisible(attribute) && !XMLNS.equals(NName)) {
260                     ns.removeMappingIfNotRender(NName);
261                 } else {
262                     if (!isOutputElement && isVisible(attribute)
263                         && inclusiveNSSet.contains(NName)
264                         && !ns.removeMappingIfRender(NName)) {
265                         Node n = ns.addMappingAndRender(NName, NNodeValue, attribute);
266                         if (n != null) {
267                             result.add((Attr)n);
268                             if (C14nHelper.namespaceIsRelative(attribute)) {
269                                 Object exArgs[] = { element.getTagName(), NName, attribute.getNodeValue() };
270                                 throw new CanonicalizationException(
271                                     "c14n.Canonicalizer.RelativeNamespace", exArgs
272                                 );
273                             }
274                         }
275                     }
276 
277                     if (ns.addMapping(NName, NNodeValue, attribute)
278                         && C14nHelper.namespaceIsRelative(NNodeValue)) {
279                         // New definition check if it is relative
280                         Object exArgs[] = { element.getTagName(), NName, attribute.getNodeValue() };
281                         throw new CanonicalizationException(
282                             "c14n.Canonicalizer.RelativeNamespace", exArgs
283                         );
284                     }
285                 }
286             }
287         }
288 
289         if (isOutputElement) {
290             // The element is visible, handle the xmlns definition
291             Attr xmlns = element.getAttributeNodeNS(XMLNS_URI, XMLNS);
292             if (xmlns != null && !isVisible(xmlns)) {
293                 // There is a definition but the xmlns is not selected by the
294                 // xpath. then xmlns=""
295                 ns.addMapping(XMLNS, "", getNullNode(xmlns.getOwnerDocument()));
296             }
297 
298             String prefix = null;
299             if (element.getNamespaceURI() != null
300                 && !(element.getPrefix() == null || element.getPrefix().length() == 0)) {
301                 prefix = element.getPrefix();
302             } else {
303                 prefix = XMLNS;
304             }
305             visiblyUtilized.add(prefix);
306 
307             for (String s : visiblyUtilized) {
308                 Attr key = ns.getMapping(s);
309                 if (key != null) {
310                     result.add(key);
311                 }
312             }
313         }
314 
315         return result.iterator();
316     }
317 
318     protected void circumventBugIfNeeded(XMLSignatureInput input)
319         throws CanonicalizationException, ParserConfigurationException,
320                IOException, SAXException {
321         if (!input.isNeedsToBeExpanded() || inclusiveNSSet.isEmpty() || inclusiveNSSet.isEmpty()) {
322             return;
323         }
324         Document doc = null;
325         if (input.getSubNode() != null) {
326             doc = XMLUtils.getOwnerDocument(input.getSubNode());
327         } else {
328             doc = XMLUtils.getOwnerDocument(input.getNodeSet());
329         }
330         XMLUtils.circumventBug2650(doc);
331     }
332 }