I'm building a custom permissions system for ASP.NET MVC, because the authorization system that comes with MVC just isn't flexible enough for our needs. This includes an MVC area that's packaged into a DLL along with views, CSS and JavaScript. I have unit tests already, but now I'm trying to create functional tests through the browser. These functional tests would be run locally from my computer or on a continuous integration server.
The permissions system I'm building doesn't do authentication. It just handles authorization. Ideally I'd like to fake the user log-ins for each test. I would like to create a user session from arbitrary usernames and passwords instead of keeping a separate table of users with their passwords, and authenticating against that.
I tried setting the GenericPrincipal
object in the session in my AccountController
, and then setting HttpContext.Current.User
before each request, but the request is always seen as unauthenticated:
AccountController
[Authorize]
public class AccountController : Controller
{
//
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginViewModel model, string ReturnUrl)
{
if (ModelState.IsValid)
{
FormsAuthentication.SetAuthCookie(model.Username, model.RememberMe);
// Add the fake user to the current session so Global.asax can set
// the user on the current HttpContext to this mock object. (See
// Global.asax, Application_AcquireRequestState)
HttpContext.Session["CurrentUser"] = new GenericPrincipal(new GenericIdentity(model.Username), new string[0]);
if (Url.IsLocalUrl(ReturnUrl))
return Redirect(ReturnUrl);
return RedirectToAction("Index", "Home");
}
ModelState.AddModelError(string.Empty, "Username or Password is incorrect");
return View(model);
}
}
Global.asax
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_AcquireRequestState(object sender, EventArgs e)
{
if (HttpContext.Current.Session != null)
{
// Try to get the mock user from the session, which is set in
// AccountController.Login...
HttpContext.Current.User = HttpContext.Current.Session["CurrentUser"] as IPrincipal;
}
}
}
I created a custom Authorize
attribute to be used in my MVC Controllers:
public class PermissionLevelAttribute : System.Web.Mvc.AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (!filterContext.HttpContext.Request.IsAuthenticated || CurrentPrincipal == null)
{
base.OnAuthorization(filterContext);
return;
}
// Custom permissions logic...
}
}
Example usage of this attribute in a Controller:
public class BlogPostsController : Controller
{
[PermissionLevel(Roles="Blogs.Posts.Edit.Update")]
public ActionResult Edit(int id)
{
// ...
}
}
When I do this, the filterContext.HttpContext.Request.IsAuthenticated
property is always false, and it bails out of the OnAuthorization
method.