Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom UserNamePasswordValidator not called

I am trying to set up a WCF webservice with BasicHttpBinding and authentication using username/password. I made custom authentication class. However, it is never called (verified by debugging). This is my web.config:

  <system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<behaviors>
  <serviceBehaviors>
    <behavior>
      <serviceCredentials>
        <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Compareware_WebApp.webservices.AuthenticationValidator, Compareware_WebApp" />
      </serviceCredentials>
      <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
      <serviceDebug includeExceptionDetailInFaults="false" />
    </behavior>
  </serviceBehaviors>
</behaviors>
<bindings>
  <basicHttpBinding>
    <binding name="BasicHttpBinding">
      <security mode="TransportCredentialOnly">
        <message clientCredentialType="UserName" />
      </security>
    </binding>
  </basicHttpBinding>
</bindings>
<services>
  <service name="Compareware_WebApp.webservices.Accounts">
    <endpoint address="/webservices/Accounts.svc" binding="basicHttpBinding"
      bindingConfiguration="BasicHttpBinding" name="BasicEndpoint"
      contract="Compareware_WebApp.webservices.IAccounts" />
  </service>
</services>
<client />

This is my authentication class:

namespace Compareware_WebApp.webservices

{

public class AuthenticationValidator : UserNamePasswordValidator
{
    public override void Validate(string userName, string password)
    {
        if (null == userName || null == password)
        {
            throw new ArgumentNullException();
        }

        if (!Membership.ValidateUser(userName, password))
        {
            // This throws an informative fault to the client.
            throw new FaultException("Unknown Username or Incorrect Password");
        }
    }
}

}

What am I doing wrong?

like image 720
Peter de Bruijn Avatar asked Sep 17 '25 06:09

Peter de Bruijn


1 Answers

I am also stuck in this problem, and I got a solution. If you want to call the Validate method of the UserNamePasswordValidator you must use the TransportWithMessageCredential security.

NOTE: You must host the WCF Services at the IIS server and have to enable SSL for your website, otherwise it will not work.

WCF Server Web.config file

<?xml version="1.0"?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
  </startup>
  <system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="wsHttp">
          <security mode="TransportWithMessageCredential">
            <message clientCredentialType="UserName"/>
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <services>
      <service name="TransportWithMessageCredential.Service1" behaviorConfiguration="wsHttpBehavior">
        <endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttp" contract="TransportWithMessageCredential.IService1">
          <identity>
            <dns value="localhost"/>
          </identity>
        </endpoint>
        <host>
          <baseAddresses>
            <add baseAddress="https://localhost:8080/WCFDemo"/>
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="wsHttpBehavior">
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="false"/>
          <serviceCredentials>
            <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="TransportWithMessageCredential.ServiceAuthanticator, TransportWithMessageCredential"/>
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
  <system.web>
    <compilation debug="true"/>
  </system.web>
</configuration>

Service Authentication class

 public class ServiceAuthanticator : UserNamePasswordValidator
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="userName"></param>
        /// <param name="password"></param>
        public override void Validate(string userName, string password)
        {
            if (String.IsNullOrEmpty(userName) || String.IsNullOrEmpty(password))
            {
                throw new FaultException("Please, Provide the username and password!!!");
            }

            if (userName != "abc" || password != "abc")
            {
                throw new FaultException("Sorry, Invalid username or password!!!");
            }
        }
    }

WCF Client app.config file

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
    <system.serviceModel>
        <bindings>
            <wsHttpBinding>
                <binding name="WSHttpBinding_IService1">
                    <security mode="TransportWithMessageCredential">
                        <transport clientCredentialType="None" />
                        <message clientCredentialType="UserName" />
                    </security>
                </binding>
            </wsHttpBinding>
        </bindings>
        <client>
            <endpoint address="https://kalpesh-pc/WCFAuth/Service1.svc" binding="wsHttpBinding"
                bindingConfiguration="WSHttpBinding_IService1" contract="ServiceReference1.IService1"
                name="WSHttpBinding_IService1">
                <identity>
                    <dns value="localhost" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>
</configuration>

Client Program to call the WCF Services

try
{
    Service1Client objClient = new Service1Client();
    objClient.ClientCredentials.UserName.UserName = "abc";
    objClient.ClientCredentials.UserName.Password = "abc";

    objClient.Open();
    string strData = objClient.GetData(10);
}
catch (FaultException ex)
{
    Console.WriteLine(ex.Message);
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
}

Console.ReadKey();

Happy Coding...

:)

like image 198
Kalpesh Rajai Avatar answered Sep 20 '25 00:09

Kalpesh Rajai