Web API Authorization, Filters, Attributes, and Simple Injector

Dec 7, 2013 at 2:28 PM
Edited Dec 7, 2013 at 3:33 PM
I have problem I’m hoping you can change my perspective on or otherwise help me solve.

I have a Web API (OData) that uses the Generic Repository stack, and Simple Injector’s WebRequestLifestyle for Injection lifetime throughout the tiers.

I’m trying to add security to my Web API and ran across this article:

http://www.codeproject.com/Articles/691721/Building-ASP-Net-Web-API-RESTful-Service-Part-8

... describing how they added basic authentication (which is what I’m looking for).

This solution uses attributes over the methods like so:
[LearningAuthorizeAttribute]

public HttpResponseMessage Get(string username)
and for example this class:
public class LearningAuthorizeAttribute : AuthorizationFilterAttribute
calls out to method to login with a user name and password in the overwritten method:
OnAuthorization that take HttpActionContext:


if (authHeader != null)
{
 
if (authHeader.Scheme.Equals("basic", StringComparison.OrdinalIgnoreCase) &&
 
!String.IsNullOrWhiteSpace(authHeader.Parameter))
{
 
var credArray = GetCredentials(authHeader);
 
var userName = credArray[0];
 
var password = credArray[1];
 
if (IsResourceOwner(userName, actionContext))
{
 
//You can use Websecurity or asp.net memebrship provider to login, for
 
//for he sake of keeping example simple, we used out own login functionality
 
if (TheRepository.LoginStudent(userName, password))
{
 
var currentPrincipal = new GenericPrincipal(new GenericIdentity(userName), null);
 
Thread.CurrentPrincipal = currentPrincipal;
 
return;
}
}
}
}
I already have an Authorization repository that can call out to the database to take the place of this LoginStudent method call, but I need to inject it, which brings me to the point… if I add my interface:
IIdentityManager
to the constructor of this filter, then the attribute over the method will need the instructor, how do I go about telling S.I. to inject something into an attribute constructor properly?

What I hope you tell me is I need to, take a step back, think differently about this, and to change my perspective somehow. That using abstraction I can accomplish anything … that I can do this with a Decorator or an Event (new Extensions Rx) or maybe this new thing called OWIN or something.

As always, thanks for your time!

Aaron
Coordinator
Dec 8, 2013 at 9:02 PM
Edited Dec 29, 2013 at 3:23 PM
> then the attribute over the method will need the instructor, how do I go about telling S.I. to inject something into an attribute constructor properly?

You don’t. Attributes are created by the CLR, so you’ll get a compile error when you try to apply an attribute with such a constructor to a particular piece of code. This isn’t specific to Simple Injector; it’s just the way the CLR works. So there are few solutions:
  • You could fall back to property injection on your attributes, but the downside of this is that it introduces temporal coupling.
  • You could split the attribute in the metadata (the attribute) and the logic (a service). But to be able to do this, you must somehow relate those two and make sure that the service gets used when the attribute gets applied.
  • You could ditch attributes all together and fallback to using decorators. Or mix decorators with the use of metadata-only attributes (so attributes without logic). Although I’m (as you might guess) a promoter of the use of decorators, it might not always be easy to apply decorators in the way you need.
To keep things a bit clean, I will write add more detailed responses per solution below.
Marked as answer by dot_NET_Junkie on 2/27/2014 at 12:13 PM
Coordinator
Dec 8, 2013 at 9:05 PM
Edited Mar 9 at 12:56 PM
If you want property injection, you need the following things:
  • Register the Web API IFilterProvider that allows integration with the Simple Injector pipeline.
  • Define a custom IPropertySelectionBehavior that allows property injection for FilterAttributes.
When using the Web API integration package, you can call the RegisterWebApiFilterProvider extension method, which will register an IFilterProvider that integrates with the Simple Injector pipeline for you:
container.RegisterWebApiFilterProvider(GlobalConfiguration.Configuration);
Without the Web API integration package, you will have to write this custom IFilterProvider yourself. Here it is:
public class SimpleInjectorActionFilterProvider : ActionDescriptorFilterProvider,
    IFilterProvider {
    private readonly Func<Type, Registration> registrationFactory;

    private readonly ConcurrentDictionary<Type, Registration> registrations =
        new ConcurrentDictionary<Type, Registration>();

    public SimpleInjectorActionFilterProvider(Container container) {
        this.registrationFactory =
            concreteType => Lifestyle.Transient.CreateRegistration(concreteType, container);
    }

    public new IEnumerable<FilterInfo> GetFilters(HttpConfiguration configuration,
        HttpActionDescriptor actionDescriptor) {
        var filters = base.GetFilters(configuration, actionDescriptor);

        filters = (filters as FilterInfo[]) ?? filters.ToArray();

        foreach (var filter in filters) {
            IFilter instance = filter.Instance;

            Registration registration =
                registrations.GetOrAdd(instance.GetType(), this.registrationFactory);

            registration.InitializeInstance(instance);
        }

        return filters;
    }
}
And this is how you register it:
GlobalConfiguration.Configuration.Services.Remove(typeof(IFilterProvider),
    GlobalConfiguration.Configuration.Services.GetFilterProviders()
        .OfType<ActionDescriptorFilterProvider>().Single());

GlobalConfiguration.Configuration.Services.Add(
    typeof(IFilterProvider),
    new SimpleInjectorActionFilterProvider(container));
The custom SimpleInjectorActionFilterProvider makes use of Simple Injector’s Registration.InitializeInstance() method. This allows initializing an existing instance by sending it through the Simple Injector Pipeline. This allows initialization delegates and to be applied and properties to be injected. The Lifestyle.CreateRegistration method doesn't verify whether the type can actually be created by Simple Injector which is very helpful in this case, since Simple Injector will in most cases not be able to create attribute instances since they usually have overloaded constructors. This however is very helpful in this case, since the InitializeInstance method can still be called in that case.

Simple Injector however, does not inject any properties by default, so you will have to configure it explicitly. That’s why you need a custom IPropertySelectionBehavior:
public class FilterAttributePropertySelectionBehavior : IPropertySelectionBehavior {
    public bool SelectProperty(Type serviceType, PropertyInfo property) {
        return property.DeclaringType.IsSubclassOf(typeof(FilterAttribute)) &&
            !property.PropertyType.IsValueType;
    }
}
When a type is resolved for the first time, Simple Injector will iterate over all properties of that type and ask the registered IPropertySelectionBehavior if this property should be injected or not (of course all this information is cached and burned into the compiled delegate, so the performance penalty is one-time). This specific implementation will return true for every property that is defined on a sub class of FilterAttribute and returns a reference type. Depending on your needs, you might need to tweak this (here's another idea). In contract to the behavior of other DI containers, the container will never silently skip a property when the SelectProperty method returns true. If Simple Injector can’t inject the property (for instance because the property is static, readonly, or the service is not properly registered) the container will throw an exception. This makes your application fail much earlier instead of having to deal with NullReferenceExceptions from somewhere deep down the call stack.

The customer property selection behavior can be registered as follows:
container.Options.PropertySelectionBehavior = 
    new FilterAttributePropertySelectionBehavior();
Downside of this approach is that the attributes are unknown to the container until they are initialized for the first time by the SimpleInjectorActionFilterProvider. This means that Simple Injector won't verify whether the attribute's dependencies can be resolved until InitializeInstance is called. This can result in an application that fails much later than is appropriate.
Coordinator
Dec 18, 2013 at 11:16 AM
Edited Feb 28 at 9:43 AM
The second option is to split the metadata from the logic. This can be done with a little bit of infrastructure: two interfaces, a base class and a custom ActionDescriptorFilterProvider:
public abstract class ActionFilterAttributeBase : ActionFilterAttribute {
    public IWebApiActionFilter Filter { get; set; }

    public override void OnActionExecuting(HttpActionContext actionContext) {
        this.Filter.OnActionExecuting(actionContext);
    }

    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) {
        this.Filter.OnActionExecuted(actionExecutedContext);
    }
}

public interface IWebApiActionFilter {
    void OnActionExecuting(HttpActionContext actionContext);
    void OnActionExecuted(HttpActionExecutedContext actionExecutedContext);
}

public interface IWebApiActionFilter<TAttribute> : IWebApiActionFilter
    where TAttribute : ActionFilterAttribute {
    TAttribute Attribute { get; set; }
}
The abstract ActionFilterAttributeBase can be used to implement custom ActionFilterAttributes. Here's an example:
public class MyAttribute : ActionFilterAttributeBase {
    public MyAttribute(int value) {
        this.Value = value;
    }

    public int Value { get; private set; }
}
This MyAttribute contains no logic. It consists purely of metadata. The logic of this class can be places in an IWebApiActionFilter<MyAttribute> implementation:
public class MyFilter : IWebApiActionFilter<MyAttribute> {
    private readonly IRepository repository;

    public MyFilter(IRepository repository) {
        this.repository = repository;
    }

    public MyAttribute Attribute { get; set; }

    public void OnActionExecuting(HttpActionContext actionContext) {
        Debug.WriteLine("OnActionExecuting " + this.Attribute.Value);
    }

    public void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) {
        Debug.WriteLine("OnActionExecuted " + this.Attribute.Value);
    }
}
This MyFilter is a normal component. It will be resolved from the container and dependencies can be injected into it. Besides the normal dependencies, the related MyAttribute will be injected into the Attribute property. This way the MyFilter can use the metadata that is defined in the attribute.

For this system to work, a custom ActionDescriptorFilterProvider needs to be created:
public class SimpleInjectorActionFilterProvider : IFilterProvider {
    private readonly Lazy<Dictionary<Type, Func<IWebApiActionFilter>>> actionFilters;
    private readonly IFilterProvider decorated;
    public SimpleInjectorActionFilterProvider(Container container, IFilterProvider decorated) {
        this.decorated = decorated;
        this.actionFilters = new Lazy<Dictionary<Type, Func<IWebApiActionFilter>>>(
            () => BuildActionFilters(container));
    }

    public IEnumerable<FilterInfo> GetFilters(HttpConfiguration configuration,
        HttpActionDescriptor actionDescriptor) {
        var filters = this.decorated.GetFilters(configuration, actionDescriptor);

        filters = (filters as FilterInfo[]) ?? filters.ToArray();

        foreach (var filter in filters) {
            var attribute = filter.Instance as ActionFilterAttributeBase;
                
            if (attribute != null) {
                this.InitializeActionFilterAttribute(attribute);
            }
        }

        return filters;
    }

    private void InitializeActionFilterAttribute(ActionFilterAttributeBase attribute) {
        Func<IWebApiActionFilter> factory;

        if (!this.actionFilters.Value.TryGetValue(attribute.GetType(), out factory)) {
            throw new InvalidOperationException(string.Format(
                "The IWebApiActionFilter<{0}> registration is missing.", 
                attribute.GetType().Name));
        }

        var filter = factory();
        attribute.Filter = filter;
        ((dynamic)filter).Attribute = (dynamic)attribute;
    }

    private static Dictionary<Type, Func<IWebApiActionFilter>> BuildActionFilters(
        Container container) {
        return (
            from registration in container.GetCurrentRegistrations()
            where registration.ServiceType.IsGenericType
            where registration.ServiceType.GetGenericTypeDefinition() == 
                typeof(IWebApiActionFilter<>)
            select Tuple.Create<Type, Func<IWebApiActionFilter>>(
                registration.ServiceType.GetGenericArguments().Single(),
                () => (IWebApiActionFilter)registration.GetInstance()))
            .ToDictionary(i => i.Item1, i => i.Item2);
    }
}
This SimpleInjectorActionFilterProvider can be registered as follows:
var oldFilterProvider = 
    GlobalConfiguration.Configuration.Services.GetFilterProviders()
        .OfType<ActionDescriptorFilterProvider>().Single();

GlobalConfiguration.Configuration.Services.Replace(typeof(IFilterProvider),
    new SimpleInjectorActionFilterProvider(container, oldFilterProvider));
The last piece missing is the registration for the IWebApiActionFilter<TAttribute> implementations. This is a simple one-liner:
container.RegisterManyForOpenGeneric(typeof(IWebApiActionFilter<>), 
    Assembly.GetExecutingAssembly());
Coordinator
Dec 29, 2013 at 3:49 PM
The third option is to use decorators. But for some odd reason, the ASP.NET Web API doesn't allow you to decorate IHttpController instances. I don't know if this is an explicit design decision, or that this is accidental, but the fact is that even though the framework provides us with an IHttpController abstraction, it always hooks onto the concrete controller type. This makes it impossible to wrap a controller with a decorator; this will result in a CastException at runtime. Compare this to ASP.NET MVC where decorating IController instances is rather straightforward.

The recommended approach for Web API seems to be the use message handlers and they behave much the same as a decorator would do.

Problem however is that message decorators are registered in Web API as singletons like this:
config.MessageHandlers.Add(new MessageHandler1());
But this is obviously a problem when message handlers get dependencies of their own. Since those dependencies are likely to have a shorter lifestyle than Singleton, so should the registered message handler.

The solution is to register a proxy class instead that will resolve the real handler just in time. Such proxy would look as follows:
public DelegatingHandlerProxy<TMessageHandler> : DelegatingHandler
    where TMessageHandler : HttpMessageHandler {
    private readonly Container container;
    public DelegatingHandlerProxy(Container container) {
        this.container = container;
    }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken) {
        var handler = this.container.GetInstance<TMessageHandler>();
        return handler.SendAsync(request, cancellationToken);
    }
}
The proxy can be registered as follows:
config.MessageHandlers.Add(new DelegatingHandlerProxy<MessageHandler1>(container));
While the proxy is a singleton, every time its SendAsync method is called, it will ask the container for a new instance of the given TMessageHandler (in the case of the example the MessageHandler1).