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!!
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With