Skip to Content.
Sympa Menu

mace-opensaml-users - Re: Re: [OpenSAML] signed SAMLRequest in SOAPMessage

Subject: OpenSAML user discussion

List archive

Re: Re: [OpenSAML] signed SAMLRequest in SOAPMessage


Chronological Thread 
  • From:
  • To:
  • Subject: Re: Re: [OpenSAML] signed SAMLRequest in SOAPMessage
  • Date: Thu, 30 Apr 2009 06:30:22 -0400 (EDT)

I don't know if I can send attachments so below is a printout of the
SOAPHandler.

It extends the RPC generic handler (javax.xml.rpc.handler.GenericHandler).
It checks the outgoing SOAPBody on clientside for a SAMLRequest, Response or
Assertion.
If it finds one, the saml is parsed into opensaml API, it is signed and the
SOAPBody child-element containing the SAML is replaced with a new
child-element containing the signed SAML message.

It has no vendor dependent code so I think it can be used in different
java-client-webservice-implementations.
You may need to do some tweeking though.
For example, I tested with Weblogic 10.3 and had to set the following system
property:
System.setProperty("weblogic.wsee.handler.allowAllModification", "true");
Without this property, you are not allowed to modify the SOAPMessage the way
I did.
Some other webservice implementations may not need this handler if they do
not break the signature when building the soapmessage, but even then it might
be useful as this handler makes sure that the signature is based on (and
included in) the xml that will eventually be sent to the webservice.

Two final remarks:
- if there are other SOAPHandlers configured on the client after the
SamlSignSoapHandler, they may no longer modify the SOAPBody-content otherwise
the SAML signature will be broken.
- if the webservice is secured with WS-Policy or something else that requires
the client to sign the entire SOAPBody or more, the SamlSignSoapHandler must
be executed before this signature is set by the client, otherwise the
WS-Policy-signature will be broken.

--- SamlSignSoapHandler.java : begin ---
package org.eh.sts.wsclient.handler;

import java.util.Properties;

import javax.xml.namespace.QName;
import javax.xml.rpc.handler.GenericHandler;
import javax.xml.rpc.handler.HandlerInfo;
import javax.xml.rpc.handler.MessageContext;
import javax.xml.rpc.handler.soap.SOAPMessageContext;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;

import org.opensaml.SAMLAssertion;
import org.opensaml.SAMLRequest;
import org.opensaml.SAMLResponse;
import org.opensaml.SAMLSignedObject;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import org.eh.sts.wsclient.STSClientException;
import org.eh.sts.wsclient.support.SAMLSignFactory;


/**
* SOAP Handler that signs SAML Messages contained in SOAPBody. <br/>
Supports signing of SAML Requests, Responses and Assertions. <br/>
* Webservice-call must be document-style with the SAML Element as input
message.
*
* @author Frederik Libert
*
* @since 1.0.0
*
*/
public class SamlSignSoapHandler extends GenericHandler {

private static final String CRYPTO_FILE = "cryptoFile";

private QName[] headers;

/** cryptographic properties to sign SAML Message. */
Properties crypto;

/**
* @see
javax.xml.rpc.handler.GenericHandler#init(javax.xml.rpc.handler.HandlerInfo)
*/
@Override
public void init(HandlerInfo config) {
this.crypto = new Properties();
String cryptoFile =
System.getProperty("SamlSignSoapHandler.cryptoFile");
if (cryptoFile == null) {
cryptoFile = (String) config.getHandlerConfig().get(CRYPTO_FILE);
}
if (cryptoFile == null) {
throw new STSClientException("Correct location of file with
cryptographic info must be set through either a System-property or a
handler-config parameter");
}
try {

this.crypto.load(SamlSignSoapHandler.class.getResourceAsStream(cryptoFile));
} catch (Exception e) {
throw new STSClientException("Could not load cryptographic
properties to sign SAML Message", e);
}
}

/**
*
* @see
javax.xml.rpc.handler.GenericHandler#handleRequest(javax.xml.rpc.handler.MessageContext)
*/
public boolean handleRequest(MessageContext context) {
SOAPMessageContext messageContext = (SOAPMessageContext) context;
try {
System.out.println("SamlSignSoapHandler -- signing SAML in
SOAPBody ...");
Node nodeBeforeSigning =
messageContext.getMessage().getSOAPBody().getFirstChild();
DOMSource source = new DOMSource(nodeBeforeSigning);
SAMLSignedObject request = transformToSAML(source);
SAMLSignFactory.getInstance().sign(request, this.crypto);
System.out.println("SamlSignSoapHandler -- SAML signed");
System.out.println("SamlSignSoapHandler -- Replacing SAML in
SOAPBody ...");
Node nodeAfterSigning = request.toDOM();

messageContext.getMessage().getSOAPBody().removeChild(nodeBeforeSigning);

messageContext.getMessage().getSOAPBody().addDocument(nodeAfterSigning.getOwnerDocument());
System.out.println("SamlSignSoapHandler -- SAML replaced");
} catch (Exception e) {
throw new STSClientException("SAML in SOAPBody could not be
signed", e);
}

return true;
}

/**
*
* @see
javax.xml.rpc.handler.GenericHandler#handleResponse(javax.xml.rpc.handler.MessageContext)
*/
public boolean handleResponse(MessageContext context) {
return true;
}

/**
*
* @see javax.xml.rpc.handler.GenericHandler#getHeaders()
*/
public QName[] getHeaders() {
return headers;
}

private SAMLSignedObject transformToSAML(Source request) {
try {
Transformer transformer =
TransformerFactory.newInstance().newTransformer();
DOMResult result = new DOMResult();
transformer.transform(request, result);
Node samlNode = result.getNode().getFirstChild();
if (samlNode.getLocalName().equals("Request")) {
return new SAMLRequest((Element) samlNode);
}
if (samlNode.getLocalName().equals("response")) {
return new SAMLResponse((Element) samlNode);
}
if (samlNode.getLocalName().equals("Assertion")) {
return new SAMLAssertion((Element) samlNode);
}
throw new IllegalArgumentException("Not supported source
(RootNode=" + samlNode.getLocalName() + ")");
} catch (Exception e) {
throw new STSClientException("Problem transforming source to
SAML", e);
}
}

}
--- SamlSignSoapHandler : end ---

to configure the handlerchain, I used the vendor specific xml-file but I
think there are standard ones also (not sure though).

--- ClientHandlerChain.xml : begin ---

<weblogic-wsee-clientHandlerChain xmlns="http://www.bea.com/ns/weblogic/90";
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
xmlns:j2ee="http://java.sun.com/xml/ns/j2ee";>
<handler>
<j2ee:handler-name>SamlSignSoapHandler</j2ee:handler-name>

<j2ee:handler-class>org.eh.sts.wsclient.handler.SamlSignSoapHandler</j2ee:handler-class>
<j2ee:init-param>
<j2ee:param-name>cryptoFile</j2ee:param-name>
<j2ee:param-value>/crypto.properties</j2ee:param-value>
</j2ee:init-param>
</handler>
</weblogic-wsee-clientHandlerChain>

--- ClientHandlerChain.xml : end ---


Hope this can help,

Frederik Libert



Archive powered by MHonArc 2.6.16.

Top of Page