Unit test Custom authorize attribute - asp.net-mvc

I've written a custom claims authorizatize attribute and I would like to unit test the code I've written but have been unable to find what I'm looking for on SO.
For example, this is my custom authorize attribute class:
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using IPD2.MVC.Interfaces.Providers;
using IPD2.MVC.Providers;
namespace IPD2.MVC.Attribute
{
public class ClaimsAuthorizeAttribute : AuthorizeAttribute
{
private readonly string _claimValue;
private readonly string _claimType;
private readonly ITokenProvider _tokenProvider;
public ClaimsAuthorizeAttribute(string type, string value)
{
_claimType = type;
_claimValue = value;
_tokenProvider = new TokenProvider();
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
var jwt = _tokenProvider.ApiToken as JwtSecurityToken;
if (jwt == null)
{
HandleUnauthorizedRequest(filterContext);
}
else
{
var claim = jwt.Claims.FirstOrDefault(expr => expr.Value == _claimValue);
var authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
var formsAuthenticationTicket = FormsAuthentication.Decrypt(authCookie.Value);
if (formsAuthenticationTicket != null && !formsAuthenticationTicket.Expired)
{
var roles = formsAuthenticationTicket.UserData.Split(',');
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(new FormsIdentity(formsAuthenticationTicket), roles);
}
}
if (claim != null)
{
base.OnAuthorization(filterContext);
}
else
{
HandleUnauthorizedRequest(filterContext);
}
}
}
}
}
Test code
public class GivenCallingClaimAuthorizationAttribute : SpecsFor<ClaimsAuthorizeAttribute>
{
//HttpActionContext actionContext;
//IPrincipal originalPrincipal;
protected override void Given()
{
SUT = new ClaimsAuthorizeAttribute(ClaimTypes.Role, "ImNotAllowedToUseController :(");
}
public class WhenUserIsNotAllowedToAccessController : GivenCallingClaimAuthorizationAttribute
{
protected override void When()
{
SUT.OnAuthorization(
new AuthorizationContext()
);
}
}
[Test]
public void ThenAssertSomethingBasedOnCodeInTest()
{
//todo: some assert
}
}
I've written this basic test class with the SpecsFor BDD framework but I'm not sure what it needs to test it succesfully.
Any ideas on how to test this? As you can see, I'm testing the class itself rather than a controller with the attribute. I'm not sure about a good way to test this.

If you want to do BDD, think about the behaviour of your class. What kind of things should it be able to do?
For instance, perhaps it should:
- authorize current users
- filter users whose ticket has expired
- assign authorized users with the correct roles
- etc.
Let's say we're going to look at the second one of those, because it's interesting. I'll ask you, "Can you give me an example of when a ticket might expire?"
And you say, "Yes, the timeout is 500ms so anything older than that is expired." Or you say, "These are tickets to a football match and are given out yearly." (I don't know what a ticket is, but this conversation would help me work that out.)
So then we can write an example:
Given we've got a handler for unauthorized tickets
Given Fred's ticket expired on 2017-05-14
And it's now 2017-05-14
When we try to authenticate Fred
Then Fred should not be authenticated
And the handler should be given Fred's details
Next I like to put these in comments in code, with the "should" as the title of the test. After that, it's just a matter of setting up the context (in the Given), passing it to your code to exercise (the When) and verifying the outcome (the Then).
However, you can see that your Specs framework only allows for one given! That's not great, since I've already identified several scenarios which require different contexts. If you use SpecsFor the way you're using it, you'll have to make one class for each of my scenarios, and they won't be very easy to read!
I highly recommend using the second style instead, and start just with the Given, When, Then in comments.
The thing is, unit tests' steps aren't really reused much, compared to say a full-system BDD scenario, in which contexts are often called several times for different capabilities. A unit of code (or class) tends to fulfil one responsibility, or it gets refactored that way, and its contexts don't bleed into other classes because Mocks.
So, I find that just having Given, When and Then in comments is enough.
I therefore recommend you switch to the "old school" way of doing things that I can see in this page (down the bottom) and just start with the comments. See how that goes for you.
By the way, if you really want to do BDD properly, then you want to drive the development with the examples of how it behaves, and incrementally fill in the code to make those examples work, rather than writing them down. The book "Growing Object Oriented Software, Guided By Tests" will be very helpful for you.

Related

How to mock Request.IsAjaxRequest() to true using FakeItEasy?

Following is the code snippet for which I want to write unit tests:
[HttpGet]
public ActionResult Edit(string id)
{
if (Request.IsAjaxRequest())
{
EditModel model = new EditModel();
.....
}
return View();
}
I want to write unit tests for this action where I can fake the result of Request.IsAjaxRequest() to true so that I can write tests for rest of the code of the action.
I have tried following but it doesn't work. _request.Headers is always empty, and Request.IsAjaxRequest() is always returning false:
[Fact]
public void Get_Edit_AjaxRequest_ExpectedActionCalled()
{
HttpRequestBase _request = A.Fake<HttpRequestBase>();
_request.Headers.Add("X-Requested-With", "XMLHttpRequest");
_controller.ControllerContext = A.Fake<ControllerContext>();
_controller.ControllerContext.HttpContext = _request;
A.CallTo(() => _controller.Request).Returns(_request);
var result = _controller.Edit(1) as RedirectToRouteResult;
}
I always get Request.IsAjaxRequest() as false. Any help on this much appreciated. Thanks
I managed to muddle past the compilation errors and use some information from Chapter 10 of FakeItEasy Succinctly, which is all about ASP.NET MVC.
Generally speaking, the ASP.NET MVC classes are not designed in a way to make them easily fakeable, but I have a test setup that causes IsAjaxRequest to return true. The two main hurdles were getting the controller to use the request object and to make sure that the request object was returning the headers we wanted.
The first part was not hard, but the second required us to have the request object use a concrete NameValueCollection. The faked one that it had been providing by default was not useful, because the right properties weren't virtual. Fortunately, using a real NameValueCollection did the trick.
Try this:
[Fact]
public void Get_Edit_AjaxRequest_ExpectedActionCalled_Blair()
{
HttpRequestBase _request = A.Fake<HttpRequestBase>();
// NameValueCollection is effectively unfakeable due to non-virtual properties,
// but a real one works just fine, so make sure the headers use one of those.
A.CallTo(() => _request.Headers).Returns(new NameValueCollection());
_request.Headers["X-Requested-With"] = "XMLHttpRequest";
var httpContext = A.Fake<HttpContextBase>();
A.CallTo(() => httpContext.Request).Returns(_request);
_controller.ControllerContext = new ControllerContext(
new RequestContext(httpContext, new RouteData()),
_controller);
var result = _controller.Edit(1) as RedirectToRouteResult;
}
Be warned that there will be lots of pitfalls like this in the MVC framework, and continuing to fake them may continue to be frustrating. You may find a more sustainable approach is to extract as much of your logic as is feasible out into plain old testable business classes that don't rely on the MVC framework.

Autofac Dependencies Per Area

I'm creating a new MVC4 site using Autoface that has a public consumer site as well as an admin area for managing the consumer facing site. The admin site will be located in a different area be using the same services as the consumer facing site, but will not having some of the custom branding features.
I've followed the advice given elsewhere of having a ViewDataFactory which provides a set of shared data for the view to use. My goal is to provide a different ViewDataFactory depending on what Area you are in.
So for example, here is the Service that implements IViewDataFactory
builder.RegisterType<SelfServiceViewDataFactory>().As<IViewDataFactory>();
This gives me one ViewFactory which is injected into all my controllers. However what I'm trying to acheive is something like this (not functional code):
builder.RegisterType<ViewDataFactory>().As<IViewDataFactory>().ForType(ControllerBase1);
builder.RegisterType<DifferentViewDataFactory>().As<IViewDataFactory>().ForType(ControllerBase2);
Where the controller type or the MVC area would determine which service is resolved.
EDIT
To clarify my post has two questions:
Is there a way in Autofac to say "only for classes of type X, a service of type Y will be provided by instance Z" ?
Is there a way to change the Autofac behavior based on the Area the component is being used in?
From everything I've been reading the answer to #1 seems to be "no" unless you have a parameter to use to check which component to supply. I know Ninject can supply a dependency based on namespace so other frameworks seems to handle this case. Seems the solution is to either supply a parameter or have two different services defined.
I haven't really seen much discussion of Autofac and MVC areas so I'm guessing #2 is also not possible without a custom solution. Thanks!
Using named services is probably your best option. So you'd do something like:
builder
.RegisterType<ViewDataFactory>()
.Named<IViewDataFactory>("Area1");
builder
.RegisterType<DifferentViewDataFactory>()
.As<IViewDataFactory>("Area2");
And then if you want to avoid having to then manually register your controllers. You could use this code that I just cobbled together and haven't tested:
Put this attribute somewhere globally accessible:
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
public class ServiceNamedAttribute : Attribute
{
private readonly string _key;
public ServiceNamedAttribute(string key)
{
_key = key;
}
public string Key { get { return _key; } }
}
Add this module to your Autofac config:
public class ServiceNamedModule : Module
{
protected override void AttachToComponentRegistration(
IComponentRegistry registry, IComponentRegistration registration)
{
registration.Preparing +=
(sender, args) =>
{
if (!(args.Component.Activator is ReflectionActivator))
return;
var namedParameter = new ResolvedParameter(
(p, c) => GetCustomAttribute<ServiceNamedAttribute>(p) != null,
(p, c) => c.ResolveNamed(GetCustomAttribute<ServiceNamedAttribute>(p).Name, p.ParameterType));
args.Parameters = args.Parameters.Union(new[] { namedParameter });
};
}
private static T GetCustomAttribute<T>(ParameterInfo parameter) where T : Attribute
{
return parameter.GetCustomAttributes(typeof(T), false).Cast<T>().SingleOrDefault();
}
}
And then you can still auto-register your controllers by decorating the constructor like so:
public class Controller1
{
public Controller1(ServiceNamed["Area1"] IViewDataFactory factory)
{ ... }
}

How to set up Ninject DI to create Hyprlinkr RouteLinker instances

I have an MVC4 Web API project and I making use of Mark Seemann's Hyprlinkr component to generate Uris to linked resources. (Customer -> Addresses for example).
I have already followed Mark's guide on Dependency injection with Web API (changing appropriately for Ninject) bit I can't quite work out what I should do to inject a IResourceLinker into my controllers.
Following Mark's guide my IHttpControllerActivator.Create create method looks like this:
IHttpController IHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
var controller = (IHttpController) _kernel.GetService(controllerType);
request.RegisterForDispose(new Release(() => _kernel.Release(controller)));
return controller;
}
It is in this method that the Hyprlinkr readme suggests to create the RouteLinker. Unfortunately I'm not sure how to register this with Ninject.
I can't just bind like below, as this results in multiple bindings:
_kernel.Bind<IResourceLinker>()
.ToMethod(context => new RouteLinker(request))
.InRequestScope();
I've got rebind working like this:
_kernel.Rebind<IResourceLinker>()
.ToMethod(context => new RouteLinker(request))
.InRequestScope();
But I'm concerned that changing the ninject binding graph is potentially a bad thing to do on every request.
What is the best way to achieve this?
Update following the request from Paige Cook
I'm using rebind here:
IHttpController IHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
_kernel.Rebind<IResourceLinker>()
.ToMethod(context => new RouteLinker(request))
.InRequestScope();
var controller = (IHttpController) _kernel.GetService(controllerType);
request.RegisterForDispose(new Release(() => _kernel.Release(controller)));
return controller;
}
IHttpControllerActivator.Create is called on every request. The rest of the bindings are made in the standard way, by standard I mean in the class generated by using the Ninject.MVC3 nuget package.
My controller looks like this:
public class CustomerController : ApiController
{
private readonly ICustomerService _customerService;
private readonly IResourceLinker _linker;
public CustomerController(ICustomerService customerService, IResourceLinker linker)
{
_customerService = customerService;
_linker = linker;
}
public CustomerModel GetCustomer(string id)
{
Customer customer = _customerService.GetCustomer(id);
if (customer == null)
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
}
return
new CustomerModel
{
UserName = customer.UserName,
Firstname = customer.Firstname,
DefaultAddress = _linker.GetUri<AddressController>(c => c.Get(customer.DefaultAddressId)),
};
}
}
Register a delegate Function to give you the linker
_kernel.Bind<Func<HttpRequestMessage, IResourceLinker>>()
.ToMethod(context => (request) => new RouteLinker(request));
Inject the delegate
readonly Func<HttpRequestMessage, IResourceLinker> _getResourceLinker;
public controller(Func<HttpRequestMessage, IResourceLinker> getResourceLinker) {
_getResourceLinker = getResourceLinker;
}
Use in your actions
public async Task<Thingy> Get() {
var linker = _getResourceLinker(Request);
linker.GetUri( ... )
}
If you only need to use RouteLinker from ApiController derivates, you don't really need to go through all the DI hoops.
You can just create it within the Controller like this:
var linker = new RouteLinker(this.Request);
IMO, using DI with RouteLinker first becomes valuable when you need a RouteLinker further down the stack - but then again, I also only use RouteLinker as a Concrete Dependency...
Thanks for adding the code sample. Based on what you have posted, you are running into your Bind/Rebind issue because you are issuing the _kernel.Bind<IResourceLinker> in the IHttpControllerActivtor.Create method every time.
You need to move the _kernel.Bind<IResourceLinker> to be registered the same way your are registering the rest of your bindings in the
...standard way, by standard I mean in the class generated by using the Ninject.MVC3 nuget package.
There should not be any need for the IResourceLinker to be binded multiple times, and this is why you are getting multiple instances, because the binding is firing every time a controller is created by the IHttpControllerActivator.
Update:
Sorry that I missed the need for an HttpRequestMessage as a constructor argument, I would go with Anthony Johnson's answer on this one.

Unit testing a controller in ASP.NET MVC 2 with RedirectToAction

I have a controller that implements a simple Add operation on an entity and redirects to the Details page:
[HttpPost]
public ActionResult Add(Thing thing)
{
// ... do validation, db stuff ...
return this.RedirectToAction<c => c.Details(thing.Id));
}
This works great (using the RedirectToAction from the MvcContrib assembly).
When I'm unit testing this method I want to access the ViewData that is returned from the Details action (so I can get the newly inserted thing's primary key and prove it is now in the database).
The test has:
var result = controller.Add(thing);
But result here is of type: System.Web.Mvc.RedirectToRouteResult (which is a System.Web.Mvc.ActionResult). It doesn't hasn't yet executed the Details method.
I've tried calling ExecuteResult on the returned object passing in a mocked up ControllerContext but the framework wasn't happy with the lack of detail in the mocked object.
I could try filling in the details, etc, etc but then my test code is way longer than the code I'm testing and I feel I need unit tests for the unit tests!
Am I missing something in the testing philosophy? How do I test this action when I can't get at its returned state?
I am using MVC2 RC2 at the moment and the answer from rmacfie didn't quite work for me but did get me on the right track.
Rightly or wrongly I managed to do this in my test instead:
var actionResult = (RedirectToRouteResult)logonController.ForgotUsername(model);
actionResult.RouteValues["action"].should_be_equal_to("Index");
actionResult.RouteValues["controller"].should_be_equal_to("Logon");
Not sure if this will help someone but might save you 10 minutes.
There is MVC Contrib TestHelper that are fantastic for testing most of the ActionResult
You can get it here:
http://mvccontrib.codeplex.com/wikipage?title=TestHelper
Here is an example of the syntax:
var controller = new TestController();
controller.Add(thing)
.AssertActionRedirect()
.ToAction<TestController>(x => x.Index());
To test if the data has been persisted successfully, you should maybe ask your database directly, I don't know if you're using an ORM or something, but you should do something to get the last insterted item in your database, then compare with the value you provided to your Add ActionResult and see if this is ok.
I don't think that testing your Details ActionResult to see if your data is persisted is the right approach. That would not be an unit test, more a functional test.
But you should also unit test your Details method to make sure that your viewdata object is filled with the right data coming from your database.
You seem to be doing way too much for a unit test. The validation and data access would typically be done by services that you call from the controller action. You mock those services and only test that they were called properly.
Something like this (using approximate syntax for Rhino.Mocks & NUnit):
[Test]
public void Add_SavesThingToDB()
{
var dbMock = MockRepository.GenerateMock<DBService>();
dbMock.Expect(x => x.Save(thing)).Repeat.Once();
var controller = new MyController(dbMock);
controller.Add(new Thing());
dbMock.VerifyAllExpectations();
}
[Test]
public void Add_RedirectsAfterSave()
{
var dbMock = MockRepository.GenerateMock<DBService>();
var controller = new MyController(dbMock);
var result = (RedirectToRouteResult)controller.Add(new Thing());
Assert.That(result.Url, Is.EqualTo("/mynew/url"));
}
I have a static helper method that tests redirection.
public static class UnitTestHelpers
{
public static void ShouldEqual<T>(this T actualValue, T expectedValue)
{
Assert.AreEqual(expectedValue, actualValue);
}
public static void ShouldBeRedirectionTo(this ActionResult actionResult, object expectedRouteValues)
{
RouteValueDictionary actualValues = ((RedirectToRouteResult)actionResult).RouteValues;
var expectedValues = new RouteValueDictionary(expectedRouteValues);
foreach (string key in expectedValues.Keys)
{
Assert.AreEqual(expectedValues[key], actualValues[key]);
}
}
}
Then creating a redirection test is very easy.
[Test]
public void ResirectionTest()
{
var result = controller.Action();
result.ShouldBeRedirectionTo(
new
{
controller = "ControllerName",
action = "Index"
}
);
}

RIA Services: How can I create custom authentication?

I am working with the Silverlight RIA Services and I want to create custom authentication. This appears to be the only thing that has virtually no documentation (I've read through the entire RIAServicesOverview.docx).
Do you know of a way for me to create a customer authentication service? I don't want to use the default ASP.NET membership model. I don't know what interface or abstract class I need to implement - although I did find System.Web.Ria.ApplicationServices.IAuthentication.
Do I need to implement IAuthentication? If so, could you give me some advice on how to go about doing so? These are the following methods:
public User GetUser();
public User Login(string userName, string password, bool isPersistent, string customData);
public User Logout();
public void UpdateUser(User user);
I don't know how I would implement any of these (except for Login) - how could the service possibly know what user is currently logged in in order for Logout() to work?
I've been scouring the web in search of how to do this for hours, and I can't find anything that describes how to create a simple DomainService that can be used for authenticating a user in an "RIA-linked" Silverlight project.
If someone could shed some light on this, I'd be sincerely grateful.
Thanks,
Charles
[EDIT]
I found the RIA Services page on the MSDN Code Gallery. There's a section called Authentication Samples, which links to some great code samples. Check it out if you want to know more about how authentication works within RIA Services.
If you create a "Silverlight Business Application" you'll see how the template implements authentication. (Or just go here and download the template sample project.)
To simplify, here's the process I used:
First, I create a domain service (FooService) that derives from LinqToEntitiesDomainService where FooContext is my entity model. In it I add all the CRUD operations to access my custom DB table and return user profiles.
Next, create a concrete User class on the serverside by deriving from UserBase:
using System.Web.Ria;
using System.Web.Ria.ApplicationServices;
public class User : UserBase
{}
Finally, derive a class from AuthenticationBase and implement the following four methods:
[EnableClientAccess]
public class AuthenticationService : AuthenticationBase<User>
{
private FooService _service = new FooService();
protected override bool ValidateUser(string username, string password)
{
// Code here that tests only if the password is valid for the given
// username using your custom DB calls via the domain service you
// implemented above
}
protected override User GetAuthenticatedUser(IPrincipal pricipal)
{
// principal.Identity.Name will be the username for the user
// you're trying to authenticate. Here's one way to implement
// this:
User user = null;
if (this._service.DoesUserExist(principal.Identity.Name)) // DoesUserExist() is a call
// added in my domain service
{
// UserProfile is an entity in my DB
UserProfile profile = this._service.GetUserProfile(principal.Identity.Name);
user.Name = profile.UserName;
user.AuthenticationType = principal.Identity.AuthenticationType;
}
return user;
}
public override void Initialize(DomainServiceContext context)
{
this._service.Initialize(context);
base.Initialize(context);
}
protected override void Dispose(bool disposing)
{
if (disposing)
this._service.Dispose();
base.Dispose(disposing);
}
}
Here is a complete official example from MS:
http://code.msdn.microsoft.com/Custom-Authentication-96ca3d20
How about implementing the IAuthorization interface?

Resources