ASP.NET MVC4 authorization depending on role and information - asp.net

I'm currently developing an ASP.NET MVC4 application which have 3 roles: admin, manager and editor. The editors can CRUD articles in the system BUT the editors can only read, update or delete their OWN articles. I've seen I can control the access to the controller and action by adding:
[Authorize(Roles="editor")]
but it only restricts the role not the information.
If the editor A created the article 1 ONLY the editor A has access to that article.
No other role has access to the controller or the information.
What would be the best practice in order to restrict the access by role and by context?

It is not practical to create a custom AuthorizeAttribute to check whether a user is allowed to update a specific article.
Instead, you want to check that logic in controller (or business logic). You can see that approach in a lot of open source projects.
[HttpPost]
[Authorize(Roles="editor")]
[ValidateAntiForgeryToken]
public ActionResult Update(ArticleModel model)
{
if(IsUserAllowedToUpdate(userId, model.ArticleId))
{
// Update article
}
return View(model);
}

You could implement this in the core of your system, for example by having a field in your datastore, identifying creator and users with permission.
Then you could implement your own authorizeattribute like;
public class CustomAuthenticateAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
// your own business logic, for instance, check if the user is the
// creator of the requested resource (check a database field you
// have created to identify the creator etc...)
// if that goes well authorize using regular roles, below
return base.AuthorizeCore(httpContext);
}
}
You would then decorate your controller with
[AuthorizeAttribute(Role = "editors")]

Related

Are all incoming requests handled by AuthorizeAttribute in ASP.NET MVC?

I am developing a ASP.NET MVC 5 website which uses local STS for authentication.
I subclassed the AuthorizeAttribute to customize authentication/authorization process, added MyAuthorizeAttribute to GlobalFilters.
When user came in without authenticated, MyAuthorizeAttribute.OnAuthorize successfully caught it and create a SignInRequest to redirect to STS. That is what I want.
I observed that when user authenticated successfully and STS redirected user back, user's browser POSTed a SAML token embedded in request body to my MVC web application, this is by design, and I expected MyAuthenticateAttribute could catch this request, so I can extract the token from request body, check and validate it, however, MyAuthenticateAttribute.OnAuthorize() function didn't get called this time, it directly went to controller.
So is there anything wrong? Where should i catch and handle the token POSTed from user? Thanks.
You need to decorate your action method with [Authorize] attribute or if you want authorization to happen for all actions in a controller, then set that attribute on the controller itself.
Also take a look at the usage of [AllowAnonymous] at https://www.codeproject.com/Articles/1008731/Insight-of-ASP-NET-MVC-s-Authorize-Attribute
AuthorizeAttribute is both an Attribute and a IAuthorizationFilter. Attributes don't actually do anything, the MVC framework scans for where this attribute is added and registers it as a filter on the fly.
However, rather than decorating controllers or action methods with it, you could add it as a global filter:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new AuthorizationAttribute());
filters.Add(new HandleErrorAttribute());
}
}
By the same token, you can create your own IAuthorizationFilter or subclass AuthorizeAttribute to do whatever you want. If registered globally, it will always run for all actions and then you can use it to do custom authorization of requests globally.

ASP.NET Identity and creating RoleFunctions

I am using the latest and greatest Identity 3.x that comes stock with MVC6 Core 1.0 when selecting 'Individual User Accounts'.
The requirements of my user auth is the following:
Users -> AspNetUsers
Roles -> AspNetRoles
UserRoles -> AspNetUserRoles
RoleFunctions -> I don't see a table for this in the Identity db structure
RoleFunctions are any kind of system function such as DeleteCustomers, AccessToCustomerPage, etc.
I am going to assume ASP.NET Identity doesn't support this extra step with Roles-Based authentication so I am going to have to create the table and functions involved myself. Is this true or is it all there for me and I'm just not seeing it?
Identity allows you to determine authorization based on a controller, or a specific action in the controller.
[Authorize]
public void controllermethod(param) {}
authorize will require authentication before this action or controller can be visited.
So, if you wanted to create an action that only the admin could perform (or any user role group you have created), above the controller method you would put
[Authorize(Roles="admin")]
public void controllerMethod(param) {}
Roles can accept a list of strings, like (Roles="Admin","Manager"), so you can put multiple roles in a single authorization claim.
You can also do this on the controller level, forcing every action in the controller to adhere to your authorization claims. Basically if you put it above the controller declaration every action will be affected, but you can whitelist a particular action with
[AllowAnonymous]
public void nosecuritycontrolleraction {}
I hope this is what you are looking for, and you can find better guides here:
http://www.asp.net/identity
UPDATE 1
For the DeleteCustomer example, I'm assuming you have some methods in a controller that handles the deletion of a customer object. Above those methods, put [Authorize(Roles="CustomerAdmin")] and then only the users with the customerAdmin role in UserRoles can use that action.
like:
[Authorize(Roles="CustomerAdmin")]
public ActionResult DeleteCustomer(string/int id){}

ASP.NET Web API get user identity in controller constructor

Is good idea to get user identity in ASP.NET Web API controller constructor, for example:
public PagesController(PageValidator pageValidator, PageMapper pageMapper, PagesManager pagesManager, UsersManager usersManager)
:base(usersManager)
{
_pageValidator = pageValidator;
_pageMapper = pageMapper;
_pagesManager = pagesManager;
if (User.Identity.IsAuthenticated)
_pagesManager.UserId = usersManager.GetByEmail(User.Identity.Name).Id;
}
Is always User.Identity was correct populated before this call raise?
This has bitten me a few times. Depending on where/how you are performing your authentication, you need to be careful where you access your identity, particularly in controller constructors.
For example, whilst the controller action is invoked AFTER an IAuthenticationFilter is instantiated, the controller's constructor is called before AuthenticateAsync; meaning any authentication you do in AuthenticateAsync will not be available in your controller's constructor (like in your example).
I typically don't rely on things being available during controller construction (unless handled by DI). Instead access the identity as you need it in your controller actions.
If you are looking at making identity lookup easier (i.e. pulling in your user object based on the User.Identity.Name property) create a base controller class that has a property or method that does it for you, then have your controllers inherit from that...
public User AuthenticatedUser
{
get
{
if (User.Identity.IsAuthenticated)
{
return usersManager.GetByEmail(User.Identity.Name);
}
return null;
}
}
EDIT
See here for a detailed breakdown of the Web.API lifecycle, showing controller creation occurring prior to authentication.
Yes. You can use this property in Controller in any place. ASP.NET has request pipeline: (http://www.dotnetcurry.com/aspnet/888/aspnet-webapi-message-lifecycle).
As you can see Authorization is early stage step in request pipeline.
Controller creation is the latest stage.

authentication and authorizing in ASP.NET MVC 5

Asp.net MVC 5 seems to have left behind using the AuthorizeAttribute class where you could create a custom authorize attribute by implementing the AuthorizeAttribute class, override its methods and hiding the SiteRole property incase you wanted to bake in your own roles. All the examples I have seen either suggest using OWIN or the identity framework. Are these the only two ways to do authentication and authorization in the new ASP.Net framework?. Will I miss out on anything if I do it the old fashioned way? I dont want to have the framework create all the user and role tables for me. What if I want to add an existing user and role table to a new application?
I also really don't see a need for social integration in every application as yet and don't think I will need it immediately as well. Is there any article that explains starting off with a bare minimum by using a custom authorize attribute and then goes on to add the new authentication features. I want something that basically explains all the clutter in a newly created project with No Authentication or Individual User Authentication selected.
You can still customize the AuthorizeAttribute in MVC 5 using ASP.NET Identity. There is an example of doing this in the SimpleSecurity Project. Here is a customized AuthorizedAttribute you can use for controllers and here is customized AuthorizeAttribute you can use for Web API's. The concept behind these custom AuthorizeAttributes is to decouple your security model from your application model which is discussed here. The one for the Web API's also supports basic authentication.
The security pipeline has changed with the introduction of OWIN and I did run into some issues with the behavior of AuthorizeAttribute for Web API's, which is discussed here.
You will also find examples in the SimpleSecurity project on porting of the old membership provider called SimpleMembership to MVC 5. Some of the issues with the upgrade process are discussed here. I did get it to work though so you could go with the old membership provider implementation. But my recommendation would be to go with the ASP.NET Identity as this is the way going forward that Microsoft will be supporting, it is a more flexible architecture, and it eliminates many of the issues found in the old membership provider implementations.
Ben Foster has a two-part series that takes you through steps on implementing cookie-based authentication with ASP.NET Identity from the ground up, starting off with a new Web app with no authentication selected. Follow along "ASP.NET Identity Stripped Bare" Part 1 and Part 2.
use the following Authorize attribute to handle unauthorized access when the user is already authenticated.
public class LoggedOrAuthorizedAttribute : AuthorizeAttribute
{
public LoggedOrAuthorizedAttribute()
{
View = "error";
Master = String.Empty;
}
public String View { get; set; }
public String Master { get; set; }
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
CheckIfUserIsAuthenticated(filterContext);
}
private void CheckIfUserIsAuthenticated(AuthorizationContext filterContext)
{
// If Result is null, we’re OK: the user is authenticated and authorized.
if (filterContext.Result == null)
return;
// If here, you’re getting an HTTP 401 status code. In particular,
// filterContext.Result is of HttpUnauthorizedResult type. Check Ajax here.
if (filterContext.HttpContext.User.Identity.IsAuthenticated)
{
if (String.IsNullOrEmpty(View))
return;
var result = new ViewResult {ViewName = View, MasterName = Master};
filterContext.Result = result;
}
}
}

What is the most unobtrusive way to add a layer of security for a private beta of website?

Let's say I have an ASP.NET site (MVC in this case) that uses Forms authentication and a typical membership system. The site allows both authenticated and anonymous users.
When I release the site as a private beta I want to add another layer of security on top of the application, like superuser's simple password system, for example. Once a user has passed this layer of security, I still want my forms authentication/membership system in place so beta testers can view the site as authenticated or anonymous users.
What's the most unobtrusive way to achieve this? I'm looking for the easiest solution that will require the least amount of new or modified code. E.g. I don't want to modify every controller to check for a special cookie. There must be a better way...
There's a very similar question here, but it seems the site in question (once public) will only serve anonymous requests, so it doesn't necessarily compare to my situation. This answer suggests ServerFault used some cookie system, but there are no further details about how it might have been implemented.
Implement security at server level, in IIS and add the accounts/passwords in Active Directory of Windows running the IIS server.
You won't need to change any of the code.
Well, I know you don't want to modify your current controllers but here's what I did for a similar behaviour.
I've created a custom ActionFilterAttribute that I've given to every controller that requires to have that specific access check. You can have something like this :
public class CheckBetaAccess : ActionFilterAttribute {
public override void OnActionExecuting(ActionExecutingContext filterContext) {
if (!canAccess) {
filterContext.Controller.ViewData["someViewData"] = "some text";
filterContext.Result = new ViewResult {
ViewName = "the-view-anonymous-users-should-see",
ViewData = filterContext.Controller.ViewData
};
filterContext.Result.ExecuteResult(filterContext);
}
}
}
Then I decorated my controllers :
[CheckBetaAccess]
public class SomeController : Controller {
//....
}

Resources