view src/share/classes/com/sun/org/apache/xml/internal/security/c14n/implementations/Canonicalizer20010315Excl.java @ 6400:c31a79eedba2

8025026: Enhance canonicalization Summary: Don't use cached null xmlns definition. Also reviewed by Alexander Fomin <alexander.fomin@oracle.com> Reviewed-by: mullan, hawtin
author xuelei
date Mon, 14 Oct 2013 18:35:40 -0700
parents 74fc78477907
children
line wrap: on
line source

/*
 * reserved comment block
 * DO NOT REMOVE OR ALTER!
 */
/*
 * 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 com.sun.org.apache.xml.internal.security.c14n.implementations;

import java.io.IOException;
import java.util.Iterator;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import javax.xml.parsers.ParserConfigurationException;

import com.sun.org.apache.xml.internal.security.c14n.CanonicalizationException;
import com.sun.org.apache.xml.internal.security.c14n.helper.C14nHelper;
import com.sun.org.apache.xml.internal.security.signature.XMLSignatureInput;
import com.sun.org.apache.xml.internal.security.transforms.params.InclusiveNamespaces;
import com.sun.org.apache.xml.internal.security.utils.Constants;
import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
/**
 * Implements &quot; <A
 * HREF="http://www.w3.org/TR/2002/REC-xml-exc-c14n-20020718/">Exclusive XML
 * Canonicalization, Version 1.0 </A>&quot; <BR />
 * Credits: During restructuring of the Canonicalizer framework, Ren??
 * Kollmorgen from Software AG submitted an implementation of ExclC14n which
 * fitted into the old architecture and which based heavily on my old (and slow)
 * implementation of "Canonical XML". A big "thank you" to Ren?? for this.
 * <BR />
 * <i>THIS </i> implementation is a complete rewrite of the algorithm.
 *
 * @author Christian Geuer-Pollmann <geuerp@apache.org>
 * @version $Revision: 1.5 $
 * @see <a href="http://www.w3.org/TR/2002/REC-xml-exc-c14n-20020718/ Exclusive#">
 *          XML Canonicalization, Version 1.0</a>
 */
public abstract class Canonicalizer20010315Excl extends CanonicalizerBase {
    /**
      * This Set contains the names (Strings like "xmlns" or "xmlns:foo") of
      * the inclusive namespaces.
      */
    TreeSet _inclusiveNSSet = new TreeSet();
    static final String XMLNS_URI=Constants.NamespaceSpecNS;
    final SortedSet result = new TreeSet(COMPARE);
        /**
         * Constructor Canonicalizer20010315Excl
         *
         * @param includeComments
         */
        public Canonicalizer20010315Excl(boolean includeComments) {
                super(includeComments);
        }

        /**
         * Method engineCanonicalizeSubTree
         * @inheritDoc
         * @param rootNode
         *
         * @throws CanonicalizationException
         */
        public byte[] engineCanonicalizeSubTree(Node rootNode)
                        throws CanonicalizationException {
                return this.engineCanonicalizeSubTree(rootNode, "",null);
        }
        /**
         * Method engineCanonicalizeSubTree
         *  @inheritDoc
         * @param rootNode
         * @param inclusiveNamespaces
         *
         * @throws CanonicalizationException
         */
        public byte[] engineCanonicalizeSubTree(Node rootNode,
                        String inclusiveNamespaces) throws CanonicalizationException {
                return this.engineCanonicalizeSubTree(rootNode, inclusiveNamespaces,null);
        }
        /**
         * Method engineCanonicalizeSubTree
         * @param rootNode
     * @param inclusiveNamespaces
     * @param excl A element to exclude from the c14n process.
         * @return the rootNode c14n.
         * @throws CanonicalizationException
         */
        public byte[] engineCanonicalizeSubTree(Node rootNode,
                        String inclusiveNamespaces,Node excl) throws CanonicalizationException {
                        this._inclusiveNSSet = (TreeSet)InclusiveNamespaces
                                        .prefixStr2Set(inclusiveNamespaces);
                        return super.engineCanonicalizeSubTree(rootNode,excl);
        }
        /**
         *
         * @param rootNode
         * @param inclusiveNamespaces
         * @return the rootNode c14n.
         * @throws CanonicalizationException
         */
        public byte[] engineCanonicalize(XMLSignatureInput rootNode,
                        String inclusiveNamespaces) throws CanonicalizationException {
                        this._inclusiveNSSet = (TreeSet)InclusiveNamespaces
                                        .prefixStr2Set(inclusiveNamespaces);
                        return super.engineCanonicalize(rootNode);
        }

        /**
         * Method handleAttributesSubtree
         * @inheritDoc
         * @param E
         * @throws CanonicalizationException
         */
        Iterator handleAttributesSubtree(Element E,NameSpaceSymbTable ns)
                        throws CanonicalizationException {
                // System.out.println("During the traversal, I encountered " +
                // XMLUtils.getXPath(E));
                // result will contain the attrs which have to be outputted
                SortedSet result = this.result;
            result.clear();
                NamedNodeMap attrs=null;

                int attrsLength = 0;
        if (E.hasAttributes()) {
            attrs = E.getAttributes();
                attrsLength = attrs.getLength();
        }
                //The prefix visibly utilized(in the attribute or in the name) in the element
                SortedSet visiblyUtilized =(SortedSet) _inclusiveNSSet.clone();

                for (int i = 0; i < attrsLength; i++) {
                        Attr N = (Attr) attrs.item(i);

                        if (XMLNS_URI!=N.getNamespaceURI()) {
                                //Not a namespace definition.
                                //The Element is output element, add his prefix(if used) to visibyUtilized
                                String prefix = N.getPrefix();
                                if ( (prefix != null) && (!prefix.equals(XML) && !prefix.equals(XMLNS)) ) {
                                                visiblyUtilized.add(prefix);
                                }
                                //Add to the result.
                                 result.add(N);
                                continue;
                        }
                        String NName=N.getLocalName();
                        String NNodeValue=N.getNodeValue();

                        if (ns.addMapping(NName, NNodeValue,N)) {
                                //New definition check if it is relative.
                if (C14nHelper.namespaceIsRelative(NNodeValue)) {
                    Object exArgs[] = {E.getTagName(), NName,
                            N.getNodeValue()};
                    throw new CanonicalizationException(
                            "c14n.Canonicalizer.RelativeNamespace", exArgs);
                }
            }
                }
                String prefix;
                if (E.getNamespaceURI() != null) {
                        prefix = E.getPrefix();
                        if ((prefix == null) || (prefix.length() == 0)) {
                                prefix=XMLNS;
                        }

                } else {
                        prefix=XMLNS;
                }
                visiblyUtilized.add(prefix);

                //This can be optimezed by I don't have time
                Iterator it=visiblyUtilized.iterator();
                while (it.hasNext()) {
                        String s=(String)it.next();
                        Attr key=ns.getMapping(s);
                        if (key==null) {
                                continue;
                        }
                        result.add(key);
                }

                return result.iterator();
        }

        /**
         * Method engineCanonicalizeXPathNodeSet
         * @inheritDoc
         * @param xpathNodeSet
         * @param inclusiveNamespaces
         * @throws CanonicalizationException
         */
        public byte[] engineCanonicalizeXPathNodeSet(Set xpathNodeSet,
                        String inclusiveNamespaces) throws CanonicalizationException {


                        this._inclusiveNSSet = (TreeSet)InclusiveNamespaces
                                        .prefixStr2Set(inclusiveNamespaces);
                        return super.engineCanonicalizeXPathNodeSet(xpathNodeSet);

        }

        /**
     * @inheritDoc
         * @param E
         * @throws CanonicalizationException
         */
        final Iterator handleAttributes(Element E, NameSpaceSymbTable ns)
                        throws CanonicalizationException {
                // result will contain the attrs which have to be outputted
                SortedSet result = this.result;
            result.clear();
                NamedNodeMap attrs = null;
                int attrsLength = 0;
        if (E.hasAttributes()) {
            attrs = E.getAttributes();
                attrsLength = attrs.getLength();
        }
                //The prefix visibly utilized(in the attribute or in the name) in the element
                Set visiblyUtilized =null;
                //It's the output selected.
                boolean isOutputElement=isVisibleDO(E,ns.getLevel())==1;
                if (isOutputElement) {
                        visiblyUtilized =  (Set) this._inclusiveNSSet.clone();
                }

                for (int i = 0; i < attrsLength; i++) {
                        Attr N = (Attr) attrs.item(i);


                        if (XMLNS_URI!=N.getNamespaceURI()) {
                                if ( !isVisible(N) )  {
                                        //The node is not in the nodeset(if there is a nodeset)
                                        continue;
                                }
                                //Not a namespace definition.
                                if (isOutputElement) {
                                        //The Element is output element, add his prefix(if used) to visibyUtilized
                                        String prefix = N.getPrefix();
                                        if ((prefix != null) && (!prefix.equals(XML) && !prefix.equals(XMLNS)) ){
                                                        visiblyUtilized.add(prefix);
                                        }
                                        //Add to the result.
                                    result.add(N);
                                }
                                continue;
                        }
                        String NName=N.getLocalName();
                        if (isOutputElement && !isVisible(N) && NName!=XMLNS) {
                        ns.removeMappingIfNotRender(NName);
                        continue;
                }
                        String NNodeValue=N.getNodeValue();

                        if (!isOutputElement && isVisible(N) && _inclusiveNSSet.contains(NName) && !ns.removeMappingIfRender(NName)) {
                                Node n=ns.addMappingAndRender(NName,NNodeValue,N);
                                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 (ns.addMapping(NName, NNodeValue,N)) {
                //New definiton check if it is relative
                if (C14nHelper.namespaceIsRelative(NNodeValue)) {
                    Object exArgs[] = {E.getTagName(), NName,
                            N.getNodeValue()};
                    throw new CanonicalizationException(
                            "c14n.Canonicalizer.RelativeNamespace", exArgs);
                }
            }
                }

                if (isOutputElement) {
           //The element is visible, handle the xmlns definition
           Attr xmlns = E.getAttributeNodeNS(XMLNS_URI, XMLNS);
           if ((xmlns!=null) &&  (!isVisible(xmlns))) {
              //There is a definition but the xmlns is not selected by the xpath.
              //then xmlns=""
              ns.addMapping(XMLNS, "", getNullNode(xmlns.getOwnerDocument()));
            }

                        if (E.getNamespaceURI() != null) {
                                String prefix = E.getPrefix();
                                if ((prefix == null) || (prefix.length() == 0)) {
                                        visiblyUtilized.add(XMLNS);
                                } else {
                                        visiblyUtilized.add( prefix);
                                }
                        } else {
                                visiblyUtilized.add(XMLNS);
                        }
                        //This can be optimezed by I don't have time
                        //visiblyUtilized.addAll(this._inclusiveNSSet);
                        Iterator it=visiblyUtilized.iterator();
                        while (it.hasNext()) {
                                String s=(String)it.next();
                                Attr key=ns.getMapping(s);
                                if (key==null) {
                                        continue;
                                }
                                result.add(key);
                        }
                }

                return result.iterator();
        }
        void circumventBugIfNeeded(XMLSignatureInput input) throws CanonicalizationException, ParserConfigurationException, IOException, SAXException {
                if (!input.isNeedsToBeExpanded() || _inclusiveNSSet.isEmpty())
                        return;
                Document doc = null;
               if (input.getSubNode() != null) {
                   doc=XMLUtils.getOwnerDocument(input.getSubNode());
               } else {
                   doc=XMLUtils.getOwnerDocument(input.getNodeSet());
               }

                XMLUtils.circumventBug2650(doc);
           }
}