I was wanting to use an attribute in some of my class methods that would make sure that the user is an authorized before using the method that they called.
I was wanting to do something like
[Authorized()]
public void updateSomething()
{
//TODO:
}
I here is my attribute class
class AuthorizedAttribute : Attribute
{
public bool IsAuthorized { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string UserEmail { get; set; }
public AuthorizedAttribute()
{
//This is not the actual implementation
this.IsAuthorized = false;
}
public AuthorizedAttribute(string userEmail, string userPassword)
{
this.UserEmail = userEmail;
this.Password = userPassword;
this.UserName = string.Empty;
BusinessLogic bc = new BusinessLogic();
if (bc.VerifyCredentials(userEmail, userPassword))
{
this.IsAuthorized = true;
}
else
{
this.IsAuthorized = false;
}
}
}
Could someone point me in the right direction? Some link would be great as well.
Thank you.
I think the fundemental mistake you have made here is to look at passing the credentials to the attribute. What the attribute should do is force an action to occur before the function you have called will take place.
So your attribute must be checked for by the request processing pipeline. i.e. when the function updateSomething() is called the calling assembly should be looking for the attribute which will then force an authorisation to occur using the current HttpContext and the User.Identity.
I have experience with the MVC AuthorizeAttribute and which can be extended by deriving from this attribute and adding authentication logic to it.
public class TestAuthAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext)
{
return ResultOfBusinsessLogic;
}
}
this can then be used on any controller action.
I hope this points you in the right direction.
Have you looked at the built-in AuthorizeAttribute?
If you are using Forms authentication / roles this is already built in - check out the PrincipalPermission attribute.
Sample usage:
[PrincipalPermission(SecurityAction.Demand, Role = "Admin")]
Related
I have a problem, I need to do something like this in order to protect my API based on permission code.
Into the "OnAuthorization" i check the jwtToken, db and soon.
[AuthorizePermissionByCode("fr")]
[HttpGet]
public int Get()
{
DO STUFF
}
I have write a class in order to manage AuthorizePermissionByCode
namespace CustomAuthorizeAttribute
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class AuthorizePermissionByCode : AuthorizeAttribute, IAuthorizationFilter
{
public string Permissions { get; set; } //Permission string to get from controller
public AuthorizePermissionByCode(string Permissions)
{
this.Permissions = Permissions;
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
}
I have no error, build success and soon, but never enter into "OnAuthorization".
I need to edit in some way my startup?
I put:
services.AddAuthentication();
services.AddAuthorization();
Not particularly sure of your intentions but i haven done something close in time pass.
Take a look at this code and refactor where appropriate.
https://www.c-sharpcorner.com/UploadFile/56fb14/custom-authorization-in-mvc/
Is it possible to have a ActionFilterAttribute parameters like this ?
[DataType(DataType.Password)]
For example I need to create something like this
[ValidateSession(Session.Required)]
public class ValidateSession : ActionFilterAttribute
{
enum Session
{
Required,
NotRequired
}
private Session _session { get; set; }
public ValidateSession(Session session)
{
this._session = session;
}
}
You can add parameters to custom ActionFilter. For more information see
this.
I am trying to implement permission based access control with aspnet core. For dynamically managing user roles and permissions(create_product, delete_product etc.), they are stored in the database. Data Model is like http://i.stack.imgur.com/CHMPE.png
Before aspnet core (in MVC 5) i was using custom AuthorizeAttribute like below to handle the issue:
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
private readonly string _permissionName { get; set; }
[Inject]
public IAccessControlService _accessControlService { get; set; }
public CustomAuthorizeAttribute(string permissionName = "")
{
_permissionName = permissionName;
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
var user = _accessControlService.GetUser();
if (PermissionName != "" && !user.HasPermission(_permissionName))
{
// set error result
filterContext.HttpContext.Response.StatusCode = 403;
return;
}
filterContext.HttpContext.Items["CUSTOM_USER"] = user;
}
}
Then i was using it in action method like below:
[HttpGet]
[CustomAuthorize(PermissionEnum.PERSON_LIST)]
public ActionResult Index(PersonListQuery query){ }
Additionally, i was using HttpContext.Items["CUSTOM_USER"] in views to show or hide html part:
#if (CurrentUser.HasPermission("<Permission Name>"))
{
}
When i decided to switch aspnet core, all my plan was failed. Because there was no virtual OnAuthorization method in the AuthorizeAttribute. I tried some ways to solve problem. Those are below:
Using new policy based authorization(i think it is not suitable for
my scenerio)
Using custom AuthorizeAttribute and AuthorizationFilter(i read this
post https://stackoverflow.com/a/35863514/5426333 but i couldn’t change it properly)
Using custom middleware(how to get AuthorizeAttribute of current
action?)
Using ActionFilter(is it correct for security purpose?)
I couldn’t decide which way is the best for my scenerio and how to implement it.
First question: Is MVC5 implementation bad practice?
Second question: Do you have any suggest to implement aspnet core?
Based on the comments, here an example on how to use the policy based authorization:
public class PermissionRequirement : IAuthorizationRequirement
{
public PermissionRequirement(PermissionEnum permission)
{
Permission = permission;
}
public PermissionEnum Permission { get; }
}
public class PermissionHandler : AuthorizationHandler<PermissionRequirement>
{
private readonly IUserPermissionsRepository permissionRepository;
public PermissionHandler(IUserPermissionsRepository permissionRepository)
{
if(permissionRepository == null)
throw new ArgumentNullException(nameof(permissionRepository));
this.permissionRepository = permissionRepository;
}
protected override void Handle(AuthorizationContext context, PermissionRequirement requirement)
{
if(context.User == null)
{
// no user authorizedd. Alternatively call context.Fail() to ensure a failure
// as another handler for this requirement may succeed
return null;
}
bool hasPermission = permissionRepository.CheckPermissionForUser(context.User, requirement.Permission);
if (hasPermission)
{
context.Succeed(requirement);
}
}
}
And register it in your Startup class:
services.AddAuthorization(options =>
{
UserDbContext context = ...;
foreach(var permission in context.Permissions)
{
// assuming .Permission is enum
options.AddPolicy(permission.Permission.ToString(),
policy => policy.Requirements.Add(new PermissionRequirement(permission.Permission)));
}
});
// Register it as scope, because it uses Repository that probably uses dbcontext
services.AddScope<IAuthorizationHandler, PermissionHandler>();
And finally in the controller
[HttpGet]
[Authorize(Policy = PermissionEnum.PERSON_LIST.ToString())]
public ActionResult Index(PersonListQuery query)
{
...
}
The advantage of this solution is that you can also have multiple handlers for a requirement, i.e. if first one succeed the second handler can determine it's a fail and you can use it with resource based authorization with little extra effort.
The policy based approach is the preferred way to do it by the ASP.NET Core team.
From blowdart:
We don't want you writing custom authorize attributes. If you need to do that we've done something wrong. Instead you should be writing authorization requirements.
I had same requirement and i have done it as below and it works fine for me. I am using .Net Core 2.0 Webapi
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Method
, AllowMultiple = true
, Inherited = true)]
public class CheckAccessAttribute : AuthorizeAttribute, IAuthorizationFilter
{
private string[] _permission;
public CheckAccessAttribute(params string[] permission)
{
_permission = permission;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
var user = context.HttpContext.User;
if (!user.Identity.IsAuthenticated)
{
return;
}
IRepository service =
(IRepositoryWrapper)context.HttpContext.RequestServices.GetService(typeof(IRepository));
var success = service.CheckAccess(userName, _permission.ToList());
if (!success)
{
context.Result = JsonFormatter.GetErrorJsonObject(
CommonResource.error_unauthorized,
StatusCodeEnum.Forbidden);
return;
}
return;
}
}
In Controller use it like below
[HttpPost]
[CheckAccess(Permission.CreateGroup)]
public JsonResult POST([FromBody]Group group)
{
// your code api code here.
}
For a solution that doesn't require you to add a policy for each permission see my answer for another question.
It lets you decorate your Controllers and Actions with any custom attributes you wish, and access them in your AuthorizationHandler.
I'm working on separating concerns in MVC. Currently everything is mixed up (Library functions, extensions, custom filter attributes, data access level), but I want to have 2 separate projects for those (MySolution.Lib and MySolution.DBModel). I want to separate my custom filter attribute to Lib project. DBModel is already referencing Lib, so I've done everything beside this one. What's the best way to implement this? Is it possible to pass to the attribute values in another custom property and work only on text inside Attribute implementation. So that the Attribute would be used something like this:
[AuthorizeUser(AccessLevel = "Admin", UserRights = DBModel.User.GetUserRights(HttpContext.User.Identity.Name)]
public ActionResult MyAction()
Here's the current implementation
public class AuthorizeUserAttribute : AuthorizeAttribute
{
// Custom property
public string AccessLevel { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var isAuthorized = base.AuthorizeCore(httpContext);
if (!isAuthorized)
{
return false;
}
List<string> accessLevels = AccessLevel.Split(new[] {','}).ToList();
//this is taken from DB by GetUserRights() method from MySecurity static class
var privilegeLevels = MySecurity.GetUserRights(httpContext.User.Identity.Name);
return accessLevels.Any(privilegeLevels.Contains)
|| privilegeLevels.Contains("Admin") || privilegeLevels.Contains("Super User");
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
var helper = new UrlHelper(filterContext.RequestContext);
filterContext.HttpContext.Response.Redirect(helper.Action("Index", "Unauthorized"));
}
}
I have an object that contains all login data, that's in my controller (it was programmed before switching to MVC3).
I'm trying to add authorization to the site, so so far I have:
public LoginObject MyLoginObject
{
get;
set;
}
[CustomAuthorization()]
public ActionResult Index()
{
return View();
}
and
public class CustomAuthorization : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
return true;
//should be return myLoginObject.IsLoggedIn;
}
}
Is there anyway to pass MyLoginObject into the AuthorizeAttribute class? If not could I at least pass in a boolean from the object that specifies if the user is authorized or not?
Edit: My solution based on Zonnenberg's advice.
public class LoginObject : IPrincipal // Now extends IPrincipal
{
... //old code
private class IdentityImpl : IIdentity
{
public string AuthenticationType
{
get;
set;
}
public bool IsAuthenticated
{
get;
set;
}
public string Name
{
get;
set;
}
}
public IIdentity Identity
{
get { return new IdentityImpl { AuthenticationType = "Custom Authentication", IsAuthenticated = this.IsLoggedIn, Name = this.Id}; }
}
}
Then I moved the instantiation of loginobject into CustomAuthorization
public override void OnAuthorization(AuthorizationContext filterContext)
{
// ... Set up LoginObject
filterContext.RequestContext.HttpContext.User = myLoginObject;
base.OnAuthorization(filterContext);
}
So now logging in, is done inside the authorization, and I can call User to access the login from the controller.
You can check wheter the user is logged in by using httpContext.User.Identity.IsAuthenticated.
To store more information you could use the httpContext.User object. You can write your own implementation of IPrincipal and IIdentity to store all kinds of login information.
Other option is to store login info in the Session.
How is your LoginObject instantiated?
If it's instantiated via a service or repository (ex. MyLoginObject = loginService.GetLogin() then you can move this call into the CustomAuthorization attribute.
If the logic is within the controller itself then this should be refactored into a service or repository depending on you solution architecture so that you can do the above.