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.transforms.implementations;
  24 
  25 import java.io.OutputStream;
  26 
  27 import javax.xml.transform.TransformerException;
  28 
  29 import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityRuntimeException;
  30 import com.sun.org.apache.xml.internal.security.signature.NodeFilter;
  31 import com.sun.org.apache.xml.internal.security.signature.XMLSignatureInput;
  32 import com.sun.org.apache.xml.internal.security.transforms.Transform;
  33 import com.sun.org.apache.xml.internal.security.transforms.TransformSpi;
  34 import com.sun.org.apache.xml.internal.security.transforms.TransformationException;
  35 import com.sun.org.apache.xml.internal.security.transforms.Transforms;
  36 import com.sun.org.apache.xml.internal.security.utils.Constants;
  37 import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
  38 import com.sun.org.apache.xml.internal.security.utils.XPathAPI;
  39 import com.sun.org.apache.xml.internal.security.utils.XPathFactory;
  40 import org.w3c.dom.DOMException;
  41 import org.w3c.dom.Element;
  42 import org.w3c.dom.Node;
  43 
  44 /**
  45  * Class TransformXPath
  46  *
  47  * Implements the <CODE>http://www.w3.org/TR/1999/REC-xpath-19991116</CODE>
  48  * transform.
  49  *
  50  * @author Christian Geuer-Pollmann
  51  * @see <a href="http://www.w3.org/TR/1999/REC-xpath-19991116">XPath</a>
  52  *
  53  */
  54 public class TransformXPath extends TransformSpi {
  55 
  56     /** Field implementedTransformURI */
  57     public static final String implementedTransformURI = Transforms.TRANSFORM_XPATH;
  58     
  59     /**
  60      * Method engineGetURI
  61      *
  62      * @inheritDoc
  63      */
  64     protected String engineGetURI() {
  65         return implementedTransformURI;
  66     }
  67 
  68     /**
  69      * Method enginePerformTransform
  70      * @inheritDoc
  71      * @param input
  72      *
  73      * @throws TransformationException
  74      */
  75     protected XMLSignatureInput enginePerformTransform(
  76         XMLSignatureInput input, OutputStream os, Transform transformObject
  77     ) throws TransformationException {
  78         try {
  79             /**
  80              * If the actual input is an octet stream, then the application MUST
  81              * convert the octet stream to an XPath node-set suitable for use by
  82              * Canonical XML with Comments. (A subsequent application of the
  83              * REQUIRED Canonical XML algorithm would strip away these comments.)
  84              *
  85              * ...
  86              *
  87              * The evaluation of this expression includes all of the document's nodes
  88              * (including comments) in the node-set representing the octet stream.
  89              */
  90             Element xpathElement =
  91                 XMLUtils.selectDsNode(
  92                     transformObject.getElement().getFirstChild(), Constants._TAG_XPATH, 0);
  93 
  94             if (xpathElement == null) {
  95                 Object exArgs[] = { "ds:XPath", "Transform" };
  96 
  97                 throw new TransformationException("xml.WrongContent", exArgs);
  98             }
  99             Node xpathnode = xpathElement.getChildNodes().item(0);
 100             String str = XMLUtils.getStrFromNode(xpathnode);
 101             input.setNeedsToBeExpanded(needsCircumvent(str));
 102             if (xpathnode == null) {
 103                 throw new DOMException(
 104                     DOMException.HIERARCHY_REQUEST_ERR, "Text must be in ds:Xpath"
 105                 );
 106             }
 107             
 108             XPathFactory xpathFactory = XPathFactory.newInstance();
 109             XPathAPI xpathAPIInstance = xpathFactory.newXPathAPI();
 110             input.addNodeFilter(new XPathNodeFilter(xpathElement, xpathnode, str, xpathAPIInstance));
 111             input.setNodeSet(true);
 112             return input;
 113         } catch (DOMException ex) {
 114             throw new TransformationException("empty", ex);
 115         }
 116     }
 117 
 118     /**
 119      * @param str
 120      * @return true if needs to be circumvent for bug.
 121      */
 122     private boolean needsCircumvent(String str) {
 123         return (str.indexOf("namespace") != -1) || (str.indexOf("name()") != -1);
 124     }
 125 
 126     static class XPathNodeFilter implements NodeFilter {
 127         
 128         XPathAPI xPathAPI;
 129         Node xpathnode; 
 130         Element xpathElement;
 131         String str;
 132         
 133         XPathNodeFilter(Element xpathElement, Node xpathnode, String str, XPathAPI xPathAPI) {
 134             this.xpathnode = xpathnode;
 135             this.str = str;
 136             this.xpathElement = xpathElement;
 137             this.xPathAPI = xPathAPI;
 138         }
 139 
 140         /**
 141          * @see com.sun.org.apache.xml.internal.security.signature.NodeFilter#isNodeInclude(org.w3c.dom.Node)
 142          */
 143         public int isNodeInclude(Node currentNode) {                    
 144             try {
 145                 boolean include = xPathAPI.evaluate(currentNode, xpathnode, str, xpathElement);
 146                 if (include) {
 147                     return 1;
 148                 }
 149                 return 0;
 150             } catch (TransformerException e) {
 151                 Object[] eArgs = {currentNode};
 152                 throw new XMLSecurityRuntimeException("signature.Transform.node", eArgs, e);
 153             } catch (Exception e) {
 154                 Object[] eArgs = {currentNode, Short.valueOf(currentNode.getNodeType())};
 155                 throw new XMLSecurityRuntimeException("signature.Transform.nodeAndType",eArgs, e);
 156             }
 157         }
 158         
 159         public int isNodeIncludeDO(Node n, int level) {
 160             return isNodeInclude(n);
 161         }
 162         
 163     }
 164 }