Monday, February 2, 2009

Pseudo errors when referencing WSDLS

@YaronNaveh

Sometimes when you "add service reference" in VS 2008 you will get a few warnings (see below). When using svcutil like this:


$> svcutil http://myHost/Service.asmx?WSDL


these warnings may appear as errors.

If you get these errors/warnings:


Attempting to download metadata from 'http://myHost/Service.asmx?WSDL' using WS-Metadata Exchange or DISCO.
Error: Cannot import wsdl:binding
Detail: The required WSDL extension element 'binding' from namespace 'http://sch
emas.xmlsoap.org/wsdl/http/' was not handled.
XPath to Error Source: //wsdl:definitions[@targetNamespace='http://myNamespace/']/wsdl:binding

[@name='myBindingHttpPost']


Error: Cannot import wsdl:port
Detail: There was an error importing a wsdl:binding that the wsdl:port is dependent on.
XPath to wsdl:binding: //wsdl:definitions[@targetNamespace='http://myNamespace/']/wsdl:binding

[@name='myBindingHttpPost']
XPath to Error Source: //wsdl:definitions[@targetNamespace='http://myNamespace/']/wsdl:service

[@name='myService']/wsdl:port[@name='myPort'
]


Generating files...


Then (usually) you have nothing to worry about. What they mean is that your WSDL contains a binding which uses HTTP Post transport. For example:


<wsdl:binding name="myHttpPost" type="tns:MyHttpPost">
  <http:binding verb="POST" />
...


WCF does not support this binding and so raised an error. So why you have nothing to worry about? The reason is that usually when a WSDL contains a HTTP Post binding it also contains a SOAP one and WCF can work with it. For example:



<wsdl:binding name="mySoapBinding" type="tns:mySoapPortType">
  <soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
...


Actually you can see that even though errors have occured a functioning proxy was still generated.

Note that if you create a .NET 2.0 (asmx) web service then there is a configuration to determine if a HTTP Post binding should be created. I can't find it now but promise to post the details later on...

@YaronNaveh

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

Friday, January 30, 2009

Interoperability Gotcha: Order of XML Elements

@YaronNaveh

This time I will talk about the importance of order within xml elements.

Let's say we have a web service with this schema:


<s:element name="root">
 <s:complexType>
  <s:sequence>
   <s:element name="elem1" type="s:string" />
   <s:element name="elem2" type="s:string" />
  </s:sequence>
 </s:complexType>
</s:element">


So of course this is a valid request:


<root>
 <elem1>I'm elem1</elem1>
 <elem2>I'm elem2</elem2>
</root>


But about about this?


<root>
 <elem2>I'm elem2</elem2>
 <elem1>I'm elem1</elem1>
</root>


This is not a valid xml instance!
The reason is that the schema contains the element which requires its sub elements to have order.

So why is it an interoperability gotcha?
The reason is that different soap stacks by different vendors behave differently in such cases. Sometimes even different stacks of the same vendor are divided...

Let's see how a .Net 2.0 proxy would look like:


...
private string elem1;
private string elem2;
...


This proxy can parse both xml instances from above.

This is how the equivalent WCF proxy would look like:


[XmlElement(Order=0)]
public string Elem1
{
...
}

[XmlElement(Order=1)]
public string Elem2
{
...
}


This proxy is stricter and actually enforces the order of elements. So it would only accept the first (legal) instance and will give unexpected results with the second. It would usually not throw an exception but rather ignore the message and use default values for the unordered elements so your fields will have a lot of NULL's and zeros.

How to fix it?

Option 1 (recommended) - Send XML with the correct order.

Option 2 - Change the WSDL to use <all> instead of <sequence>. The former does not require correct order of elements (there are some other subtle differences). Note that in case the WSDL is dynamically generated this may be hard to maintain.

Option 3 - Remove the "Order=..." property from the WCF proxy. Note that when the proxy will be regenerated the "Order" property will come back so this is also a maintenance challenge.

@YaronNaveh

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

Friday, January 23, 2009

Stateful Security Context Tokens in WCF

@YaronNaveh

When a custom binding is used in WCF it is possible to configure the value of requireSecurityContextCancellation. The name of this property doesn't exactly indicate in what scenarios it should be used.

When the client and server use WS-SecureConversation (by setting authenticationMode to "SecureConversation") the client get some token from the server in the initial handshake and needs to send it in every connection attempt. The server can extract this token and find the relevant data of this session in its memory. But what happens when the server/IIS is restarted? The memory is cleared and the session becomes invalid. The way to overcome this is to set requireSecurityContextCancellation to false (the default is true). In this mode the session key is saved at the client side and it sends it to the server in every request. This means that even if the server is restarted the session key is available in the request. This also means that the size of each request is a little bigger.

Since with this mode the server does not need to save the session key it does not need to be informed when the session is over and from here the property name requireSecurityContextCancellation.

BTW From performance point of view it is not always recommended to use a secure conversation.

Read more on the subject in the MSDN page.

@YaronNaveh

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

Saturday, January 17, 2009

WCF Sessions Explained

@YaronNaveh

Richard Blewett has published a great post about WCF sessions. He explains how sessions are implemented in each of the bindings and how they can be used.

One addition over this post is that sessions can also be used in WCF via the asp.net compatibility mode. Here, the way to access the session is:


HttpContext.Current.Session["key"] = "value";


In this mode the session is implemented via an HTTP cookie - exactly as with classic .Net 2.0 web services / asp.net. This means that this mode is available only when hosting in IIS and using HTTP transport. This mode should be used in case backward compatibility with an old service/client is required. It should not be used with new services as it adds some overhead to the pipeline.

@YaronNaveh

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

Monday, January 5, 2009

Signing custom headers in WCF

@YaronNaveh

Recently I had an interesting case with WCF "raw message" contract:


public interface IUniversalContract
{
  [OperationContract(Action = "*", ReplyAction = "*")]
  Message ProcessMessage(Message message);
}


The message I used on the client side contained some SOAP headers. Since this is an untyped message these headers were neither encrypted nor signed. That was a show stopper for me.

I saw this blog post by Nicholas Allen and immediatelly tried the following syntax:


ChannelProtectionRequirements requirements = bindingParameters.Find();
XmlQualifiedName qName = new XmlQualifiedName(header, ns);
MessagePartSpecification part = new MessagePartSpecification(qName);
requirements.OutgoingSignatureParts.AddParts(part, action);


However the request message was still not being encrypted nor signed. I struggled with this issue for some time until I was lucky enough to find Pedro Felix's message in the WCF MSDN forum:


The MSDN docs state that

a) IncomingSignatureParts - Gets a collection of message parts that are signed for messages from client to server

b) OutgoingSignatureParts - Gets a collection of message parts that are signed for messages from server to client


In other words the OutgoingSignatureParts always relates to server outgoing messages while client outgoing stuff is always considered as "incoming". After fixing this the code worked like a charm. I probably should have proactively RTFM myself but at least I felt good for not being the only one who fell for this...

@YaronNaveh

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

Saturday, January 3, 2009

How to use clear username/password with WCF?

@YaronNaveh

WCF does not allow to authenticate clients with cleartext username/password. While this is generally considered an unsecured mechanism there are some valid reasons to use it (such as SSL passthrough of load balancers like F5's BIG-IP, or for interoperability reasons). So let's see what can still be done with WCF.

First attempt - using basicHttpBinding with MessageClientCredentialType of "Username".
Unfortunetelly this would yield the following exception:


BasicHttp binding requires that BasicHttpBinding.Security.Message.ClientCredentialType be equivalent to the BasicHttpMessageCredentialType.Certificate credential type for secure messages. Select Transport or TransportWithMessageCredential security for UserName credentials.


Second attempt - using basicHttpBinding with TransportWithMessageCredential mode.

Since this mode implies that we need to secure the transport we get any of these exceptions, depending if we are on the client or the server side:


The provided URI scheme 'http' is invalid; expected 'https'.
Parameter name: via



Could not find a base address that matches scheme https for the endpoint with binding BasicHttpBinding. Registered base address schemes are [http].


Third attempt - using wsHttpBinding with MessageClientCredentialType of "Username".

Depending on several other settings, and wheather we're on the client or the server, we would get any of these exceptions:


Object reference not set to an instance of an object.



The service certificate is not provided for target 'http://localhost/MyWebServices/Services/SimpleService.asmx'. Specify a service certificate in ClientCredentials.



The service certificate is not provided. Specify a service certificate in ServiceCredentials.


Forth attempt - using wsHttpBinding with TransportWithMessageCredential mode.

Similarily to the second attempt we get:


The provided URI scheme 'http' is invalid; expected 'https'.
Parameter name: via


OR


Could not find a base address that matches scheme https for the endpoint with binding WSHttpBinding. Registered base address schemes are [http].


Fifth attempt - using customBinding with httpTransport and security element with authenticationMode of UserNameOverTransport

This time we get:


"The 'CustomBinding'.'http://tempuri.org/' binding for the 'SimpleServiceSoap'.'http://tempuri.org/' contract is configured with an authentication mode that requires transport level integrity and confidentiality. However the transport cannot provide integrity and confidentiality."


So it really seems like Microsoft is trying to (im)politely convince us not to use clear username/password. But what can we do for cases where this behaviour is really required?

The solution

The solution s to use ClearUsernameBinding. This binding seamlessly integrates with WCF and allows us to use clear username/password.

Read more about ClearUsernameBinding for WCF.

@YaronNaveh

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

Saturday, November 22, 2008

Securing Web Services With Username/Password

@YaronNaveh

Many web services authenticate clients using username/password. In the soap message it looks like this:


<wsse:Username>yaron</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">1234</wsse:Password>


You can notice that the username/password are clear (not encrypted). This means that everyone that can see this message can steal the password.

There are typically 3 ways to overcome this.

1. Sending the hashed password only:


<wsse:Username>yaron</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">iuacnq2G/t0nWcYgCMx66UtFlxA=</wsse:Password>


Where the digest is calculated from the password, a timestamp and a nonce.
However this is not really secure. A hacker can use a dictionary attack to extract the password.

2. Protecting the username with SSL.
This is a valid option but is limited to HTTP web service only and denies us from some of the rich WS-Security options. There are some other transports which are inherently secured (like SSL passthrough of load balancers as F5's BIG-IP) but I will not discuss them here.

3. Protecting the username with message-level X.509 certificate.
This is another valid option but sometimes more complex to implement.

In practice if you want to use username/password you would need to decide between options 2&3. Some frameworks, like Microsoft's WCF, even prevents you from using option #1 at all. Nevertheless there are a few exceptions where option #1 is valid:

  • Your network is inherently secured so you are not afraid of password stealers.

  • You are required to interoperate with a service that requires to send clear username/password


  • If you are using WCF and have the above needs you should use the WCF ClearUsernameBinding.

    @YaronNaveh

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