October 18, 2007 - 16:41 UTC - Tags: WSS4J Web Services WSE X509 security Axis .NET
Some of you may have seen my
old posting where I presented some configuration for accessing a WSS4J secured Axis service from .NET using WSE3.0. I have gotten a lot of questions about how to make this work the other way around. This post contains a working configuration for a WSS4J secured client talking to a WSE3.0 secured web service using x509 certificates.
Update 2008-04-19: The config was updated to work better with with self-generated certificates and without a custom .NET assertion. So now I have a working configuration without any special implementations.
Basic setupI once again used the interop certificates and keystores from the WSS4J 1.5.3
1.5 release package together with Microsoft WSE 3.0.
Update 2008-04-19: I was also able to make it work with my own certificates issued by the windows certificate authority when using WSS4J 1.5.3. I've added a new post about this here:
WSE and WSS4J: Issuing working certificates using Windows Certification Authority.
Java WSS4J client configurationThe client-config.wsdd looks as follows. The crypto.properties file is the file from the WSS4J-package.
Update 2008-04-19: Moved to SKIKeyIdentifier for encryptionKeyIdentifier and disabled signatureconfirmation on responseflow.
<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<transport name="http" pivot="java:org.apache.axis.transport.http.HTTPSender"/>
<globalConfiguration>
<parameter name="enableNamespacePrefixOptimization" value="false" />
<requestFlow>
<handler type="java:org.apache.ws.axis.security.WSDoAllSender">
<parameter name="action" value="Signature Encrypt Timestamp"/>
<parameter name="passwordCallbackClass" value="interop.PWCallback"/>
<parameter name="signaturePropFile" value="crypto.properties" />
<parameter name="encryptionPropFile" value="crypto.properties" />
<parameter name="signatureKeyIdentifier" value="DirectReference" />
<!-- changed as of 2008-04-19 -->
<parameter name="encryptionKeyIdentifier" value="SKIKeyIdentifier" />
<parameter name="encryptionUser" value="bob" />
<parameter name="user" value="alice"/>
<parameter name="encryptionSymAlgorithm" value="http://www.w3.org/2001/04/xmlenc#aes128-cbc" />
<parameter name="encryptionKeyTransportAlgorithm" value="http://www.w3.org/2001/04/xmlenc#rsa-1_5" />
</handler>
</requestFlow>
<responseFlow>
<handler type="java:org.apache.ws.axis.security.WSDoAllReceiver">
<parameter name="passwordCallbackClass" value="interop.PWCallback"/>
<parameter name="action" value="Signature Encrypt Timestamp"/>
<parameter name="signaturePropFile" value="crypto.properties" />
<parameter name="decryptionPropFile" value="crypto.properties" />
<parameter name="encryptionPropFile" value="crypto.properties" />
<!-- added as of 2008-04-19 -->
<parameter name="enableSignatureConfirmation" value="false" />
</handler>
</responseFlow>
</globalConfiguration>
</deployment>
.NET sideThe .NET side was a bit more difficult to set up.
It seems WSS4J sends both the signature key and the encryption key in the security header, even though they may be the same key. WSE did not like this (WSE2007 error - as mentioned in the bottom section), so I had to implement a small change to the MutualCertificate10Assertion (yes still not using the MutualCertificate11Assertion ), where I removed the extra element before the assertion verified the XML. Usings are removed for brevity:Update 2008-04-19: No longer needed
// no longer needed as of 2008-04-19
The policy XML was changed to use this custom assertion instead.Update 2008-04-19: I've reinstated the native MutualCertificate10Assertion:
<policies xmlns="http://schemas.microsoft.com/wse/2005/06/policy">
<extensions>
<extension name="authorization" type="Microsoft.Web.Services3.Design.AuthorizationAssertion, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<!-- CUSTOM -->
<extension name="mutualCertificate10Security" type="Microsoft.Web.Services3.Design.MutualCertificate10Assertion, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<extension name="x509" type="Microsoft.Web.Services3.Design.X509TokenProvider, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<extension name="requireActionHeader" type="Microsoft.Web.Services3.Design.RequireActionHeaderAssertion, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</extensions>
<policy name="x509">
<authorization>
<allow user="CN=Alice, OU=OASIS Interop Test Cert, O=OASIS" />
<deny user="*" />
</authorization>
<mutualCertificate10Security establishSecurityContext="false" renewExpiredSecurityContext="false" requireSignatureConfirmation="false" messageProtectionOrder="SignBeforeEncrypt" requireDerivedKeys="false" ttlInSeconds="300">
<serviceToken>
<x509 storeLocation="LocalMachine" storeName="My" findValue="CN=Bob, OU=OASIS Interop Test Cert, O=OASIS" findType="FindBySubjectDistinguishedName" />
</serviceToken>
<protection>
<request signatureOptions="IncludeSoapBody" encryptBody="true" />
<response signatureOptions="IncludeSoapBody" encryptBody="true" />
<fault signatureOptions="" encryptBody="false" />
</protection>
</mutualCertificate10Security>
</policy>
</policies>
For web.config the Microsoft.Web.Services3 element looked like this:
<microsoft.web.services3>
<security>
<binarySecurityTokenManager>
<add valueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3">
<keyAlgorithm name="RSA15"/>
</add>
</binarySecurityTokenManager>
<x509 skiMode="ThumbprintSHA1" verifyTrust="false" storeLocation="LocalMachine"/>
<securityTokenManager>
<add type="Microsoft.Web.Services3.Security.Tokens.EncryptedKeyTokenManager, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="http://www.w3.org/2001/04/xmlenc#" localName="EncryptedKey">
<keyAlgorithm name="AES128"/>
</add>
</securityTokenManager>
</security>
<policy fileName="wse3policyCache.config"/>
<diagnostics>
<trace enabled="true" input="D:\projects\websites\SecuredServiceInteropTest\trace.in" output="D:\projects\websites\SecuredServiceInteropTest\trace.out"/>
</diagnostics>
</microsoft.web.services3>
Now if anybody has a working configuration for Axis2 with Rampart, please let me know.Update 2007-11-21: Shelly Saunders sent me a link to a blog post with a configuration for WCF and Rampart/Axis2:
Shelly's blog postError messages I got during development"Signature verification failed" - the solution to this error was to set the enableNamespacePrefixOptimization to false in the client-config.wsdd. XML-optimizations and XML-signatures don't work well together.
"WSE2007: More than one X509SecurityToken is present in the security header of the incoming message, but only one was expected" - the solution to this was to use the SKIKeyIdentifier for the server certificate
implement the MutualCertificate10Assertion subclass.