Plain-Text Username Password Authentification with WCF


If you got it, it’s easy. If you’re starting from scratch it ain’t as easy. We were in need of such a Username+Password Authentification so I started googling around.

I found several articles but had to mash it all together in a trial-and-error session. Now that I am enlightened I want to share my knowledge:

Step 1: Implement an UserNamePasswordValidator class and override the Validate method.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IdentityModel.Tokens;
using System.IdentityModel.Selectors;

namespace sones.Pandora.Database.Hosting
{
    public class UserNamePasswordAuthentification: UserNamePasswordValidator
    {

        public override void Validate(string userName, string password)
        {
            if ((userName != "Username") || (password != "Password"))
            {
                throw new SecurityTokenException("Validation Failed!");
            }
        }
    }
}

Step 2: Edit the App.config file to enable the previously implemented UsernamePasswordValidator.

    <bindings>
      <basicHttpBinding>
        <binding name="CustomAuthentication">
          <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Basic" proxyCredentialType="Basic"/>
          security>
        binding>
      basicHttpBinding>
    bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="SecurityBehavior">
          <serviceCredentials>
            <userNameAuthentication
            userNamePasswordValidationMode="Custom"
            customUserNamePasswordValidatorType="sones.Pandora.Database.Hosting.UserNamePasswordAuthentification, PandoraDB_WebServiceHost_UsernamePasswordAuth"/>
          serviceCredentials>
        behavior>
      serviceBehaviors>
    behaviors>
    <services>
      <service behaviorConfiguration="SecurityBehavior" name="sones.Pandora.Database.Hosting.PandoraDatabaseHost">
        <endpoint address="" binding="basicHttpBinding" bindingConfiguration="CustomAuthentication"
          name="ep1" contract="sones.Pandora.Database.Hosting.IPandoraDatabaseHost" />
      service>
    services>

In this example the ServiceHost will use no server SSL certificate and therefor allow normal http access instead of just using https ssl. You can configure that behavior with the <security mode=”TransportCredentialOnly”> line. Just change there and define an apropriate certificate and you’re good to go with https / ssl.

  1. #1 by Dave M on October 7, 2011 - 16:58

    Thanks. I have used the above settings. It was helpful but I am still getting an error (The remote server returned an error: (401) Unauthorized.) when I try to consume the service from my client.

    Right now I have a test service and client on my local machine. Both are in IIS. I want to pass the username and password in clear text (we will be behind ssl in production). The security settings for both the server and client are set to Enable anonymous access. ONly the server has basic authentication checked.

    ***client config***

    ***server config***

    </system.serviceModel

    My server interface has the default DoWork routine and I have added a Validate routine. In the server service code the signature of Validate is

    Public Overrides Sub Validate(ByVal userName As String, ByVal password As String) Implements abc.def.ghi.IService1.Validate

    In my client code I have
    Dim x As New ServiceReference1.Service1Client
    x.ClientCredentials.UserName.UserName = "dave"
    x.ClientCredentials.UserName.Password = "dave"
    x.Validate("dave", "dave")

    Please help. I have to believe I am so close to a solution on this.

  2. #2 by Dave M on October 7, 2011 - 23:26

    Since this is going through IIS I realized that I need to actually pass my network id and pwd to the Validate function in the client code. However, things have changed. I am now required to consume a web service that uses UserTokenName passed in the headers.

    I have everything set up correctly (I think). I cannot seem to find code that I can use on the server side to confirm that the values I entered into the client config are correct. Any help would be appreciated.

Comments are closed.