I have been searhcing for this for a couple of days now.
I am just trying to have a Username / Password being passed into my RESTful service using Basic HTTP Authentications. Everything else works awesomly!
Here is what my web.config looks like:
<?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
      <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    </modules>
  </system.webServer>
  <system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="">
          <security mode="Message">
            <message clientCredentialType="UserName" />
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
    <standardEndpoints>
      <webHttpEndpoint>
        <!-- 
            Configure the WCF REST service base address via the global.asax.cs file and the default endpoint 
            via the attributes on the <standardEndpoint> element below
        -->
        <standardEndpoint name="" helpEnabled="true" defaultOutgoingResponseFormat="Json" automaticFormatSelectionEnabled="true"/>
      </webHttpEndpoint>
    </standardEndpoints>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <serviceCredentials>
            <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="ParkingPandaREST.CustomUserNameValidator, ParkingPandaREST" />
          </serviceCredentials>      
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>
Then I created a CustomUserNameValidator class that has the following:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace ParkingPandaREST
{
    public class CustomUserNameValidator : System.IdentityModel.Selectors.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 System.ServiceModel.FaultException("Unknown Username or Incorrect Password");
                // When you do not want to throw an infomative fault to the client,
                // throw the following exception.
                // throw new SecurityTokenException("Unknown Username or Incorrect Password");
            }
        }
    }
}
I am simply running the service on my local machine and trying to hit a break point in the CustomUserNameValidator class but it never gets there. So I am not using SSL right now, simply just trying to get the username / Password being passed in.
Here is the answer I came up with. It may need to be tweaked a bit, but it is the core that you need to get the job done.
Note: Turn off basic authentication in IIS
           // Get the Header Authorization Value
            string headerValue = operationContext.IncomingRequest.Headers[HttpRequestHeader.Authorization];
            headerValue = headerValue.Replace("Basic ", "");
            headerValue = DecodeBase64String(headerValue);
            // Get Username and Password
            string userName = headerValue.Substring(0, headerValue.IndexOf(":"));
            string password = headerValue.Substring(headerValue.IndexOf(":") + 1, headerValue.Length - userName.Length - 1);
            // Do Custom Authorization here with the userName and password
.......
Also here is the DecodeBase64String function
    public static string DecodeBase64String(string encodedData)
    {
        byte[] encodedDataAsBytes = System.Convert.FromBase64String(encodedData);
        string returnValue = System.Text.ASCIIEncoding.ASCII.GetString(encodedDataAsBytes);
        return returnValue;
    }
Hope that help some other people who were having the same problem - cheers!
The default binding for the HTTP transport in WCF 4 is basicHttpBinding. If you convert your wsHttpBinding element to a basicHttpBinding element and configure it for custom validation then your code should execute.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With