views:

62

answers:

3

i need to pass a value from client everytime a request sent to WCF and check that value on server and decide to make the request or not, can any one write an example of that ?im not sure how is that is going be implemented

case: im generating a key based on the hardware of the client and i want to send that key to the server with every request to check if the key is accepted in the server db and then decide to process the request or not.

thanks in advance.

+2  A: 

You are looking for message inspector. Check this article.

Edit:

Mentioned approach is the easiest one in your case. You will create client message inspector to add custom header and dispatch message inspector to extract header and validate key. If the key is not valid you will throw an exception.

The clean solution is to create custom token and cutom credentials but it is really complex so unless you want to dive deeply into WCF security implementation use message inspectors.

Ladislav Mrnka
im generating a key based on the hardware of the client and i want to send that key to the server with every request to check if the key is accepted in the server db and then decide to process the request or not
Stacker
So is it an authentication (just checking that the client with key can access the service) or authorization (different keys can use different set of operations)?
Ladislav Mrnka
just check that the client with key can access the service
Stacker
I have added some information into my answer.
Ladislav Mrnka
+1  A: 

I've implemented something like this to deal with some particularly "custom" authentication where methods are allowed or denied based on database state. It uses PerSession implementation, which allows you to avoid passing that key every time, since you can maintain the proxy for the duration of execution. It also provides some performance benefits by eliminating the overhead of instantiating the proxy repeatedly (may not be an issue depending on your design).

  1. Implement your service with an InstanceContextMode of "PerSession" [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
  2. Provide an initialization method in your service which accepts the key, and keeps a reference to it.
  3. In your service's methods, check that key, other conditions, etc. to determine what you need to do.
  4. Now when you instantiate the client proxy, call that initialization method first passing the key, and from that point forward you can proceed to make calls without it.
msulis
actually i have implemented it already , thanks so much for trying to help , i used a different method iw ill post an answer to that soon
Stacker
A: 

first we need to implement Behavior and inspector in the client side to send Key to authenticate the client :

    class AuthenticationBehaviour : IEndpointBehavior
{
    #region IEndpointBehavior Members

    public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
    {
        AuthenticationMessageInspector inspector = new AuthenticationMessageInspector();
        clientRuntime.MessageInspectors.Add(inspector);
    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
    {
        //AuthenticationMessageInspector inspector = new AuthenticationMessageInspector();
        //endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector);
    }

    public void Validate(ServiceEndpoint endpoint)
    {
    }

    class AuthenticationMessageInspector : IClientMessageInspector
{
    private const string HeaderKey = "Authentication";

    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {

        if (Session.MachineId == 0)
        {
            Session.MachineId = LicenseGenerator.GenerateLicense();
        }


        request.Headers.Add(MessageHeader.CreateHeader(HeaderKey, string.Empty, Session.MachineId));
        return null;
    }

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

    }

}

now we need to implement Behavior and inspector in the server side (WCF service) to inspect every request made and extract the header then validate it :

  public class AuthenticationBehaviour : IEndpointBehavior
{
    #region IEndpointBehavior Members

    public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
    {
        //AuthenticationMessageInspector inspector = new AuthenticationMessageInspector();
        //clientRuntime.MessageInspectors.Add(inspector);
    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
    {
        AuthenticationMessageInspector inspector = new AuthenticationMessageInspector();
        endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector);
        //Console.WriteLine("Dispatcher Applied!");
    }

    public void Validate(ServiceEndpoint endpoint)
    {
    }

    #endregion
}

   public class AuthenticationMessageInspector : IDispatchMessageInspector

{

    #region Members
    private string conStr = "", commStr = "";
    public IDbConnection Connection { get; set; }
    public IDbCommand Command { get; set; }
    public IDataReader Reader { get; set; }

    #endregion        
    private const string HeaderKey = "Authentication";
    public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
    {
        //Console.WriteLine("recieved Request! ");
        int headerIndex = request.Headers.FindHeader(HeaderKey, string.Empty);
        if (headerIndex < 0 || string.IsNullOrEmpty(request.Headers.GetHeader<String>(headerIndex)))
        {

            throw (new Exception("Access Denied!\n"));
            return null;
        } 


        bool valid = Validate(request.Headers.GetHeader<String>(headerIndex));
        if (!valid)
        {
            Console.WriteLine("recieved Request! From " + request.Headers.GetHeader<String>(headerIndex) + " and Access Denied!\n");
            throw (new Exception("Access Denied!\n" + request.Headers.GetHeader<String>(headerIndex) + " License Number is not athourized! "));         
        }
        if (headerIndex != -1)
        {
            Console.WriteLine("recieved Request! From " + request.Headers.GetHeader<String>(headerIndex));
        }
        return null;

    }

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

    }
}

now lets register the behavior :

            _routingHost.Description.Endpoints[0].Behaviors.Add(new Gateway.Controllers.AuthenticationBehaviour());
_routingHost.Open();

that is it thanks.

Stacker