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;
  24 
  25 import java.io.IOException;
  26 import java.io.OutputStream;
  27 import java.util.concurrent.ConcurrentHashMap;
  28 import java.util.Map;
  29 import javax.xml.parsers.ParserConfigurationException;
  30 
  31 import com.sun.org.apache.xml.internal.security.c14n.CanonicalizationException;
  32 import com.sun.org.apache.xml.internal.security.c14n.InvalidCanonicalizerException;
  33 import com.sun.org.apache.xml.internal.security.exceptions.AlgorithmAlreadyRegisteredException;
  34 import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException;
  35 import com.sun.org.apache.xml.internal.security.signature.XMLSignatureInput;
  36 import com.sun.org.apache.xml.internal.security.transforms.implementations.TransformBase64Decode;
  37 import com.sun.org.apache.xml.internal.security.transforms.implementations.TransformC14N;
  38 import com.sun.org.apache.xml.internal.security.transforms.implementations.TransformC14N11;
  39 import com.sun.org.apache.xml.internal.security.transforms.implementations.TransformC14N11_WithComments;
  40 import com.sun.org.apache.xml.internal.security.transforms.implementations.TransformC14NExclusive;
  41 import com.sun.org.apache.xml.internal.security.transforms.implementations.TransformC14NExclusiveWithComments;
  42 import com.sun.org.apache.xml.internal.security.transforms.implementations.TransformC14NWithComments;
  43 import com.sun.org.apache.xml.internal.security.transforms.implementations.TransformEnvelopedSignature;
  44 import com.sun.org.apache.xml.internal.security.transforms.implementations.TransformXPath;
  45 import com.sun.org.apache.xml.internal.security.transforms.implementations.TransformXPath2Filter;
  46 import com.sun.org.apache.xml.internal.security.transforms.implementations.TransformXSLT;
  47 import com.sun.org.apache.xml.internal.security.utils.Constants;
  48 import com.sun.org.apache.xml.internal.security.utils.HelperNodeList;
  49 import com.sun.org.apache.xml.internal.security.utils.SignatureElementProxy;
  50 import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
  51 import org.w3c.dom.Document;
  52 import org.w3c.dom.Element;
  53 import org.w3c.dom.NodeList;
  54 import org.xml.sax.SAXException;
  55 
  56 /**
  57  * Implements the behaviour of the <code>ds:Transform</code> element.
  58  *
  59  * This <code>Transform</code>(Factory) class acts as the Factory and Proxy of
  60  * the implementing class that supports the functionality of <a
  61  * href=http://www.w3.org/TR/xmldsig-core/#sec-TransformAlg>a Transform
  62  * algorithm</a>.
  63  * Implements the Factory and Proxy pattern for ds:Transform algorithms.
  64  *
  65  * @author Christian Geuer-Pollmann
  66  * @see Transforms
  67  * @see TransformSpi
  68  */
  69 public final class Transform extends SignatureElementProxy {
  70 
  71     /** {@link org.apache.commons.logging} logging facility */
  72     private static java.util.logging.Logger log = 
  73         java.util.logging.Logger.getLogger(Transform.class.getName());
  74 
  75     /** All available Transform classes are registered here */
  76     private static Map<String, Class<? extends TransformSpi>> transformSpiHash = 
  77         new ConcurrentHashMap<String, Class<? extends TransformSpi>>();
  78     
  79     private final TransformSpi transformSpi;
  80     
  81     /**
  82      * Generates a Transform object that implements the specified 
  83      * <code>Transform algorithm</code> URI.
  84      *
  85      * @param doc the proxy {@link Document}
  86      * @param algorithmURI <code>Transform algorithm</code> URI representation, 
  87      * such as specified in 
  88      * <a href=http://www.w3.org/TR/xmldsig-core/#sec-TransformAlg>Transform algorithm </a>
  89      * @throws InvalidTransformException
  90      */
  91     public Transform(Document doc, String algorithmURI) throws InvalidTransformException {
  92         this(doc, algorithmURI, (NodeList)null);
  93     }
  94     
  95     /**
  96      * Generates a Transform object that implements the specified 
  97      * <code>Transform algorithm</code> URI.
  98      *
  99      * @param algorithmURI <code>Transform algorithm</code> URI representation, 
 100      * such as specified in 
 101      * <a href=http://www.w3.org/TR/xmldsig-core/#sec-TransformAlg>Transform algorithm </a>
 102      * @param contextChild the child element of <code>Transform</code> element
 103      * @param doc the proxy {@link Document}
 104      * @throws InvalidTransformException
 105      */
 106     public Transform(Document doc, String algorithmURI, Element contextChild) 
 107         throws InvalidTransformException {
 108         super(doc);
 109         HelperNodeList contextNodes = null;
 110         
 111         if (contextChild != null) {
 112             contextNodes = new HelperNodeList();
 113     
 114             XMLUtils.addReturnToElement(doc, contextNodes);
 115             contextNodes.appendChild(contextChild);
 116             XMLUtils.addReturnToElement(doc, contextNodes);
 117         }
 118 
 119         transformSpi = initializeTransform(algorithmURI, contextNodes);
 120     }
 121 
 122     /**
 123      * Constructs {@link Transform}
 124      *
 125      * @param doc the {@link Document} in which <code>Transform</code> will be 
 126      * placed
 127      * @param algorithmURI URI representation of <code>Transform algorithm</code>
 128      * @param contextNodes the child node list of <code>Transform</code> element
 129      * @throws InvalidTransformException
 130      */
 131     public Transform(Document doc, String algorithmURI, NodeList contextNodes)
 132         throws InvalidTransformException {
 133         super(doc);
 134         transformSpi = initializeTransform(algorithmURI, contextNodes);
 135     }
 136 
 137     /**
 138      * @param element <code>ds:Transform</code> element
 139      * @param BaseURI the URI of the resource where the XML instance was stored
 140      * @throws InvalidTransformException
 141      * @throws TransformationException
 142      * @throws XMLSecurityException
 143      */
 144     public Transform(Element element, String BaseURI)
 145         throws InvalidTransformException, TransformationException, XMLSecurityException {
 146         super(element, BaseURI);
 147 
 148         // retrieve Algorithm Attribute from ds:Transform
 149         String algorithmURI = element.getAttributeNS(null, Constants._ATT_ALGORITHM);
 150 
 151         if (algorithmURI == null || algorithmURI.length() == 0) {
 152             Object exArgs[] = { Constants._ATT_ALGORITHM, Constants._TAG_TRANSFORM };
 153             throw new TransformationException("xml.WrongContent", exArgs);
 154         }
 155      
 156         Class<? extends TransformSpi> transformSpiClass = transformSpiHash.get(algorithmURI);
 157         if (transformSpiClass == null) {
 158             Object exArgs[] = { algorithmURI };
 159             throw new InvalidTransformException("signature.Transform.UnknownTransform", exArgs);
 160         }
 161         try {
 162             transformSpi = transformSpiClass.newInstance();
 163         } catch (InstantiationException ex) {
 164             Object exArgs[] = { algorithmURI };
 165             throw new InvalidTransformException(
 166                 "signature.Transform.UnknownTransform", exArgs, ex
 167             );
 168         } catch (IllegalAccessException ex) {
 169             Object exArgs[] = { algorithmURI };
 170             throw new InvalidTransformException(
 171                 "signature.Transform.UnknownTransform", exArgs, ex
 172             );
 173         }
 174     }
 175     
 176     /**
 177      * Registers implementing class of the Transform algorithm with algorithmURI
 178      *
 179      * @param algorithmURI algorithmURI URI representation of <code>Transform algorithm</code>
 180      * @param implementingClass <code>implementingClass</code> the implementing 
 181      * class of {@link TransformSpi}
 182      * @throws AlgorithmAlreadyRegisteredException if specified algorithmURI 
 183      * is already registered
 184      */
 185     @SuppressWarnings("unchecked")
 186     public static void register(String algorithmURI, String implementingClass)
 187         throws AlgorithmAlreadyRegisteredException, ClassNotFoundException, 
 188             InvalidTransformException {
 189         // are we already registered?
 190         Class<? extends TransformSpi> transformSpi = transformSpiHash.get(algorithmURI);
 191         if (transformSpi != null) {
 192             Object exArgs[] = { algorithmURI, transformSpi };
 193             throw new AlgorithmAlreadyRegisteredException("algorithm.alreadyRegistered", exArgs);
 194         }
 195         Class<? extends TransformSpi> transformSpiClass = 
 196             (Class<? extends TransformSpi>)
 197                 ClassLoaderUtils.loadClass(implementingClass, Transform.class);
 198         transformSpiHash.put(algorithmURI, transformSpiClass);
 199     }
 200     
 201     /**
 202      * Registers implementing class of the Transform algorithm with algorithmURI
 203      *
 204      * @param algorithmURI algorithmURI URI representation of <code>Transform algorithm</code>
 205      * @param implementingClass <code>implementingClass</code> the implementing 
 206      * class of {@link TransformSpi}
 207      * @throws AlgorithmAlreadyRegisteredException if specified algorithmURI 
 208      * is already registered
 209      */
 210     public static void register(String algorithmURI, Class<? extends TransformSpi> implementingClass)
 211         throws AlgorithmAlreadyRegisteredException {
 212         // are we already registered?
 213         Class<? extends TransformSpi> transformSpi = transformSpiHash.get(algorithmURI);
 214         if (transformSpi != null) {
 215             Object exArgs[] = { algorithmURI, transformSpi };
 216             throw new AlgorithmAlreadyRegisteredException("algorithm.alreadyRegistered", exArgs);
 217         }
 218         transformSpiHash.put(algorithmURI, implementingClass);
 219     }
 220 
 221     /**
 222      * This method registers the default algorithms.
 223      */
 224     public static void registerDefaultAlgorithms() {
 225         transformSpiHash.put(
 226             Transforms.TRANSFORM_BASE64_DECODE, TransformBase64Decode.class
 227         );
 228         transformSpiHash.put(
 229             Transforms.TRANSFORM_C14N_OMIT_COMMENTS, TransformC14N.class
 230         );
 231         transformSpiHash.put(
 232             Transforms.TRANSFORM_C14N_WITH_COMMENTS, TransformC14NWithComments.class
 233         );
 234         transformSpiHash.put(
 235             Transforms.TRANSFORM_C14N11_OMIT_COMMENTS, TransformC14N11.class
 236         );
 237         transformSpiHash.put(
 238             Transforms.TRANSFORM_C14N11_WITH_COMMENTS, TransformC14N11_WithComments.class
 239         );
 240         transformSpiHash.put(
 241             Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS, TransformC14NExclusive.class
 242         );
 243         transformSpiHash.put(
 244             Transforms.TRANSFORM_C14N_EXCL_WITH_COMMENTS, TransformC14NExclusiveWithComments.class
 245         );
 246         transformSpiHash.put(
 247             Transforms.TRANSFORM_XPATH, TransformXPath.class
 248         );
 249         transformSpiHash.put(
 250             Transforms.TRANSFORM_ENVELOPED_SIGNATURE, TransformEnvelopedSignature.class
 251         );
 252         transformSpiHash.put(
 253             Transforms.TRANSFORM_XSLT, TransformXSLT.class
 254         );
 255         transformSpiHash.put(
 256             Transforms.TRANSFORM_XPATH2FILTER, TransformXPath2Filter.class
 257         );
 258     }
 259     
 260     /**
 261      * Returns the URI representation of Transformation algorithm
 262      *
 263      * @return the URI representation of Transformation algorithm
 264      */
 265     public String getURI() {
 266         return this.constructionElement.getAttributeNS(null, Constants._ATT_ALGORITHM);
 267     }
 268 
 269     /**
 270      * Transforms the input, and generates {@link XMLSignatureInput} as output.
 271      *
 272      * @param input input {@link XMLSignatureInput} which can supplied Octet 
 273      * Stream and NodeSet as Input of Transformation
 274      * @return the {@link XMLSignatureInput} class as the result of 
 275      * transformation
 276      * @throws CanonicalizationException
 277      * @throws IOException
 278      * @throws InvalidCanonicalizerException
 279      * @throws TransformationException
 280      */
 281     public XMLSignatureInput performTransform(XMLSignatureInput input)
 282         throws IOException, CanonicalizationException,
 283                InvalidCanonicalizerException, TransformationException {
 284         return performTransform(input, null);
 285     }
 286    
 287     /**
 288      * Transforms the input, and generates {@link XMLSignatureInput} as output.
 289      *
 290      * @param input input {@link XMLSignatureInput} which can supplied Octect 
 291      * Stream and NodeSet as Input of Transformation
 292      * @param os where to output the result of the last transformation
 293      * @return the {@link XMLSignatureInput} class as the result of 
 294      * transformation
 295      * @throws CanonicalizationException
 296      * @throws IOException
 297      * @throws InvalidCanonicalizerException
 298      * @throws TransformationException
 299      */
 300     public XMLSignatureInput performTransform(
 301         XMLSignatureInput input, OutputStream os
 302     ) throws IOException, CanonicalizationException,
 303         InvalidCanonicalizerException, TransformationException {
 304         XMLSignatureInput result = null;
 305 
 306         try {
 307             result = transformSpi.enginePerformTransform(input, os, this);
 308         } catch (ParserConfigurationException ex) {
 309             Object exArgs[] = { this.getURI(), "ParserConfigurationException" };
 310             throw new CanonicalizationException(
 311                 "signature.Transform.ErrorDuringTransform", exArgs, ex);
 312         } catch (SAXException ex) {
 313             Object exArgs[] = { this.getURI(), "SAXException" };
 314             throw new CanonicalizationException(
 315                 "signature.Transform.ErrorDuringTransform", exArgs, ex);
 316         }
 317 
 318         return result;
 319     }
 320 
 321     /** @inheritDoc */
 322     public String getBaseLocalName() {
 323         return Constants._TAG_TRANSFORM;
 324     }
 325     
 326     /**
 327      * Initialize the transform object.
 328      */
 329     private TransformSpi initializeTransform(String algorithmURI, NodeList contextNodes)
 330         throws InvalidTransformException {
 331 
 332         this.constructionElement.setAttributeNS(null, Constants._ATT_ALGORITHM, algorithmURI);
 333 
 334         Class<? extends TransformSpi> transformSpiClass = transformSpiHash.get(algorithmURI);
 335         if (transformSpiClass == null) {
 336             Object exArgs[] = { algorithmURI };
 337             throw new InvalidTransformException("signature.Transform.UnknownTransform", exArgs);
 338         }
 339         TransformSpi newTransformSpi = null;
 340         try {
 341             newTransformSpi = transformSpiClass.newInstance();
 342         } catch (InstantiationException ex) {
 343             Object exArgs[] = { algorithmURI };
 344             throw new InvalidTransformException(
 345                 "signature.Transform.UnknownTransform", exArgs, ex
 346             );
 347         } catch (IllegalAccessException ex) {
 348             Object exArgs[] = { algorithmURI };
 349             throw new InvalidTransformException(
 350                 "signature.Transform.UnknownTransform", exArgs, ex
 351             );
 352         }
 353 
 354         if (log.isLoggable(java.util.logging.Level.FINE)) {
 355             log.log(java.util.logging.Level.FINE, "Create URI \"" + algorithmURI + "\" class \""
 356                       + newTransformSpi.getClass() + "\"");
 357             log.log(java.util.logging.Level.FINE, "The NodeList is " + contextNodes);
 358         }
 359 
 360         // give it to the current document
 361         if (contextNodes != null) {
 362             for (int i = 0; i < contextNodes.getLength(); i++) {
 363                 this.constructionElement.appendChild(contextNodes.item(i).cloneNode(true));
 364             }
 365         }
 366         return newTransformSpi;
 367     }
 368 
 369 }