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