In our MVC solution we have two custom implementations of AuthorizeAttribute - one is named BasicHttpAuthorizeAttribute and has been used in production for years, and the other RoleAuthorizeAttribute, which was recently added.
When creating RoleAuthorizeAttribute I simply copied BasicHttpAuthorizeAttribute and modified some of the already-overridden methods.
Both attributes serve the purpose of authenticating the user, and the RoleAuthorizeAttribute of verifying that the user has the required role.
However, RoleAuthorizeAttribute never authenticates the user. It is simply not being called and instead our MVC controllers throw an exception when a non-logged-in user reaches the controller action and the code requests the context user.
Below is the outline for this custom AuthorizeAttribute. If I put breakpoints on all of those methods I find that none of them are hit when a request is made.
Can anyone explain why this class is not being used to authenticate users? Why is it that an unauthenticated user is not being redirected to the login page, but if I swap RoleAuthorize for BasicHttpAuthorize or simply the base Authorize then they are redirected?
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public class RoleAuthorizeAttribute : System.Web.Http.AuthorizeAttribute
{
/// <summary>
/// Gets or sets the <see cref="Role"/> enumerations required for authorization.
/// </summary>
public Role[] RequiredRoles
{
get {...}
set {...}
}
public bool RequireSsl { get; set; };
public bool RequireAuthentication { get; set; }
public RoleAuthorizeAttribute(params Role[] requiredRoles)
{
// ...
}
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
{
// ...
}
protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
{
// ...
}
private bool Authenticate(System.Web.Http.Controllers.HttpActionContext actionContext)
{
// ...
}
public static bool TryGetPrincipal(string authHeader, out IPrincipal principal)
{
// ...
}
public static bool TryGetAuthCookie(out IPrincipal principal)
{
// ...
}
private static string[] ParseAuthHeader(string authHeader)
{
// ...
}
private static bool TryGetPrincipal(string username, string password, out IPrincipal principal)
{
// ...
}
}
And here is an example of its usage:
namespace MyProject.Areas.Customer.Controllers
{
[RoleAuthorize(Role.Customer, Role.CompanyAdmin)]
public partial class OrderController : MyCustomController
{
private static readonly ILog Log = LogManager.GetLogger(typeof (OrderController));
public ActionResult Index(int id)
{
// ...
}
}
}
We use Basic Authentication so there's a header set thus:
I've seen older questions asking about the same problem, but in those cases, they also override an AuthorizeCore method which no longer seems to be present on the AuthorizeAttribute class.
I figured out myself why this was happening.
There are two AuthorizeAttributes - one in the System.Web.Http namespace and the other in System.Web.Mvc. I wasn't aware of this and was trying to build a one-size-fits-all attribute, so my attribute was working for WebAPI requests but not for MVC controller requests.
The difference in these two attributes is in the OnAuthorize method where they each take a different context argument.
Once I had built two separate attributes (which are almost identical), each deriving from a different AuthorizeAttribute, everything worked as expected.
Related
I am trying to set up some authorisation for a Web API I have. My project uses Entity framework context, and dependency injection.
I have a Web API function like this:
[Authorize2]
[HttpPost]
[Route("whatever")]
public async Task<IHttpActionResult> APIfunction()
{
//Do something...
return Ok();
}
and I have extended the AuthorizeAttribute class to this:
public class Authorize2 : AuthorizeAttribute
{
/// <summary>
///
/// </summary>
/// <param name="actionContext"></param>
public override void OnAuthorization(HttpActionContext actionContext)
{
}
}
This means that the OnAuthorization function will fire before this API function is hit - which is as I want and working fine.
I have a function that is used to determine if the user has permission to access this function. The function is defined in an interface, implemented in a class and the class is instantiated using dependency injection eg:
public interface IPermissions
{
bool hasPermission();
}
public class Permissions : IPermissions
{
public Permissions(numerous DI interfaces passed into the constructor)
{
//Assign values....
}
public bool hasPermission()
{
{
}
and my dependency config has this:
container.Register<Permissions, IPermissions>();
My issue is that I want to call the hasPermission function in my OnAuthorization function eg like this:
public override void OnAuthorization(HttpActionContext actionContext)
{
var perm = _permissions.hasPermission();
}
But I do not know how I can do this, or if it is even possible?
I cannot manually create the classes as there are to many classes and constructors to add it and it is not practical.
I have tried making Authorize2 implement an interface and then create an instance in my dependency constructor, but that would mean passing in a parameter her [Authorize2], which is not possible.
The only other way I can see is to create this function manually within my Authorize class, but I really do not want to do this unless I have to.
Adding this to the to the token is not an option and the data is dynamic and has to be evaluated on a case by case basis
Since the attributes do not allow dependency injection, use service location via the DependencyResolver which you can get via the ActionContext
public override void OnAuthorization(HttpActionContext actionContext) {
var resolver = actionContext.RequestContext.Configuration.DependencyResolver;
var _permissions = (IPermissions)resolver.GetService(typeof(IPermissions));
var perm = _permissions.hasPermission();
//...
}
You need to resolve dependency using parameterized constructor.
Modify your Authorize2 class,
public class Authorize2 : AuthorizeAttribute
{
private readonly IPermissions _permissions;
public Authorize2(IPermissions permissions)
{
this._permissions=permissions;
}
public override void OnAuthorization(HttpActionContext actionContext)
{
var perm = _permissions.hasPermission();
}
}
I am creating a session control on my project and I need help at the moment.
Basically, my HomeController inherits from CustomController.
HomeController manages the methods and CustomController runs before methods to check session info.
public class HomeController : CustomController
{
public ActionResult Index()
{
}
}
public class CustomController : Controller
{
public OnActionExecuting()
{
// Check session
}
}
My problem is, I do not want to check Session before HomeController/Index method. Is this possible?
You could do it with a custom attribute class as follows:
/// <summary>
/// Indicates whether session checking is enabled for an MVC action or controller.
/// </summary>
public class CheckSessionAttribute : Attribute
{
public CheckSessionAttribute(bool enabled)
{
this.Enabled = enabled;
}
public bool Enabled { get; }
}
Then annotate the action method you want to exclude session checking with [CheckSession(false)].
Lastly, include the following in the OnActionExecuting method of the base class:
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
// Check if the CheckSession attribute is present and skip the session
// check if [CheckSession(false)] was explicitly provided.
bool checkSession = filterContext.ActionDescriptor.GetCustomAttributes(typeof(CheckSession), true)
.OfType<CheckSession>()
.Select(attr => attr.Enabled)
.DefaultIfEmpty(true)
.First();
if (checkSession)
{
// Check session
}
}
This checks for the presence of the [CheckSession(false)] attribute and disables the session check in that case. In this way, you can configure the methods that should not check the session info simply by annotating them with the new attribute. This also makes it immediately clear that the session is not checked for that specific action.
As I am working on Asp.Net core Authorization part, I needed a new property in AuthorizeAttribute which I want to utilize as a extra permission value. So, I have extended the AuthorizeAttribute in my own custom Authorize attribute. See below:
public class RoleAuthorizeAttribute : Microsoft.AspNetCore.Authorization.AuthorizeAttribute
{
public string Permission { get; private set; }
public RoleAuthorizeAttribute(string policy, string permission) : base(policy)
{
this.Permission = permission;
}
}
Then, I've created an AuthorizationHandler to check for the requirement as below:
public class RolePermissionAccessRequirement : AuthorizationHandler<RolePermissionDb>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, RolePermissionDb requirement)
{
// check here..
context.Succeed(requirement);
return Task.FromResult(0);
}
}
All respective service collection mapping I have already done, just omitted here.
Now, I want my attribute to use like this on controller action level:
[RoleAuthorize("DefaultPolicy", "CustomPermission")]
public IActionResult List()
{
}
Would anybody suggest me how would I access the permission property value given on the top of Action method in the handler RolePermissionAccessRequirement ??
I want to perform some sort of access rule based on custom permission value given in the Authorize attribute on top of Action method.
Thanks in advance!
To parametrize a custom Authorize attribute, create an authorization filter implementing IAsyncAuthorizationFilter. Then wrap the filter in a TypeFilterAttribute-derived attribute. This attribute can accept parameters and pass it to the authorization filter's constructor.
Usage example:
[AuthorizePermission(Permission.Foo, Permission.Bar)]
public IActionResult Index()
{
return View();
}
Implementation:
public class AuthorizePermissionAttribute : TypeFilterAttribute
{
public AuthorizePermissionAttribute(params Permission[] permissions)
: base(typeof(PermissionFilter))
{
Arguments = new[] { new PermissionRequirement(permissions) };
Order = Int32.MinValue;
}
}
public class PermissionFilter : Attribute, IAsyncAuthorizationFilter
{
private readonly IAuthorizationService _authService;
private readonly PermissionRequirement _requirement;
public PermissionFilter(
IAuthorizationService authService,
PermissionRequirement requirement)
{
//you can inject dependencies via DI
_authService = authService;
//the requirement contains permissions you set in attribute above
//for example: Permission.Foo, Permission.Bar
_requirement = requirement;
}
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
bool ok = await _authService.AuthorizeAsync(
context.HttpContext.User, null, _requirement);
if (!ok) context.Result = new ChallengeResult();
}
}
In addition, register a PermissionHandler in DI to handle PermissionRequirement with permission list:
public class PermissionHandler : AuthorizationHandler<PermissionRequirement>
Look at this this GitHub project for a complete example.
I'm having some problem with my custom AuthorizeAttribute
public class ExplicitAuthorizeAttribute : AuthorizeAttribute
{
private readonly MembershipUserRole[] _acceptedRoles;
public ExplicitAuthorizeAttribute()
{
}
public ExplicitAuthorizeAttribute(params MembershipUserRole[] acceptedRoles)
{
_acceptedRoles = acceptedRoles;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
//Validation ...
}
}
I use it like this:
[ExplicitAuthorize[(MembershipUserRole.Admin, MembershipUserRole.SuperAdmin)]
It works perfectly for HttpGet and HttpPost to validate my controllers and methods.
But when I use it in a ApiController and make ajax calls, AuthorizeCore isn't running and I got a security breach. :/
My enum looks like this
[Flags]
public enum MembershipUserRole
{
Admin= 1,
SuperAdmin = 2
}
Does anyone know why my AuthorizeCore isn't validating in this context?
By the way If I use
[Authorized(Roles ="Admin, SuperAdmin")]
It's validates perfectly, but I'd like to have Stronly Typed Roles,that's why I'm using enums.
You have derived from the wrong class: System.Web.Mvc.AuthorizeAttribute whereas for a Web API controller you should derive from System.Web.Http.AuthorizeAttribute.
Don't forget that ASP.NET MVC and ASP.NET Web API are 2 completely different frameworks and even if they share some common principles and names, the corresponding classes are located in 2 completely different namespaces.
So what you have done is decorate an ASP.NET Web API action with an AuthorizeAttribute that it doesn't know anything about.
If you want to make authorization in ASP.NET Web API make sure you have derived from the correct attribute:
public class ExplicitAuthorizeAttribute : System.Web.Http.AuthorizeAttribute
{
private readonly MembershipUserRole[] _acceptedRoles;
public ExplicitAuthorizeAttribute()
{
}
public ExplicitAuthorizeAttribute(params MembershipUserRole[] acceptedRoles)
{
_acceptedRoles = acceptedRoles;
}
protected override bool IsAuthorized(HttpActionContext actionContext)
{
//Validation ...
}
}
Authorization and authentication in MVC application
I have an internal web app developed in C# using MVC 2. I want to use AD roles/groups to do authorization. Thus I have 3 access group Admin, Basic, Readonly. The access to the application will be controlled through these groups.
Now when I hit an action/page of my MVC app, the requirements are:
1) Check level of access (is in either group Admin, Basic or Readonly)
2) If in a group - serve the page.
If not - serve the 401 Unauthorized page.
I am probably confusing myself with the concepts authorization/authentication, but this is how it is set up so far (from answers, google and my own efforts flowing from this question:
public static class AuthorizationModule
{
public static bool Authorize(HttpContext httpContext, string roles)
{
...
//Check Configuration.AppSettings for the roles to check
//using httpContext.User check .IsInRole for each role and return true if they are
...
//other wise throw new HttpException(401,.....)
}
...
}
public class AuthorizeByConfigurationAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
//Essentially at the moment this is pretty much the same as AuthorizationModule.Authorize(HttpContext httpContext, string roles)
}
}
//This code from http://paulallen.com.jm/blog/aspnet-mvc-redirect-unauthorized-access-page-401-page
public class RequiresAuthenticationAttribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.User.Identity.IsAuthenticated)
{
filterContext.Result = new ViewResult {ViewName = "AccessDenied"};
}
else
{
base.HandleUnauthorizedRequest(filterContext);
}
}
}
The problems with this are that I seem to need to decorate my action methods twice now, ala:
[AuthorizeByConfiguration(Roles = "Admin, Basic, Readonly")]
[RequiresAuthentication(Roles = "Admin, Basic, Readonly")]
public ActionResult Index(string msg)
{
...
}
And the next problem is that it seems I have three separate methods all trying to do the same thing. I am overriding methods based on advice and not entirely sure how they were meant to work originally. How could I go about implementing my requirements?
edit: Since this is an IntrAnet app, all users who sign on with their network accounts will be able to access this app. I need to restrict the access so that only those who belong to certain Active Directory security groups can access this app
I have wrapped all the methods concerning auth with the interface IAuthorization.
Here is an example custom attrbiute you would need to add the Roles property and your own implementaion.
Attribute calls the filter itself for testability reasons.
public class SomeAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
var filter = new SomeAuthorizeFilter(DependencyLookup.Resolve<IAuthorization>());
filter.OnAuthorization(filterContext);
}
}
public class SomeAuthorizeFilter : IAuthorizationFilter
{
private readonly IAuthorization _authorization;
public SomeAuthorizeFilter(IAuthorization authorization)
{
_authorization = authorization;
}
protected virtual ActionResult ResultWhenNotAuthenticated(AuthorizationContext filterContext)
{
//snip..
//default
RouteValueDictionary redirectTargetDictionary = new RouteValueDictionary
{
{"action", "Index"},
{"controller", "Home"}
};
return new RedirectToRouteResult(redirectTargetDictionary);
}
#region IAuthorizationFilter Members
public void OnAuthorization(AuthorizationContext filterContext)
{
if (!_authorization.GetCurrentUserIdentity().IsAuthenticated)
{
filterContext.Result = ResultWhenNotAuthenticated(filterContext);
}
}
#endregion
}