Friday, July 1, 2011

I'm an MVP (again!)

@YaronNaveh

I guess I can skip the traditional email quote by now. I just got the 2011 MVP award in Connected System Developer. Becoming an MVP last year was the beginning of a very interesting year. I'm super exited to get this award for the second time. I'll do my best to justify this recognition.

@YaronNaveh

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

Saturday, June 18, 2011

Binding Box now supprots the Wcf Interop Bindings

@YaronNaveh

Earlier this week Microsoft had released the Wcf Interop Bindings and VS extension. You can download and try it from here.

Today I am proud to announce that the Wcf Binding Box supports these interoperability bindings.



What is the Wcf Binding Box?
It is an online bindings converter. You give it a binding configuration (e.g. WSHttpBinding) and it returns an equivalent custom binding.

Full explanation is here.

Why do we need it?
Because it's fun :) And also allows to take a working WSHttpBinding and further customize it with settings which it does not directly expose, for example MaxClockSkew.

How the interop bindings relate to this?
Suppose you use the interop bindings to author a Wcf service which WebLogic consumes. You may want to further configure your Wcf service with settings that the WebLogicBinding does not expose. Since the WebLogicBinding internally inherits from WSHttpBinding this is a similar use case to the original purpose of the binding box.

Example

Put this WebSphere binding as the input in the binding box:

<bindings>
   <webSphereBinding>
     <binding name="interopBinding" messageEncoding="Text">
       <security mode="MutualCertificate" establishSecurityContext="true" algorithmSuite="TripleDes" />
     </binding>
   </webSphereBinding>
</bindings>

and this is the custom binding output:


<customBinding>
   <binding name="NewBinding0">
     <transactionFlow transactionProtocol="WSAtomicTransaction11" />
     <security authenticationMode="SecureConversation" algorithmSuite="TripleDes" messageSecurityVersion="WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10">
       <secureConversationBootstrap authenticationMode="MutualCertificate" requireSignatureConfirmation="true" algorithmSuite="TripleDes" messageSecurityVersion="WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10" requireDerivedKeys="false" />
     </security>
     <textMessageEncoding />
     <httpTransport />
   </binding>
</customBinding>

Check out the binding box here.

@YaronNaveh

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

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!

Sunday, May 8, 2011

Cannot resolve KeyInfo for unwrapping key

@YaronNaveh

With web services sometimes your client is able to receive a good response from the server but your client will still throw exception due to some policy violation. With wcf / mutual authentication the following error can appear:


Cannot resolve KeyInfo for unwrapping key: KeyInfo 'SecurityKeyIdentifier
(
IsReadOnly = False,
Count = 1,
Clause[0] = X509IssuerSerialKeyIdentifierClause(Issuer = 'CN=MyCert', Serial = '-903515464456238801534567116928')
)
', available tokens 'SecurityTokenResolver
(
TokenCount = 0,
)

This error usually means that the server had digitally signed its response using an unexpected certificate. The expected certificate is the one which the client has configured as the server certificate and have possibly used to encrypt the message with.

So as with many of the security interoperability problems, you should verify that you use the correct certificate on both sides of the wire.

@YaronNaveh

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

Anyone else having problems with Google Calendar?

@YaronNaveh

Update (july 11): Fixed!

I'll start by saying that google calendar is a great product which I was happy to use for quite a while. Not any more, it seams. For some reason I intermittently don't get email notifications about scheduled events. I have first noticed that over a year ago and assumed it is a one off glitch. I have then noticed it in many more occasions and since last week I don't get notifications at all.

I mainly use gcal as a "send myself a future email reminder" application. While it does not contain any important appointments, I do have there information about birthdays, random arrangements, sites without rss which I periodically visit etc. And while managing to live without these unsent reminders makes me wonder if I had ever needed them anyway, it is still annoying.

This issue appears in several gcal forum threads, has a special troubleshooting page, and is actually a known issue. The last link says "We're currently investigating reports from users who indicate that they're not receiving email notifications for their events". How many users? What is the current status?

Just out of curiosity - does anyone else experience missing email notifications from google calendar?

@YaronNaveh

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

Friday, May 6, 2011

Wcf with WS-Addressing March 2004

@YaronNaveh

Wcf supports two WS-Addressing versions – the August 2004 draft and the actual standard v 1.0. There is another wsa version which is used by some soap stacks (who said wse 2?) – the march 2004 draft. To turn this fact to a more practical  problem, you might need to write a wcf client to a (non Wcf) service which expects a request like this:

<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/03/addressing">

 
<Header>

   
<wsa:Action>http://myAction</wsa:Action>
   
<wsa:MessageID>uuid:5024616c-d0r2-56h3-bjj7-ab10p89eee63</wsa:MessageID>
   
<wsa:ReplyTo>
     
<wsa:Address>http://schemas.xmlsoap.org/ws/2004/03/addressing/role/anonymous</wsa:Address>
   
</wsa:ReplyTo>
   
<wsa:To>http://server/Calc</wsa:To>
...

(note the bold wsa version – wcf cannot emit it).

One straight forward way to do this with wcf is to push these headers to the soap using a message inspector. But what if you also need to sign the wsa headers with a digital signature?

In this case you need to write a custom behavior which push the wsa headers to the IncomingSignatureParts property. The whole code looks like this:
 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Security;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using MyApplication.ServiceReference1;

namespace MyApplication
{

   
public class SignMessageHeaderBehavior : Attribute, IEndpointBehavior
   
{

       
string action;

       
List<XmlQualifiedName> headers;



       
public SignMessageHeaderBehavior(List<XmlQualifiedName> headers, string action)
       
{

           
this.headers = headers;            

           
this.action = action;

       
}

       
public void Validate(ServiceEndpoint endpoint)
       
{

       
}

       
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
       
{
           
var requirements = bindingParameters.Find<ChannelProtectionRequirements>();

           
foreach (var h in headers)
           
{                
               
var part = new MessagePartSpecification(h);
               
requirements.IncomingSignatureParts.AddParts(part, action);
           
}
       
}

       
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
       
{

       
}

       
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
       
{

           
clientRuntime.MessageInspectors.Add(new AddHeaderMessageInspector());

       
}

   
}

   
[DataContract(Namespace="http://schemas.xmlsoap.org/ws/2004/03/addressing")]
   
public class ReplyToHeader
   
{        
       
[DataMember]
       
public string Address { get; set; }
   
}


   
public class AddHeaderMessageInspector : IClientMessageInspector
   
{

       
public object BeforeSendRequest(ref Message request, IClientChannel channel)
       
{

           
request.Headers.Add(MessageHeader.CreateHeader("Action", "http://schemas.xmlsoap.org/ws/2004/03/addressing", "http://myAction"));
           
request.Headers.Add(MessageHeader.CreateHeader("MessageID", "http://schemas.xmlsoap.org/ws/2004/03/addressing", "uuid:5024616c-d0r2-56h3-bjj7-ab10p89eee63"));
           
request.Headers.Add(MessageHeader.CreateHeader("ReplyTo", "http://schemas.xmlsoap.org/ws/2004/03/addressing", new ReplyToHeader() { Address = "http://schemas.xmlsoap.org/ws/2004/03/addressing/role/anonymous" }));
           
request.Headers.Add(MessageHeader.CreateHeader("To", "http://schemas.xmlsoap.org/ws/2004/03/addressing", "http://server/Calc"));
            

           
return request;

       
}

       
public void AfterReceiveReply(ref Message reply, object correlationState)
       
{

       
}

   
}

   
class Program
   
{

       
static void Main(string[] args)
       
{

           
var c = new SimpleServiceSoapClient();

           
var headers = new List<XmlQualifiedName>();
           
headers.Add(new XmlQualifiedName("Action", "http://schemas.xmlsoap.org/ws/2004/03/addressing"));
           
headers.Add(new XmlQualifiedName("MessageID", "http://schemas.xmlsoap.org/ws/2004/03/addressing"));
           
headers.Add(new XmlQualifiedName("ReplyTo", "http://schemas.xmlsoap.org/ws/2004/03/addressing"));
           
headers.Add(new XmlQualifiedName("To", "http://schemas.xmlsoap.org/ws/2004/03/addressing"));

          
c.Endpoint.Behaviors.Add(
               
new SignMessageHeaderBehavior(headers, "http://tempuri.org/EchoString"));

           
c.EchoString("123");

       
}
   
}
}

@YaronNaveh

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

Saturday, April 23, 2011

svcutil.exe with a wsdl on the local disk

@YaronNaveh

svcutil.exe is a command line to generate wcf proxies from wsdl files (and more).

for example the following command:

$> svcutil http://localhost/MyServices/Service.svc?WSDL

will generate Service.cs which is the proxy you can add to your project.

Sometimes the wsdl file is not on a url but on the local disk. In theory this should work:

$> svcutil c:\services\calc.wsdl

In practice this would work only if the wsdl does not reference other wsdl or xsd files (even if their relative reference is correct). The same would work with "add service reference" in VS so not sure why it fails here. One solution is to explicitly specify all the referenced schema files in the command:

$> svcutil" c:\services\calc.wsdl" "c:\person.xsd c:\units.xsd"

This usually works but requires manual work and is not always desired when a large number of references is used.

An alternative would be to upload the wsdl and the references to a web server and svcutil from there. If you have iis on your dev machine this is actually pretty simple:

1. copy the wsdl root folder to a subfolder under c:\inetpub\wwwroot
2. run

$> svcutil http://localhost/root/calc.wsdl

That's all, no need to specify all files. svcutil works well from url locations. Do not forget to remove the wsdl folder after so your iis folder would stay clean.

@YaronNaveh

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

Friday, April 22, 2011

...and, we're back!

@YaronNaveh

This post violates at least 4 of the blogging cliches. Read at your own risk!

You might have noticed I've disappeared for a while. The reason is that I have been practically leaving on an airplane in the last two months beeing over 80 hours in flights.

In early march I have visited Redmond for the MVP global summit. I've met people which so far I've only seen in the cover of their books. I've met some of my favorite bloggers and readers. And even though I'm a Connected Systems MVP I took a picture with the Biztalk MVP's (thanks to leonid who took the photo):


I have then visited customers in many states in the US. I never regretted for taking that extra coat and clothes because some places were damn cold! Still I had a lot of fun, met some super smart people, and also had time to visit beautiful places:



Shortly after I came back home I got my 5th star in the MSDN forums:


I'm very proud for being able to help so many people. I am going to continue and participate in these forums not only because I love to help but also since I learn a lot on the way.

@YaronNaveh

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

Friday, February 25, 2011

More lessons learned on Windows Azure pricing

@YaronNaveh

My Bart Simpson's guide to windows Azure has been highly successful. From Twitter to the post comments to my mail box I got a lot of good feedback.

Here are some insights you might want to know:

Extra small instances might not be included in your free Azure account.
David Pallmann was the first to notice that some of the special Azure offers (like the MSDN one) actually have some small letters:

**Extra small compute instances are available in beta and are billed separately from other compute instance sizes.

This practically means you pay for these instances from day 1! Here is my account:


So you should check your account details and determine if extra small instances work for you.

I also recommend you check out David's Hidden Costs in the Cloud series which has some important insights.

Hot news: Azure trial with extra small instances
A few days ago Microsoft has started to offer an introductory offer which includes 750 free monthly hours of x-small instances (until June). Check it out.

Also thanks to David Makogon I've fixed an error in the config sample to configure extra small instances.

@YaronNaveh

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

Saturday, February 19, 2011

Bart Simpson's guide to Windows Azure

@YaronNaveh

The original name of this post was "a poor developer's guide to windows azure" but then I found the Bart Simpson's Chalkboard Generator:


My Azure story begins back in PDC08 where Microsoft announced a community preview of Windows Azure which includes a free subscription for a limited period. I took advantage of this to develop the Wcf binding box (which btw got some good reviews). A few months after, the preview has ended and my account became read only. I was not too bothered by it as I had other things in mind. A few weeks ago I had a crazy idea to build a wsdl2-->wsdl1 converter. The most natural way to do it was to create an online service. But my azure trial is already in freeze, and I did not want to pay a hosting service just to host a free contribution I make for the community. What could I do? I then remembered that I (and my contest winners) have a special MSDN premium Azure offer. And this is how wsdl2wsdl came to life. Veni, vidi, vici? Oh my...

A few days after going on air I get this email from Microsoft:

Your Windows Azure Platform Usage Estimate - 75% of Base Units Consumed‏

This e-mail notification comes to you as a courtesy to update you on your Windows Azure platform usage. Our records indicate that your subscription has exceeded 75% of the compute hours amount included with your offer for your current billing period. Any hours in excess of the amount included with your offer will be charged at standard rates.

Total Consumed*: 592.000000 Compute Hours
Amount included with your offer: 750 Compute Hours
Amount over (under) your monthly average: -158.000000 Compute Hours


Let's see... I should get 750 compute hours / month, a month has 31 days (a worse case analyses), 750 / 31 > 24 which means I should have more than 24 complimentary compute hours per day. How could they run out so fast?


Bart Simpson's Azure Rule #1:


As a developer, it made too much sense to develop the binding box and wsdl2wsdl in a separate visual studio solutions. This yields two separate azure hosted services:


And this yields two separate bill items per day:


This means I was not paying for 24 compute hours per day, I was paying 24*2!


Now you may say RTFM. But nobody does it. Not when we download some open source library from the web, and not when we upload something in the other direction.

But why did the bill had 4 itmes and not two?


Bart Simpson's Azure Rule #2:


Not only did I had two hosted services online, but I also had two environments for each - staging and deployment. You pay for what you get:

2 services * 2 deployments = 4 * 24 hours a day = 96 hours a day!


Bart Simpson's Azure Rule #3:


I was on my way to a Chapter 11 when I decided to panically press the stop button on my unintended deployments:


However this does not reduce costs:

Suspending your deployment will still result in charges because the compute instances are allocated to you and cannot be allocated to another customer.

Remember: Always delete deployments you do not want to pay for. Suspending / stopping them still results in charges.


Bart Simpson's Azure Rule #4:


For applications with very small needs an extra small instance should be enough. It can save you costs by up to 60%! Configuring it is very easy:

<WebRole name="WebRole1" vmsize="ExtraSmall">


Conclusion

Homer Simpson once said "Trying is the first step towards failure." In my case it was the first step to this blog post and to my first two weeks Azure bill:


I'll end the month on around 50$ which is not too bad for a commercial site. But for a contribution to the community and my fun? Oh my...

Weather you are an independent developer or a Fortune 5000 company - know the Azure pricing model and how your account fits in.

@YaronNaveh

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

Sunday, February 13, 2011

Wcf: Keyset does not exist

@YaronNaveh

When using X.509 certificates with Wcf the below error may appear:

System.Security.Cryptography.CryptographicException: Keyset does not exist
ArgumentException: The certificate 'CN=MyCert' must have a private key that is capable of key exchange. The process must have access rights for the private key.

95% of the time this means that the certificate which the server/client use either does not have a private key or the Wcf host process does not have permissions to the key.

No private key
This case applies when the certificate is expected to have a private key, e.g. the server private certificate when defined on the server side, and not the server public when defined on the client. To check if the certificate has a private key follow these steps:

1. start-->run-->"mmc"

2. file-->add remove snap in...

3. double click "certificates" in the list

4. Choose "My user account" if the certificate is located in the current user store, or "Computer account" if located on the local machine store. If you are unsure you can repeat the process twice each time with a different choice.

5. click Finish + Ok

6. now expand the tree to the correct store and when you see the certificate double click it. Then check if it has the little key icon on it. If it does not then you did not import it with its private key (or got the wrong cert).


No permissions
Even if the certificate has a private key, it still does not mean all users on the machine have access to it. One common gotcha is to give access to the admin (or logged in user) but forget that IIS usually runs under another user account. This may cause a code to work correctly under an interactive user but to fail under IIS or any windows service. One way to check if this is the case is אם give the user full permissions to the key (temporarily!).

How to give permissions to a key?
the hard way is using WinHttpCertCfg.exe (details ,download):

winhttpcertcfg -g -c LOCAL_MACHINE\My -s CN=WSE2QuickStartServer -a SomeUser

Another way is using some gui utility and WseCertificate2.exe is a good one:

1. install the Wse2 sdk

2. run C:\Program Files\Microsoft WSE\v2.0\Tools\Certificates\WseCertificate2.exe

3. choose the certificate using the location / store drop down lists and the "open certificate" button.

4. click the "view private key file properties..." button on the bottom.

5. depending on your OS version, grant permissions for the user you want.


If all this did not help ten make sure that when have you installed the certificate you checked the "mark this key as exportable" checkbox:


Sometimes these permissions are cached so you can also restart IIS (and maybe even the PC). And as always with certificate, when you're already pulling out your hair it's time to uninstall all certificates and start all over again.

@YaronNaveh

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

Saturday, February 12, 2011

Wcf support for Wsdl2

@YaronNaveh

Last time I introduced wsdl2wsdl, an online wsdl2-->wsdl1 converter.
Today I am proud to announce svcutil2 - a Wcf proxy generator for Wsdl2. svcutil2, like the original svcutil, generates Wcf proxies from Wsdl2 documents. This is a huge accelerator for web services interoperability. See related discussion here.

svcutil2 is fully open sourced in CodePlex.

How to generate Wcf clients from Wsdl2 documents?
1. Download the latest version of svcutil2.exe from CodePlex

2. Open the VS command console or otherwise make sure the original svcutil.exe is in the current path (usually located in C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin)

3. Use svcutil2 exactly like you use svcutil:

$> svcutil2.exe http://webservices20.cloudapp.net/wsdl2wsdl/wsdl/simple2.wsdl

you can also work with Wsdl's from file system or use any of the svcutil available flags.

@YaronNaveh

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

Saturday, February 5, 2011

Downgrade! Convert Wsdl 2.0 to Wsdl 1.1 (Wsdl2Wsdl)

@YaronNaveh


Wsdl2Wsdl is Here!

Wsdl 2.0 never fulfilled its promises: It did not replace Wsdl 1.1 and soap stacks rarely support it. It did not became the Metadata standard for Rest based web services. And in an era where a service metadata can be summed up with a resource uri, Wsdl 2.0 is barely looked at as a simplification. All this is hardly Wsdl 2.0 fault. It's the timing. The backlash against Soap/Wsdl based services was far behind its point of no return in the period where Wsdl 2.0 was expected to get high adoption. It is not too risky to bet that Wsdl 2.0 will never be implemented by existing soap stacks, and Wcf is no exception.

And the sky is blue. So?
While service authors may elegantly ignore Wsdl 2, if you're on the consumer side you might need to consume a service which metadata is a Wsdl 2 document. Most chances are that your client stack does not support code generation from this version of Wsdl. This is an annoying interoperability problem.

Wsdl2Wsdl
I have written an online Wsdl 2 --> Wsdl 1 converter. While there are a number of Wsdl1 --> Wsdl 2 converters available, I have yet to find one in the opposite direction.
Wsdl2Wsdl provides you a url which dynamically converts the Wsdl per demand. This means you always get the live version of the wsdl.


Can I run Wsdl2Wsdl on my premise?
The current version of Wsdl2Wsdl is web based so if your Wsdl has some secrets / IP you should take this into consideration. I plan to open source it and ship an on premise version. You are welcome to contact me if you need this urgently.

Where is Wsdl2Wsdl?
It's hosted on my Azure account:

http://webservices20.cloudapp.net/wsdl2wsdl.html

Drop me a mail with any issue or feedback.

@YaronNaveh

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

Wednesday, February 2, 2011

Utility to export X.509 certificates

@YaronNaveh

The number of X.509 formats \ stores can be overwhelming: pfx, p12, pem, jks, windows store and more. When working on multi platform projects exporting the certificate from one format \ store to the other is essential. Traditionally the way to do it was with openssl. While there is nothing wrong with that, you usually forget how to use it a minute after you do, and need to learn it again the next time.

Over a year ago travis had published a super relevant utility to export certificates. It is really easy to use and prevents that recurring learning curve with openssl.

@YaronNaveh

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

Sunday, January 30, 2011

Xml Digital Signature: Signing the KeyInfo

@YaronNaveh

Frederic Vidal had shown me recently a nice trick with Xml digital signatures. Suppose you want to add a signature which looks like this:

<ds:Signature xmlns:ds='http://www.w3.org/2000/09/xmldsig#' Id='Signature001'>
   <ds:SignedInfo>
     <ds:CanonicalizationMethod Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315' />
     <ds:SignatureMethod Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1' />
     <ds:Reference URI=''>
       <ds:Transforms>
         <ds:Transform Algorithm='http://www.w3.org/2000/09/xmldsig#enveloped-signature' />
       </ds:Transforms>
       <ds:DigestMethod Algorithm='http://www.w3.org/2000/09/xmldsig#sha1' />
       <ds:DigestValue>sXe2PnaG...</ds:DigestValue>
     </ds:Reference>
     <ds:Reference URI='#KeyInfo001'>
       <ds:DigestMethod Algorithm='http://www.w3.org/2000/09/xmldsig#sha1' />
       <ds:DigestValue>ZOS23PQ9TcDu+G...</ds:DigestValue>
     </ds:Reference>
   </ds:SignedInfo>
   <ds:SignatureValue>jTLX0/8XkY2aCte7...</ds:SignatureValue>
     <ds:KeyInfo Id='KeyInfo001'>
       <ds:X509Data>
         <ds:X509Certificate>E3wdSY4n7MgUmJzMIGfMA0...</ds:X509Certificate>
     </ds:X509Data>
   </ds:KeyInfo>
</ds:Signature>

The interesting part is the second reference (in bold) – the signature signs the KeyInfo (#KeyInfo001), which is part of the signature element itself. The regular api to add reference to a signature is this:

var reference = new Reference();
reference.Uri = "#KeyInfo001";

However it will not work here since it will look for an element with this ID in the signed document (e.g. soap envelope). However the ID is inside the signature element itself, which is still not a part of the document because it was not create yet.
Frederic had found a nice trick: Inherit from SignedXml and override the default logic to find the references such that it will search in the signature itself (which is the base class).

public class CustomIdSignedXml : SignedXml
{
   public CustomIdSignedXml(XmlDocument doc) : base(doc)
   {
     return;
   }

   public override XmlElement GetIdElement(XmlDocument doc, string id)
   {
     if (String.Compare(id, this.KeyInfo.Id, StringComparison.OrdinalIgnoreCase) == 0)
       return this.KeyInfo.GetXml();
     else
       return base.GetIdElement(doc, id);
   }
}

This is applicable to web services, since many soap stacks will not allow to customize them to sign the KeyInfo, and if this is required you would need to sign the message like this yourself.

@YaronNaveh

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

Saturday, January 29, 2011

gSoap and Wcf Routing Services are not friends

@YaronNaveh

One common patterns with web services is the router service. It can hide routing logic from the client or help with load balancing. Wcf 4 ships with libraries and samples to help build such a router very quickly.

Stephen Liedig had notified me recently on a problem which happens when a gSoap client calls a Wcf router. gSoap is a very popular CPP web services stack.

This was the deployment:



The gSoap client was sending this message to the router:

<soap:Envelope xmlns="http://tempuri.org/" xmlns:p="http://myNs/" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 
<soap:Body>
   
<AddUser>
     
<user xsi:type="p:User">
       
<name>yaron</name>
     
</user>
   
</AddUser>
 
</soap:Body>
</soap:Envelope>


If the router would call the service using the http endpoint, everything would work. If it used the tcp endpoint, it could send the message, but the service implementation would never be called and the service would report this exception:


The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://tempuri.org/:user. The InnerException message was 'Element 'http://tempuri.org/:user' contains data of the ':User' data contract. The deserializer has no knowledge of any type that maps to this contract. Add the type corresponding to 'User' to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding it to the list of known types passed to DataContractSerializer.'.  Please see InnerException for more details.

Analysis

We need to ask two questions: Why this error happens? Why not with Http?

First we must take a look in the message that the router sent to the service. Here is how it appears in the Wcf log:

<soap:Envelope xmlns="http://tempuri.org/" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 
<soap:Body>
   
<AddUser>
     
<user xsi:type="p:User">
       
<name>yaron</name>
     
</user>
   
</AddUser>
 
</soap:Body>
</soap:Envelope>


Something is missing – the “p” prefix declaration (xmlns:p=http://myNs/) which was present in the message form the client to the router does not appear. This makes this message invalid as it references the undeclared prefix "p" in the "p:User" derived type attribute. But why did the router sent an invalid message when the client sent it a good one? And why not with Http?

Let’s take a look at how Wcf routes messages. We can use the reflector to inspect System.ServiceModel.Routing.SoapProcessingBehavior+SoapProcessingInspector.MarshalMessage():

internal Message MarshalMessage(Message source, Uri to, MessageVersion targetVersion)
{
   
Message message;
   
MessageVersion version = source.Version;
   
if ((version == targetVersion) && !RoutingUtilities.IsMessageUsingWSSecurity(understoodHeaders))
   
{
       
...
       
return source;
   
}
   
...
   
else
   
{
       
XmlDictionaryReader readerAtBodyContents = source.GetReaderAtBodyContents();
       
message = Message.CreateMessage(targetVersion, headers.Action, readerAtBodyContents);
   
}

   
this.CloneHeaders(message.Headers, headers, to, understoodHeadersSet);    
   
return message;
}

Wcf uses this logic:

  • If the input message (from client) and output message (to server) have the same version, and no security is involved, then take the input as is and send it. This explains why the Http case works.
  • Otherwise take the input message body and copy it to a new message. Then copy custom user headers.

Since the “p” prefix is not defined under the body but under the root “envelope” element, this prefix is not sent which makes the message invalid. This explains the netTcp bug.

 

Why Wcf behaves in this way?

Dismissing this behavior as a bug will miss an important discussion. Consider the naïve fix: Parse each attribute under the body and search for the something:something pattern. Since the router has no information about the message semantics it has no way to know if the pattern relates to a prefix or is just a string which looks like this. Moreover doing this would be a huge performance hit, especially with big messages.

 

What should be the correct behavior?

In order to take both the functional and performance requirements into account, I would recommend the following approach:

  • Copy all namespace declarations from the root Envelope and Body elements of the original message into the corresponding elements of the new one (including the default namespace).
  • Make sure not to overload the previous prefixes with new definitions in both elements.

Yes, I can think of a few edge cases where this scheme fails. But a more comprehensive solution would cost in performance.


Conclusion

As it stands now, the default gSoap client fails to call the default Wcf router when protocol bridging is used, which is a real interoperability problem.

And Just to clarify, this web service does not define any derived (=inherited = known) types. For some reason the gSoap default message generation logic uses the xsi:type even on base types. This is  not forbidden since it uses the correct type name, although there is no real reason to do it. Anyway this makes this case quite common and not limited to services with derived types.

And, yes, this is one of the reasons not everyone likes Xml.

@YaronNaveh

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