4

Ok following up with this thread, here's what I came up with...

public class SharweAuthorizeAttribute : AuthorizeAttribute
{
    private bool isAuthenticated = false;
    private bool isAuthorized = false;
    public new string[] Roles { get; set; }

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        if (SessionManager.CheckSession(SessionKeys.User) == true)
        {
            isAuthenticated = true;
            foreach (string role in Roles)
            {
                if (RolesService.HasRole((string)role))
                    isAuthorized = true;
            }
        }
        return (isAuthenticated && isAuthorized);
    }

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (!isAuthenticated)
        {
            filterContext.Result = new RedirectToRouteResult(
                            new RouteValueDictionary 
                            {
                                { "action", "User" },
                                { "controller", "Login" }
                            });
        } else if(!isAuthorized) {
            filterContext.Result = new RedirectToRouteResult(
                            new RouteValueDictionary 
                            {
                                { "action", "Home" },
                                { "controller", "Error" }
                            });
        }
    }
}

How/why I came up with this? Because I believe the AuthorizeAttribute workflow goes as follows:

  1. First, AuthorizeCore is triggered. If it returns true, the user is authorized. If it returns false, HandleUnauthorizedRequest is triggered. Is that right?
  2. I read somewhere that I need to use the new keyword to override a property. Therefore, this is how I overrode the Roles property. But what if the overriding property was of a different type of the initial one (the one in the base class), does that also hide it or creates a totally different property?

So what do you think? Should that actually work? I cannot test it now because I haven't set up the UI (waiting for the designer to get done with the design)... In fact, this is the first time I appreciate the benefits of TDD, I used to think it's utterly stupid and useless, but I was wrong :)

P.S: On this thread, @tvanfosson is setting the CachePolicy of the context (I think), could someone explain that and why I might need to do that please?

Thanks in advance.

Community
  • 1
  • 1
Kassem
  • 8,116
  • 17
  • 75
  • 116
  • 1
    Do not put security-sensitive information in `Session` It's not intended to be secure. Google "ASP.NET Session hijacking." – Craig Stuntz Feb 22 '11 at 19:41
  • I'm not actually putting any sensitive information inside the Session. What's in the Session is not the User object itself, it's an object containing two properties: The ID of the user and its nickname. Does that sacrifice any important data? – Kassem Feb 22 '11 at 20:46
  • 1
    The user's identity is perhaps the most security-sensitive piece of information imaginable. If I can pretend to be you, then I can do anything you can do. – Craig Stuntz Feb 22 '11 at 22:07
  • @Craig Stuntz: hmmm... But using SSL should prevent anyone from hijacking a session, right? – Kassem Feb 22 '11 at 22:18
  • 3
    No, using SSL does not prevent that. Using SSL assures the *client* that they are talking to you. It does not validate the claims the client makes about their identity. – Craig Stuntz Feb 22 '11 at 22:33
  • @Craig Stuntz: Hmmm... you are right. What do you suggest I should do instead? What other mechanism can I use to manage all this stuff (authentication & authorization)? – Kassem Feb 23 '11 at 19:16
  • It's not clear why you want to do this. The MS membership provider works. So do off-the-shelf alternatives like OpenID. It isn't clear why you're trying to re-invent the wheel. Perhaps you need to ask about the problem you're actually trying to solve, instead of your proposed solution to it. – Craig Stuntz Feb 23 '11 at 19:27
  • I am trying to avoid using the Membership API because it's very different from my project's requirements. Plus it's going to add a lot of unnecessary schema to my database. That is why I'm trying to re-create a Membership solution that abides by my project requirements. Also, I checked the off-the-shelf alternatives, and all of them just wrap around the MS Membership API. – Kassem Feb 23 '11 at 19:33
  • 1
    You're still not stating your actual problem. You're just insisting that the solution everyone else uses can't possibly work. Pardon me for saying it, but they're not half as broken as what you've proposed here. So instead of insisting that a very flexible system can't possibly work for you, why not explain the business problem you're trying to solve, and ask for the best solution to *that.* – Craig Stuntz Feb 23 '11 at 21:12
  • @CraigStuntz I do not understand you comment on `Session Hi-jacking`. The data I put in session always remains on server, so there is no chance a attacker who hijacks my user's session can get hold of that data. And secondly, if attacker has hijacked the session then he can very well do everything that an authenticated user can do, so putting or not putting things in session, per me, does not change anything. – Suhas May 03 '12 at 19:47
  • @Kassem What exactly is your question. I share your feeling about membership provider and I have implemented `AuthorizeAttribute` in my application in almost same way which works like a charm. But what is your question here? – Suhas May 03 '12 at 19:48
  • @Suhas: That is confused. Session and authentication are orthogonal. You can steal a session without being able to crack authentication. – Craig Stuntz May 05 '12 at 02:28
  • @CraigStuntz Yeah, Session and authentication are orthogonal etc. But what's the relation between "ASP.NET session hijacking" and "putting sensitive information in session". I'm not recommending putting sensitive information in session, that's a wrong practice. But I did not get the relation. – Suhas May 06 '12 at 18:38

1 Answers1

2
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    private readonly bool _authorize;
    private readonly string[] _roles;

    public CustomAuthorizeAttribute(string roles)
    {
        _authorize = true;
        _roles = roles.Split(',');
    }

    public CustomAuthorizeAttribute(string roles, bool isAdminPath)
    {
        _authorize = true;
        _roles = roles.Split(',');
    }

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        //if controller have role auth and user is not loged
        if(_authorize && !httpContext.User.Identity.IsAuthenticated)
            return false;

        // if controller have role auth and user is loged
        if(_roles != null)
        {
            //grab user roles from DB
            var UserRole = RoleRepository.GetUserRole(new Guid(httpContext.User.Identity.Name));
            if (_roles.Contains(UserRole))
               return true;
        }
        return false;
    }
}

In Controller

[CustomAuthorize("Administrator,Company,OtherRole")]
public ActionResult Test(){
    return View();
}
Thomas Ayoub
  • 29,063
  • 15
  • 95
  • 142
Novkovski Stevo Bato
  • 1,013
  • 1
  • 23
  • 56