Custom UserNamePassword Validators in .Net Framework 3.5

In the version of WCF that shipped with .Net Framework 3.0 we didn't support custom validators with transport level HTTP security. We received much feedback from the community that this was a highly desired feature, so I'm happy to say we added support for this scenario in the 3.5 release of the .Net Framework.

Note that this is only supported under self hosted services.

Here is what you'll need to do to get it to work:

1. Create your validator:

 namespace Sample
{
   using System.ServiceModel;
   using System.IdentityModel.Selectors;
   using System.ServiceModel.Security;

   public class CustomUserNameValidator : UserNamePasswordValidator
   {
       // This method validates users. It allows in two users, test1 and test2 
       // with passwords 1tset and 2tset respectively.
       // This code is for illustration purposes only and 
       // must not be used in a production environment because it is not secure. 
       public override void Validate(string userName, string password)
       {
           if (null == userName || null == password)
           {         
               throw new ArgumentNullException();
           }

           if (!(userName == "test1" && password == "1tset") && !(userName == "test2" && password == "2tset"))
           {
               throw new SecurityTokenException("Unknown Username or Incorrect Password");
           }
      }
   }
}

 2. Configure your service; you'll want to use Transport security and Basic clientCredentialType, this way the authentication header will be protected by SSL.

Configuration for the binding and behavior:

 <bindings>
 <wsHttpBinding>
  <binding name="BasicAuthentication">
   <security mode="Transport">
    <transport clientCredentialType="Basic" />
   </security>
  </binding>
 </wsHttpBinding>
</bindings>


<behaviors>
 <serviceBehaviors>
  <behavior name="CustomUserNamePassword">
   <serviceCredentials>
    <userNameAuthentication 
     userNamePasswordValidationMode="Custom" 
     customUserNamePasswordValidatorType="Sample.CustomUserNameValidator, assemblyName"/>
   </serviceCredentials>
  </behavior>
 </serviceBehaviors>
</behaviors>

You can also add the custom validator through code:

 host.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = new CustomUserNameValidator();
host.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;

Comments

  • Anonymous
    January 14, 2008
    Hello. I'm using a custom validator with the "web programming model" (WebServiceHost, ...). However, when an exception is thrown in the Validate method, the resulting HTTP response contains a "403-Forbidden" status code. Shouldn't this be a "401-Authorized" so that the user-agent requests another username and password from the user?

  • Anonymous
    April 28, 2008
    I've had scattered posts in the past talking about the messaging features and enhancements in Orcas.

  • Anonymous
    January 23, 2009
    Phil Henning has written about creating a custom username/password validator for HTTP , which is another