views:

894

answers:

3

I'm writing a JAXWS-RI client that must call a .NET Web Service that is using WS-Security. The service's WSDL does not contain any WS-Security info, but I have an example soap message from the service's authors and know that I must include wsse:Security headers, including X:509 tokens.

I've been researching, and I've seen example of folks calling this type of web service from Axis and CXF (in conjunction with Rampart and/or WSS4J), but nothing about using plain JAXWS-RI itself. However, I'm (unfortunately) constrained to using JAXWS-RI by my gov't client. Does anyone have any examples/documentation of doing this from JAXWS-RI?

I need to ultimately generate a SOAP header that looks something like the one below - this is a sample soap:header from a .NET client written by the service's authors. (Note: I've put the 'VALUE_HERE' string in places where I need to provide my own values)

<soapenv:Envelope xmlns:iri="http://EOIR/IRIES" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"&gt;
  <soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing"&gt;
    <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401- wss-wssecurity-secext-1.0.xsd">
     <xenc:EncryptedKey Id="VALUE_HERE">
       <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"/&gt;
       <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"&gt;
          <wsse:SecurityTokenReference>
             <wsse:KeyIdentifier EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"&gt;
             VALUE_HERE
            </wsse:KeyIdentifier>
         </wsse:SecurityTokenReference>
       </ds:KeyInfo>
       <xenc:CipherData>
          <xenc:CipherValue>VALUE_HERE</xenc:CipherValue>
       </xenc:CipherData>
       <xenc:ReferenceList>
         <xenc:DataReference URI="#EncDataId-8"/>
       </xenc:ReferenceList>
    </xenc:EncryptedKey>
  </wsse:Security>
+1  A: 

Try configuring your port with a

com.sun.xml.ws.api.security.CallbackHandlerFeature

That uses a custom implementation of

javax.security.auth.callback.CallbackHandler

that accepts a

java.security.PrivateKey

and

java.security.cert.X509Certificate

that you load from a resource on your classpath. I just blogged about this here: http://upthescala.blogspot.com/2010/03/essential-sources-for-jax-ws-x509.html .

See com.sun.xml.ws.commons.EC2 (in the source download linked in the blog entry noted above) for an example of configuring the port (including loading the private key and X.509 certs from a file).

I'd post more code but I don't have my dev box with me so I can't really test.

Good luck!

LES2
elduff
A: 

I am still working through some issues trying to solve this issue, but I wanted to update with some details of the approach I've settled on. The first thing that I realized was that I had to upgrade from using JAXWS-RI 2.1 to Metro 2.0. We had previously used JAXWSRI-2.1 in this project, but we'd never had to deal with any WS-Security before. Anyway, I realized that I needed to upgrade, so I did that to take advantage of Metro 2.0 and the WSIT jars that were included with it. Then, I was still confused about exactly how to do about generating the WS-Security headers that I needed w/o having the WS-Policy info from the service's WSDL file. I had attempted to set a CallbackHandlerFeature using the APIs suggested by LES2, but that was not generating the headers for me. So, I posted a question on the Metro/JAXB board at java.net here:

http://forums.java.net/jive/message.jspa?messageID=392451#392451

In the responses to that, one answerer suggested using NetBeans to write a dummy web service and set up the security settings that I though the .NET's service was using. Once I did that, NetBeans generated a WS-Policy section in the wsit-.xml file that I could use. I plugged that WS-Policy section into my local copy of the .NET service's WSDL, and also used it to create a wsit-client.xml file that I put in my WEB-INF/classes directory.

Once I did that, Metro/WSIT began adding the WS-Security headers to request for me. I was then running into some issues, because Metro was using a different version of WS-Addressing than was required by the .NET service (they use MemberSubmissionAddressing). So, I ended up tweaking my WS-Policy settings to use

<wsap:UsingAddressing                   xmlns:wsap="http://schemas.xmlsoap.org/ws/2004/08/addressing/policy" />

Now, I'm at the point where I've got my SOAP request looking like this:

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:exc14n="http://www.w3.org/2001/10/xml-exc-c14n#" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"&gt;
<S:Header>
<To xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing" wsu:Id="_5003">https://10.49.38.78/2009/12/CaseDetailsService.asmx&lt;/To&gt;
<Action xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing" wsu:Id="_5004">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT&lt;/Action&gt;
<ReplyTo xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing" wsu:Id="_5002">
    <Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous&lt;/Address&gt;
</ReplyTo>
<MessageID xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing" wsu:Id="_5005">uuid:89a0dfdf-014c-4be7-a677-ab1b4d30cdb5</MessageID>
<wsse:Security S:mustUnderstand="1">
  <wsu:Timestamp xmlns:ns10="http://www.w3.org/2003/05/soap-envelope" 
       xmlns:ns11="http://docs.oasis-open.org/ws-sx/ws-secureconversation/200512" xmlns:ns12="http://schemas.xmlsoap.org/ws/2006/02/addressingidentity" wsu:Id="_3">
       <wsu:Created>2010-03-22T19:48:04Z</wsu:Created>
       <wsu:Expires>2010-03-22T19:53:04Z</wsu:Expires> 
    </wsu:Timestamp>
    <wsse:BinarySecurityToken xmlns:ns10="http://www.w3.org/2003/05/soap-envelope" 
    xmlns:ns11="http://docs.oasis-open.org/ws-sx/ws-secureconversation/200512" 
    xmlns:ns12="http://schemas.xmlsoap.org/ws/2006/02/addressingidentity" 
    wsu:Id="uuid_e861f15d-dd66-4b05-b101-c9fed7feda38" 
    EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"&gt;DATA_HERE
</wsse:BinarySecurityToken>
<xenc:EncryptedKey xmlns:ns10="http://www.w3.org/2003/05/soap-envelope" xmlns:ns11="http://docs.oasis-open.org/ws-sx/ws-secureconversation/200512" xmlns:ns12="http://schemas.xmlsoap.org/ws/2006/02/addressingidentity" Id="_5007">
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"/&gt;
<ds:KeyInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="KeyInfoType">
<wsse:SecurityTokenReference>
<ds:X509Data>
<ds:X509IssuerSerial>
<ds:X509IssuerName>CN=server</ds:X509IssuerName>
<ds:X509SerialNumber>-24583240032357195994117623470001087391</ds:X509SerialNumber>
</ds:X509IssuerSerial>
</ds:X509Data>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
<xenc:CipherData>
<xenc:CipherValue></xenc:CipherValue>
</xenc:CipherData>
<xenc:ReferenceList>
<xenc:DataReference URI="#_5008"/>
</xenc:ReferenceList>
</xenc:EncryptedKey>
<ds:Signature xmlns:ns10="http://www.w3.org/2003/05/soap-envelope" 
xmlns:ns11="http://docs.oasis-open.org/ws-sx/ws-secureconversation/200512" xmlns:ns12="http://schemas.xmlsoap.org/ws/2006/02/addressingidentity" Id="_1">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"&gt;
<exc14n:InclusiveNamespaces PrefixList="wsse S"/>
</ds:CanonicalizationMethod>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/&gt;
<ds:Reference URI="#_5002">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"&gt;
<exc14n:InclusiveNamespaces PrefixList="S"/>
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/&gt;
<ds:DigestValue>vtf9n+OcI1nT0exavD4/ZQy6jm8=</ds:DigestValue></ds:Reference>
<ds:Reference URI="#_5003">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"&gt;&lt;exc14n:InclusiveNamespaces PrefixList="S"/></ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/&gt;
<ds:DigestValue>
</ds:DigestValue>
</ds:Reference>
<ds:Reference URI="#_5004"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"&gt;
<exc14n:InclusiveNamespaces PrefixList="S"/>
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/&gt;
<ds:DigestValue></ds:DigestValue>
</ds:Reference>
<ds:Reference URI="#_5005"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"&gt;&lt;exc14n:InclusiveNamespaces PrefixList="S"/></ds:Transform></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/&gt;&lt;ds:DigestValue&gt;hn2umVvzokVW6dgXUzXcG00vfq8=&lt;/ds:DigestValue&gt;
</ds:Reference><ds:Reference URI="#_5006"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"&gt;&lt;exc14n:InclusiveNamespaces PrefixList="S"/>
</ds:Transform></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/&gt;
<ds:DigestValue>MIH/94A7R2iHn/und3ElJLRTWKY=</ds:DigestValue>
</ds:Reference><ds:Reference URI="#_3"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"&gt;
<exc14n:InclusiveNamespaces PrefixList="wsu wsse S"/></ds:Transform></ds:Transforms>
<ds:DigestMethodAlgorithm="http://www.w3.org/2000/09/xmldsig#sha1"/&gt;&lt;ds:DigestValue&gt;olcbTjCNnXuZ5eVR1glEWRJxQpw=&lt;/ds:DigestValue&gt;
</ds:Reference></ds:SignedInfo><ds:SignatureValue>
</ds:SignatureValue><ds:KeyInfo>
<wsse:SecurityTokenReference><wsse:Reference ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" URI="#uuid_e861f15d-dd66-4b05-b101-c9fed7feda38"/>
</wsse:SecurityTokenReference></ds:KeyInfo></ds:Signature>
</wsse:Security>
</S:Header>

And, while that doesn't exactly match the sample given to me by the .NET team, I think it that it is correct. However, I'm still getting an error when I call the .NET service. This is the error message that comes back in a SOAPFault from them:

System.Web.Services.Protocols.SoapHeaderException: Server unavailable, please try later ---> System.ApplicationException: WSE841: An error occured processing an outgoing fault response. ---> System.Web.Services.Protocols.SoapHeaderException: Microsoft.Web.Services3.Security.SecurityFault: The security token could not be authenticated or authorized ---> System.Security.SecurityException: WSE3003: The certificate's trust chain could not be verified. Please check if the certificate has been properly installed in the Trusted People Certificate store. Or you might want to set allowTestRoot configuration section to true if this is a test certificate.

So, I'm currently working with them to figure out why the certificate's trust chain can't be verified - I'm unclear on whether that particular issue is on my end or theirs. Any suggestions would be appreciated!

elduff
+1  A: 

After working on this for quite a while, our team of developers here has determined that we couldn't do this. We simply could not write a Metro(JAXWS-RI+WSIT) client that would correctly call & process a response from the .NET WSE 3.0 web service that used WS-Security. I wanted to write up our different approaches, though, for those who might try something like this in the future.

To recap: 1. Our first pass: WSE 3.0 web service with MutualCerticates11 Security (WS-Addressing, encryption, signing, secure conversation (ws-trust)). We reverse engineered a WS-Policy snippet to place in our local copy of the WSDL to hande this, but could not get the secure conversation initial handshake request to be accepted by WSE.

  1. Next, they downgraded to WSE 3.0 MutualCerticates10, as there is some chatter about it being 'more interoperable'. Again, we could not get the secure conversation handshake to work.

  2. We asked the .NET team to turn off the SecureConversation (WS-Trust) layer (the encyption & signature requirements where still there). Again, we reverse engineered the WS-Policy file (essentially, just removed the 'BootstrapPolicy' section that deals with WS-Trust/SC). At this point, we were able to send an encrypted, signed message to them, and they recieved it and sent a message back. We thought this was a victory, but unforunately, WSIT choked on their response message with a canonicalization error. At this point, I think we hit the limitations of WSIT, as it does not claim to be interoperable with WSE 3.0 (only WCF), so we talked to the WSIT guys on their forum and logged an issue with them. Here's that link.

  3. So, we concluded that it wouldn't be possible for the .NET team to leave the encryption/signature layer on (for the moment, anyway - the WSIT team may fix the bug at some point). From their side, you can't turn off just the signature and leave encryption, unfortunately.

  4. We also asked them to turn off the WS-Security settings on their (.NET) side completely, and at that point, were are able to send requests & receive responses from their service using JAXWS-RI just fine. However, they may not be able to deploy this way in production.

  5. So, now we are at the point where the .NET team must determine if they will be allowed to run the web service in production w/o the WS-Security settings. If not, then we will not be able to connect to their service until they upgrade to WCF. And, in fact, that has been our recommendation to them all along - that they upgrade to WCF - and now we're more familiar than we'd like to be about the reasons why!

elduff