views:

1894

answers:

3

Hi,
I am developing WCF services with basicHttpBinding, these services should be accessible using .net 1.1 & .net 2.0, for this purpose I am using basicHttpBinding.
In old ASMX web services I assed one Soap Header (AuthHeader) to authenticate the user every request.

How Can I authenticate in WCF using basicHttpBinding? Any sample Or tutorial will helpfull.

Thanks
nRk

+1  A: 

First of all - yes you can! It depends on whether you use Transport or Message binding - if you're internet-facing, you're more likely to use message-based security.

Unfortunately, for message-based security, basicHttpBinding only supports certificates which is a bit of a pain.

wsHttpBinding on the other hand would support username/password or other methods as well.

You'd configure wsHttpBinding with username/password client credentials over message-based security like this:

  <system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="wsUserName">
          <security mode="Message">
            <message clientCredentialType="UserName"/>
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <services>
      <service name="yourservice">
        <endpoint name="YourEndpoint"
                  address=""
                  binding="wsHttpBinding"
                  bindingConfiguration="wsUserName"
                  contract="IYourService" />
      </service>
    </services>
  </system.serviceModel>

The section under <bindings> defines a binding configuration for wsHttpBinding that uses message-security with username/password client credentials.

The section under <service> defines a sample service that uses wsHttpBinding and that references that binding configuration that we just defined.

On the server side, you could now use the username/password that's being sent over the wire to validate your callers either in your Active Directory (everyone calling needs an AD account with you), or in the ASP.NET membership system database; or if you really really must, you could write your own authentication mechanism, too.

Find a lot of useful information on WCF security at Codeplex - excellent resource.

marc_s
nRk
@nrk: yes, if you use message-security in basicHttpBinding, you can only use certificates to authenticate. If you would use transport security, then you could use other means of authentication
marc_s
A: 

Check the scenarios here to try to match one to your situation. Each scenario is provided with a chceklist of items required to implement the solution.

Tanner
A: 

You can use AuthHeader as you did before switching to WCF. Maybe it will be more convinient for you, cause the princples will remain the same. The bad thing i see in this solution is a plain text password transfer. Anyway, it's just another option and you can encrypt/decrypt the password somehow.

In this case you should implement your own your IDispatchMessageInspector & IClientMessageInspector, like

[AttributeUsage(AttributeTargets.Class)]
public class CredentialsExtractorBehaviorAttribute : Attribute, IContractBehavior, IDispatchMessageInspector
{
    #region IContractBehavior implementation.

    public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint,
                                      DispatchRuntime dispatchRuntime)
    {
        dispatchRuntime.MessageInspectors.Add(this);
    }

    ... empty interface methods impl skipped ...

    #endregion

    #region IDispatchMessageInspector implementation.

    public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
    {
        int i = request.Headers.FindHeader("username", "sec");
        if (-1 != i)
        {
            string username = request.Headers.GetHeader<string>("username", "sec");
            ... do smth ...
        }
        return null;
    }

    public void BeforeSendReply(ref Message reply, object correlationState)
    {
        return;
    }

    #endregion
}

In a sample i placed to header only username, but you can implement your a class containing username and password and use it instead of string. On the client:

internal class CredentialsInserter : IContractBehavior, IClientMessageInspector
{
    private string m_username;

    public CredentialsInserter(string username)
    {
        m_username = username;
    }

    #region IContractBehavior implementation.

    ... empty interface methods impl skipped ...

    public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint,
                                    ClientRuntime clientRuntime)
    {
        clientRuntime.MessageInspectors.Add(this);
    }

    #endregion

    #region IClientMessageInspector implementation.

    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        MessageHeader<string> mh = new MessageHeader<string>(m_username);
        request.Headers.Add(mh.GetUntypedHeader("username", "sec"));
        return null;
    }

    public void AfterReceiveReply(ref Message reply, object correlationState)
    {
        return;
    }

    #endregion
}

Then you should place attribute CredentialsExtractorBehaviorAttribute on your service implementation class.

[CredentialsExtractorBehavior]
public class DummyService : IDummyService
{
   ... impl ...
}

And on the client side you should do the following:

        using (DummyServiceClient c = new DummyServiceClient("TcpEndpoint"))
        {
            c.ChannelFactory.Endpoint.Contract.Behaviors.Add(
                new CredentialsInserter("_username_"));
            c.DummyMethod();
        }
fspirit