How to: Use a Custom User Name and Password Validator

By default, when a user name and password is used for authentication, Windows Communication Foundation (WCF) uses Windows to validate the user name and password. However, WCF allows for custom user name and password authentication schemes, also known as validators. To incorporate a custom user name and password validator, create a class that derives from UserNamePasswordValidator and then configure it.

For a sample application, see User Name Password Validator.

To create a custom user name and password validator

  1. Create a class that derives from UserNamePasswordValidator.

    
    public class CustomUserNameValidator : UserNamePasswordValidator
    {
    
    Public Class CustomUserNameValidator
        Inherits UserNamePasswordValidator
    
  2. Implement the custom authentication scheme by overriding the Validate method.

    Do not use the code in the following example that overrides the Validate method in a production environment. Replace the code with your custom user name and password validation scheme, which might involve retrieving user name and password pairs from a database.

    To return authentication errors back to the client, throw a FaultException in the Validate method.

    // 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"))
        {
            // This throws an informative fault to the client.
            throw new FaultException("Unknown Username or Incorrect Password");
            // When you do not want to throw an informative fault to the client,
            // throw the following exception.
            // throw new SecurityTokenException("Unknown Username or Incorrect Password");
        }
    }
    
    ' 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 Overrides Sub Validate(ByVal userName As String, ByVal password As String)
        If Nothing = userName OrElse Nothing = password Then
            Throw New ArgumentNullException()
        End If
    
        If Not (userName = "test1" AndAlso password = "[PLACEHOLDER]") AndAlso Not (userName = "test2" AndAlso password = "[PLACEHOLDER]") Then
            ' This throws an informative fault to the client.
            Throw New FaultException("Unknown Username or Incorrect Password")
            ' When you do not want to throw an informative fault to the client,
            ' throw the following exception:
            ' Throw New SecurityTokenException("Unknown Username or Incorrect Password")
        End If
    
    End Sub
    

To configure a service to use a custom user name and password validator

  1. Configure a binding that uses message security over any transport or transport-level security over HTTP(S).

    When using message security, add one of the system-provided bindings, such as a <wsHttpBinding>, or a <customBinding> that supports message security and the UserName credential type.

    When using transport-level security over HTTP(S), add either the <wsHttpBinding> or <basicHttpBinding>, a <netTcpBinding> or a <customBinding> that uses HTTP(S) and the Basic authentication scheme.

    Note

    When using .NET Framework 3.5 or later versions, you can use a custom username and password validator with message and transport security. With WinFX, a custom username and password validator can only be used with message security.

    Tip

    For more information on using <netTcpBinding> in this context, see <security>.

    1. In the configuration file, under the <system.serviceModel> element, add a <bindings> element.

    2. Add a <wsHttpBinding> or <basicHttpBinding> element to the bindings section. For more information about creating an WCF binding element, see How to: Specify a Service Binding in Configuration.

    3. Set the mode attribute of the <security> or <security> to Message, Transport, or TransportWithMessageCredential.

    4. Set the clientCredentialType attribute of the <message> or <transport>.

      When using message security, set the clientCredentialType attribute of the <message> to UserName.

      When using transport-level security over HTTP(S), set the clientCredentialType attribute of the <transport> or <transport> to Basic.

      Note

      When a WCF service is hosted in Internet Information Services (IIS) using transport-level security and the UserNamePasswordValidationMode property is set to Custom, the custom authentication scheme uses a subset of Windows authentication. That is because in this scenario, IIS performs Windows authentication prior to WCF invoking the custom authenticator.

    For more information about creating an WCF binding element, see How to: Specify a Service Binding in Configuration.

    The following example shows the configuration code for the binding:

    <system.serviceModel>
      <bindings>
      <wsHttpBinding>
          <binding name="Binding1">
            <security mode="Message">
              <message clientCredentialType="UserName" />
            </security>
          </binding>
        </wsHttpBinding>
      </bindings>
    </system.serviceModel>
    
  2. Configure a behavior that specifies that a custom user name and password validator is used to validate user name and password pairs for incoming UserNameSecurityToken security tokens.

    1. As a child to the <system.serviceModel> element, add a <behaviors> element.

    2. Add a <serviceBehaviors> to the <behaviors> element.

    3. Add a <behavior> element and set the name attribute to an appropriate value.

    4. Add a <serviceCredentials> to the <behavior> element.

    5. Add a <userNameAuthentication> to the <serviceCredentials>.

    6. Set the userNamePasswordValidationMode to Custom.

      Important

      If the userNamePasswordValidationMode value is not set, WCF uses Windows authentication instead of the custom user name and password validator.

    7. Set the customUserNamePasswordValidatorType to the type that represents your custom user name and password validator.

    The following example shows the <serviceCredentials> fragment to this point:

    <serviceCredentials>
      <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Microsoft.ServiceModel.Samples.CalculatorService.CustomUserNameValidator, service" />
    </serviceCredentials>
    

Example

The following code example demonstrates how to create a custom user name and password validator. Do not use the code that overrides the Validate method in a production environment. Replace the code with your custom user name and password validation scheme, which might involve retrieving user name and password pairs from a database.

using System;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;

using System.Security.Principal;

using System.ServiceModel;
Imports System.IdentityModel.Selectors
Imports System.IdentityModel.Tokens

Imports System.Security.Principal

Imports System.ServiceModel

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"))
        {
            // This throws an informative fault to the client.
            throw new FaultException("Unknown Username or Incorrect Password");
            // When you do not want to throw an informative fault to the client,
            // throw the following exception.
            // throw new SecurityTokenException("Unknown Username or Incorrect Password");
        }
    }
}
Public Class CustomUserNameValidator
    Inherits 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 Overrides Sub Validate(ByVal userName As String, ByVal password As String)
        If Nothing = userName OrElse Nothing = password Then
            Throw New ArgumentNullException()
        End If

        If Not (userName = "test1" AndAlso password = "[PLACEHOLDER]") AndAlso Not (userName = "test2" AndAlso password = "[PLACEHOLDER]") Then
            ' This throws an informative fault to the client.
            Throw New FaultException("Unknown Username or Incorrect Password")
            ' When you do not want to throw an informative fault to the client,
            ' throw the following exception:
            ' Throw New SecurityTokenException("Unknown Username or Incorrect Password")
        End If

    End Sub
End Class

See also