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 }