| |
| /* |
| * Copyright 1999-2004 The Apache Software Foundation. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ |
| package org.apache.xml.security.c14n.implementations; |
| |
| |
| |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.SortedSet; |
| import java.util.TreeSet; |
| |
| import org.apache.xml.security.c14n.CanonicalizationException; |
| import org.apache.xml.security.c14n.helper.C14nHelper; |
| import org.apache.xml.security.utils.Constants; |
| import org.w3c.dom.Attr; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.NamedNodeMap; |
| import org.w3c.dom.Node; |
| |
| |
| /** |
| * Implements <A HREF="http://www.w3.org/TR/2001/REC-xml-c14n-20010315">Canonical |
| * XML Version 1.0</A>, a W3C Recommendation from 15 March 2001. |
| * |
| * @author Christian Geuer-Pollmann <geuerp@apache.org> |
| * @version $Revision$ |
| */ |
| public abstract class Canonicalizer20010315 extends CanonicalizerBase { |
| boolean firstCall=true; |
| final SortedSet result= new TreeSet(COMPARE); |
| static final String XMLNS_URI=Constants.NamespaceSpecNS; |
| static final String XML_LANG_URI=Constants.XML_LANG_SPACE_SpecNS; |
| /** |
| * Constructor Canonicalizer20010315 |
| * |
| * @param includeComments |
| */ |
| public Canonicalizer20010315(boolean includeComments) { |
| super(includeComments); |
| } |
| |
| /** |
| * Returns the Attr[]s to be outputted for the given element. |
| * <br> |
| * The code of this method is a copy of {@link #handleAttributes(Element, |
| * NameSpaceSymbTable)}, |
| * whereas it takes into account that subtree-c14n is -- well -- subtree-based. |
| * So if the element in question isRoot of c14n, it's parent is not in the |
| * node set, as well as all other ancestors. |
| * |
| * @param E |
| * @param ns |
| * @return the Attr[]s to be outputted |
| * @throws CanonicalizationException |
| */ |
| Iterator handleAttributesSubtree(Element E, NameSpaceSymbTable ns ) |
| throws CanonicalizationException { |
| if (!E.hasAttributes() && !firstCall) { |
| return null; |
| } |
| // result will contain the attrs which have to be outputted |
| final SortedSet result = this.result; |
| result.clear(); |
| NamedNodeMap attrs = E.getAttributes(); |
| int attrsLength = attrs.getLength(); |
| |
| for (int i = 0; i < attrsLength; i++) { |
| Attr N = (Attr) attrs.item(i); |
| String NUri =N.getNamespaceURI(); |
| |
| if (XMLNS_URI!=NUri) { |
| //It's not a namespace attr node. Add to the result and continue. |
| result.add(N); |
| continue; |
| } |
| |
| String NName=N.getLocalName(); |
| String NValue=N.getValue(); |
| if (XML.equals(NName) |
| && XML_LANG_URI.equals(NValue)) { |
| //The default mapping for xml must not be output. |
| continue; |
| } |
| |
| Node n=ns.addMappingAndRender(NName,NValue,N); |
| |
| if (n!=null) { |
| //Render the ns definition |
| result.add(n); |
| if (C14nHelper.namespaceIsRelative(N)) { |
| Object exArgs[] = { E.getTagName(), NName, N.getNodeValue() }; |
| throw new CanonicalizationException( |
| "c14n.Canonicalizer.RelativeNamespace", exArgs); |
| } |
| } |
| } |
| |
| if (firstCall) { |
| //It is the first node of the subtree |
| //Obtain all the namespaces defined in the parents, and added to the output. |
| ns.getUnrenderedNodes(result); |
| //output the attributes in the xml namespace. |
| addXmlAttributesSubtree(E, result); |
| firstCall=false; |
| } |
| |
| return result.iterator(); |
| } |
| |
| /** |
| * Float the xml:* attributes of the parent nodes to the root node of c14n |
| * @param E the root node. |
| * @param result the xml:* attributes to output. |
| */ |
| private void addXmlAttributesSubtree(Element E, SortedSet result) { |
| // E is in the node-set |
| Node parent = E.getParentNode(); |
| Map loa = new HashMap(); |
| |
| if ((parent != null) && (parent.getNodeType() == Node.ELEMENT_NODE)) { |
| // parent element is not in node set |
| for (Node ancestor = parent; |
| (ancestor != null) |
| && (ancestor.getNodeType() == Node.ELEMENT_NODE); |
| ancestor = ancestor.getParentNode()) { |
| Element el=((Element) ancestor); |
| if (!el.hasAttributes()) { |
| continue; |
| } |
| // for all ancestor elements |
| NamedNodeMap ancestorAttrs = el.getAttributes(); |
| int length=ancestorAttrs.getLength(); |
| for (int i = 0; i < length; i++) { |
| // for all attributes in the ancestor element |
| Attr currentAncestorAttr = (Attr) ancestorAttrs.item(i); |
| if (XML_LANG_URI==currentAncestorAttr.getNamespaceURI()) { |
| String name=currentAncestorAttr.getName(); |
| if (!loa.containsKey(name) ) { |
| loa.put(name, currentAncestorAttr); |
| } |
| } |
| } |
| } |
| } |
| |
| result.addAll( loa.values()); |
| |
| } |
| |
| /** |
| * Returns the Attr[]s to be outputted for the given element. |
| * <br> |
| * IMPORTANT: This method expects to work on a modified DOM tree, i.e. a DOM which has |
| * been prepared using {@link org.apache.xml.security.utils.XMLUtils#circumventBug2650( |
| * org.w3c.dom.Document)}. |
| * |
| * @param E |
| * @param ns |
| * @return the Attr[]s to be outputted |
| * @throws CanonicalizationException |
| */ |
| Iterator handleAttributes(Element E, NameSpaceSymbTable ns ) throws CanonicalizationException { |
| // result will contain the attrs which have to be outputted |
| boolean isRealVisible=isVisible(E); |
| NamedNodeMap attrs = null; |
| int attrsLength = 0; |
| if (E.hasAttributes()) { |
| attrs=E.getAttributes(); |
| attrsLength= attrs.getLength(); |
| } |
| |
| |
| SortedSet result = this.result; |
| result.clear(); |
| |
| |
| for (int i = 0; i < attrsLength; i++) { |
| Attr N = (Attr) attrs.item(i); |
| String NUri =N.getNamespaceURI(); |
| |
| if (XMLNS_URI!=NUri) { |
| //A non namespace definition node. |
| if (isRealVisible){ |
| //The node is visible add the attribute to the list of output attributes. |
| result.add(N); |
| } |
| //keep working |
| continue; |
| } |
| |
| String NName=N.getLocalName(); |
| String NValue=N.getValue(); |
| if ("xml".equals(NName) |
| && XML_LANG_URI.equals(NValue)) { |
| /* except omit namespace node with local name xml, which defines |
| * the xml prefix, if its string value is http://www.w3.org/XML/1998/namespace. |
| */ |
| continue; |
| } |
| //add the prefix binding to the ns symb table. |
| //ns.addInclusiveMapping(NName,NValue,N,isRealVisible); |
| if (isVisible(N)) { |
| //The xpath select this node output it if needed. |
| Node n=ns.addMappingAndRenderXNodeSet(NName,NValue,N,isRealVisible); |
| if (n!=null) { |
| result.add(n); |
| if (C14nHelper.namespaceIsRelative(N)) { |
| Object exArgs[] = { E.getTagName(), NName, N.getNodeValue() }; |
| throw new CanonicalizationException( |
| "c14n.Canonicalizer.RelativeNamespace", exArgs); |
| } |
| } |
| } |
| } |
| if (isRealVisible) { |
| //The element is visible, handle the xmlns definition |
| Attr xmlns = E.getAttributeNodeNS(XMLNS_URI, XMLNS); |
| Node n=null; |
| if (xmlns == null) { |
| //No xmlns def just get the already defined. |
| n=ns.getMapping(XMLNS); |
| } else if ( !isVisible(xmlns)) { |
| //There is a definition but the xmlns is not selected by the xpath. |
| //then xmlns="" |
| n=ns.addMappingAndRenderXNodeSet(XMLNS,"",nullNode,true); |
| } |
| //output the xmlns def if needed. |
| if (n!=null) { |
| result.add(n); |
| } |
| //Float all xml:* attributes of the unselected parent elements to this one. |
| addXmlAttributes(E,result); |
| } |
| |
| return result.iterator(); |
| } |
| /** |
| * Float the xml:* attributes of the unselected parent nodes to the ciurrent node. |
| * @param E |
| * @param result |
| */ |
| private void addXmlAttributes(Element E, SortedSet result) { |
| /* The processing of an element node E MUST be modified slightly when an |
| * XPath node-set is given as input and the element's parent is omitted |
| * from the node-set. The method for processing the attribute axis of an |
| * element E in the node-set is enhanced. All element nodes along E's |
| * ancestor axis are examined for nearest occurrences of attributes in |
| * the xml namespace, such as xml:lang and xml:space (whether or not they |
| * are in the node-set). From this list of attributes, remove any that are |
| * in E's attribute axis (whether or not they are in the node-set). Then, |
| * lexicographically merge this attribute list with the nodes of E's |
| * attribute axis that are in the node-set. The result of visiting the |
| * attribute axis is computed by processing the attribute nodes in this |
| * merged attribute list. |
| */ |
| |
| // E is in the node-set |
| Node parent = E.getParentNode(); |
| Map loa = new HashMap(); |
| |
| if ((parent != null) && (parent.getNodeType() == Node.ELEMENT_NODE) |
| &&!isVisible(parent)) { |
| |
| // parent element is not in node set |
| for (Node ancestor = parent; |
| (ancestor != null) |
| && (ancestor.getNodeType() == Node.ELEMENT_NODE); |
| ancestor = ancestor.getParentNode()) { |
| Element el=((Element) ancestor); |
| if (!el.hasAttributes()) { |
| continue; |
| } |
| // for all ancestor elements |
| NamedNodeMap ancestorAttrs =el.getAttributes(); |
| int length=ancestorAttrs.getLength(); |
| for (int i = 0; i < length; i++) { |
| // for all attributes in the ancestor element |
| Attr currentAncestorAttr = (Attr) ancestorAttrs.item(i); |
| if (XML_LANG_URI==currentAncestorAttr.getNamespaceURI()) { |
| String name=currentAncestorAttr.getName(); |
| if (!loa.containsKey(name) ) { |
| loa.put(name, currentAncestorAttr); |
| } |
| } |
| } |
| } |
| } |
| result.addAll(loa.values()); |
| |
| } |
| |
| /** |
| * Always throws a CanonicalizationException because this is inclusive c14n. |
| * |
| * @param xpathNodeSet |
| * @param inclusiveNamespaces |
| * @return none it always fails |
| * @throws CanonicalizationException always |
| */ |
| public byte[] engineCanonicalizeXPathNodeSet(Set xpathNodeSet, String inclusiveNamespaces) |
| throws CanonicalizationException { |
| |
| /** $todo$ well, should we throw UnsupportedOperationException ? */ |
| throw new CanonicalizationException( |
| "c14n.Canonicalizer.UnsupportedOperation"); |
| } |
| |
| /** |
| * Always throws a CanonicalizationException because this is inclusive c14n. |
| * |
| * @param rootNode |
| * @param inclusiveNamespaces |
| * @return none it always fails |
| * @throws CanonicalizationException |
| */ |
| public byte[] engineCanonicalizeSubTree(Node rootNode, String inclusiveNamespaces) |
| throws CanonicalizationException { |
| |
| /** $todo$ well, should we throw UnsupportedOperationException ? */ |
| throw new CanonicalizationException( |
| "c14n.Canonicalizer.UnsupportedOperation"); |
| } |
| } |