Setting Up FluentSecurity to Use Ninject for Dependency Resolution
A couple of months ago, I blogged about how to secure an ASP.NET MVC application using the excellent library FluentSecurity. I described how to install and configure FluentSecurity; however, I didn’t go into detail about how exactly you would set up a dependency injection framework, which is necessary for FluentSecurity to resolve its policy violation handlers.
In this post, you’ll learn how to use Ninject to register and resolve concrete implementations for a custom FluentSecurity policy violation handler. I assume that you have at least a basic understanding of dependency injection (or inversion of control). If that’s not the case, I recommend you read the Wikipedia article on dependency injection before diving into this post.
Integrating Ninject into Your ASP.NET MVC Application #
Given that you already have an ASP.NET MVC application with FluentSecurity set up, install the NuGet package Ninject.MVC3 to integrate Ninject:
Install-Package Ninject.MVC3
After you have installed the above package, you will find a newly created file called NinjectWebCommon.cs in your application’s App_Start folder. This is where you configure Ninject and register the services you want resolved.
Introducing FluentSecurity to Ninject #
FluentSecurity doesn’t magically know that it’s supposed to use Ninject to resolve services. To use dependency injection, you have to call one of the following two overloads of the ResolveServicesUsing method in FluentSecurity’s configuration section:
ResolveServicesUsing(Func<Type, IEnumerable<object>> servicesLocator)ResolveServicesUsing(ISecurityServiceLocator securityServiceLocator)
The first overload requires you to pass it a method pointer for its servicesLocator parameter. The method you point to has to accept a single Type parameter and return a collection of services that are registered for that specific type. (You can optionally pass in a second parameter that resolves a Type and returns a single service.)
The second overload accepts an instance of a class that implements the interface ISecurityServiceLocator. That interface specifies two methods, Resolve and ResolveAll, which have the same signature as the method pointers used by the parameters of the first overload.
Either overload tells FluentSecurity where to retrieve the required services from. In the end, both provide the same functionality, so which one you use is just a matter of personal preference: You can either implement an interface specifying the methods necessary for resolving services, or you can directly pass the pointers to those methods yourself.
Implementing a Custom Policy Violation Handler #
If a policy is violated, FluentSecurity tries to resolve a policy violation handler that determines what to do. Let’s take the DenyAnonymousAccessPolicy, for example. If an unauthenticated user requests an action that is secured by that policy, FluentSecurity denies access because the policy is violated. It then looks for an appropriate policy violation handler that knows how to handle the specific violation. To be a match for the DenyAnonymousAccessPolicy, the violation handler has to meet the following criteria:
- Its class name has to be
DenyAnonymousAccessPolicyViolationHandler. - It has to implement
IPolicyViolationHandler. - It has to be registered with the dependency injection framework you're using.
Note that the first criterion isn’t required in version 2.0 of FluentSecurity. If you register a policy violation handler called DefaultPolicyViolationHandler, FluentSecurity will use that handler as a fallback if it cannot find a more specific handler for the policy violation.
A possible policy violation handler implementation for the DenyAnonymousAccessPolicy might look like this:
public class DenyAnonymousAccessPolicyViolationHandler : IPolicyViolationHandler
{
public ActionResult Handle(PolicyViolationException exception)
{
return new RedirectToRouteResult("SignIn", routeValues: null);
}
}
Note that you'll have to register a route named SignIn for the handler to function correctly:
routes.MapRoute("SignIn", "SignIn", new { controller = "Account", action = "SignIn" });
It's up to you what type of ActionResult you want to return. Instead of redirecting to the SignIn action, you could also return a special view for unauthorized access, for example.
Registering a Policy Violation Handler #
Before we dive into the FluentSecurity specifics, let’s have a look at how you register services with Ninject in general.
Open the NinjectWebCommon.cs file and locate the RegisterServices method. This is where you register the services for your application. You can also do some advanced stuff in there, such as loading Ninject modules. However, that’s a topic in its own right and won’t be covered in this post.
Ninject provides a fluent syntax to bind interfaces to concrete implementations. A kernel holds the service binding information. The binding syntax is very clean and reads nicely:
kernel.Bind<T>().To<TImplementation>();
To apply the interface binding to your custom policy violation handler scenario, you can bind the IPolicyViolationHandler interface to your DenyAnonymousAccessPolicyViolationHandler as follows:
kernel.Bind<IPolicyViolationHandler>().To<DenyAnonymousAccessPolicyViolationHandler>();
This solution works fine, but it has a catch: For each new policy violation handler that you create, you will have to bind the IPolicyViolationHandler interface to that handler to register it with Ninject. That’ll become tedious work, and you’ll have to remember to update your bindings every time. Plus, manually registering violation handlers doesn’t follow the Open/Closed Principle.
Enough with Poor Man’s Violation Handler Binding™ — let’s take a look at a better solution.
Registering All Policy Violation Handlers in an Entire Assembly #
A more effective approach to registering policy violation handlers is to scan the current assembly for all types implementing IPolicyViolationHandler and to register all of them at once. The code for that is fairly straightforward:
private static void BindPolicyViolationHandlers(IKernel kernel)
{
Type handlerType = typeof(IPolicyViolationHandler);
Func<Type, bool> typeIsHandler = handlerType.IsAssignableFrom;
IEnumerable<Type> assemblyTypes = Assembly.GetExecutingAssembly().GetTypes();
IEnumerable<Type> handlersInAssembly = assemblyTypes.Where(typeIsHandler);
foreach (Type handler in handlersInAssembly)
{
kernel.Bind<IPolicyViolationHandler>().To(handler);
}
}
You can simply call the above method from the RegisterServices method like this:
BindPolicyViolationHandlers(kernel);
With that configuration in place, you can now add new policy violation handlers to your application without any further manual work, such as adding Ninject service bindings. Just remember to name new policy violation handlers according to the naming convention <PolicyName>ViolationHandler and to implement the interface IPolicyViolationHandler.
