Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET MVC4 Security, Authentication, and Authorization

I'm working on a new asp.net mvc4 project using Visual Studio 2011 beta and am trying to get my head around the whole security thing. It's an internal Intranet application that will initially use single sign on, so the user will not (yet) be prompted for a Windows ID/password. The company has a custom application for storing roles for different applications and will be available via a stored procedure call. It will take a user's logon ID and return some sort of collection containing roles e.g. "MyApp.Data", "MyApp.User, "MyApp.Admin". So what is this referred to as - is this a custom Membership provider, custom Roles provider or something else?

I've been reading up on all the ins and outs of Authorization, Authentication, Membership, Roles, etc. and I can't see the wood for the trees at the moment. I've read that the existing ASP.NET Security objects have been tried and tested, and unless there are very complex requirements the in-built ones will suffice, so I'm happy to use what's already there.

So if a user is already signed in to the network this means they are authenticated - correct? If so then I just need to implement Authorization. Is it necessary to decorate each Controller or Action with the Authorize attribute? If so how does the "ABC" part of [Authorize(Roles = "ABC")] get set if I retrieve roles from my custom role storage app?

I read several articles and blog posts including this one from Jon Galloway but I got lost towards the end:

Customizing Authentication and Authorization The Right Way

So many questions...if anyone knows of good high level description of how all this hangs together then I'm all ears :)

like image 340
Ciarán Bruen Avatar asked May 24 '12 17:05

Ciarán Bruen


3 Answers

Ok in the absence of an answer that gives a high level view of how all this hangs together I thought I'd scribble down my findings so far:

  • The company uses Active Directory to store user logon details, so as this is used for Membership I don't need a custom Membership provider. Once a user is logged on to the company network then they are authenticated. Adding a global Authorize filter ensures that any user accessing the system will need to be authenticated. Up to date info from Rick Anderson on msdn:

    http://blogs.msdn.com/b/rickandy/archive/2012/03/23/securing-your-asp-net-mvc-4-app-and-the-new-allowanonymous-attribute.aspx

So in Global.asax I would add:

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new HandleErrorAttribute());
    filters.Add(new System.Web.Mvc.AuthorizeAttribute()); //new
}
  • Once a user is authenticated I then need to take care of Authorization. The company have an existing global data store for roles that I won't have update access to, only read access, so I can retrieve the roles for a given user via a stored proc call. It can take from a few days to a couple of weeks for the helpdesk to create roles after a request is made, so for this reason 2 standard roles will be initially created, User and Admin, and subsequent roles will be stored in our application database.

  • Along with these 2 standard roles subsequent roles are required such as Superuser, etc. These roles will have various rights depending on business rules etc. and will need to be stored in our application database. So for this scenario I will need to create a custom Role provider, add the appropriate asp.net role tables to my app database, and plug it into the web.config. Here's an ms page titled Managing Authorization Using Roles that I'm picking bits out of:

    http://msdn.microsoft.com/en-us/library/9ab2fxh0.aspx

  • From what I've read so far the only tables I need for a custom role provider are Roles and UsersInRoles.

    CREATE TABLE Roles ( Rolename Text (255) NOT NULL, ApplicationName Text (255) NOT NULL, CONSTRAINT PKRoles PRIMARY KEY (Rolename, ApplicationName) )

    CREATE TABLE UsersInRoles ( Username Text (255) NOT NULL, Rolename Text (255) NOT NULL, ApplicationName Text (255) NOT NULL, CONSTRAINT PKUsersInRoles PRIMARY KEY (Username, Rolename, ApplicationName) )

  • Once all this is setup I need to figure out how to merge the 2 standard roles (User and Admin) from the global data store with the custom roles stored in my app database, and if I can use (e.g.) [Authorize(Roles="Admin, Superuser")] on a Controller/Action or if I need to subclass AuthoriseAttribute and do something more clever.

  • I just realised that as I use AD for authentication I need a way of adding / injecting the collection of roles the current user is a member of. So although I don't need any custom membership provider functionality I still have to interact with httpContext.User to update its Roles collection.

like image 54
Ciarán Bruen Avatar answered Nov 07 '22 19:11

Ciarán Bruen


If your authentication is already being handled by Windows (I'm guessing via Active Directory), then what you're looking for is an authorization mechanism which match roles to users. One option you have is to load the user roles into the current session once successfully. Then create a custom authorize attribute that will check if the current session has the necessary roles that you're working with

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited=true, AllowMultiple=true)]
public class CustomAuthorizationAttribute : AuthorizeAttribute
{
   protected override bool AuthorizeCore(HttpContextBase httpContext)
   {         
      IPrincipal user = httpContext.User;
      if (!user.Identity.IsAuthenticated)
      {
          return false;
      }

     //check your users against a database and return true or false
      return base.AuthorizeCore(httpContext);
   }
}

Then you can use the attribute like this

[CustomAuthorization]
public ActionResult SomeAction()
{
   return View();
}

UPDATE

AuthorizeCore is the method that will be used to check whether this user should be allowed to access the respective Action Method. Within this method you can check the httpContext.User.Identity.Name property against your database or where your roles are stored. If you're using Windows Authentication via Active Directory, HttpContext.User.Identity should be an instance of WindowsIdentity

like image 42
cecilphillip Avatar answered Nov 07 '22 20:11

cecilphillip


Your RolePrincipal, updated in concert with your RoleProvider, should be all that is needed to fetch the list of roles associated with the authenticated user. Remember, the RolePrincipal will already contain the proper WindowsIdentity.

You don't need a custom Authorize attribute. The RolePrincipal/RoleProvider will fetch the needed roles and work with the standard Authorize attribute.

What does seem a bit odd is that you want to have roles peculiar to your application, but you say you also want roles that are associated with the Windows users from a separate corporate store as well. As you said, you want to merge them. This doesn't seem right to me. Either you want to manage roles at the corporate level for your application, or you want to manage them at a local level. Generally you would not do both.

But if that really is what you want to do, then it sounds as if your RoleProvider needs to make a service (e.g. WCF) call or AD call to obtain additional information. Perhaps the names of "groups" that the windows user belongs to can serve as "roles". You would then filter out only those groups that your application cares about, and combine with the roles you found in your local roles databases.

Once all that information has been gathered, be sure to have the roleManager instructed to store role information in a cookie. No sense in going through that hullabaloo with every request the user makes.

like image 1
Brent Arias Avatar answered Nov 07 '22 20:11

Brent Arias