views:

10244

answers:

6

I'm creating an asp.net mvc application that has the concept of users. Each user is able to edit their own profile. For instance:

Nothing particularly exciting there...

However, I have run into a bit of trouble with the Authorization scheme. There are only two roles in the system right now, "Administrator" and "DefaultUser", but there will likely be more in the future.

I can't use the regular Authorize attribute to specify Authorization because both users are in the same role (i.e., "DefaultUser").

So, if I specify the Authorize Filter like so:

[Authorize(Roles = "DefaultUser")]

then there is no effect. PersonID=1 can go in and edit their own profile (as they should be able to), but they can also just change the URL to http://localhost/person/edit/2 and they have full access to edit PersonID=2's profile as well (which they should not be able to do).

Does this mean that I have to create my own Authorization filter that checks if the action the user is requesting "belongs" to them before allowing them access? That is, if the edit action, with parameter = 1 is being requested by the currently logged in person, do I need to do a custom check to make sure that the currently logged in person is PersonID=1, and if so, authorize them, and if not, deny access?

Feels like I'm missing something obvious here, so any guidance would be appreciated.

+23  A: 

Maybe you could organize the controller action such that the URL is more like http://localhost/person/editme and it displays the edit form for the currently-logged-in user. That way there's no way a user could hack the URL to edit someone else.

Matt Hamilton
+5  A: 

Matt is right.

What the authorisation is for is to show that they're allowed to perform that function - what you're trying to do is say whether they can perform the function for that particular ID.

So two solutions:

  1. Like Matt said, make an action that takes no ID, but looks up the current logged in user from the session information, and retrieves them.
  2. Make an action that takes an ID, but only allow administrators access - so they can modify other users information if required.

But to answer the question, the Authorisation is only to say "Yes, this person can use the modify user action", not based on the parameter entered.

The other way is that you could make it check that the user retrieved == the current user, or redirect to another action saying that they cannot edit that user - but it'd be better just to provide an action that doesn't take an id, and just gets the current logged in user.

crucible
A: 

You could have no Authorize attribute and check the if the user should be allowed to access there page then either redirect or allow the page to be displayed.

Schotime
+10  A: 

A more elegant solution would be to write your own Authorization action filter, either by extending [Authorize], or implementing IAuthorizationFilter, as follows:

public class AuthorizeOwnerAttribute: FilterAttribute, IAuthorizationFilter
{
    #region IAuthorizationFilter Members

    public void OnAuthorization(AuthorizationContext filterContext)
    {
        // add logic here that compares the currently logged in user, to the owner of the profile that is being edited
        // get currently logged in user info from filterContext.HttpContext.User.Identity;
        // get profile being edited from filterContext.RouteData or filterContext.Something
    }

    #endregion
}

I'm not sure on what the actual logic would be that goes into the OnAuthorization method, but my comments should give you a starting point. You'd have to Google to find out more - how to redirect the user to a different view, or whether to throw an strongly typed exception that is handled somewhere else (maybe in a [HandleError] attribute).

Saajid Ismail
How to implement your own authorization action filter has been answered many times on SO. For example, see http://stackoverflow.com/questions/427598/customizing-authorization-in-asp-net-mvc
bzlm
+7  A: 

My $.02:

Authorized & authenticated are two different things. Simply put, the question is can you do this thing are you supposed to do it? You can pick your friends, you can pick your nose but you can't pick your friends nose! There's no need to check authorization if every role can do it (user has hand and a nose). Have a Post method for users to get to their own profile and test the profile id w/the form's hidden values or redirect (not your nose, go away).

Have a Get method for editing others profiles and just check for the admin role here - (I'm a doctor, I'm authorized to stick things up your nose)...

James Fleming
Hilarious post.
Roger Rogers
+2  A: 

Solution for this problem: http://nerddinnerbook.s3.amazonaws.com/Part9.htm

"Using the User.Identity.Name property when Editing Dinners

Let's now add some authorization logic that restricts users so that they can only edit the properties of dinners they themselves are hosting..."

Wojtek