Finally! Usernames over Transport Authentication in WCF

Sometimes you have to wonder why the most basic features are missing in a v1 product…

Imagine this scenario: You have a public facing web service. You want the widest possible reach and compatibility – so the perfect technologies for that are HTTP, SSL and basic authentication (usernames and passwords) – and your customer accounts are no Windows accounts.

There was no sane way to pull this off in WCF v1 (besides fiddling around with the HTTP pipeline and simulating the basic auth handshake – but that tied you to IIS/ASP.NET).

You may say now – isn’t that exactly what TransportWithMessageCredential is supposed to do? Not exactly – because this involves sending a basic WS-Security SOAP header inside of the message. I want simple HTTP basic auth….

(Christian and me had this very scenario at a customer just a few weeks ago…)

The good news is that WCF in .NET 3.5 will finally support this!

How does that work?

a) use transport security (e.g. basicHttpBinding)

<bindings>
  <basicHttpBinding>
    <binding name="secureBasic">
      <security mode="Transport">
        <transport clientCredentialType="Basic" />
      </security>
    </binding>
  </basicHttpBinding>
</bindings>

b) write a username/password validator

public class CustomUsernamePasswordValidator : UserNamePasswordValidator
{
    public override void Validate(string userName, string password)
    {
        if (!AuthenticateUser(userName, password))
            throw new SecurityTokenValidationException("...");
    }
}

c) hook up the validator in a serviceCredentials behavior

<behaviors>
  <serviceBehaviors>
    <behavior name="userName">
      <serviceCredentials>
        <userNameAuthentication customUserNamePasswordValidatorType="..."
                                userNamePasswordValidationMode="Custom" />
      </serviceCredentials>
    </behavior>
  </serviceBehaviors>
</behaviors>

d) send a username/password using the client proxy

ChannelFactory<IService> cf = new ChannelFactory<IService>("Service");
cf.Credentials.UserName.UserName = "bob";
cf.Credentials.UserName.Password = "foo";

IService proxy = cf.CreateChannel();
Console.WriteLine(proxy.Ping());

((IClientChannel)proxy).Close();

This entry was posted in WCF. Bookmark the permalink.

3 Responses to Finally! Usernames over Transport Authentication in WCF

  1. Pingback: Send username and password in clear text to web service over HTTP | BlogoSfera

  2. John Waters says:

    I am trying this with IIS hosting where in IIS the only Anonymous authentication is enabled. When I run, I get:

    The service ‘/DacsaServer/TestService.svc’ cannot be activated due to an exception during compilation. The exception message is: The authentication schemes configured on the host (‘Anonymous’) do not allow those configured on the binding ‘BasicHttpsBinding’ (‘Basic’). Please ensure that the SecurityMode is set to Transport or TransportCredentialOnly

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s