I have an ASP.Net MVC application using Windows Authentication, and I am checking group membership for security on controller actions.
Simple as it sounds, I've found no other Question that can resolve the problem I am experiencing.
First Attempt: [Authorize]
The classic method is to simply slap an Authorize
data annotation attribute on the controller action and go to town:
[Authorize(Roles = @"domain\groupName1")]
No dice. I am prompted for credentials. Usually this means something is wrong with the Windows Authentication configuration but it's setup fine: (1) HttpContext.User
is a WindowsPrincipal
object, and (2) I confirmed another known group name works.
Second Attempt: IsInRole()
The next step taken was to go a more old fashioned route and use IPrincipal.IsInRole()
, and again, one returns false
, the other true
.
var wp = (WindowsPrincipal)User;
// false
var inGroup1 = wp.IsInRole(@"domain\groupName1");
// true
var inGroup2 = wp.IsInRole(@"domain\groupName2");
Stumped... so I hit up my systems nerds and we double check everything. User is a group member? Yes. Group name is spelled correctly? Yes. The next step was to snag the SID.
Third Attempt: Search Identity's Group Collection
In my controller I check the WindowsIdentity
and look through the group collection for the SID of the troublesome group:
var wi = (WindowsIdentity)wp.Identity;
var group = wi.Groups.SingleOrDefault(g => g.Value == "group1-sidValue");
The group
variable is the SecurityIdentifier
object. Because it is not null, we can be certain that this current user is a member of the group that both the [Authorize()]
or IsInRole()
attempts fail to confirm.
Fourth Attempt: DirectoryServices.AccountManagement
At this point, I'm going nuts and add reference to the AccountManagement APIs. I search the domain context for the GroupPrincipal
by both name and SID:
var pc = new PrincipalContext(ContextType.Domain, "domain");
var gp1byName = GroupPrincipal.FindByIdentity(pc, "groupName1")
var gp1bySid = GroupPrincipal.FindByIdentity(pc, IdentityType.Sid, "group1-sidValue");
Both group principal variables are ripe with the same object, and I verified through a watch variable that the principal's Members
collection contains a UserPrincipal
object with the same SID as the current WindowsPrincipal
on HttpContext
.
Question:
What in the hell have I missed here? Why would both role checking methodologies fail when it is plain and clear through object exploration that the user is a valid member of this given group?
The fact that one group checks fine and the other does not seems the most strange part at this point.
Answer:
Essentially it's translation issues between
WindowsIdentity
andNTAccount
(both of these System.Security.Principal) and lastly, the actual Active Directory entry.When validating a
WindowsIdentity
against AD, if you want to use anything other than the Sam or the Sid, you will need to useSystem.DirectoryServices.AccountManagement
.Caveat: In .Net 4.5 the security principals include Claims but that's out of context.
Long Explanation:
In a Windows Authenticated web application,
HttpContext.User
is aWindowsPrincipal
object wrapping an underlyingWindowsIdentity
.WindowsIdentity
has for most intents and purposes only two properties with which the authenticated user can be identified:Name
andUser
.These properties translate to two properties on the identity's corresponding AD account entry:
WindowsIdentity.Name
=SamAccountName
WindowsIdentity.User
=SID
The
[Authorize]
filter attribute ultimately callsIsInRole(string role)
on the underlying principal... and theIsInRole()
string overload instantiates anNTAccount
with therole
(the "SamAccountName" in an AD entry).This explains the failure in #1 and #2 above.
To authorize the
HttpContext.User
against anything but his/her Sid or SamAccountName, you'll needDirectoryServices.AccountManagement
or classic LDAP.I have an ASP.Net MVC application using Windows Authentication, and I am checking group membership for security on controller actions. Simple as it sounds, I've found no other Question that can resolve the problem I am experiencing. Took me a lot of time to find something http://www.c-sharpcorner.com/uploadfile/scottlysle/test-for-user-group-membership-in-Asp-Net-C-Sharp/
My code to check if user belongs to an AD group :
That is all I needed beside
<authentication mode="Windows"/>
in Web.config file