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 transformSpi = transformSpiClass.newInstance(); 164 } catch (InstantiationException ex) { 165 Object exArgs[] = { algorithmURI }; 166 throw new InvalidTransformException( 167 "signature.Transform.UnknownTransform", exArgs, ex 168 ); 169 } catch (IllegalAccessException ex) { 170 Object exArgs[] = { algorithmURI }; 171 throw new InvalidTransformException( 172 "signature.Transform.UnknownTransform", exArgs, ex 173 ); 174 } 175 } 176 177 /** 178 * Registers implementing class of the Transform algorithm with algorithmURI 179 * 180 * @param algorithmURI algorithmURI URI representation of <code>Transform algorithm</code> 181 * @param implementingClass <code>implementingClass</code> the implementing 182 * class of {@link TransformSpi} 183 * @throws AlgorithmAlreadyRegisteredException if specified algorithmURI 184 * is already registered 185 * @throws SecurityException if a security manager is installed and the 186 * caller does not have permission to register the transform 187 */ 188 @SuppressWarnings("unchecked") 189 public static void register(String algorithmURI, String implementingClass) 190 throws AlgorithmAlreadyRegisteredException, ClassNotFoundException, 191 InvalidTransformException { 192 JavaUtils.checkRegisterPermission(); 193 // are we already registered? 194 Class<? extends TransformSpi> transformSpi = transformSpiHash.get(algorithmURI); 195 if (transformSpi != null) { 196 Object exArgs[] = { algorithmURI, transformSpi }; 197 throw new AlgorithmAlreadyRegisteredException("algorithm.alreadyRegistered", exArgs); 198 } 199 Class<? extends TransformSpi> transformSpiClass = 200 (Class<? extends TransformSpi>) 201 ClassLoaderUtils.loadClass(implementingClass, Transform.class); 202 transformSpiHash.put(algorithmURI, transformSpiClass); 203 } 204 205 /** 206 * Registers implementing class of the Transform algorithm with algorithmURI 207 * 208 * @param algorithmURI algorithmURI URI representation of <code>Transform algorithm</code> 209 * @param implementingClass <code>implementingClass</code> the implementing 210 * class of {@link TransformSpi} 211 * @throws AlgorithmAlreadyRegisteredException if specified algorithmURI 212 * is already registered 213 * @throws SecurityException if a security manager is installed and the 214 * caller does not have permission to register the transform 215 */ 216 public static void register(String algorithmURI, Class<? extends TransformSpi> implementingClass) 217 throws AlgorithmAlreadyRegisteredException { 218 JavaUtils.checkRegisterPermission(); 219 // are we already registered? 220 Class<? extends TransformSpi> transformSpi = transformSpiHash.get(algorithmURI); 221 if (transformSpi != null) { 222 Object exArgs[] = { algorithmURI, transformSpi }; 223 throw new AlgorithmAlreadyRegisteredException("algorithm.alreadyRegistered", exArgs); 224 } 225 transformSpiHash.put(algorithmURI, implementingClass); 226 } 227 228 /** 229 * This method registers the default algorithms. 230 */ 231 public static void registerDefaultAlgorithms() { 232 transformSpiHash.put( 233 Transforms.TRANSFORM_BASE64_DECODE, TransformBase64Decode.class 234 ); 235 transformSpiHash.put( 236 Transforms.TRANSFORM_C14N_OMIT_COMMENTS, TransformC14N.class 237 ); 238 transformSpiHash.put( 239 Transforms.TRANSFORM_C14N_WITH_COMMENTS, TransformC14NWithComments.class 240 ); 241 transformSpiHash.put( 242 Transforms.TRANSFORM_C14N11_OMIT_COMMENTS, TransformC14N11.class 243 ); 244 transformSpiHash.put( 245 Transforms.TRANSFORM_C14N11_WITH_COMMENTS, TransformC14N11_WithComments.class 246 ); 247 transformSpiHash.put( 248 Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS, TransformC14NExclusive.class 249 ); 250 transformSpiHash.put( 251 Transforms.TRANSFORM_C14N_EXCL_WITH_COMMENTS, TransformC14NExclusiveWithComments.class 252 ); 253 transformSpiHash.put( 254 Transforms.TRANSFORM_XPATH, TransformXPath.class 255 ); 256 transformSpiHash.put( 257 Transforms.TRANSFORM_ENVELOPED_SIGNATURE, TransformEnvelopedSignature.class 258 ); 259 transformSpiHash.put( 260 Transforms.TRANSFORM_XSLT, TransformXSLT.class 261 ); 262 transformSpiHash.put( 263 Transforms.TRANSFORM_XPATH2FILTER, TransformXPath2Filter.class 264 ); 265 } 266 267 /** 268 * Returns the URI representation of Transformation algorithm 269 * 270 * @return the URI representation of Transformation algorithm 271 */ 272 public String getURI() { 273 return this.constructionElement.getAttributeNS(null, Constants._ATT_ALGORITHM); 274 } 275 276 /** 277 * Transforms the input, and generates {@link XMLSignatureInput} as output. 278 * 279 * @param input input {@link XMLSignatureInput} which can supplied Octet 280 * Stream and NodeSet as Input of Transformation 281 * @return the {@link XMLSignatureInput} class as the result of 282 * transformation 283 * @throws CanonicalizationException 284 * @throws IOException 285 * @throws InvalidCanonicalizerException 286 * @throws TransformationException 287 */ 288 public XMLSignatureInput performTransform(XMLSignatureInput input) 289 throws IOException, CanonicalizationException, 290 InvalidCanonicalizerException, TransformationException { 291 return performTransform(input, null); 292 } 293 294 /** 295 * Transforms the input, and generates {@link XMLSignatureInput} as output. 296 * 297 * @param input input {@link XMLSignatureInput} which can supplied Octect 298 * Stream and NodeSet as Input of Transformation 299 * @param os where to output the result of the last transformation 300 * @return the {@link XMLSignatureInput} class as the result of 301 * transformation 302 * @throws CanonicalizationException 303 * @throws IOException 304 * @throws InvalidCanonicalizerException 305 * @throws TransformationException 306 */ 307 public XMLSignatureInput performTransform( 308 XMLSignatureInput input, OutputStream os 309 ) throws IOException, CanonicalizationException, 310 InvalidCanonicalizerException, TransformationException { 311 XMLSignatureInput result = null; 312 313 try { 314 result = transformSpi.enginePerformTransform(input, os, this); 315 } catch (ParserConfigurationException ex) { 316 Object exArgs[] = { this.getURI(), "ParserConfigurationException" }; 317 throw new CanonicalizationException( 318 "signature.Transform.ErrorDuringTransform", exArgs, ex); 319 } catch (SAXException ex) { 320 Object exArgs[] = { this.getURI(), "SAXException" }; 321 throw new CanonicalizationException( 322 "signature.Transform.ErrorDuringTransform", exArgs, ex); 323 } 324 325 return result; 326 } 327 328 /** @inheritDoc */ 329 public String getBaseLocalName() { 330 return Constants._TAG_TRANSFORM; 331 } 332 333 /** 334 * Initialize the transform object. 335 */ 336 private TransformSpi initializeTransform(String algorithmURI, NodeList contextNodes) 337 throws InvalidTransformException { 338 339 this.constructionElement.setAttributeNS(null, Constants._ATT_ALGORITHM, algorithmURI); 340 341 Class<? extends TransformSpi> transformSpiClass = transformSpiHash.get(algorithmURI); 342 if (transformSpiClass == null) { 343 Object exArgs[] = { algorithmURI }; 344 throw new InvalidTransformException("signature.Transform.UnknownTransform", exArgs); 345 } 346 TransformSpi newTransformSpi = null; 347 try { 348 newTransformSpi = transformSpiClass.newInstance(); 349 } catch (InstantiationException ex) { 350 Object exArgs[] = { algorithmURI }; 351 throw new InvalidTransformException( 352 "signature.Transform.UnknownTransform", exArgs, ex 353 ); 354 } catch (IllegalAccessException ex) { 355 Object exArgs[] = { algorithmURI }; 356 throw new InvalidTransformException( 357 "signature.Transform.UnknownTransform", exArgs, ex 358 ); 359 } 360 361 if (log.isLoggable(java.util.logging.Level.FINE)) { 362 log.log(java.util.logging.Level.FINE, "Create URI \"" + algorithmURI + "\" class \"" 363 + newTransformSpi.getClass() + "\""); 364 log.log(java.util.logging.Level.FINE, "The NodeList is " + contextNodes); 365 } 366 367 // give it to the current document 368 if (contextNodes != null) { 369 for (int i = 0; i < contextNodes.getLength(); i++) { 370 this.constructionElement.appendChild(contextNodes.item(i).cloneNode(true)); 371 } 372 } 373 return newTransformSpi; 374 } 375 376 }