Showing posts with label ClearUsernameBinding. Show all posts
Showing posts with label ClearUsernameBinding. Show all posts

Tuesday, March 23, 2010

Customizing ClearUsernameBinding

@YaronNaveh

ClearUsernameBinding has became very popular recently and many people ask how to modify it for their needs. Most people want to increase message size quotas but there are definitely other required customizations.

Suresh has written a nice post on how to increase some of the message quotas. Also the comments to the original post contain more useful information.

Generally speaking, most customizations can just imitate the way messageVersion is handled, so just search for wherever this string appears (5 places) and add you equivalnet code for what you are customizing. Hopefully soon I'll publish a concrete example.

@YaronNaveh

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

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!

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!