Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
252 views
in Technique[技术] by (71.8m points)

c# - Active Directory Group Membership Checking in .Net 4.5

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 = @"domaingroupName1")]

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(@"domaingroupName1");
// true
var inGroup2 = wp.IsInRole(@"domaingroupName2");

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Answer:

Essentially it's translation issues between WindowsIdentity and NTAccount (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 use System.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 a WindowsPrincipal object wrapping an underlying WindowsIdentity.

WindowsIdentity has for most intents and purposes only two properties with which the authenticated user can be identified: Name and User.

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 calls IsInRole(string role) on the underlying principal... and the IsInRole() string overload instantiates an NTAccount with the role (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 need DirectoryServices.AccountManagement or classic LDAP.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...