Skip to content

Web Authentication Overview

mikeobrien edited this page Sep 14, 2010 · 2 revisions

When designing Restful resources its common to secure specific verbs while others are public. For example if we have a library who exposes a “books” resource, GET will be public while POST, PUT and DELETE will require authentication. You may also want to secure one service but expose another one publicly. The WCF REST Contrib web authentication behavior enables you to secure individual services or individual operations. Web authentication requires two components; one to handle the authentication and another to validate credentials.

Defining an Authentication Handler

An authentication handler implements WcfRestContrib.ServiceModel.Dispatcher.IWebAuthenticationHandler and has a parameterless constructor. You can create your own or use the WCF REST Basic Authentication Handler (See more about that under Basic Authentication Handler Overview). This interface only has one method, “Authenticate” which is passed information about the request/response. When securing operations the deserialized method parameters will be passed. The method also accepts a “source” parameter which is an arbitrary string identifying the application that is authenticating (See more about this below). The job of this handler is to extract the credentials from the request and validate them with the UserNamePasswordValidator that is passed in.

public class MyCustomAuthenticationHandler : WcfRestContrib.ServiceModel.Dispatcher.IWebAuthenticationHandler 
{
     public IIdentity Authenticate(
            IncomingWebRequestContext request, 
            OutgoingWebResponseContext response, 
            object[] parameters, 
            UserNamePasswordValidator validator, 
            string source)
    {
        string username = ...;
        string password = ...;
        validator.Validate(username, password);
        return new GenericIdentity(username, "MyCustomAuthenticationHandler");
    }
}

Defining a UserNamePasswordValidator

The credentials validator is the stock .NET one; System.IdentityModel.Selectors.UserNamePasswordValidator. Simply inherit from this class and override the Validate method. This class must have a parameterless constructor.

public class MySecurityValidator : System.IdentityModel.Selectors.UserNamePasswordValidator
{
    public override void Validate(string userName, string password)
    {
        if (userName != "tony" || password != "clifton")
            throw new Exception();
    }
}

If authentication fails, simply throw an exception.

Enabling Web Authentication

Now that we have an authentication handler and credentials validator we can secure our services or operations. First we need to specify the handler and validator the service or operations will use. We can do this declaratively with the WcfRestContrib.ServiceModel.Description.WebAuthenticationConfigurationAttribute:

[WebAuthenticationConfiguration(
    typeof(MyApplication.MyCustomAuthenticationHandler),
    typeof(MyApplication.MySecurityValidator),
    "My Application")]
public class Service: IService {...}

Or in configuration as a service behavior:

<system.serviceModel>
    <extensions>
        <behaviorExtensions>
            <add name="webAuthentication" 
                 type="WcfRestContrib.ServiceModel.Configuration.WebAuthentication.ConfigurationBehaviorElement, WcfRestContrib, 
                       Version=x.x.x.x, Culture=neutral, PublicKeyToken=89183999a8dc93b5"/>
        </behaviorExtensions>
    </extensions>
    <serviceBehaviors>
        <behavior name="Rest">
            <webAuthentication 
                    authenticationHandlerType="MyApplication.MyCustomAuthenticationHandler, MyApplication" 
                    usernamePasswordValidatorType="MyApplication.MySecurityValidator, MyApplication" 
                    source="My Application"/>
        </behavior>
    </serviceBehaviors>
</system.serviceModel>

Note that you can specify an arbitrary string as the “source”. This simply identifies the application authenticating and can be used for logging, etc.

Now we simply apply either the WcfRestContrib.ServiceModel.Description.ServiceAuthenticationAttribute to the service or service contract we want secured:

[ServiceContract]
[ServiceAuthentication]
public interface IService
{
    [WebGet(UriTemplate = "/{id}")]
    [OperationContract]
    Item GetSomething(string id);
    ...
}

Or the WcfRestContrib.ServiceModel.Description.OperationAuthenticationAttribute to the individual operations we want secured:

[ServiceContract]
public interface IService
{
    [WebGet(UriTemplate = "/{id}")]
    [OperationContract]
    Item GetSomething(string id);

    [WebInvoke(Method="POST")]
    [OperationContract]
    [OperationAuthentication]
    void AddSomething(Item item);

    [WebInvoke(UriTemplate = "/{id}", Method="DELETE")]
    [OperationContract]
    [OperationAuthentication]
    void DeleteSomething(string id);
}

Notice that only operations modifying a resource are secured, the readonly operation is not secured.

NOTE: The WcfRestContrib.ServiceModel.Web.WebServiceHost allows you to specify configuration based behaviors if you do not want to specify this declaratively. See more about it under Declarative Binding & Behavior Overview.