ASP.NET MVC How does AuthorizeAttribute support checking Roles? - asp.net

In my controllers, I have code like [Authorize(Roles = "Administrators")] annotated above some actions, and I want to know how AuthorizeAttribute uses the Roles parameter (the implementation of the checking mechanism). My goal is to create an extension of this class, called PrivilegeAttribute for example, so that I can annotate actions like [Privilege(Privileges = "read")]. In this class, I would check if the Role of the user has at least one of the privileges in this custom filter (read in this example). I have already created the association between roles and privileges in the code and in the database, and what I want help with is checking whether the role is associated to the privilege.
I tried seeing if that information is there in HttpContextBase.User.Identity but I couldn't find it.
Thank you.

If you don't need your own custom attribute and could live with using someone else attribute, than I would suggest to use the package Thinktecture.IdentityModel.Owin.ResourceAuthorization.Mvc as described here
Blog Post by Dominick Baier
and here
Git Hub Sample Code for the Package
so it basically works like this:
you put an attribute over your action like this:
[ResourceAuthorize("View", "Customer")]
The first argument is the name of the Action to check, the second one is the name of the attribute.
Then you derive from ResourceAuthorizationManager in your code and override the CheckAccessAssync Method
public class MyAuthorization : ResourceAuthorizationManager
{
public override Task<bool> CheckAccessAsync(ResourceAuthorizationContext context)
{
var resource = context.Resource.First().Value;
var action = context.Action.First().Value;
// getting the roles that are connected to that resource and action
// from the db. Context could of course be injected into the
// constructor of the class. In my code I assume that the table
// thank links roles, resources and actions is called Roles ToActions
using(var db = MyContext())
var roles = db.RolesToActions // Use your table name here
.Where(r => r.Resource == resource && r.Action == action).ToList();
foreach(var role in roles)
{
if(context.Principal.IsInRole(role.Name)
{
return Ok();
}
}
return Nok();
}
}
}
So I hope this helps. If you prefer to implement your own attribute however, than the source code from the ResourceAuthorization GitHub Repository should be a good starting point

Related

Using claims or just roles in ASP.NET Core MVC

In my ASP.NET Core MVC project, I have this scenario: a manager can do anything in the web application, you can call it super manager, and there is only one user. This "super" manager can add other managers that are more restricted, for example these managers cannot create users of type manager, or cannot see some information.
Technically, they have a lot in common. I already have many role types so I do not want to create another one called super manager where I will be creating only one user. So in this case should I use claims? or is it better to just create two roles? I know it will be less complicated but I want to know the best practice.
I'm new to ASP.NET Core so I appreciate examples or articles that could help me, thank you!
In my opinion, there is no difference between add the superadmin by claims or role claim, the role claim is also a type of claims.
In my opinion, if you don't have special requirement which need to add the user superadmin by claims, the best way is using claims. Since you could directly use the [Authorize(Roles = "Superadmin")] and no need to write another codes to add the claims by using identity factory.
If you want to add the superadmin by claims, you should use UserClaimsPrincipalFactory like this answer and add the claims policy like this article shows.
I suggest if you need to create many roles, you use
Claims-based authorization .
You can use Authorize[Roles = "Admin"] property or you can create a custom AuthorizeAttribute, for example:
public class AuthorizeAccess : AuthorizeAttribute, IAuthorizationFilter
{
public string UniqueCode { get; set; }
public void OnAuthorization(AuthorizationFilterContext context)
{
if (!context.HttpContext.User.HasClaim(c => c.Type == "CustomAccess" && c.Value.Equals(UniqueCode)))
{
// Redirect AccessDenied when the claim not exist.
context.Result = new RedirectToPageResult("/AccessDenied");
return;
}
}
}
And we can use it
[AuthorizeAccess(UniqueCode = "EDIT")]
public class IndexModel : PageModel
{
....
}
In this case you need to load a claim list in the login access
identity.AddClaim(new Claim("CustomAccess", "HOME_PAGE"));
identity.AddClaim(new Claim("CustomAccess", "EDIT"));
identity.AddClaim(new Claim("CustomAccess", "DELETE"));
identity.AddClaim(new Claim("CustomAccess", "INSERT"));

How to override Authorize attribute in ASP.MVC 5 with multiple authorization conditions?

I am implementing authorization/authentication in a MVC project. They problem I am facing is that there are many conditions for a login user like roles, positions, permissions and some others. I thought the best way is to override AthorizeAttribute and set all logic in there by passing the data as string arrays in constructor and validate them but I do have more than 100 permissions and more than 40 positions which makes this attribute almost useless because I can not write in every action for example 60 position etc.
I thought I could group them somehow but I can see it is not a good point because all actions are dynamic and I would make tons of groups for user permissions and user positions.
I red in some posts for creating a base controller to make all validations there but I am using ASP.NET Identity and I don`t like going in 'old' fashion way...
If anybody had any situation like that before I would be grateful if you share your solution!
EDIT - Adding code example
public class XAuthorizeAttribute : AuthorizeAttribute
{
public XAuthorizeAttribute() { }
public XAuthorizeAttribute(params string[] roles)
{
Roles = string.Join(",", roles.Select(x => x));
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
bool isAuthenticAttribute =
(filterContext.ActionDescriptor.IsDefined(typeof(XAuthorizeAttribute), true) ||
filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(XAuthorizeAttribute), true)) &&
filterContext.HttpContext.User.Identity.IsAuthenticated;
if (!isAuthenticAttribute) return;
UrlHelper urlHelper = new UrlHelper(filterContext.RequestContext);
if (filterContext.HttpContext.User.Identity.IsAuthenticated)
{
IdentityManager.SignInManager.AuthenticationManager.SignOut(
DefaultAuthenticationTypes.ApplicationCookie, DefaultAuthenticationTypes.ExternalCookie);
}
filterContext.Result =
new RedirectResult(urlHelper.Action("Index", "Home", new {area = ""}));
base.HandleUnauthorizedRequest(filterContext);
}
}
Here is the action...
[XAuthorize("Administrator", "articlelists", "HOD Engineering", "HOD Interior"....)]
public ActionResult Index()
{
return View("Index");
}
As you can see I only put 4 roles, just imagine putting 60 roles and permissions etc.... This is just a demo to get the idea because in my project I do not have only roles as I do have here.
Instead of hard coding roles into attributes it may be better to create a custom generic [XAuthorizeAction] attribute that would start off the process of checking your database for permission configuration.
Step 1.) Configure database to know permissions for action level calls
Step 2.) Create authorization attribute for controller actions that need this level of permission control
Step 3.) Inside attribute determine the caller and the calling controller and action
Step 4.) Query the database for this controller and action to determine the actions permissions.
Step 5.) Query the database for the users permissions and see if they match

Are there any packages etc implementing dynamic role controller access for MVC3?

I have statically allowed access to controllers/action methods using the standard Authorize attribute with roles. I am using the default ASP.Net Membership Provider.
One of our clients wants finer grained access control. They would like to be able to dynamically assign which roles can access which controllers/actions etc. I've seen answers saying implement a CustomAuthorize Attribute.
Just wondered if there were any toolkits etc to this. It seems a reasonably standard feature. I guess something like this http://kbochevski.blogspot.com/2009/11/mvc-custom-authorization.html
Try a custom attribute like this:
public class DynamicAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var controllerName = httpContext.Request.RequestContext.RouteData.Values["controller"];
var actionName = httpContext.Request.RequestContext.RouteData.Values["action"];
// Get this string (roles) from a database or somewhere dynamic using the controllerName and actionName
Roles = "Role1,Role2,Role3"; // i.e. GetRolesFromDatabase(controllerName, actionName);
return base.AuthorizeCore(httpContext);
}
}
Just put this attribute on any action method that requires authorization and do a look up in a database with the controller name and action name to get the required roles.
Hope this helps,
Mark

ASP.NET MVC3 Role and Permission Management -> With Runtime Permission Assignment

ASP.NET MVC allows users the ability to assign permissions to functionality (i.e. Actions) at Design Time like so.
[Authorize(Roles = "Administrator,ContentEditor")]
public ActionResult Foo()
{
return View();
}
To actually check the permission, one might use the following statement in a (Razor) view:
#if (User.IsInRole("ContentEditor"))
{
<div>This will be visible only to users in the ContentEditor role.</div>
}
The problem with this approach is that all permissions must be set up and assigned as attributes at design time. (Attributes are compiled in with the DLL so I am presently aware of no mechanism to apply attributes (to allow additional permissions) such as [Authorize(Roles = "Administrator,ContentEditor")] at runtime.
In our use case, the client needs to be able to change what users have what permissions after deployment.
For example, the client may wish to allow a user in the ContentEditor role to edit some content of a particular type. Perhaps a user was not allowed to edit lookup table values, but now the client wants to allow this without granting the user all the permissions in the next higher role. Instead, the client simply wants to modify the permissions available to the user's current role.
What options are strategies are available to allow permissions on MVC Controllers/Views/Actions to be defined outside of attributes (as in a database) and evaluated and applied at runtime?
If possible, we would very much like to stick as closely as we can to the ASP.NET Membership and Role Provider functionality so that we can continue to leverage the other benefits it provides.
Thank you in advance for any ideas or insights.
What options are strategies are available to allow permissions on MVC
Controllers/Views/Actions to be defined outside of attributes (as in a
database) and evaluated and applied at runtime?
A custom Authorize attribute is one possibility to achieve this:
public class MyAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
Roles = ... go ahead and fetch those roles dynamically from wherever they are stored
return base.AuthorizeCore(httpContext);
}
}
and then:
[MyAuthorize]
public ActionResult Foo()
{
return View();
}
As I'm lazy I couldn't be bothered rolling my own attribute and used FluentSecurity for this. In addition to the ability to apply rules at run time it allows a custom way to check role membership. In my case I have a configuration file setting for each role, and then I implement something like the following;
// Map application roles to configuration settings
private static readonly Dictionary<ApplicationRole, string>
RoleToConfigurationMapper = new Dictionary<ApplicationRole, string>
{
{ ApplicationRole.ExceptionLogViewer, "ExceptionLogViewerGroups" }
};
the application roles are then applied like so
SecurityConfigurator.Configure(
configuration =>
{
configuration.GetAuthenticationStatusFrom(() =>
HttpContext.Current.User.Identity.IsAuthenticated);
configuration.GetRolesFrom(() =>
GetApplicationRolesForPrincipal(HttpContext.Current.User));
configuration.ForAllControllers().DenyAnonymousAccess();
configuration.For<Areas.Administration.Controllers.LogViewerController>()
.RequireRole(ApplicationRole.ExceptionLogViewer);
});
filters.Add(new HandleSecurityAttribute());
and then the check is performed by
public static object[] GetApplicationRolesForPrincipal(IPrincipal principal)
{
if (principal == null)
{
return new object[0];
}
List<object> roles = new List<object>();
foreach (KeyValuePair<ApplicationRole, string> configurationMap in
RoleToConfigurationMapper)
{
string mappedRoles = (string)Properties.Settings.Default[configurationMap.Value];
if (string.IsNullOrEmpty(mappedRoles))
{
continue;
}
string[] individualRoles = mappedRoles.Split(',');
foreach (string indvidualRole in individualRoles)
{
if (!roles.Contains(configurationMap.Key) && principal.IsInRole(indvidualRole))
{
roles.Add(configurationMap.Key);
if (!roles.Contains(ApplicationRole.AnyAdministrationFunction))
{
roles.Add(ApplicationRole.AnyAdministrationFunction);
}
}
}
}
return roles.ToArray();
}
You could of course pull roles from a database. The nice thing about this is that I can apply different rules during development, plus someone has already done the hard work for me!
You could also consider doing task/activity based security and dynamically assign permission to perform those tasks to different groups
http://lostechies.com/derickbailey/2011/05/24/dont-do-role-based-authorization-checks-do-activity-based-checks/
You would need to mangle the provider a little bit to work with this but it is possible to stay inline with the .net authorisation
http://www.lhotka.net/weblog/PermissionbasedAuthorizationVsRolebasedAuthorization.aspx
If you need to do Method or Controller based authorization (deny access to the whole method or controller) then you can override OnAuthorization in the controller base and do your ouwn authorization. You can then build a table to lookup what permissions are assigned to that controller/method and go from there.
You can also do a custom global filter, which is very similar.
Another option, using your second approach, is to say something like this:
#if (User.IsInRole(Model.MethodRoles))
{
<div>This will be visible only to users in the ContentEditor role.</div>
}
And then in your controller populate MethodRoles with the roles assigned to that method.

Role/Permission based forms authorizing/authentication?

While looking into forms authorizing/authentication, I found that it is possible to do role based authorizing by adding an array of roles to a FormsAuthenticationTicket. That way I can write
User.IsInRole(role from database)
But is there any way to do the same thing with permissions on a role like :
if (User.IsInRole(role from database)) {
if (User.CanRead()) {
//--- Let the user read
}
if (User.CanWrite()) {
//--- Let the user write
}
}
I have read a couple of articles and forum post's where permission is added to the array instead of the roles, resulting in using
User.IsInRole(permission from database)
However that's not the same thing. Hope someone can give some input on this matter, throw a link to an article or better yet, an code sample.
You're better off changing the way you think about a role. Use the term "permission" or "claim" if that helps. Then create all the roles you need and link a given user to all the necessary roles.
One user can belong to multiple roles. This way, the following simple code will work fine and you don't need to build your own unique way of how things work.
if(User.IsInRole(someRole) && User.IsInRole(someOtherRole))
{
// do something
}
You can make some C# extension methods to make this more readable too:
if(User.IsInSomeRoleAndOtherRole())
{
// do something
}
The extension methods can look something like the following. Create a new class with the following code, then include the class namespace in your code, and you can use the extension method as shown above.
using System.Security.Principal;
namespace MyCompany
{
public static class MyExtensions
{
public static bool IsInSomeRoleAndOtherRole(this IPrincipal principal)
{
if (!principal.IsInRole("someRole"))
return false;
if (!principal.IsInRole("someOtherRole"))
return false;
return true; // the user meets the requirements
}
}
}

Resources