How to provide a ServiceSecurityContext?

Topics: Web Api
Aug 24, 2011 at 7:23 PM

Hi,

I have looked a bit at Web API and i'm considering moving some of my REST web services to it.

In my current solution (WCF/REST) I've created my own WebServiceHost/WebServiceHostFactory in order to inject custom interceptors.
One of these interceptors intercept the message and adds a new ServiceSecurityContext as it's properties (through SecurityMessageProperty).

So my question is, how do I do this the easiest way with Web API? So far I've created my own DelegatingChannel and added most of my authentication there.
But I have not been successful with adding a SecurityMessageProperty to the message.

Thanks,

Robin 

Aug 25, 2011 at 4:27 PM
Edited Aug 25, 2011 at 4:31 PM

Here's a modified example of how I accomplished this using Unity:

ApiServiceAuthorizationChannel
SetMessageHandlerFactory(httpMessageChannel => new ApiServiceAuthorizationChannel(httpMessageChannel, _Container))
/// <summary>
/// Defines a WebApi delegating channel which handles authentication.
/// </summary>
/// <remarks></remarks>
internal class ApiServiceAuthorizationChannel : DelegatingChannel
{
    #region Fields

    private readonly IUnityContainer _Container;

    #endregion

    #region Constructors

    /// <summary>
    /// Initializes a new instance of the <see cref="ApiServiceAuthorizationChannel"/> class.
    /// </summary>
    /// <param name="innerChannel">The inner channel.</param>
    /// <param name="container">The container.</param>
    /// <remarks></remarks>
    public ApiServiceAuthorizationChannel(HttpMessageChannel innerChannel, IUnityContainer container)
        : base(innerChannel)
    {
        _Container = container;
    }

    #endregion

    #region Methods

    /// <summary>
    /// Sends the async request.
    /// </summary>
    /// <param name="request">The request.</param>
    /// <param name="cancellationToken">The cancellation token.</param>
    /// <returns><see cref="Task&lt;HttpResponseMessage&gt;"/> instance to send.</returns>
    /// <remarks></remarks>
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        AuthenticateRequest(request);

        return base.SendAsync(request, cancellationToken);
    }

    private void AuthenticateRequest(HttpRequestMessage request)
    {
        if (request.Headers.Authorization == null)
        {
            return;
        }

        var authenticationScheme = request.Headers.Authorization.Scheme;
        if (!String.IsNullOrWhiteSpace(authenticationScheme))
        {
            var cryptographyProvider = _Container.Resolve<ICryptographyManager>().Provider;
            var authenticationProvider = _Container.Resolve<INetworkAccessTokenAuthenticationProvider>(authenticationScheme.ToLower());
            if (authenticationProvider != null)
            {
                authenticationProvider.AuthenticateToken(request.Headers.Authorization.Parameter.ToNameValueCollection(',', '='))
                                      .Do(principals =>
                                          {
                                              var principal = principals.Single();  // IPrincipal with IIdentity
                                              request.Properties.Add("RequestPrincipal", principal);
                                          });
            }
        }
    }

    #endregion
}

The code snippet below is used for resolving the service via Unity which supports Interception.  I register my service endpoints in Unity with their interface contracts.

_Container.RegisterType(route.ServiceContractType, route.ServiceType, new Interceptor<InterfaceInterceptor>(), new InterceptionBehavior<PolicyInjectionBehavior>());
HttpHostConfiguration.Create()
    .SetResourceFactory(
        (serviceType, instanceContext, requestMessage) =>
        instanceContext.Host
.Description
.Endpoints .MaybeFirst() .Bind(serviceEndpoint => _Container.Resolve(serviceEndpoint.Contract.ContractType, new DependencyOverride<HttpRequestMessage>(requestMessage)) .ToMaybe()) .FromMaybe(null), null)

ApiResourceBase.cs  << All services inherit from this.

    /// <summary>
    /// Defines an abstract base class for API services.
    /// </summary>
    public abstract class ApiResourceBase : IDisposable
    {
        // .... CODE REMOVE TO SIMPLIFY EXAMPLE ....

        /// <summary>
        /// Gets the service token for the incoming request.
        /// </summary>
        protected ServicePrincipal Principal
        {
            get
            {
                return Thread.CurrentPrincipal as ServicePrincipal;
            }
        }

        /// <summary>
        /// Initializes dependencies.
        /// </summary>
        /// <param name="httpRequestMessage">The HTTP request message.</param>
        /// <param name="unityContainer">The unity container.</param>
        /// <remarks>Used by Unity to set dependencies upon resolve.</remarks>
        [InjectionMethod]
        public void Initialize(
            [Dependency]HttpRequestMessage httpRequestMessage, 
            [Dependency]IUnityContainer unityContainer)
        {
            _RequestMessage = httpRequestMessage;
            _UnityContainer = unityContainer;

            LookupPrincipal();
        }

        private void LookupPrincipal()
        {
            if (_RequestMessage.Properties.ContainsKey("RequestPrincipal"))
            {
                Thread.CurrentPrincipal = (IPrincipal)_RequestMessage.Properties["RequestPrincipal"];
            }
        }
    }

Resource Authorization

In my service contracts I have Unity Interception attributes which implement ICallHandler and I have written custom providers which implement IAuthorizationProvider. These are part of Enterprise Library.

[ServiceContract]
public interface IExampleResource
{
[RequiredCredentialsAuthorization(NetworkAuthorization.SiteCredentials)]
[WebGet(UriTemplate = "subscriptions/{subscriptionId}/item")]
HttpResponseMessage<ServiceResponse<ItemDto>> GetItemFromSubscription(Int32 subscriptionId);
}

Hope this helps!