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 Aug 27 at 6:55 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:
// NOTE: You dont need this class if you use the integration package!
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 contrast 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 custom 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 May 19 at 8:36 PM
The second option is to split the metadata from the logic. The following article explains this in detail: Dependency Injection in Attributes: don’t do it!
Coordinator
Dec 29, 2013 at 3:49 PM
Edited Oct 21 at 10:13 AM
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 sealed class DelegatingHandlerProxy<THandler> : DelegatingHandler
    where THandler : DelegatingHandler {
    private readonly Container container;

    public DelegatingHandlerProxy(Container container) {
        this.container = container;
    }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken) {

        // Important: Trigger the creation of the scope.
        request.GetDependencyScope();

        var handler = this.container.GetInstance<THandler>();

        handler.InnerHandler = this.InnerHandler;

        var invoker = new HttpMessageInvoker(handler);

        return invoker.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).
Oct 21 at 9:57 AM
Hi guys,
Sorry to reply to old thread, but I was just trying to implement authentication on WebApi using 3rd option above and was having some compile problems.
I copied the above DelegatingHandlerProxy class but it's throwing compile error on the last line "return handler.SendAsync(request, cancellationToken);"
I'm a bit new to this so any advise or better way.
Thanks,
Simon

Error 1 Cannot access protected member 'System.Net.Http.HttpMessageHandler.SendAsync(System.Net.Http.HttpRequestMessage, System.Threading.CancellationToken)' via a qualifier of type 'TMessageHandler'; the qualifier must be of type 'DelegatingHandlerProxy<TMessageHandler>' (or derived from it)
Coordinator
Oct 21 at 10:15 AM
Hi simmohall, unfortunately the given example is incorrect. The Web API integration guide contains an updated (and working) example of this. I just updated my previous answer above to match the integration guide.
Oct 21 at 10:59 AM
Fantastic works a treat!
Thanks for the quick reply