Tuesday, June 14, 2011

Test drive the shiny new Wcf interop bindings

@YaronNaveh

wcf.codeplex.com is the place where most of the wcf action happens at these days. If you have been following it recently you have seen a lot of activity around Rest and Http. As of yesterday Soap officially joins the codepex party. Microsoft has just released the WCF Express Interop Bindings - a new Visual Studio extension for Soap web services interoperability. If you use Wcf this matters to you!

What did Microsoft release yesterday?

Web services interoperability is always a pain. When security is involved it is usualy more then a casual 'oouch'. Yes, WsHttpBinding has a specific permutation of settings which can interoperate with Oracle web logic. And I know a lot of people who have tried to find that permutation in a brute force manner. Mostly doing this is a waste of time which we prefer to invest in more productive areas.

So here's the idea behind yesterday's shipping: We now have a new binding, WebLogicBinding, which only allow us to configure settings which are interoperable with web logic. So all settings are interoperable! We also have bindings for web sphere, axis2 (wso2) and metro (wsit / glassfigh / tango).
In addition we got a nice wizard on top of Visual Studio's new project dialog which allows us to easily author interoperable services using these bindings.



But don't we already have WS-Policy for interoperability?

WS-Policy helps clients to generate proxies which complies with the service requirements as expressed by the Wsdl. The express bindings solves a prior problem: How to write from the first place a service which a specific client platform can support? Once we write such a service its Wsdl will contain the WS-Policy pixy dust so that the client can auto-configure itself.

Nice... I'll take two!
You can take four: MetroBinding, WebSphereBinding, WebLogicBinding and Wso2InteropBinding.
Take them from here.


Tutorial - WCF and Metro interop

Let's see why web services interoperability just got a whole lot easier.
We'll create a WCF service with mutual x.509 certificates in the message level and consume it with a Metro client.

1. Prepare the environment
You need VS 2010 and the express bindings. After you extract the bindings zip simply execute bin\Microsoft.ServiceModel.Interop.Extension.vsix which will install it on VS.


2. Create a new service

In VS create a new project. Note how the Wcf node now contains a new project type "Express Interop Wcf Service Application":


Choose that project type.

3. Configure the express binding wizard

A few moments after creating the project you will see the wizard.
First choose the platform our clients will use - Metro, this time.


Now we need to configure our security requirements. Choose "mutual certificate" which means both client and server will present an x.509 certificate in the message level. It also implies encryption and digital signature (in this case). To keep it simple we omit the secure conversation.


Next in the advanced settings use the Basic128 algorithm since it is the one Metro supports by default (for Basic256 a patch needs to be applied).


Finally configure the certificate.


I recommend to use this certificate (password: adminadmin):



Now run the service. This is a web site project so it will open the documentation page with the Wsdl link. Make sure to have the Wsdl url handy since we will use it in a moment.



Now we want to configure Metro.

1. Set up the environment

You should have NetBeans 7 (or higher), though NetBeans 6.7 also worked for me.


2. Create a new project of type Java Application:


Any of the default settings are fine:


3. Right click the package in the project view and add a new "web service client":


Now is a good time to paste that Wsdl url:


4. The service reference is now in the project view so right click it and edit the Web Service Attributes (similar to the Wcf configuration... just very different :):


5. This step is a workaround if your NetBeans version ships with Metro 2.0 (which is the case for NetBeans 7). See below how to know if you need it.

We can see that Metro had automatically identified that client and server certificates are required. This was due to the WS-Policy in the Wsdl.

Before we continue we need to do some trick. NetBeans 7 ships with Metro 2.0 which has a bug with certificates. In favor of those who reach this post via a search engine this is the error message:

java.lang.NullPointerException
...
at com.sun.xml.ws.security.impl.policy.CertificateRetriever.digestBST (CertificateRetriever.java:136)

To solve this you need to download Metro 2.1 (or higher). For now just extract it to some folder.

Now as part of this workaround check the "use development defaults" drop down in the quality attributes dialog you opened in step 4. Also approve any message you are prompt with.


Click Ok to close the dialog.

In the project pane expand the libraries node. It should look like this:


This workaround applies to version 2. If you see another version (even smaller) no need for this. What you need to do is delete all the references to Metro jar files (don't delete the jdk though). Instead of them right click the "libraries" node, choose "add jar/folder..." and choose the jar files in metro\bin folder from the metro 2.1 zip you just extracted. Add all jar files in that folder. The libraries node will now look like this:


6. We are now ready to do the actual configuration. Open again the web service quality attribute form as you did in step 4. Uncheck the "use development defaults" check box. Now configure the keystore and trust store. I recommend to use this java key store file:



Open "keystore..." and "Truststore.." each in its turn and do the below.
Set the path to the .jks file you extracted form the certificates file above, set the password to "adminadmin", and click "load alias". The alias for the key store is xws-security-client and for the trust store is xws-security-server.





7. Now we need to write the client code.

Since most of my readers are .Net developers let's see if we can pull this one out without any Java coding at all.

Drag the GetData node from the project pane to the main() method. It should now look like this (depending on the netbeans version):

public static void main(String[] args) {

  try { // Call Web Service Operation
     org.tempuri.Service service = new org.tempuri.Service();
     org.tempuri.IService port = service.getMetroBindingIService();
     // TODO initialize WS operation arguments here
     java.lang.Integer value = Integer.valueOf(0);
     // TODO process result here
     java.lang.String result = port.getData(value);
     System.out.println("Result = "+result);
  }
 catch (Exception ex) {

  }

}


if you use Netbeans 7 it will only generate a method so you would need to add code that calls it:

public static void main(String[] args) {
  try
  {
     String s = getData(2);
     System.out.println("result is" + s);
  } catch (Exception ex) {
     System.out.println(ex.getMessage() + ex.getStackTrace().toString());
  }
}

private static String getData(java.lang.Integer value) {
   org.tempuri.Service service = new org.tempuri.Service();
   org.tempuri.IService port = service.getMetroBindingIService();
   return port.getData(value);
}
}

7. Now run the application (F6).

Here is the output:

the result is: 2


Web services interoperability was never easier!

@YaronNaveh

What's next? get this blog rss updates or register for mail updates!

44 comments:

Pablo Cibraro said...

Great post Yaron!!. Good work putting all this together as usual. Thanks!!

scott_m said...

In our case, we have a wcf relying party that uses ws2007FederationHttpBinding and a token issuer uses ws2007FederationHttpBinding (token as credential) and ws2007HttpBinding (username/pwd as credential). How do we make those interoperable?

Using .NET 4.0, Microsoft W.I.F.


thanks

Yaron Naveh (MVP) said...

@scott - if you look for concrete guidance here are two good ones by Jesus Rodriguez:

Wcf & WebLogic federation:

http://msdn.microsoft.com/en-us/netframework/gg413253.aspx


Wcf & WebSphere federation:

http://msdn.microsoft.com/en-us/netframework/gg413262.aspx

There is nothing in your configuration which prevents interoperability, though due to the richness of the underlying ws-* standards you might need to fine tune some settings, depending on the platforms you need to interoperate with.

Yaron Naveh (MVP) said...

@Pablo - Thanks!

Spaceman Spiff said...

Good job Yaron! Very interesting. Thank you. Tom

Kennyboy666 said...

Hello Yaron.

First, let me say congratulations on MVP.

I have tried to follow you guide step- by step, But i cant get it to
work no matter what i do.

At least one security token in the message could not be validated.

Is this an error in the certificate?

Yaron Naveh (MVP) said...

Hi Kenny

Do you get this error from the WCF side? Turn on wcf log and trace to see exactly what is the error message.

Try to use the certificates from this post as it can be the issue.

Yaron

Anonymous said...

thanks for this post.i got the same error:At least one security token in the message could not be validated.
in netbeans,now after all trials its my dream to see that a java client webservice runs without a bug.

Anonymous said...

thanks for this great post.but i got the same error in netbeans:At least one security token in the message could not be validated.
i dont really know how can i resolve this.

Yaron Naveh (MVP) said...

Hi مرد مرده

Did you use the certificates I published here?

I suggest you turn on wcf tracde and log to see additional error message, and also if any response came back at all.

Anonymous said...

im back,here is my stack elements:
At least one security token in the message could not be validated.
com.sun.xml.ws.fault.SOAP12Fault.getProtocolException(SOAP12Fault.java:229)
com.sun.xml.ws.fault.SOAPFaultBuilder.createException(SOAPFaultBuilder.java:126)
com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:123)
com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:93)
com.sun.xml.ws.client.sei.SEIStub.invoke(SEIStub.java:144)
$Proxy40.getData(Unknown Source)
javaapplication15.JavaApplication15.getData(JavaApplication15.java:34)
javaapplication15.JavaApplication15.main(JavaApplication15.java:19)

i got my certificate all setup,and its been running by iis,i got this issue and im totally trapped,any help would be much appreciated.thanks.

Anonymous said...

and at last :
System.IdentityModel.Tokens.SecurityTokenValidationException, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

Anonymous said...

and the error message is:

The X.509 certificate CN=localhost chain building failed. The certificate that was used has a trust chain that cannot be verified. Replace the certificate or change the certificateValidationMode. A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider.

Anonymous said...

finally i used ur certificates and i got that "The EncryptedKey clause was not wrapped with the required encryption tokenmessage" u already posted about that it is because the certificates are not match.
i really did exactly what u told and showed in ur post.plz take a time to see what is wrong in the ur post plzzzz...im on a real hard deadline for my WSIT project.really thanks.

Anonymous said...

sorry i was wrong in my last comment,now i did all the things u said and i got this message in wcf trace:

The X.509 certificate CN=xwssecurityclient, OU=SUN, O=Internet Widgits Pty Ltd, S=Some-State, C=AU chain building failed. The certificate that was used has a trust chain that cannot be verified. Replace the certificate or change the certificateValidationMode. A certificate chain could not be built to a trusted root authority.

this causes an exception in netbeans:At least one security token in the message could not be validated.

i have imported xwssecurityclient.pfx into currentuser/personal/certificates and also into xwssecurityclient.pfx into currentuser/trustedpeople/certificates

sorry about all this intruption.

Yaron Naveh (MVP) said...

in this scenario there should be one message outgoing from wcf to metro and one from metro to wcf. does wcf send this message? does metro receive it? does metro sends back a correct response?

Make sure your wcf side has certificateValidationMode="None" (just for testing)

ems9tech said...

Yaron, great post!

I'm struggling with this exact same scenario. My WCF 4.0 service is running inside IIS 6 and we could also use IIS 7.

The client is running Metro inside of IBM Websphere!~@).

Our client told me this: our web framework is developed exclusively using IBM WebSphere. So I have deployed the Metro stack into our IBM WebSphere (and Eclipse) environments....which had many side effects, including the need to disable the IBM web services stack in order to make Metro work.

Anyway, after creating the binding with the MS extension tool, I see the underlined in red in VS and an error:

The element 'bindings' has invalid child element 'metroBinding'. List of possible elements expected: lists all valid binding types... Does this matter at run-time? I also can't pull up the config in the Service Config Editor.

Also, currently I am using one of your custom bindings with success for my .Net client. We have a SSL site and using Username in clear text. Should I use the binding created by the MS tool or convert it back to a custom binding?

Thanks!

Yaron Naveh (MVP) said...

Hi ems9tech

the red line in VS is not really important, this is just an IDE issue.

When you actually try to receive a message from the client what error you get? How does the message look like?

ems9tech said...

Thanks Yaron, OK, I was able to get the web.config on the server

The error he gets is:

[10/18/11 14:56:18:172 EDT] 00000025 secconv 1 WSSC1009:Generating RST send request message: http://schemas.xmlsoap.org/ws/2005/02/sc/scthttp://schemas.xmlsoap.org/ws/2005/02/trust/IssueSMguSHUy5IpyfuHBk31pvljXdDhZvdfEk0ZtSDjkrr0=256http://schemas.xmlsoap.org/ws/2005/02/trust/SymmetricKeyhttp://schemas.xmlsoap.org/ws/2005/02/trust/CK/PSHA1.


[10/18/11 14:56:18:659 EDT] 00000025 secconv 1 WSSC1012:Received RSTR for Issue:http://schemas.xmlsoap.org/ws/2005/02/sc/scturn:uuid:98849589-a7f9-430a-86c6-a92de634f36ahttp://schemas.xmlsoap.org/ws/2005/02/trust/CK/PSHA15YJa4eIxm7cUdx63EBC2dcpiWWofpy8CK2vAIx69wMU=2011-10-18T18:56:18.556Z2011-10-19T09:56:18.556Z256.


[10/18/11 14:56:18:957 EDT] 00000025 SystemOut O 14:56:18,956 FATAL GenericWorker run javax.xml.ws.soap.SOAPFaultException: The message could not be processed. This is most likely because the action 'https://www.upmchp.com/CORETransactions/RealTimeTransaction' is incorrect or because the message contains an invalid or expired security context token or because there is a mismatch between bindings. The security context token would be invalid if the service aborted the channel due to inactivity. To prevent the service from aborting idle sessions prematurely increase the Receive timeout on the service endpoint's binding.
at com.sun.xml.ws.fault.SOAP12Fault.getProtocolException(SOAP12Fault.java:229)....

With the metroBinding, I get this error: Could not find a base address that matches scheme http for the endpoint with binding metroBinding. Registered base address schemes are [https].

Does the MetroBinding use http under the covers?

Raj said...

how to generate the Client and server certificates?
When I use SelfSigned Certificates and exported as .pfx and deployed in Localmachine - all fine but when I see details of certificates - it shows an Error mark.

Yaron Naveh (MVP) said...

Raj

Self signed certificates are not trusted by default. You should get a certificate from a certificate authority that you trust, or create your own authority and put its cert in the trusted root store. You can also put the self signed cert there to make it trusted

Virendra Mishra said...

If you have followed the steps as described in the bolg and used the same certificate and getting the following error - "At least one security token in the message could not be validated"

Try importing the client pfx file in the Trusted People store of the CurrentUser

It should work.

Virendra Mishra said...

Also I forgot to mention that for it to work you will have to modify the server config file and in tag after definition add following

Raj said...

Hi Yaron,
Thanks for your response.
I am currently testing at my DEV, so when it goes to UAT or PRD I can raise request to get it. between How to Generate it?
As you mentioned:
"create your own authority and put its cert in the trusted root store"

Can you send me a link or any steps would be a gr8 help.

Yaron Naveh (MVP) said...

Raj

Why does the error mark matters? You can configure your application not to do validations while testing. in WCF this is certificateValidationMode="None", see here:

http://stackoverflow.com/questions/338385/how-do-i-tell-wcf-to-skip-verification-of-the-certificate

jmdesp said...

The words "brute forcing" the correct settings really hit a string. I'm currently trying hard to make WCF interop with some jboss based WS Service implementation, but no success until now.
It needs mutually signed (not encrypted) message on an SSL connexion.

I'm stuck on the following :
- If I set Message protection, my message are encrypted which I don't want : ProtectionLevel.Sign seems to be set on the interface, but my interface is auto-generated from the WSDL and I don't want to change the generated code. So how do I change it on the custom binding instead ?
- What's more if I set Message protection, the binding refuses a https URL. Is there a way to override that ? I tried to use a local stunnel, but it's not a great solution
- If I set CertificateOverTransport, the returned message is signed and I get the error "Cannot find a token authenticator for the 'System.IdentityModel.Tokens.X509SecurityToken' token type. Tokens of that type cannot be accepted according to current security settings.".
But allowSerializedSigningTokenOnReply changes nothing, I still have the error. Maybe I can just write a custom message encoder to remove that header, but I don't really like the option (and would like to find some code sample if I decide to do it).

Yaron Naveh (MVP) said...

Hi jmdesp

First let's make it work by changing the generated code, then we'll optimize it :)

the message protection should not affect the ssl setting, in particular you are always allowed to be more secured than the setting. make sure you have httpsTransport in your custom binding.

In most cases "MutualCertificate" is the way to go.

You can send me in a mail a sample request / response envelope and your current setting.

jmdesp said...

Thanks you for the answer that's encouraged me to try some more, although it's not our top priority so I can't spend too much time on it.

The exchange works in MutualCertificate mode, by adding a node

to the binding and also


However I'm stuck again !
The value of the endpoint gets used to verify both the SSL certificate, and the one that signs the response, and it's not the same name. If I put a dns value to match the SSL cert, it fails when verifying the answer, and if I put the name of the signature cert in it, it fails when verifying the identity at the SSL level.
I could send you the settings, and request/response, but I'm not sure it brings much at this stage, I believe you already have the important info, WS Security with mutual certificates and signature only, and HTTPS with a different certificate.

Yaron Naveh (MVP) said...

jmdesp

you should set the dns to match the messgae level certificate name. then implement ssl validation like this:

http://webservices20.blogspot.com/2008/12/wcf-gotcha-disabling-ssl-validation.html

another option is for you to decide that validating the response in the message level does not matter and then you can set enableUnsecuredResponse="true" and strip the security in a custom encoder.

A third option is to implement a schem for separate message and transport certificates:

http://blogesh.wordpress.com/2009/10/08/separate-certificates-for-transport-and-message-security-in-wcf/

that article is server focused but you could easily migrate it to the client

jmdesp said...

Finally ! This works.

To sum up :
- Switch to custom binding, using settings compatibles with BasicHttpBinding (your online converter is useful there)
- Set MutualCertificate authentication mode
- Set https transport <httpsTransport requireClientCertificate="false" />
- Set signature only <context protectionLevel="Sign" />
- Set the <identity> node of the endpoint to the identity used in message signature
- Disable globally the SSL server certificate name verification by modifying the ServicePointManager.ServerCertificateValidationCallback implementation

Yaron Naveh (MVP) said...

great news!

JyotiBox said...

great it is working.
I need some technical support to consume oracle web logic web service which is hosted at client side and our environment is Microsoft .net .
I have used WSE 3.0 or wcf to consume the service but the result is failure .
The weblogic service security is maintained with user token and x509 certificate
The webservice link is http://XXX.XXX.XXX.XX/MMS/MMSService?wsdl and the client provides me the client code how they are consuming their service in weblogic environment .

Please help me any type of compatibility or inter operability between .net and oracle weblogic service as per link.
http://docs.oracle.com/cd/E12839_01/web.1111/e13759/interop.htm#BABFCJCD[^]
and client code like http://stackoverflow.com/questions/11823849/consume-java-weblogic-web-service-having-usernametoken-and-client-certificate-in[^]

Yaron Naveh (MVP) said...

jyoti

please send me a sample working soap request for this service (with security)

JyotiBox said...

hi thanks for your responce i have sent you a mail about all credentials and .jks certificate to consume service.

Keith said...

Your example on how to use Netbeans/Metro was great. Its saved me a lot of headaches. I tried to use what I'd learned on a real world WCF webservice and I came across an issue that when calling a method and the body had a \r\n in it an exception was thrown. With the \r in the body Metro and .NET were computing different digests. Has anyone come across this? Can I deal with it on the Java Client side, or is it the .NET web services responsibility?

Thanks.

Yaron Naveh (MVP) said...

Keith

This sounds like a bug in one of the frameworks. If you can deal with it on the client side (remove the line breaks) it is best.

Keith said...

In regards to my earlier post regarding exceptions thrown when a \r is in the message body (SEVERE: WSS1717: Error occurred while doing digest verification of body/payload)it looks to be a known Metro client WCF service issue. Unfortunitely from what I've been finding on the web its WCF's fault(or so the Java people claim). Is there any way to ignore the exception? ie. Ignore the digests not matching up?

Yaron Naveh (MVP) said...

Keith

Do you have a link that says it is WCF fault?

You cannot customize the way Wcf handles signatures. Assuming the message is only signed and not encrypted, you coul tell Wcf to ignore the signature all together, and then either do the validation yourself or decide not to do it.

Keith said...

Here is a couple of sites that explain the problem:

http://www.java.net/node/689103

http://javakenai-dev.cognisync.net/forum/topic/glassfish/metro-and-jaxb/wsit-and-wcf-interop-issue-different-digest-same-text-0

Regards
Keith

Yaron Naveh (MVP) said...

maybe you can replace the \r\n values in the body with some other char, and put them back in the server. Otherwise the only way I see is to turn off security in the wcf side all together and do the validaiton yourself or not do it.

Keith said...

I've reported to problem to the owner of the web service. The other clients for this service are all .Net so of course they don't have any problems. Shame there isn't some setting to ignore whether or not the digests match up on the client side.

Thanks for your help.

Keith

BALAJI VEERARAGHAVAN said...

Can this WCF Interop be done with .Net framework 3.5/VS 2008?

Thanks
BV

Yaron Naveh (MVP) said...

In .net 3.5 you could use custom binding

worrywort said...

Your tutorial really helped me. Thanks so much!!!