3

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

Community
  • 1
  • 1
baron
  • 11,011
  • 20
  • 54
  • 88
  • If you put your attributes on the class declaration then it will apply to all actions (methods). – CRice Aug 09 '11 at 04:02
  • Why not combine those two filters, forget the 'original implementation' and write it how you want it to work now? – CRice Aug 09 '11 at 04:21
  • @CRice that would be fine. I'm not sure how to "forget the original implementation". Because i'm overriding existing behaviour. E.g. if I wanted to put it all in `AuthorizeCore` - I can't because I don't have `AuthorizationContext filterContext` and I can't return my AccessDenied view in it because it returns `bool`. Do I write my "one main method" and then just call it from each of these events ? Can you provide same code/stubs... Thanks – baron Aug 09 '11 at 05:04

1 Answers1

2

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
}
CRice
  • 12,279
  • 7
  • 57
  • 84
  • Ok I have no idea what you are doing in `public override void OnAuthorization(AuthorizationContext filterContext)` and `DependencyLookup` does not exist in the current context. Also line `if (!_authorization.GetCurrentUserIdentity().IsAuthenticated)` - Microsoft.Data.Schema.ScriptDom.Sql.IAuthorization does not contain a definition for GetCurrentUserIdentity. And how do I now decorate my controller actions/methods? How on earth do you get such a specific knowledge of how the methods work-so you can understand how to rewrite them/override them !?!?? – baron Aug 09 '11 at 06:17
  • Dependency lookup is just a call to my service locator to get me the IAuthorization instance (a new instance of a class Authorization that I wrote). So this could be written as "new Authorization()" instead. If you read the first line of my answer I mentioned I created this interface so that would also be why you don't have IAuthorization. It's not a copy and paste job - just an example for you to use to create your implementaion from. – CRice Aug 09 '11 at 06:45
  • I basically stayed with the skeleton I had above. I brought everything into `AuthorizeByConfigurationAttribute` and then the authentication life cycle actually started to work how it is supposed to and everything started to play together. (`AuthorizeCore` would pass on to `HandleUnauthorizedRequest` depending). I _DID_ work with your solution, but couldn't really understand it (as compared to my skeleton) and couldn't get something working to compile - and had to abandon. Unfortunately, I still have no idea what the `IAuthorizationFilter` was about. I guess I need to research interfaces. – baron Aug 29 '11 at 08:10