views:

254

answers:

1

Hi,

This is my first post here, so hello :) Okay, let's get to the point... I am writing my first app in ASP.NET MVC Framework and i have a problem with checking privileges to use instances of model classes (read, edit). Sample code looks like this:

// Controller action

[CustomAuthorize(Roles="Editor, Admin")]
public ActionResult Stats(int id)
{
    User user = userRepository.GetUser(id);

    if (user == null || !user.Activated || user.Removed)
        return View("NotFound");
    else if (!user.IsCurrentSessionUserOwned)
        return View("NotAuthorized");

    return View(user);
}

So far authorize attribute protects only controller actions, so my question is: how to make CustomAuthorize attribute to check not only user role, usernames but also did i.e. resources instantiated in action methods (above: User class, but there are other ORM LINQ2SQL classes like News, Photos etc.) All of these object to check have their unique ID's, so user entity have own ID, News have their ID's and UserID field referecned to Users table. How should i resolve that problem?

+1  A: 

If i understand right, you want to let the user who write News,Articles to edit his own News or Articles even if he doesnt has the role of "Admin" or "Editor"..

Well that is a tricky one, the simple solution would be:

Let your CustomAuthorize as it is, BUT let it continue to the Action, instead of returning a error View or something just inject an action parameter ie:

CustomAuthorize:

//..Your Role Validation Logic Here...
  if (filterContext.ActionParameters.Keys.Contains("isAuthorize"))
       {
         filterContext.ActionParameters.Remove("isAuthorize");
       }
   filterContext.ActionParameters.Add("isAuthorize", isAuthorized);

Where isAuthorized will hold the result of the role validation logic.

So in your controller, you must add a 2nd parameter:

[CustomAuthorize(Roles="Editor, Admin")]
public ActionResult Stats(int id, bool isAuthorized)
{
    User user = userRepository.GetUser(id);

    if (user == null || !user.Activated || user.Removed)
        return View("NotFound");
    else if (user.Id != CurrentUser.Id && !isAuthorized)
            //not Authorized by roles
            //not the owner get away from here =D
        return View("NotAuthorized");

    return View(user);
}

I'm assuming you have access to a CurrentUser that comes from a property in BaseController (abstrac class).

Implementing something more elaborated than that will result in a complex situation.

For instance you can, but not recommended:

A. Send the userID of the owner as a parameter (so every time you send an ID on the url GET or POST request you must add the user ID of the owner as a parameter). But this can lead to really ugly security flaws, because you depend on the userID that is send by the wire that can be tamper by the user and woala! im authorized now.

B. Try to instance the object in the action filter (but you must figure out first what entity you are trying to instance, this can lead to a long switch statement and a 3rd parameter in the CustomAuthorize so you know which entity to get from the DB).

Omar