Hi all.

I need to sign a SAML2 message and I'm using JSR105 for this. I'm using my
own implementation of SAML2 but I need to sign the assertions. I've created
a message with the following code and is signed without problems. However, I
can't validate the signature. As you can see the elements that contains the
nodes are OMElement. I would be very pleased if you could tell me what's the
problem (or if you can propose a better solution to sign SAML2 assertion, as
far as I know the Axis2 security module doesn't use SAML2)

The error I get is:

Exception in thread "main" javax.xml.crypto.dsig.XMLSignatureException:
javax.xml.crypto.URIReferenceException:
com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException:
Cannot resolve element with ID 1
at org.jcp.xml.dsig.internal.dom.DOMReference.dereference(DOMReference.java
:366)
at org.jcp.xml.dsig.internal.dom.DOMReference.validate(DOMReference.java
:318)
at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.validate(
DOMXMLSignature.java:230)
at SignedSoap.main(SignedSoap.java:272)
Caused by: javax.xml.crypto.URIReferenceException:
com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException:
Cannot resolve element with ID 1
at org.jcp.xml.dsig.internal.dom.DOMURIDereferencer.dereference(
DOMURIDereferencer.java:84)
at org.jcp.xml.dsig.internal.dom.DOMReference.dereference(DOMReference.java
:358)
... 3 more
Caused by:
com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException:
Cannot resolve element with ID 1
at
com.sun.org.apache.xml.internal.security.utils.resolver.implementations.ResolverFragment.engineResolve(Unknown
Source)
at
com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolver.resolve(Unknown
Source)
at org.jcp.xml.dsig.internal.dom.DOMURIDereferencer.dereference(
DOMURIDereferencer.java:77)
... 4 more
javax.xml.crypto.URIReferenceException:
com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException:
Cannot resolve element with ID 1
at org.jcp.xml.dsig.internal.dom.DOMURIDereferencer.dereference(
DOMURIDereferencer.java:84)
at org.jcp.xml.dsig.internal.dom.DOMReference.dereference(DOMReference.java
:358)
at org.jcp.xml.dsig.internal.dom.DOMReference.validate(DOMReference.java
:318)
at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.validate(
DOMXMLSignature.java:230)
at SignedSoap.main(SignedSoap.java:272)
Caused by:
com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException:
Cannot resolve element with ID 1
at
com.sun.org.apache.xml.internal.security.utils.resolver.implementations.ResolverFragment.engineResolve(Unknown
Source)
at
com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolver.resolve(Unknown
Source)
at org.jcp.xml.dsig.internal.dom.DOMURIDereferencer.dereference(
DOMURIDereferencer.java:77)
... 4 more

 My code is as follows

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.Provider;
import java.security.SecureRandom;
import java.util.Calendar;
import java.util.Collections;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dom.*;
import javax.xml.crypto.dsig.dom.*;
import javax.xml.crypto.dsig.keyinfo.*;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
import javax.xml.soap.*;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.*;

import org.apache.axiom.om.OMAttribute;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMNamespace;
import org.apache.axiom.om.impl.dom.factory.OMDOMFactory;
import org.apache.xmlbeans.impl.piccolo.xml.XMLStreamReader;
import org.w3c.dom.*;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
//import org.xmlsoap.schemas.soap.encoding.DateTime;

/**
* Construct a SOAP message, sign it and then validate the signature.
* This implementation follows the
* <a ref="http://www.w3.org/TR/SOAP-dsig/";>
* W3C Note on digital signatures in SOAP messages
* </a>.
* The validating key is included in the signature.
* DOM Level 2 is used throughout.
*

* The following SOAP message is signed:
* <pre><code>
*
* <?xml version="1.0" encoding="UTF-8"?>
* <soap-env:Envelope
* xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/";>
* <soap-env:Header>
* <SOAP-SEC:Signature
* mustUnderstand="1"
* xmlns:SOAP-SEC="http://schemas.xmlsoap.org/soap/security/2000-12"/>
* </soap-env:Header>
* <soap-env:Body id="Body">
* <m:GetLastTradePrice xmlns:m="http://wombats.ztrade.com";>
* <symbol>SUNW</symbol>
* </m:GetLastTradePrice>
* </soap-env:Body>
* </soap-env:Envelope>
*
* </code></pre>
*/
public class SignedSoap {

private static boolean debug = false;

public static void main(String[] args) throws Exception {

int argc = args.length;

if (argc == 1) {
if (args[0].equalsIgnoreCase("-help")) {
System.out.println("Usage: SignedSoap [-debug]");
System.out.println(" -debug\tactivates debug messages");
return;
}
debug = args[0].equalsIgnoreCase("-debug");
}

// Create the SOAP message

OMDOMFactory omfact=new OMDOMFactory();
//Node nodo1=fd.newDomNode(options);
OMNamespace namespace=omfact.createOMNamespace("
http://schemas.xmlsoap.org/soap/security/2000-12";, "soapenv");
OMNamespace namespace2=omfact.createOMNamespace("
http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";,
"wsu");
OMAttribute attr=omfact.createOMAttribute("mustUnderstand",namespace,"1");
OMAttribute id=omfact.createOMAttribute("id",namespace,"1");
OMAttribute id2=omfact.createOMAttribute("id",namespace,"2");
OMElement sec=omfact.createOMElement("Security", "
http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd
","wsse");
OMElement timestamp=omfact.createOMElement("Timestamp",namespace2);
OMElement created=omfact.createOMElement("Created",namespace2);
OMElement expires=omfact.createOMElement("Expires",namespace2);

created.setText("12122007");
expires.setText("12122008");

timestamp.addAttribute(id);
timestamp.addChild(created);
timestamp.addChild(expires);

sec.addChild(timestamp);

System.out.println("Generating the DOM tree...");
// Get input source

org.w3c.dom.Node security = (Node)sec;

//if (debug) {
// dumpDOMDocument(root);
//}

// Generate a DSA key pair

System.out.println("Generating the DSA keypair...");
KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
kpg.initialize(1024, new SecureRandom("not so random".getBytes()));
KeyPair keypair = kpg.generateKeyPair();

// Assemble the signature parts

System.out.println("Preparing the signature...");
String providerName = System.getProperty
("jsr105Provider", "org.jcp.xml.dsig.internal.dom.XMLDSigRI");
XMLSignatureFactory sigFactory = XMLSignatureFactory.getInstance("DOM",
(Provider) Class.forName(providerName).newInstance());
Reference ref = sigFactory.newReference("#1",
sigFactory.newDigestMethod(DigestMethod.SHA1, null));
SignedInfo signedInfo = sigFactory.newSignedInfo(
sigFactory.newCanonicalizationMethod(
CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS,
(C14NMethodParameterSpec) null),
sigFactory.newSignatureMethod(SignatureMethod.DSA_SHA1, null),
Collections.singletonList(ref));
KeyInfoFactory kif = sigFactory.getKeyInfoFactory();
KeyValue kv = kif.newKeyValue(keypair.getPublic());
KeyInfo keyInfo = kif.newKeyInfo(Collections.singletonList(kv));

XMLSignature sig = sigFactory.newXMLSignature(signedInfo, keyInfo);

// Insert XML signature into DOM tree and sign

System.out.println("Signing the SOAP message...");
// Find where to insert signature

Element ts = getFirstChildElement(envelope);

DOMSignContext sigContext =
new DOMSignContext(keypair.getPrivate(), sec);
// Need to distinguish the Signature element in DSIG (from that in SOAP)
sigContext.putNamespacePrefix(XMLSignature.XMLNS, "ds");
// register Body ID attribute getNextSiblingElement(
sigContext.setIdAttributeNS
(ts,
"http://schemas.xmlsoap.org/soap/security/2000-12","id";);
sig.sign(sigContext);

if (debug) {
dumpDOMDocument(envelope);
}

// Validate the XML signature

// Locate the signature element
Element sigElement = getNextSiblingElement(ts);
// Validate the signature using the public key generated above
DOMValidateContext valContext =
new DOMValidateContext(keypair.getPublic(), sigElement);
// register Body ID attribute getNextSiblingElement(
valContext.setIdAttributeNS
(ts,
"http://schemas.xmlsoap.org/soap/security/2000-12","id";);

boolean isValid = sig.validate(valContext);
System.out.println("Validating the signature... " +
(isValid ? "valid" : "invalid"));

}

/*
* Outputs DOM representation to the standard output stream.
*
* @param root The DOM representation to be outputted
*/
private static void dumpDOMDocument(org.w3c.dom.Node root)
throws TransformerException, TransformerConfigurationException {

System.out.println("\n");
// Create a new transformer object
Transformer transformer =
TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
// Dump the DOM representation to standard output
transformer.transform(new DOMSource(root), new StreamResult(System.out));
System.out.println("\n");
}

/**
* Returns the first child element of the specified node, or null if there
* is no such element.
*
* @param node the node
* @return the first child element of the specified node, or null if there
* is no such element
* @throws NullPointerException if <code>node == null</code>
*/
private static Element getFirstChildElement(org.w3c.dom.Node node) {
org.w3c.dom.Node child = node.getFirstChild();
while (child != null &&
child.getNodeType() != org.w3c.dom.Node.ELEMENT_NODE) {
child = child.getNextSibling();
}
return (Element) child;
}

/**
* Returns the next sibling element of the specified node, or null if there
* is no such element.
*
* @param node the node
* @return the next sibling element of the specified node, or null if there
* is no such element
* @throws NullPointerException if <code>node == null</code>
*/
public static Element getNextSiblingElement(org.w3c.dom.Node node) {
org.w3c.dom.Node sibling = node.getNextSibling();
while (sibling != null &&
sibling.getNodeType() != org.w3c.dom.Node.ELEMENT_NODE) {
sibling = sibling.getNextSibling();
}
return (Element) sibling;
}
}

Thanks in advance, regards.

Christina.

Reply via email to