AD Roles based Authorization in MVC3 - asp.net-mvc-3

In our MVC3 based Intranet app, one AD User may belong to many roles and during login, they will choose the role they want to login as. We are currently authenticating the user using the following approach: http://www.codeproject.com/KB/system/everythingInAD.aspx#35
Once the user is authenticated and found to belong to the role they are trying to login as, we would like to authorize access to specific Controllers and Actions based on their Role. We would prefer to use the Authorize attribute of the MVC.
Since we are not using any providers to autnenticate, can we still somehow use the Authorize attribute to restrict access?
Thanks!
Bala

You can use the Authorize attribute as long as your custom membership provider inherits from the asp.net MemberShipProvider class.
But if you decide to have an entirely new provide which doesn't inherit from asp.net MembershipProvider class than you can't use the Authorize attirbute.

#Pankaj is right but You can define you'r custom Attribute for exam: class MyAuthorizationAttribute : FilterAttribute, IAuthorizationFilter and override OnAuthorization method of it. then decorate each action with this custom attribute and calculate authorization in body of OnAuthorization. this is a sample:
public class MyAuthorizationAttribute : FilterAttribute, IAuthorizationFilter
{
public string _name;
public MyAuthorizationAttribute(string name)
{
this._name = curPerm.name;
}
public void OnAuthorization(AuthorizationContext filterContext)
{
// Calculate permissions...
if (!permit)
{
Exception e = new MethodAccessException("Access to partial denied!");
throw new Exception("Can't access via address bar!", e);
}
}
}
and use in action
[MyAuthorizationAttribute ("Add")]
public ActionResult Index()
{
ViewBag.Message = "About page";
return View();
}
Hope this useful.
Good luck.

Related

Where can I load the user information to the session in ASP.NET MVC 5 with windows authentication?

I want to use the ASP.NET MVC 5 for my web app. I need use the windows authentication.
If I use the windows authentication where is the best place for reading user information (userid and roles) and store its to the Session?
I have the method for getting the user information by username from the database like this:
public class CurrentUser
{
public int UserId { get; set; }
public string UserName { get; set; }
public Roles Roles { get; set; }
}
public enum Roles
{
Administrator,
Editor,
Reader
}
public class AuthService
{
public CurrentUser GetUserInfo(string userName)
{
var currentUser = new CurrentUser();
//load from DB
return currentUser;
}
}
You've asked two questions (1) the best place to obtain user information and (2) how to store it in the Session. I'll answer (1) and in so doing perhaps show that you need not put any additional information in the session.
You've stated that your application is using Windows Authentication, so that means the hard work of authenticating the user has already been done by IIS/HttpListener before your app receives the request. When you receive the request there will be a WindowsPrincipal in HttpContext.User. This will have the windows username and AD roles already established, but you wish to use additional roles stored in the database...
You could access your AuthService from anywhere in your application, but probably the best approach is to register an IAuthorizationFilter and do the work there. By following this approach, the additional roles and other information you fetch from the database will be available in your controller methods and, perhaps more importantly, from any additional library code that needs to check user credentials.
Prior to .Net 4.5, if you wanted to add additional information to the WindowsPrincipal I think your only choice was to replace the system-provided User with another object that implemented the IPrincipal interface. This approach is still available (and what I recommend), but since the introduction of Windows Identity Foundation (WIF) in .Net 4.5, WindowsPrincipal is derived from  System.Security.Claims.ClaimsIdentityClaimsIdentity, which supports adding additional roles (and other useful information) to the system-provided principal. However, as several people have found, there is a bug/feature in Windows which can cause an exception The trust relationship between the primary domain and the trusted domain failed to be thrown when checking roles that have been added programmatically. We have found that a simple and reliable way to avoid this is to replace the User with a GenericPrincipal.
Steps required:
(1) create an IAuthorizationFilter.
class MyAuthorizationFilter : IAuthorizationFilter
{
AuthService _authService;
public MyAuthorizationFilter(AuthService authService)
{
_authService = authService;
}
public void OnAuthorization(AuthorizationContext filterContext)
{
var principal = filterContext.HttpContext.User;
if (principal.Identity != null && principal.Identity.IsAuthenticated)
{
// Add username (and other details) to session if you have a need
filterContext.HttpContext.Session["User"] = principal.Identity.Name;
// get user info from DB and embue the identity with additional attributes
var user = _authService.GetUserInfo(principal.Identity.Name);
// Create a new Principal and add the roles belonging to the user
GenericPrincipal gp = new GenericPrincipal(principal.Identity, user.RoleNames.ToArray());
filterContext.HttpContext.User = gp;
}
}
}
(2) Register your filter. This can be registered at the controller level or globally. Typically you will do this in App_Start\FilterConfig.cs:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new MyAuthorizationFilter(new AuthService()));
}
}
(3) Use the provided GenericPrincipal in your application code to answer questions about the user identification and other credentials. e.g. in your controller method you can access the username or any other "claims" (e.g. email address) stored in the GenericPrincipal by your filter.
public ActionResult Index()
{
ViewBag.Name = HttpContext.User.Identity.Name;
if(HttpContext.User.IsInRole("Administrator"))
{
// some role-specific action
}
return View();
}
Because you've used the built-in mechanism to record Principal roles, you can access user details from anywhere using HttpContext.User or System.Threading.Thread.CurrentPrincipal. Also you can use the AuthorizeAttribute in you controller methods to declare which actions are available to certain roles or users. e.g.
public class HomeController : Controller
{
[Authorize(Roles = "Administrator")]
public ActionResult Admin()
{
return View();
}
See MSDN for further details about ClaimsIdentity
I hope this helps
-Rob
First and foremost: never, never, never store user details in the session. Seriously. Just don't do it.
If you're using Windows Auth, the user is in AD. You have use AD to get the user information. Microsoft has an MSDN article describing how this should be done.
The long and short is that you create a subclass of UserIdentity and extend it with the additional properties you want to return on the user:
[DirectoryRdnPrefix("CN")]
[DirectoryObjectClass("inetOrgPerson")]
public class InetOrgPerson : UserPrincipal
{
// Inplement the constructor using the base class constructor.
public InetOrgPerson(PrincipalContext context) : base(context)
{
}
// Implement the constructor with initialization parameters.
public InetOrgPerson(PrincipalContext context,
string samAccountName,
string password,
bool enabled)
: base(context,
samAccountName,
password,
enabled)
{
}
InetOrgPersonSearchFilter searchFilter;
new public InetOrgPersonSearchFilter AdvancedSearchFilter
{
get
{
if ( null == searchFilter )
searchFilter = new InetOrgPersonSearchFilter(this);
return searchFilter;
}
}
// Create the mobile phone property.
[DirectoryProperty("mobile")]
public string MobilePhone
{
get
{
if (ExtensionGet("mobile").Length != 1)
return null;
return (string)ExtensionGet("mobile")[0];
}
set
{
ExtensionSet( "mobile", value );
}
}
...
}
In the example code above, a property is added to bind to the AD's user's mobile field. This is done by implementing the property as shown utilizing ExtensionSet, and then annotating the property with the DirectoryProperty attribute to tell it what field it binds to.
The DirectoryRdnPrefix and DirectoryObjectClass attributes on the class need to line up with how your AD is set up.
Once this is implemented, then you will be able to get at the values simply by referencing them off User.Identity. For example, User.Identity.MobilePhone would return the mobile field from AD for the user.

Role management in MVC 6

I am looking for role and permission management in MVC6. Basically my requirement is I will be having roles and those roles will have some set of permissions(Like Add,Edit,Delete,Modify etc.).
So, based on this I want to achieve following things
Show/Hide content of view based on role and there permission for user.
To restrict access to controller and its action methods.
Any help on this appreciated !
Partial answer:
2: Just add attributes to your controller and/or methods, e.g.
[Authorize(Roles = "Administrator, PowerUser")]
public class ControlPanelController : Controller
{
public ActionResult SetTime()
{
}
[Authorize(Roles = "Administrator")]
public ActionResult ShutDown()
{
}
}
https://docs.asp.net/en/latest/security/authorization/roles.html

WebApi External Bearer Authentication and Injecting User into respositories

I have a webapi project and a repositories project.
I have configured to use oauth, which uses owin middleware bearer token authentication.
I have a unitofwork with multiple repositories.
Inside the repositories I want to filter data based on the logged on user.
I would like all repositories to get the logged in user via dependency injection.
I can access the logged on user in the webapi action, but I am struggling to work out if/how I can inject the current user using DI; because the authorization is happening via the webapi Authorize?:
[Authorize(Roles = "User")]
public IQueryable<Folder> Folders()
{
// return UnitOfWork.FolderRepository.All().OrderBy(o=>o.FolderId).Skip(10).Take(50);
var test = HttpContext.Current.GetOwinContext().Authentication;
//test is populated with the logged on user here, but I don't want to set the user details of the UOW in every action in my controllers
return UnitOfWork.FolderRepository.All();
}
So in the action Folders the Authorize annotation logs the user on. But I have already instantiated the unit of work in the controller constructor with DI:
public FolderController(IUnitOfWork uow, UserManager<IdentityUser,int> usermanager)
{
UnitOfWork = uow;
UserManager = usermanager;
}
IOC container:
public static IContainer Initialize()
{
ObjectFactory.Initialize(x =>
{
x.Scan(scan =>
{
scan.TheCallingAssembly();
scan.WithDefaultConventions();
});
x.For<HttpContextBase>()
.HybridHttpOrThreadLocalScoped()
.Use(() => new HttpContextWrapper(HttpContext.Current));
x.For<IUnitOfWork>().HttpContextScoped().Use(
() => new UnitOfWork(new BreezeValidator
(new UserManager<AspNet.Identity.SQLServer.IdentityUser, int>(new UserStore(new SqlDatabase()))))
);
}
}
I had tried to pass in HttpContext.Current.GetOwinContext(), but at that point the authorization hasn't taken place and so the Principal has not been set.
I have looked at actionfilters (which are run after the authorization filter), but can't figure out how I would return a new unit of work instance with the logged on user set, back to the controller.
...Or whether I can set a property on the controller from an action filter?
So the question is really, how can I set the user details in all my controller's unitofwork, without lots of duplication?
Thanks
EDIT: I have a working solution, but still not sure it's the right way to go:
I created an action filter and then from there get the controller and set a UserPrincipal property on the controller's unitOfWork property.
using Project1.Web.Controllers;
using System;
using System.Linq;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
namespace Project1.Web.Filters
{
public class InjectUserAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var action = actionContext.ControllerContext.Controller;
UowApiController ctrl = (UowApiController)actionContext.ControllerContext.Controller;
ctrl.UnitOfWork.UserPrincipal = actionContext.RequestContext.Principal;
}
}
Then, in my UnitOfWork setter of the UserPrincipal I set the UserPrincipal in the contained repositories:
public IPrincipal UserPrincipal
{
get
{
return this.userPrincipal;
}
set
{
this.userPrincipal = value;
((Repository<Folder>)FolderRepository).UserPrincipal = value;
}
}
This works now, but it doesn't achieve dependency injection.
Also I would like to know if this is a "right" way to do it, or what would be a better approach?
I was searching for the same thing and decided on this. I think this answer will be relevant to you as well.
Proper way to dependency inject authenticated user to my repository class
I've just added a getter to the service classes that accesses the user identity at request time.
public class MyService
{
//ctor...
public IEnumerable<Results> GetResults()
{
return _ResultRepository.GetResultsByUser(UserIdentity);
}
IIdentity UserIdentity
{
get { return Thread.CurrentPrincipal.Identity; }
}
}

global authorization not working - results in blank page rendered

I am trying to implement a very basic login scheme for my MVC3 site. If I understand correctly, instead of adding the [Authorize] markup to each of my controller classes, I should be able to simply implement a global setting. To accomplish this, I have added the following into global.asax:
protected void Application_Start()
{
RegisterGlobalFilters(GlobalFilters.Filters);
}
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new AuthorizeAttribute());
}
and in my webconfig, I added:
<authentication mode="Forms">
<forms loginUrl="~/Account/LogOn" timeout="2880" />
</authentication>
The result is that the resulting page is totally blank. Looking at the url, it seems that mvc is redirecting to my login route as expected except the page empty. If I comment out the code in global.asax and just place the [Authorize] markup directly in each contoller, it works as expected.
As a workaround, I have implemented what I have read the MVC2 best practice to be, which was to create a BaseController:Controller class, add the [Authorize] markup to it, and then change the inherentences of all of my controllers to inheret from BaseController instead of Controller.
That seems to work well enough for now.
But why isn't the global.asax implementation working?
Let's see what's happening here:
You are navigating to /
Your global authorize attribute kicks in and since the user is not authenticated he is redirected to ~/Account/LogOn (as instructed in your web.config file) for authentication
Your global authorize attribute kicks in and since the user is not authenticated he is redirected to ~/Account/LogOn (as instructed in your web.config file) for authentication
Same as 3.
Same as 4.
...
I think you get the point. The LogOn action should be excluded from authentication otherwise the user can never get a chance to login to your web site.
Since you have applied the Authorize attribute globally this cannot be done. One possible way is to write a custom AuthorizeAttribute that will be applied globally and which will exclude this action from authentication.
So you could write a marker attribute:
public class AllowAnonymousAttribute : Attribute
{
}
and a global custom authorize attribute:
public class MyAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
var exclude = ((AllowAnonymousAttribute[])filterContext.ActionDescriptor.GetCustomAttributes(typeof(AllowAnonymousAttribute), false)).Any();
if (!exclude)
{
base.OnAuthorization(filterContext);
}
}
}
that will be registered:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new MyAuthorizeAttribute());
}
Now all that's left for you is to decorate the controller actions that you want to be excluded from authentication with our marker attribute:
public class AccountController : Controller
{
[AllowAnonymous]
public ActionResult LogOn()
{
return View();
}
[AllowAnonymous]
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
...
}
}

how to implement custom authorization in asp.net mvc 3?

Looking for a custom authorization solution for a asp.net mvc 3 application with sql server 2008. I dont want to use the ASPNETDB.mdf though.
At the moment I am trying to use a customactionfilter but I dont know how to return a boolean here. Does anyone have a good sample of a similar scenario?
public class CustAuthFilterAttribute : ActionFilterAttribute, IActionFilter
{
public string Roles {get;set;}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//return true/false based on Role the user has
base.OnActionExecuting(filterContext);
}
}
You should be deriving from AuthorizeAttribute if you want to implement custom authorization.
This answer gives you a short example in how to use it.
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
// check context and roles
...
return true;
}
}

Resources