8

I'm building an intranet app using ASP.NET MVC 5.

My goal is to have the authentication of any user made by the Active Directory (i.e. I'm using the "Windows Authentication"), then add groups to any user inside the application (NOT using domain groups).

I've found some very interesting piece of code here:

http://brockallen.com/2013/01/17/adding-custom-roles-to-windows-roles-in-asp-net-using-claims/

But it's not working in my scenario: when I decorate the controller with [Authorize(Role="AppRole")], I can't be authorized even if the user (using Claims) is associated with the "AppRole" role.

This is my code:

In Global.asax.cs

void Application_PostAuthenticateRequest()
    {
        if (Request.IsAuthenticated)
        {

            string[] roles = Utils.GetRolesForUser(User.Identity.Name);

            var id = ClaimsPrincipal.Current.Identities.First();
            foreach (var role in roles)
            {
                //id.AddClaim(new Claim(ClaimTypes.Role, role.ToString()));
                id.AddClaim(new Claim(ClaimTypes.Role, @"Kairos.mil\Compliance"));
            }


            bool pippo = User.IsInRole("Compliance");

            HttpContext.Current.User = (IPrincipal)id ;

            bool pippo2 = User.IsInRole("Compliance");


        }
    }

The function GetRolesForUser is as follows (and is working fine):

 public static string[] GetRolesForUser(string username)
    {
        dbOrdiniPersonaliEntities db = new dbOrdiniPersonaliEntities();

        string utente = StripDomain(username);

        string[] gruppi = new string[db.vGruppiUtentis.Where(t => t.KairosLogin == utente).Count()];

        int i=0;

        foreach (var gruppo in db.vGruppiUtentis.Where(t => t.KairosLogin == utente))
        {

            gruppi[i]=gruppo.GruppoDes;
            i=i++;
        }
        return gruppi;
    }

And the controller is decorated with the "standard" Authorize clause:

[Authorize(Roles="AppRole")]
    public ActionResult Index(string sortOrder, string currentFilter, string DesSearchString,int? page)
    {
      // my code here
    }

Any idea?

Thanks in advance

UPDATE

Thanks @Leandro I've tried as you suggested the following code

void Application_PostAuthenticateRequest()
    {
        if (Request.IsAuthenticated)
        {

            string[] roles = Utils.GetRolesForUser(User.Identity.Name);

            ClaimsIdentity id = ClaimsPrincipal.Current.Identities.First();
            foreach (var role in roles)
            {
                //id.AddClaim(new Claim(ClaimTypes.Role, role.ToString()));
                id.AddClaim(new Claim(ClaimTypes.Role, @"Kairos.mil\Compliance"));
            }

            bool pippo = User.IsInRole("Compliance");

            SetPrincipal((IPrincipal)id);

            bool pippo2 = User.IsInRole("Compliance");


        }
    }

But I receive a run-time error when the code reaches this point

SetPrincipal((IPrincipal)id);

The error is as follows

Unable to cast object of type 'System.Security.Principal.WindowsIdentity' to type 'System.Security.Principal.IPrincipal'.

Thanks for your help

UPDATE 2 (maybe solved)

Hi Looking deeper into SO, I've found this resource

ASP.NET MVC and Windows Authentication with custom roles

Following the answer of @Xhalent, I modified my code as follows

protected void Application_PostAuthenticateRequest()
    {
        if (Request.IsAuthenticated)
        {
            String[] roles = Utils.GetRolesForUser(User.Identity.Name);

            GenericPrincipal principal = new GenericPrincipal(User.Identity, roles);

            Thread.CurrentPrincipal = HttpContext.Current.User = principal;
        }
    }

It seems now working fine! Any comments? Any drawbacks? Thanks a lot!!

Community
  • 1
  • 1
  • This works. I am happy to find this. Just something which can be improved a bit. Instead of setting Principle in Application_PostAuthenticateRequest, using Application_AuthenticateRequest as mentioned in the link https://forums.asp.net/t/2124141.aspx?How+to+use+custom+Roles+using+Windows+Authentication+in+MVC+Application. Please use the code inside an if with the condition HttpContext.Current.User != null as this method gets called before setting the User as well as after setting the User . – Sumesh Kuttan Feb 04 '18 at 11:24

1 Answers1

3

Use this method to save the principal, so it sets up also in the thread:

     private void SetPrincipal(IPrincipal principal)
        {
            Thread.CurrentPrincipal = principal;
            if (HttpContext.Current != null)
            {
                HttpContext.Current.User = principal;
            }
        }

Update: Also allow anonymous and test if User.IsInRole is getting something inside the method.

Leandro Bardelli
  • 10,561
  • 15
  • 79
  • 116
  • thanks. Where I have to use the method SetPrincipal? Which piece of code should call this method? – Andrea Panzeri May 06 '15 at 16:16
  • 1
    In the global ajax after you authorize the user. You set HttpContext.Current.User = (IPrincipal)id but you need set up the principal. Check out here for examples: http://stackoverflow.com/questions/26464848/custom-authorization-in-asp-net-webapi-what-a-mess – Leandro Bardelli May 06 '15 at 16:20