1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 /* 6 * Copyright 1999-2004 The Apache Software Foundation. 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 9 * use this file except in compliance with the License. You may obtain a copy of 10 * the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 16 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 17 * License for the specific language governing permissions and limitations under 18 * the License. 19 * 20 */ 21 package com.sun.org.apache.xml.internal.security.c14n.implementations; 22 23 import java.io.IOException; 24 import java.util.Iterator; 25 import java.util.Set; 26 import java.util.SortedSet; 27 import java.util.TreeSet; 28 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.helper.C14nHelper; 33 import com.sun.org.apache.xml.internal.security.signature.XMLSignatureInput; 34 import com.sun.org.apache.xml.internal.security.transforms.params.InclusiveNamespaces; 35 import com.sun.org.apache.xml.internal.security.utils.Constants; 36 import com.sun.org.apache.xml.internal.security.utils.XMLUtils; 37 import org.w3c.dom.Attr; 38 import org.w3c.dom.Document; 39 import org.w3c.dom.Element; 40 import org.w3c.dom.NamedNodeMap; 41 import org.w3c.dom.Node; 42 import org.xml.sax.SAXException; 43 /** 44 * Implements " <A 45 * HREF="http://www.w3.org/TR/2002/REC-xml-exc-c14n-20020718/">Exclusive XML 46 * Canonicalization, Version 1.0 </A>" <BR /> 47 * Credits: During restructuring of the Canonicalizer framework, Ren?? 48 * Kollmorgen from Software AG submitted an implementation of ExclC14n which 49 * fitted into the old architecture and which based heavily on my old (and slow) 50 * implementation of "Canonical XML". A big "thank you" to Ren?? for this. 51 * <BR /> 52 * <i>THIS </i> implementation is a complete rewrite of the algorithm. 53 * 54 * @author Christian Geuer-Pollmann <geuerp@apache.org> 55 * @version $Revision: 1.5 $ 56 * @see <a href="http://www.w3.org/TR/2002/REC-xml-exc-c14n-20020718/ Exclusive#"> 57 * XML Canonicalization, Version 1.0</a> 58 */ 59 public abstract class Canonicalizer20010315Excl extends CanonicalizerBase { 60 /** 61 * This Set contains the names (Strings like "xmlns" or "xmlns:foo") of 62 * the inclusive namespaces. 63 */ 64 TreeSet<String> _inclusiveNSSet = new TreeSet<String>(); 65 static final String XMLNS_URI=Constants.NamespaceSpecNS; 66 final SortedSet<Attr> result = new TreeSet<Attr>(COMPARE); 67 /** 68 * Constructor Canonicalizer20010315Excl 69 * 70 * @param includeComments 71 */ 72 public Canonicalizer20010315Excl(boolean includeComments) { 73 super(includeComments); 74 } 75 76 /** 77 * Method engineCanonicalizeSubTree 78 * @inheritDoc 79 * @param rootNode 80 * 81 * @throws CanonicalizationException 82 */ 83 public byte[] engineCanonicalizeSubTree(Node rootNode) 84 throws CanonicalizationException { 85 return this.engineCanonicalizeSubTree(rootNode, "",null); 86 } 87 /** 88 * Method engineCanonicalizeSubTree 89 * @inheritDoc 90 * @param rootNode 91 * @param inclusiveNamespaces 92 * 93 * @throws CanonicalizationException 94 */ 95 public byte[] engineCanonicalizeSubTree(Node rootNode, 96 String inclusiveNamespaces) throws CanonicalizationException { 97 return this.engineCanonicalizeSubTree(rootNode, inclusiveNamespaces,null); 98 } 99 /** 100 * Method engineCanonicalizeSubTree 101 * @param rootNode 102 * @param inclusiveNamespaces 103 * @param excl A element to exclude from the c14n process. 104 * @return the rootNode c14n. 105 * @throws CanonicalizationException 106 */ 107 public byte[] engineCanonicalizeSubTree(Node rootNode, 108 String inclusiveNamespaces,Node excl) throws CanonicalizationException { 109 this._inclusiveNSSet = getInclusiveNameSpace(inclusiveNamespaces); 110 return super.engineCanonicalizeSubTree(rootNode,excl); 111 } 112 /** 113 * 114 * @param rootNode 115 * @param inclusiveNamespaces 116 * @return the rootNode c14n. 117 * @throws CanonicalizationException 118 */ 119 @SuppressWarnings("unchecked") 120 public byte[] engineCanonicalize(XMLSignatureInput rootNode, 121 String inclusiveNamespaces) throws CanonicalizationException { 122 this._inclusiveNSSet = getInclusiveNameSpace(inclusiveNamespaces); 123 return super.engineCanonicalize(rootNode); 124 } 125 126 /** 127 * Method handleAttributesSubtree 128 * @inheritDoc 129 * @param E 130 * @throws CanonicalizationException 131 */ 132 Iterator<Attr> handleAttributesSubtree(Element E,NameSpaceSymbTable ns) 133 throws CanonicalizationException { 134 // System.out.println("During the traversal, I encountered " + 135 // XMLUtils.getXPath(E)); 136 // result will contain the attrs which have to be outputted 137 SortedSet<Attr> result = this.result; 138 result.clear(); 139 NamedNodeMap attrs=null; 140 141 int attrsLength = 0; 142 if (E.hasAttributes()) { 143 attrs = E.getAttributes(); 144 attrsLength = attrs.getLength(); 145 } 146 //The prefix visibly utilized(in the attribute or in the name) in the element 147 SortedSet<String> visiblyUtilized = getNSSetClone(); 148 149 for (int i = 0; i < attrsLength; i++) { 150 Attr N = (Attr) attrs.item(i); 151 152 if (XMLNS_URI!=N.getNamespaceURI()) { 153 //Not a namespace definition. 154 //The Element is output element, add his prefix(if used) to visibyUtilized 155 String prefix = N.getPrefix(); 156 if ( (prefix != null) && (!prefix.equals(XML) && !prefix.equals(XMLNS)) ) { 157 visiblyUtilized.add(prefix); 158 } 159 //Add to the result. 160 result.add(N); 161 continue; 162 } 163 String NName=N.getLocalName(); 164 String NNodeValue=N.getNodeValue(); 165 166 if (ns.addMapping(NName, NNodeValue,N)) { 167 //New definition check if it is relative. 168 if (C14nHelper.namespaceIsRelative(NNodeValue)) { 169 Object exArgs[] = {E.getTagName(), NName, 170 N.getNodeValue()}; 171 throw new CanonicalizationException( 172 "c14n.Canonicalizer.RelativeNamespace", exArgs); 173 } 174 } 175 } 176 String prefix; 177 if (E.getNamespaceURI() != null) { 178 prefix = E.getPrefix(); 179 if ((prefix == null) || (prefix.length() == 0)) { 180 prefix=XMLNS; 181 } 182 183 } else { 184 prefix=XMLNS; 185 } 186 visiblyUtilized.add(prefix); 187 188 //This can be optimezed by I don't have time 189 Iterator<String> it=visiblyUtilized.iterator(); 190 while (it.hasNext()) { 191 String s=it.next(); 192 Attr key=ns.getMapping(s); 193 if (key==null) { 194 continue; 195 } 196 result.add(key); 197 } 198 199 return result.iterator(); 200 } 201 202 /** 203 * Method engineCanonicalizeXPathNodeSet 204 * @inheritDoc 205 * @param xpathNodeSet 206 * @param inclusiveNamespaces 207 * @throws CanonicalizationException 208 */ 209 public byte[] engineCanonicalizeXPathNodeSet(Set<Node> xpathNodeSet, 210 String inclusiveNamespaces) throws CanonicalizationException { 211 212 this._inclusiveNSSet = getInclusiveNameSpace(inclusiveNamespaces); 213 return super.engineCanonicalizeXPathNodeSet(xpathNodeSet); 214 215 } 216 217 @SuppressWarnings("unchecked") 218 private TreeSet<String> getInclusiveNameSpace(String inclusiveNameSpaces) { 219 return (TreeSet<String>)InclusiveNamespaces.prefixStr2Set(inclusiveNameSpaces); 220 } 221 222 223 @SuppressWarnings("unchecked") 224 private SortedSet<String> getNSSetClone() { 225 return (SortedSet<String>) this._inclusiveNSSet.clone(); 226 } 227 228 229 /** 230 * @inheritDoc 231 * @param E 232 * @throws CanonicalizationException 233 */ 234 final Iterator<Attr> handleAttributes(Element E, NameSpaceSymbTable ns) 235 throws CanonicalizationException { 236 // result will contain the attrs which have to be outputted 237 SortedSet<Attr> result = this.result; 238 result.clear(); 239 NamedNodeMap attrs = null; 240 int attrsLength = 0; 241 if (E.hasAttributes()) { 242 attrs = E.getAttributes(); 243 attrsLength = attrs.getLength(); 244 } 245 //The prefix visibly utilized(in the attribute or in the name) in the element 246 Set<String> visiblyUtilized =null; 247 //It's the output selected. 248 boolean isOutputElement=isVisibleDO(E,ns.getLevel())==1; 249 if (isOutputElement) { 250 visiblyUtilized = getNSSetClone(); 251 } 252 253 for (int i = 0; i < attrsLength; i++) { 254 Attr N = (Attr) attrs.item(i); 255 256 257 if (XMLNS_URI!=N.getNamespaceURI()) { 258 if ( !isVisible(N) ) { 259 //The node is not in the nodeset(if there is a nodeset) 260 continue; 261 } 262 //Not a namespace definition. 263 if (isOutputElement) { 264 //The Element is output element, add his prefix(if used) to visibyUtilized 265 String prefix = N.getPrefix(); 266 if ((prefix != null) && (!prefix.equals(XML) && !prefix.equals(XMLNS)) ){ 267 visiblyUtilized.add(prefix); 268 } 269 //Add to the result. 270 result.add(N); 271 } 272 continue; 273 } 274 String NName=N.getLocalName(); 275 if (isOutputElement && !isVisible(N) && NName!=XMLNS) { 276 ns.removeMappingIfNotRender(NName); 277 continue; 278 } 279 String NNodeValue=N.getNodeValue(); 280 281 if (!isOutputElement && isVisible(N) && _inclusiveNSSet.contains(NName) && !ns.removeMappingIfRender(NName)) { 282 Node n=ns.addMappingAndRender(NName,NNodeValue,N); 283 if (n!=null) { 284 result.add((Attr)n); 285 if (C14nHelper.namespaceIsRelative(N)) { 286 Object exArgs[] = { E.getTagName(), NName, N.getNodeValue() }; 287 throw new CanonicalizationException( 288 "c14n.Canonicalizer.RelativeNamespace", exArgs); 289 } 290 } 291 } 292 293 294 295 if (ns.addMapping(NName, NNodeValue,N)) { 296 //New definiton check if it is relative 297 if (C14nHelper.namespaceIsRelative(NNodeValue)) { 298 Object exArgs[] = {E.getTagName(), NName, 299 N.getNodeValue()}; 300 throw new CanonicalizationException( 301 "c14n.Canonicalizer.RelativeNamespace", exArgs); 302 } 303 } 304 } 305 306 if (isOutputElement) { 307 //The element is visible, handle the xmlns definition 308 Attr xmlns = E.getAttributeNodeNS(XMLNS_URI, XMLNS); 309 if ((xmlns!=null) && (!isVisible(xmlns))) { 310 //There is a definition but the xmlns is not selected by the xpath. 311 //then xmlns="" 312 ns.addMapping(XMLNS,"",nullNode); 313 } 314 315 if (E.getNamespaceURI() != null) { 316 String prefix = E.getPrefix(); 317 if ((prefix == null) || (prefix.length() == 0)) { 318 visiblyUtilized.add(XMLNS); 319 } else { 320 visiblyUtilized.add( prefix); 321 } 322 } else { 323 visiblyUtilized.add(XMLNS); 324 } 325 //This can be optimezed by I don't have time 326 //visiblyUtilized.addAll(this._inclusiveNSSet); 327 Iterator<String> it=visiblyUtilized.iterator(); 328 while (it.hasNext()) { 329 String s=it.next(); 330 Attr key=ns.getMapping(s); 331 if (key==null) { 332 continue; 333 } 334 result.add(key); 335 } 336 } 337 338 return result.iterator(); 339 } 340 void circumventBugIfNeeded(XMLSignatureInput input) throws CanonicalizationException, ParserConfigurationException, IOException, SAXException { 341 if (!input.isNeedsToBeExpanded() || _inclusiveNSSet.isEmpty()) 342 return; 343 Document doc = null; 344 if (input.getSubNode() != null) { 345 doc=XMLUtils.getOwnerDocument(input.getSubNode()); 346 } else { 347 doc=XMLUtils.getOwnerDocument(input.getNodeSet()); 348 } 349 350 XMLUtils.circumventBug2650(doc); 351 } 352 }