Thursday, April 30, 2009

Introducing WCF ClearUsernameBinding

@YaronNaveh




Update
: ClearUsernameBinding is now hosted on GitHub. This post contains the updated usage instructions.


Using cleartext username/password is usually not recommended. However it is sometimes required (like with F5's BIG-IP). WCF does not natively allow us to use such scenario. For this reason I have written ClearUsernameBinding - a WCF binding that enables to send cleartext username/password over HTTP.

Full source code is available in google code github.

So without any further preparations let's see how to use ClearUsernameBinding.

Step 1: Download latest release
Download it here or go to google code github.
Then extract the zip to some folder, let's say C:\program files\ (the ClearUsernameBinding subfolder will be created when extracting the zip).

Step 2 (optional) - Run the sample project
It can be useful to run the sample application.

Run the server:

C:\program files\ClearUsernameBinding\TestService\bin\Release\
TestService.exe




And now the client:


C:\program files\ClearUsernameBinding\TestClient\bin\Release\
TestClient.exe




And if everything went smoothly you have just seen ClearUsernameBinding in first action!

Step 3 (optional) - Investigate the sample project source code
The best way to learn a new (and very simple in this case) technology is by looking at existing projects. Just open with VS 2008 the solution file:


C:\program files\ClearUsernameBinding\ClearUsernameBinding.sln


And look at the source of the projects TestClient and TestService. These two projects are just normal WCF projects configured to use ClearUsernameBinding. In other words, making a WCF client/service use ClearUsernameBinding is just a matter of changing web.config and does not require coding. We will see in the next steps how to do it from scratch.

I'll probably have a separate post on the binding implementation itself. It is pretty straight forward and the handling of security is as I learned from Nicholas Allen's blog.

Step 4 - Creating your own service
For this step just create any normal WCF web site or a self hosted service.

Step 5 - Configure the service to use ClearUsernameBinding
Add your project a dll reference to


C:\Program Files\ClearUsernameBinding\ClearUserPassBinding\bin\
Release\ClearUsernameBinding.dll


Then open web.config and register the ClearUsernameBinding under the system.ServiceModel section:



<extensions>
  <bindingExtensions>
   <add name="clearUsernameBinding" type="WebServices20.BindingExtenions
.ClearUsernameCollectionElement, ClearUsernameBinding" />
  </bindingExtensions>
</extensions>

<bindings>
  <clearUsernameBinding>
   <binding name="myClearUsernameBinding"
messageVersion="Soap12">
   </binding>
  </clearUsernameBinding>
</bindings>


Finally configure your endpoint to use ClearUsernameBinging and its configuration:


<endpoint binding="clearUsernameBinding" bindingConfiguration="myClearUsernameBinding"
contract="WebServices20.SampleService.IEchoService" />


An example of the complete web.config is inside the full project binary&source in


C:\Program Files\ClearUsernameBinding\TestService\bin\Release\
TestService.exe.config


Step 6 (optional) - Configure the message version
If you need to use a specific message version configure it in the "messageVersion" attribute in the above configuration. Valid values are: Soap11WSAddressing10, Soap12WSAddressing10, Soap11WSAddressingAugust2004, Soap12WSAddressingAugust2004, Soap11, Soap12, None, Default.

Example:


<binding name="myClearUsernameBinding" messageVersion="Soap12">
</binding>


Step 7 - Configure the username authentication
This one needs to be done in any username/password authenticated service and not just one that uses ClearUsernameBinding. By default your server will authenticate the users against your active directory domain. If you want to do your own custom authentication you need to create a new class library project with a class that implements System.IdentityModel.Selectors.UserNamePasswordValidator

The class can look like this:



public class MyUserNameValidator : UserNamePasswordValidator
{
  public override void Validate(string userName, string password)
  {
   if (userName != "yaron")
    throw new SecurityTokenException("Unknown Username or Password");
  }
}


Don't forget to add dll reference to System.IdentityModel and System.IdentityModel.Selectors or the project will not compile. Then add this project as a project reference to your service project/website and configure the latter to use this custom authenticator:


<behaviors>
  <serviceBehaviors>
   <behavior name="SampleServiceBehaviour">
...
    <serviceCredentials>
    <userNameAuthentication     userNamePasswordValidationMode="Custom"
    customUserNamePasswordValidatorType=
"WebServices20.Validators.MyUserNameValidator, MyUserNameValidator" />
    </serviceCredentials>
   </behavior>
  </serviceBehaviors>
</behaviors>
...
<service behaviorConfiguration="SampleServiceBehaviour" name="WebServices20.SampleService.EchoService">
...


Again the full sample is available for download.


Step 8 - Run the service
Yes, the service is now ready to be activated, so run it when you are ready (run it directly from VS, just press F5).


Step 9 -Build a client
A service is worth nothing if there are no clients to consume it.
Create a new console application.
Right click the "References" node in the solution explorer and choose "Add service reference". Specify the WSDL of the server. If you are running the server from the given sample then the wsdl is in http://localhost:8087/SampleService/?WSDL. If you used your own server just run it and get the wsdl.

Now add some client code that uses the proxy to call the service. Don't forget to specify your username/password. For example:



ServiceReference1.EchoServiceClient client = new TestClient.ServiceReference1.EchoServiceClient();
client.ClientCredentials.UserName.UserName = "yaron";
client.ClientCredentials.UserName.Password = "1234";
client.EchoString("hello");



Step 10 - Configure the client
Configuring the client is as simple as configuring the service.
Here is the full client app.config:



<system.serviceModel>
  <client>
   <endpoint address="http://localhost.:8087/SampleService/" binding="clearUsernameBinding"
   bindingConfiguration="myClearUsernameBinding"   contract="ServiceReference1.IEchoService"
   name="ClearUsernameBinding_IEchoService" />
  </client>

  <extensions>
   <bindingExtensions>
    <add name="clearUsernameBinding"    type="WebServices20.BindingExtenions
.ClearUsernameCollectionElement   , ClearUsernameBinding" />
   </bindingExtensions>
  </extensions>

  <bindings>
   <clearUsernameBinding>
    <binding name="myClearUsernameBinding"
messageVersion="Soap12">

    </binding>
   </clearUsernameBinding>
  </bindings>

</system.serviceModel>



Step 11 - Done, Done, Done!
That's all. You can now run your client and see how WCF can be used to access a service with a cleartext username/password. Use a tool like fiddler to verify that indeed a clear username is sent (I've shorten some low-level stuff from bellow message):


<Envelope>
  <Header>
   <Security>
...
    <UsernameToken>
     <Username>yaron</Username>
     <Password>1234</Password>
    </UsernameToken>
   </Security>
  </Header>
  <Body>
   <EchoString xmlns="http://tempuri.org/">
    <s>hello</s>
   </EchoString>
  </Body>
</Envelope>


Conclusion
Sending username/password on the clear is not available out of the box with WCF (for reasons mentioned above). If such a scenario is required then ClearUsernameBinding needs to be used.

@YaronNaveh

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

Wednesday, April 29, 2009

Interoperability Gotcha: Visual Studio 2008 Proxy Flavours

@YaronNaveh

The following interoperability issue can happen with a .Net 3.5 clients and older web services from various platforms (including Java. and .Net)

Everyone knows that Visual Studio 2008 has a build-in support for WCF which is the latest generation of Microsoft soap stack. By default, when writing web service clients in VS 2008 a WCF-flavored proxy is generated. However WCF only supports a subset of XML schema and WSDL patterns. For example it does not support RPC/Encoded WSDLs and XML attributes. Many older WSDLs use RPC/Encoded. With such WSDLs WCF is supposed to gracefully downgrade itself to .Net 2.0 which does support these WSDLs. I have noticed that in some cases this does not happen correctly. The result can be web service methods returning null instead of values.

The solution for such cases is to manually instruct VS 2008 to use its backward compatible proxy. All you need to do is:

1. Press the "Add Service Reference" as usual



2. Press the "Advanced..." button



3. Select "Add Web Reference..."



4. Use the good old .Net 2.0 proxy flavours

@YaronNaveh

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

Sunday, April 26, 2009

Java, WCF & Web Services Interoperability (part 2 of N): Know your X.509

@YaronNaveh


So, you want to write an Axis2 web service and have .Net WCF clients too? Or maybe you already have a .Net 2.0 endpoint and want it to be consumed by WSIT? Yes, that’s possible, but there is some important stuff you should know about. Whether you are a .Net WCF, AXIS2, Metro or any other framework developer/tester – you want to stay tuned for this series.

When a Java client sends a request to a secured WCF service sometimes this soap fault can come back:

An error occurred when verifying security for the message


Insdie the WCF trace log these errors appear:

Message security verification failed.


And the inner exception is:

Cannot read the token from the 'BinarySecurityToken' element with the 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' namespace for BinarySecretSecurityToken, with a 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v1' ValueType. If this element is expected to be valid, ensure that security is configured to consume tokens with the name, namespace and value type specified.


The problem is with the X.509 certificate/key that the client is using: It is of version 1 of X.509. WCF only supports version 3 certificates. We can see that the request strictly stated it was using v1:

<o:BinarySecurityToken u:Id="uuid-856599a5-7c38-465c-9ae8-69b59af419b7-1" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v1" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">MIIBxDCCAW6gA…


Interestingly enough, Wcf can work with the certificate content itself so if we could change the SOAP to have “v3” instead of “v1” everything would have worked. However the straight forward way to solve this is to use X.509V3 at the client side.
BTW We can see the certificate version by double clicking its file in windows:


@YaronNaveh

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

Saturday, April 18, 2009

WCF Performance: Making your service run 3 times faster

@YaronNaveh

A lot of people use WCF default settings on production. In many cases changing these defaults can gear up the service throughput dramatically.

Let's look at the following use case:


  • WsHttpBinding is used

  • Message level security is used: X.509 certificate or windows authentication, where client can also use a username/password or be anonymous

  • (Optional assumption) A typical client makes one service call and then disconnects



  • The WsHttpBinding implicit defaults can be explicitly written as bellow:


    <wsHttpBinding>
      <binding name="BadPerformanceBinding">
       <security mode="Message">
        <message clientCredentialType="..."
         negotiateServiceCredential="true"
         establishSecurityContext="true" />
       </security>
      </binding>
    </wsHttpBinding>


    Let's simulate a load on this service by employing many virtual users who constantly call the service one time and immediately disconnect. The number of users should be large enough such that service will use its max capacity. The results are:


    Transactions per second: 15.235
    Average time of a transaction: 1.4 seconds


    Note: I didn't use a super strong server here but as we can see below it shouldn't matter for our needs. Also a load of just a few minutes was enough to prove our theory.






    Those are not very good results of course.

    Now let's tweak the configuration a little bit:


    <wsHttpBinding>
      <binding name="BetterPerformanceBinding">
       <security mode="Message">
        <message clientCredentialType="..."
         negotiateServiceCredential="false"
         establishSecurityContext="false" />
       </security>
      </binding>
    </wsHttpBinding>


    And with the same amount of virtual users we get these results:


    Transactions per second: 51.833
    Average time of a transaction: 0.384 seconds


    That's 3.5 times faster!





    So, what happened here?
    Since the only change we did is in two settings we need to analyze each of them.

    negotiateServiceCredential
    This setting determines whether the clients can get the service credential (e.g. certificate) using negotiation with the service. The credentials are used in order to authenticate the service and to protect (encrypt) the messages. When this setting is set to "true" a bunch of infrastructure soap envelopes are sent on the wire before the client sends its request. When set to "false" the client needs to have the service credentials out of band.

    The trade off here is better performance (using "false") versus more convenience (using "true"). Setting "false" has its hassles as we now need to propagate the service credential to clients. However, performance wise, setting "negotiateServiceCredential" to "false" is always better.

    Take a look at how many infrastructure messages are exchanged when negotiateServiceCredential is "true":



    While when not negotiating life is much brighter:



    establishSecurityContext
    This setting determines whether WS-SecureConversation sessions are established between the client and the server. So what is a secure conversation anyway? In a very simplified manner we can say that a normal secured web service request requires one asymmetric encryption. Respectively, normal N requests require N asymmetric encryptions. Since asymmetric encryption is very slow, setting up a secure conversation is usually a good practice: It requires a one-time asymmetric encrypted message exchange in order to set up a session; Further calls in the session use symmetric encryption which is much faster.

    Now remember that in our case we assume that clients call the service just one time and disconnect. If a secure session is established the message exchange will look like this:


    Message 1: Setting up a secure session (asymmetric encryption)
    Message 2: The actual request (symmetric encryption)


    If we do not use secure session we have:


    Message 1: The actual request (asymmetric encryption)


    So it is clear that we're better off in the latter case.

    With secure sessions there isn't really any trade off and the decision is quite scientific: When only one client request is expected set establishSecurityContext to "false".

    Summary
    Wisely changing WCF defaults can yield a significant improvement in your service performance. The exact changes need to be made and their exact effect are dependent in the scenario. The example above showed how to speed up a certain service 3 times faster.

    @YaronNaveh

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

    Wednesday, April 15, 2009

    WCF Gotcha: Disabling SSL Validation

    @YaronNaveh

    When you use SSL with WCF or .Net 2.0 web services you might get this exception:


    SecurityNegotiationException:

    Could not establish trust relationship for the SSL/TLS secure channel with authority 'localhost'.


    This means that the X.509 certificate that the server presented is not valid according to your client's trust chain. the trust chain is the list of certificate issuers that you trust. In many cases this means you should not trust this web service. In some cases you decide to trust it anyway, due to the fact that you know the author or are still in early testing stages. You have two options:

    Option 1 - Make the certificate valid
    You would need to have the server certificate or its issuer's certificate in the trusted certificates store of your client. This can be done using WinHttpCertCfg.exe or using the "mmc" console.

    Option 2 - Configure WCF/.Net 2.0 to not validate the certificate
    With WCF, a common gotcha is to try and achieve that by setting:


    <serviceCertificate>
    <authentication certificateValidationMode="None" />
    </serviceCertificate>


    However this will not work with transport level security (SSL) but only with message level security. The correct way to do it is the same one as with .Net 2.0 web services. Just add this code before calling the service:


    using System.Net;
    using System.Net.Security;
    using System.Security.Cryptography.X509Certificates;
    ...
    ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(OnValidationCallback);
    ...
    public static bool OnValidationCallback(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors errors)
    {
    return true;
    }

    @YaronNaveh

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

    Tuesday, April 7, 2009

    Who Moved My Service Reference?

    @YaronNaveh

    When you use Visual Studio to add a Service Reference (VS 2008) or a Web Reference (VS 2005) to a web service you do not see the generated proxy immediately. One reason can be that th proxy was not generated due to errors and in this case VS notifies you in the "Error List" pane. If import was successful you can see the generated code by clicking the "Show All Files" option (see images).

    Before





    After





    BTW most of the time you don't really need to look inside the proxy - you can just use it.

    @YaronNaveh

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

    Sunday, April 5, 2009

    Web Service Attachments Support Matrix

    @YaronNaveh

    Many web services require sending or receiving large files. There is an interesting evolution of attachments standards - however today MTOM is the preferred way to do this. Nevertheless not all SOAP stacks support MTOM and in addition some existing services might already employ older techniques. These techniques may include Soap With Attachments (SwA) or WSI attachment profile (SwaRef) MIME attachments or DIME. I have investigated the attachments support of a few known soap stacks: .Net WSE2 & WSE3, WCF, Axis, Axis2, Metro (WSIT), CXF (XFire), gSOAP, SpringWS and JBossWS. The bellow table summarizes the web service attachments support matrix (click to enlarge):



    Note: Some of this information I took from the providers web sites which did not always supplied a nice sheet with the list of supported standards. You are encouraged to correct me if I made a mistake.

    The conclusion is as expected: MTOM should be used for new web services; If you know you’ll never have .Net clients then you can also use Soap With Attachments (SwA) or WSI attachment profile (SwaRef) MIME attachments; Beware of DIME if you care for I14Y.

    @YaronNaveh

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