blob: 8bf0646e4d2e14406ea2a10d358a358ba1354cfb [file] [log] [blame]
/*
* Copyright 1999-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
*/
package org.apache.xml.security.c14n.implementations;
import java.util.Iterator;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import org.apache.xml.security.c14n.CanonicalizationException;
import org.apache.xml.security.c14n.helper.C14nHelper;
import org.apache.xml.security.signature.XMLSignatureInput;
import org.apache.xml.security.transforms.params.InclusiveNamespaces;
import org.apache.xml.security.utils.Constants;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
/**
* Implements &quot; <A
* HREF="http://www.w3.org/TR/2002/REC-xml-exc-c14n-20020718/">Exclusive XML
* Canonicalization, Version 1.0 </A>&quot; <BR />
* Credits: During restructuring of the Canonicalizer framework, Ren??
* Kollmorgen from Software AG submitted an implementation of ExclC14n which
* fitted into the old architecture and which based heavily on my old (and slow)
* implementation of "Canonical XML". A big "thank you" to Ren?? for this.
* <BR />
* <i>THIS </i> implementation is a complete rewrite of the algorithm.
*
* @author Christian Geuer-Pollmann <geuerp@apache.org>
* @version $Revision$
* @see <a href="http://www.w3.org/TR/2002/REC-xml-exc-c14n-20020718/ Exclusive#">
* XML Canonicalization, Version 1.0</a>
*/
public abstract class Canonicalizer20010315Excl extends CanonicalizerBase {
/**
* This Set contains the names (Strings like "xmlns" or "xmlns:foo") of
* the inclusive namespaces.
*/
TreeSet _inclusiveNSSet = new TreeSet();
static final String XMLNS_URI=Constants.NamespaceSpecNS;
final SortedSet result = new TreeSet(COMPARE);
/**
* Constructor Canonicalizer20010315Excl
*
* @param includeComments
*/
public Canonicalizer20010315Excl(boolean includeComments) {
super(includeComments);
}
/**
* Method engineCanonicalizeSubTree
* @inheritDoc
* @param rootNode
*
* @throws CanonicalizationException
*/
public byte[] engineCanonicalizeSubTree(Node rootNode)
throws CanonicalizationException {
return this.engineCanonicalizeSubTree(rootNode, "",null);
}
/**
* Method engineCanonicalizeSubTree
* @inheritDoc
* @param rootNode
* @param inclusiveNamespaces
*
* @throws CanonicalizationException
*/
public byte[] engineCanonicalizeSubTree(Node rootNode,
String inclusiveNamespaces) throws CanonicalizationException {
return this.engineCanonicalizeSubTree(rootNode, inclusiveNamespaces,null);
}
/**
* Method engineCanonicalizeSubTree
* @param rootNode
* @param inclusiveNamespaces
* @param excl A element to exclude from the c14n process.
* @return the rootNode c14n.
* @throws CanonicalizationException
*/
public byte[] engineCanonicalizeSubTree(Node rootNode,
String inclusiveNamespaces,Node excl) throws CanonicalizationException {
this._inclusiveNSSet = (TreeSet)InclusiveNamespaces
.prefixStr2Set(inclusiveNamespaces);
return super.engineCanonicalizeSubTree(rootNode,excl);
}
/**
*
* @param rootNode
* @param inclusiveNamespaces
* @return the rootNode c14n.
* @throws CanonicalizationException
*/
public byte[] engineCanonicalize(XMLSignatureInput rootNode,
String inclusiveNamespaces) throws CanonicalizationException {
this._inclusiveNSSet = (TreeSet)InclusiveNamespaces
.prefixStr2Set(inclusiveNamespaces);
return super.engineCanonicalize(rootNode);
}
/**
* Method handleAttributesSubtree
* @inheritDoc
* @param E
* @throws CanonicalizationException
*/
Iterator handleAttributesSubtree(Element E,NameSpaceSymbTable ns)
throws CanonicalizationException {
// System.out.println("During the traversal, I encountered " +
// XMLUtils.getXPath(E));
// result will contain the attrs which have to be outputted
SortedSet result = this.result;
result.clear();
NamedNodeMap attrs=null;
int attrsLength = 0;
if (E.hasAttributes()) {
attrs = E.getAttributes();
attrsLength = attrs.getLength();
}
//The prefix visibly utilized(in the attribute or in the name) in the element
SortedSet visiblyUtilized =(SortedSet) _inclusiveNSSet.clone();
for (int i = 0; i < attrsLength; i++) {
Attr N = (Attr) attrs.item(i);
if (XMLNS_URI!=N.getNamespaceURI()) {
//Not a namespace definition.
//The Element is output element, add his prefix(if used) to visibyUtilized
String prefix = N.getPrefix();
if ( (prefix != null) && (!prefix.equals(XML) && !prefix.equals(XMLNS)) ) {
visiblyUtilized.add(prefix);
}
//Add to the result.
result.add(N);
continue;
}
String NName=N.getLocalName();
String NNodeValue=N.getNodeValue();
if (ns.addMapping(NName, NNodeValue,N)) {
//New definition check if it is relative.
if (C14nHelper.namespaceIsRelative(NNodeValue)) {
Object exArgs[] = {E.getTagName(), NName,
N.getNodeValue()};
throw new CanonicalizationException(
"c14n.Canonicalizer.RelativeNamespace", exArgs);
}
}
}
if (E.getNamespaceURI() != null) {
String prefix = E.getPrefix();
if ((prefix == null) || (prefix.length() == 0)) {
visiblyUtilized.add(XMLNS);
} else {
visiblyUtilized.add(prefix);
}
} else {
visiblyUtilized.add(XMLNS);
}
//This can be optimezed by I don't have time
Iterator it=visiblyUtilized.iterator();
while (it.hasNext()) {
String s=(String)it.next();
Attr key=ns.getMapping(s);
if (key==null) {
continue;
}
result.add(key);
}
return result.iterator();
}
/**
* Method engineCanonicalizeXPathNodeSet
* @inheritDoc
* @param xpathNodeSet
* @param inclusiveNamespaces
* @throws CanonicalizationException
*/
public byte[] engineCanonicalizeXPathNodeSet(Set xpathNodeSet,
String inclusiveNamespaces) throws CanonicalizationException {
this._inclusiveNSSet = (TreeSet)InclusiveNamespaces
.prefixStr2Set(inclusiveNamespaces);
return super.engineCanonicalizeXPathNodeSet(xpathNodeSet);
}
/**
* @inheritDoc
* @param E
* @throws CanonicalizationException
*/
final Iterator handleAttributes(Element E, NameSpaceSymbTable ns)
throws CanonicalizationException {
// result will contain the attrs which have to be outputted
SortedSet result = this.result;
result.clear();
NamedNodeMap attrs = null;
int attrsLength = 0;
if (E.hasAttributes()) {
attrs = E.getAttributes();
attrsLength = attrs.getLength();
}
//The prefix visibly utilized(in the attribute or in the name) in the element
Set visiblyUtilized =null;
//It's the output selected.
boolean isOutputElement = isVisible(E);
if (isOutputElement) {
visiblyUtilized = (Set) this._inclusiveNSSet.clone();
}
for (int i = 0; i < attrsLength; i++) {
Attr N = (Attr) attrs.item(i);
if ( !isVisible(N) ) {
//The node is not in the nodeset(if there is a nodeset)
continue;
}
if (XMLNS_URI!=N.getNamespaceURI()) {
//Not a namespace definition.
if (isOutputElement) {
//The Element is output element, add his prefix(if used) to visibyUtilized
String prefix = N.getPrefix();
if ((prefix != null) && (!prefix.equals(XML) && !prefix.equals(XMLNS)) ){
visiblyUtilized.add(prefix);
}
//Add to the result.
result.add(N);
}
continue;
}
String NName=N.getLocalName();
String NNodeValue=N.getNodeValue();
if (ns.addMapping(NName, NNodeValue,N)) {
//New definiton check if it is relative
if (C14nHelper.namespaceIsRelative(NNodeValue)) {
Object exArgs[] = {E.getTagName(), NName,
N.getNodeValue()};
throw new CanonicalizationException(
"c14n.Canonicalizer.RelativeNamespace", exArgs);
}
}
}
if (isOutputElement) {
//The element is visible, handle the xmlns definition
Attr xmlns = E.getAttributeNodeNS(XMLNS_URI, XMLNS);
if ((xmlns!=null) && (!isVisible(xmlns))) {
//There is a definition but the xmlns is not selected by the xpath.
//then xmlns=""
ns.addMapping(XMLNS,"",nullNode);
}
if (E.getNamespaceURI() != null) {
String prefix = E.getPrefix();
if ((prefix == null) || (prefix.length() == 0)) {
visiblyUtilized.add(XMLNS);
} else {
visiblyUtilized.add( prefix);
}
} else {
visiblyUtilized.add(XMLNS);
}
//This can be optimezed by I don't have time
//visiblyUtilized.addAll(this._inclusiveNSSet);
Iterator it=visiblyUtilized.iterator();
while (it.hasNext()) {
String s=(String)it.next();
Attr key=ns.getMapping(s);
if (key==null) {
continue;
}
result.add(key);
}
} else /*if (_circunvented)*/ {
Iterator it=this._inclusiveNSSet.iterator();
while (it.hasNext()) {
String s=(String)it.next();
Attr key=ns.getMappingWithoutRendered(s);
if (key==null) {
continue;
}
result.add(key);
}
}
return result.iterator();
}
}