cxf-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Steve Shaw <st...@intelliware.ca>
Subject WS-Security/UsernameToken signature with CXF
Date Wed, 27 Aug 2008 19:25:35 GMT
Hi all,

I've searched the archives and documentation and haven't been able to
find a sample or other questions about my particular problem.

Short version: I'm having trouble verifying a signature created by
signing with the UsernameToken.

Longer version: I've got a @WebServiceProvider that looks like this:

@WebServiceProvider(portName="helloWorldPort", serviceName="helloWorld")
@ServiceMode(value=Service.Mode.MESSAGE)
public class SampleWebServiceProvider implements Provider<SOAPMessage> {
	
  public SampleWebServiceProvider() {
  }

  public SOAPMessage invoke(SOAPMessage soapMessage) {
    try {
      return processSOAPMessage(soapMessage);
    } catch (SOAPException e) {
      throw new MessageException(e);
    } catch (RuntimeException e) {
      throw new MessageException(e);
    }
  }

  public static SOAPMessage processSOAPMessage(SOAPMessage request)
throws SOAPException {
    SOAPMessage response = MessageFactory.newInstance().createMessage();
    Name bodyName =
SOAPFactory.newInstance().createName("helloWorldResponse");
    response.getSOAPBody().addBodyElement(bodyName);
    SOAPElement respContent =
response.getSOAPBody().addChildElement("hello");
    respContent.setValue("world");
    response.saveChanges();
    return response;
  }

It is based on the sample from
http://cwiki.apache.org/CXF20DOC/provider-services.html.

The spec we're working from specifies that we need UsernameToken
authentication with digest password and that we need to sign the body
with the UsernameToken. So I set up the endpoint in Spring like this:

<jaxws:endpoint address="/helloWorld">
  <jaxws:implementor>
    <bean
class="ca.intelliware.example.webservice.SampleWebServiceProvider">
    </bean>
  </jaxws:implementor>
  <jaxws:inInterceptors>
    <bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
      <constructor-arg>
        <map>
	  <entry key="action" value="UsernameToken UsernameTokenSignature"/>
          <entry key="passwordType" value="PasswordDigest"/>
	  <entry key="passwordCallbackRef">
	    <ref bean="examplePasswordCallback"/>
	  </entry>
        </map>
      </constructor-arg>
    </bean>
  </jaxws:inInterceptors>
</jaxws:endpoint>

<bean id="examplePasswordCallback"
class="ca.intelliware.example.webservice.PasswordCallback">
  <constructor-arg ref="ca.intelliware.example.service.UserService"/>	
</bean>

Since I wasn't able to determine any way to invoke a @WebServiceProvider
using the client CXF framework (and any pointers on how to do this would
be appreciated), I fell back on using WSS4J to set the authentication
and signature parameters.

Here is the relevant part of my client code:

Document document = soapMessage.getSOAPPart();
		
WSSecHeader secHeader = new WSSecHeader();
secHeader.insertSecurityHeader(document);

// UsernameToken
WSSecUsernameToken ut = new WSSecUsernameToken();
ut.setPasswordType(WSConstants.PASSWORD_DIGEST);
ut.setUserInfo("pierre", "pierre");
ut.addCreated();
ut.addNonce();
ut.prepare(document);

// Signature
WSSecSignature sign = new WSSecSignature();
Vector<WSEncryptionPart> signParts = new Vector<WSEncryptionPart>();
       
String name = "Body";
String namespace = "http://schemas.xmlsoap.org/soap/envelope/";
String encMod = "Content";
WSEncryptionPart part = new WSEncryptionPart(name, namespace, encMod);
signParts.add(part);
       
if(signParts.size() > 0) {
  sign.setParts(signParts);
}
       
sign.setUsernameToken(ut);
sign.setKeyIdentifierType (WSConstants.UT_SIGNING);
sign.setSignatureAlgorithm(XMLSignature.ALGO_ID_MAC_HMAC_SHA1);

try {
  sign.build(document, null, secHeader);
} catch (WSSecurityException e) {
  e.printStackTrace();
}
ut.prependToHeader(secHeader);

The resultant XML is then posted to the web service.

Here's the message the web service receives:

<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header>
<wsse:Security
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
SOAP-ENV:mustUnderstand="1"><wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
wsu:Id="UsernameToken-9949215" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><wsse:Username
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">pierre</wsse:Username><wsse:Password
Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">oNKL/OieFuA0ABiibLJ3/krPkv4=</wsse:Password><wsse:Nonce
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">ijPV1heraxFNxCiCiLY9rA==</wsse:Nonce><wsu:Created
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity!
 -utility-1.0.xsd">2008-08-27T16:59:06.865Z</wsu:Created></wsse:UsernameToken><ds:Signature
xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="Signature-7461949">
<ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">

<ds:CanonicalizationMethod
Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
<ds:SignatureMethod
Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
<ds:Reference URI="#id-7318012"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:Transforms xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
<ds:DigestValue
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">TnDmYWNSt0r0OQppE2X8cHFBVkI=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">Q/Km3csM6o2psR2rB5DJAtFeR70=</ds:SignatureValue>
<ds:KeyInfo Id="KeyId-1321194"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<wsse:SecurityTokenReference
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
wsu:Id="STRId-33040770" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><wsse:Reference
URI="#UsernameToken-9949215" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#UsernameToken"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"/></wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature></wsse:Security></SOAP-ENV:Header><SOAP-ENV:Body
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
wsu:Id="id-7318012"><helloWorld>
	<stuff>stuff goes here</stuff>
</helloWorld></SOAP-ENV:Body></SOAP-ENV:Envelope>

It results in a server warning and stack trace that looks like this:

WARNING: Security processing failed (actions mismatch)
27-Aug-2008 12:59:07 PM
org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor handleMessage
WARNING: 
org.apache.ws.security.WSSecurityException: An error was discovered
processing the <wsse:Security> header
	at
org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.handleMessage(WSS4JInInterceptor.java:227)
	at
org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.handleMessage(WSS4JInInterceptor.java:65)

Further notes that may be of interest:

1. The service and client calls work properly if all the security stuff
is removed. They still work properly when the UsernameToken
authentication is added on its own. It's only when I add the signature
code that it no longer works.

2. I'm using maven to build and deploy the project. I'm specifying
version 2.0.8 of CXF, which pulls in WSS4J 1.5.4 and xmlsec 1.4.0.

3. I suspect the code might make more sense if there was a client-side
CXF method to invoke a WebServiceProvider. There aren't any samples at
http://cwiki.apache.org/CXF20DOC/provider-services.html, and all of the
samples of WS-Security stuff at
http://cwiki.apache.org/CXF20DOC/ws-security.html specify using
interceptors and certificates - there's nothing there about signing with
UsernameToken.

My general question is: what am I doing wrong? Specifically, is there
something in my client code that is generating an incorrect signature?

Other questions: is there a known problem with this sort of signature?
Is there an easy way to debug what's actually going wrong in the code
(the initial exception appears to occur in the xmlsec signature code, which
is resistant to debugging unless I check out and compile my own copy of
it)?

Any help is appreciated.

-Steve

Mime
View raw message