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.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 }