role-based security and ActiveDirectory

S

SpaceMarine

hello,

im having a little problem w/ role-based security and ActiveDirectory
(AD), hoping someone can help. im trying to restrict access to my app
to only users within a particular AD group. details:

- ASP.NET 3.5 intranet app; Visual Studio 2008

- deployed to a Windows Server 2008 (IIS7) machine

- uses Windows authentication

- all desired domain users reside in a custom AD group, "FOO_BAR".

- requesting the User.Identity.Name yields: "OURDOMAIN\SomeUserName"

- requesting all group membership yields:

Everyone
OURDOMAIN\Domain Users
OURDOMAIN\FOO_BAR

....all looks good. so the problem? when i request:

User.IsInRole(@"OURDOMAIN\FOO_BAR") or
User.IsInRole("FOO_BAR") or

....i get False.

this is problematic because in my web.config im trying to restrict
access to the group-only:

<authorization>
<!-- Allow only group users -->
<allow roles="FOO_BAR"/>
<deny users="*"/>
<deny users="?"/>
</authorization>


any idea whats up? i read that ASP.NET's role-based security model
should be able to pick up a Windows-authenticated AD user's groups as
roles. is this not the case?


thanks!
sm


ps - here is how i get a loop of a user's group memberships...useful:

//convert user's groups to readable NT thang
IdentityReferenceCollection usersGroups = WindowsIdentity.GetCurrent
().Groups.Translate(System.Type.GetType
("System.Security.Principal.NTAccount"));

StringBuilder sb = new StringBuilder(200);

foreach (IdentityReference group in usersGroups)
sb.Append(group.Value + "<br/>");
 
A

Alexey Smirnov

any idea whats up? i read that ASP.NET's role-based security model
should be able to pick up a Windows-authenticated AD user's groups as
roles. is this not the case?

You need to use ADAM or similar
http://msdn.microsoft.com/en-us/library/ms998331.aspx

        //convert user's groups to readable NT thang
        IdentityReferenceCollection usersGroups = WindowsIdentity.GetCurrent
().Groups.Translate(System.Type.GetType
("System.Security.Principal.NTAccount"));

        StringBuilder sb = new StringBuilder(200);

        foreach (IdentityReference group in usersGroups)
                sb.Append(group.Value + "<br/>");

You can assign user to roles manually from the code.

In global.asax in Application_AuthenticateRequest you can use your
code from above as

string[] roles = new string[] { };

// your code here....

foreach (IdentityReference group in usersGroups)
roles.Add(group.Value);

//and then add our own custom principal to the request containing the
roles in the auth ticket
Context.User = new GenericPrincipal(Context.User.Identity, roles);
 
A

Alexey Smirnov

any idea whats up? i read that ASP.NET's role-based security model
should be able to pick up a Windows-authenticated AD user's groups as
roles. is this not the case?

You need to use ADAM or similar
http://msdn.microsoft.com/en-us/library/ms998331.aspx

        //convert user's groups to readable NT thang
        IdentityReferenceCollection usersGroups = WindowsIdentity.GetCurrent
().Groups.Translate(System.Type.GetType
("System.Security.Principal.NTAccount"));

        StringBuilder sb = new StringBuilder(200);

        foreach (IdentityReference group in usersGroups)
                sb.Append(group.Value + "<br/>");

You can assign user to roles manually from the code.

In global.asax in Application_AuthenticateRequest you can use your
code from above as

string[] roles = new string[] { };

// your code here....

foreach (IdentityReference group in usersGroups)
roles.Add(group.Value);

//and then add our own custom principal to the request containing the
roles in the auth ticket
Context.User = new GenericPrincipal(Context.User.Identity, roles);
 
J

Joe Kaplan

This should work. It may be the case that the group in question either is
not security enabled and thus would not be the user's token or it has a
different account name than you think it does.

What you should do is verify what's actually in the token. Write some code
that translates the User.Identity object to a WindowsIdentity and then use
the Translate method on the IdentityReferenceCollection to translate to
NTAccount objects. Then you can dump out the names and see what's in there.

Alexey suggested using ADAM or creating a GenericPrincipal object but
neither of these are needed. I can't actually see why ADAM would help with
this scenario at all. The WindowsPrincipal should do exactly what you want
it to.

Joe K.
 
J

Joe Kaplan

This should work. It may be the case that the group in question either is
not security enabled and thus would not be the user's token or it has a
different account name than you think it does.

What you should do is verify what's actually in the token. Write some code
that translates the User.Identity object to a WindowsIdentity and then use
the Translate method on the IdentityReferenceCollection to translate to
NTAccount objects. Then you can dump out the names and see what's in there.

Alexey suggested using ADAM or creating a GenericPrincipal object but
neither of these are needed. I can't actually see why ADAM would help with
this scenario at all. The WindowsPrincipal should do exactly what you want
it to.

Joe K.
 
S

SpaceMarine

This should work.  It may be the case that the group in question eitheris
not security enabled and thus would not be the user's token or it has a
different account name than you think it does.

i see. if i ask our admins whether the group is "security enabled"
will that mean something to them, something they can check?


sm
 
S

SpaceMarine

This should work.  It may be the case that the group in question eitheris
not security enabled and thus would not be the user's token or it has a
different account name than you think it does.

i see. if i ask our admins whether the group is "security enabled"
will that mean something to them, something they can check?


sm
 
J

Joe Kaplan

I hope so. :) It is radio button in the normal AD GUI. If the AD admins
don't know what you are talking about, I would lobby for qualified people to
take their positions.

--
Joe Kaplan-MS MVP Directory Services Programming
Co-author of "The .NET Developer's Guide to Directory Services Programming"
http://www.directoryprogramming.net
This should work. It may be the case that the group in question either is
not security enabled and thus would not be the user's token or it has a
different account name than you think it does.

i see. if i ask our admins whether the group is "security enabled"
will that mean something to them, something they can check?


sm
 
J

Joe Kaplan

I hope so. :) It is radio button in the normal AD GUI. If the AD admins
don't know what you are talking about, I would lobby for qualified people to
take their positions.

--
Joe Kaplan-MS MVP Directory Services Programming
Co-author of "The .NET Developer's Guide to Directory Services Programming"
http://www.directoryprogramming.net
This should work. It may be the case that the group in question either is
not security enabled and thus would not be the user's token or it has a
different account name than you think it does.

i see. if i ask our admins whether the group is "security enabled"
will that mean something to them, something they can check?


sm
 
S

SpaceMarine

I hope so. :) It is radio button in the normal AD GUI.

ok it wasnt that :(. they sent me a screenshot -- Security was
selected, Distribution was not.

so it looks like this is next:
What you should do is verify what's actually in the token. Write some code
that translates the User.Identity object to a WindowsIdentity and then use
the Translate method on the IdentityReferenceCollection to translate to
NTAccount objects. Then you can dump out the names and see what's in there.

....is that something substainally different than my group looping
above?


thanks,
sm
 
S

SpaceMarine

I hope so. :) It is radio button in the normal AD GUI.

ok it wasnt that :(. they sent me a screenshot -- Security was
selected, Distribution was not.

so it looks like this is next:
What you should do is verify what's actually in the token. Write some code
that translates the User.Identity object to a WindowsIdentity and then use
the Translate method on the IdentityReferenceCollection to translate to
NTAccount objects. Then you can dump out the names and see what's in there.

....is that something substainally different than my group looping
above?


thanks,
sm
 
S

SpaceMarine

You can assign user to roles manually from the code.

// your code here....

foreach (IdentityReference group in usersGroups)
roles.Add(group.Value);

//and then add our own custom principal to the request containing the
roles in the auth ticket
Context.User = new GenericPrincipal(Context.User.Identity, roles);

assuming i cant get this to work 100% out-of-the-box (users' AD Group
memberships equating to ASP.NET's Roles), you are right -- i could
always loop thru my above group collection and all each to the Roles
collection.

just seems kinda silly. :(


sm
 
S

SpaceMarine

You can assign user to roles manually from the code.

// your code here....

foreach (IdentityReference group in usersGroups)
roles.Add(group.Value);

//and then add our own custom principal to the request containing the
roles in the auth ticket
Context.User = new GenericPrincipal(Context.User.Identity, roles);

assuming i cant get this to work 100% out-of-the-box (users' AD Group
memberships equating to ASP.NET's Roles), you are right -- i could
always loop thru my above group collection and all each to the Roles
collection.

just seems kinda silly. :(


sm
 
J

Joe Kaplan

It should work fine. Normally a problem like this is that either:

- You have an incorrect name and the string match is failing as a result
- You have a domain local group from a domain in a different domain than
the web server
- You have a nested group and are still in Win2K mixed mode with AD
- The group isn't security enabled

You've already eliminated the last one and the other two seem less likely.
The idea behind looping through the groups is just for debug purposes to see
what's actually in the user's token. That will give you a better clue what's
going on and you can go from there.

--
Joe Kaplan-MS MVP Directory Services Programming
Co-author of "The .NET Developer's Guide to Directory Services Programming"
http://www.directoryprogramming.net
You can assign user to roles manually from the code.

// your code here....

foreach (IdentityReference group in usersGroups)
roles.Add(group.Value);

//and then add our own custom principal to the request containing the
roles in the auth ticket
Context.User = new GenericPrincipal(Context.User.Identity, roles);

assuming i cant get this to work 100% out-of-the-box (users' AD Group
memberships equating to ASP.NET's Roles), you are right -- i could
always loop thru my above group collection and all each to the Roles
collection.

just seems kinda silly. :(


sm
 
J

Joe Kaplan

It should work fine. Normally a problem like this is that either:

- You have an incorrect name and the string match is failing as a result
- You have a domain local group from a domain in a different domain than
the web server
- You have a nested group and are still in Win2K mixed mode with AD
- The group isn't security enabled

You've already eliminated the last one and the other two seem less likely.
The idea behind looping through the groups is just for debug purposes to see
what's actually in the user's token. That will give you a better clue what's
going on and you can go from there.

--
Joe Kaplan-MS MVP Directory Services Programming
Co-author of "The .NET Developer's Guide to Directory Services Programming"
http://www.directoryprogramming.net
You can assign user to roles manually from the code.

// your code here....

foreach (IdentityReference group in usersGroups)
roles.Add(group.Value);

//and then add our own custom principal to the request containing the
roles in the auth ticket
Context.User = new GenericPrincipal(Context.User.Identity, roles);

assuming i cant get this to work 100% out-of-the-box (users' AD Group
memberships equating to ASP.NET's Roles), you are right -- i could
always loop thru my above group collection and all each to the Roles
collection.

just seems kinda silly. :(


sm
 
S

SpaceMarine

The idea behind looping through the groups is just for debug purposes to see
what's actually in the user's token. That will give you a better clue what's
going on and you can go from there.

ah...my initial thought was that by looping thru the current
WindowsIdentity's Groups and translating to NTAccounts as I am doing
(first post) was doing exactly that. but now i see the User.Identity
is NOT the same as the WindowsIdentity.GetCurrent(). (seems the
WindowsIdentity represents the thread running the ASP.NET code,
whereas User.Identity just represents the "client" identity. im still
learning the diffs!)

thus youre suggesting I "translate" the User.Identity to a
WindowsIdentity. so i did this:

WindowsIdentity winIdentity2 = (WindowsIdentity)User.Identity;

.....and re-created winIdentity2's groups collection, translating to
NTAccount. results -- group membership is *the same* as when i used:

WindowsIdentity.GetCurrent(true); //true = app is using
impersonation

....same exact groups when looped thru.


the plot thickens!!


btw i really appreciate your knowledge & help.
sm
 
S

SpaceMarine

It should work fine.  Normally a problem like this is that either:

 - You have an incorrect name and the string match is failing as a result
 - You have a domain local group from a domain in a different domain than
the web server
 - You have a nested group and are still in Win2K mixed mode with AD
 - The group isn't security enabled

You've already eliminated the last one and the other two seem less likely..

....yep, last is eliminated. first: i hope not, but that would be
easiest. ive tried w/ "FOO_BAR" (my group name, w/ an underscore in
it), as well as copying the full "OURDOMAIN\FOO_BAR" out of the group
collection -- i had to add the @ sign for csharp, so its @"OURDOMAIN
\FOO_BAR". both return False....

that leaves the middle two. im going to ask w/ my admin about them.

on #2 - while my group memberships say "OURDOMAIN\XXX", on the web
server the "My Computer->Properties" say "Domain: ourdomain.com". (the
server is hit internally via ("http://boxname.ourdomain.com")


sm
 
J

Joe Kaplan

Yes, this is well documented. WindowsIdentity.GetCurrent is only the same
as User.Identity when you have impersonation enabled. The thing that is
checked against when you use the <authorization> element in web.config or
when you do Context.User.IsInRole is the current authenticated user.

The idea behind this model is that ASP.NET has a generic mechanism for
representing authenticated user identity via Context.User (IPrincipal). Any
type of auth mechanism can plug into this by implementing IPrincipal.
Windows auth builds a WindowsPrincipal whereas Forms auth builds a
FormsPrincipal. You can also implement your own auth mechanisms that build
their own IPrincipal and IIdentity types.

The question is still whether or not Context.User.Identity belongs to the
group in question or not. If it does and the spelling is correct, then
Context.User.IsInRole *should* give you the behavior you want (as should
checks with the <authorization> element or PrincipalPermission.Demand
checks). It still isn't clear to me what the story is there from your
reply.

Since all code in Windows runs under the security context of a Windows
identity (represented by a security token), you can also determine what this
identity is at any time by doing WindowsIdentity.GetCurrent. This can
either be the process identity/token or an impersonated identity. However,
this identity only matters for Windows security checks made by the code. It
does not necessarily have anything to do with the authenticated user in a
web app. In cases where you are authenticating against something like a SQL
store using the membership provider, there IS no Windows user for that
person so it would not make sense for the code to be executing as that user
from the Windows perspective.

I hope that helps clarify things.

--
Joe Kaplan-MS MVP Directory Services Programming
Co-author of "The .NET Developer's Guide to Directory Services Programming"
http://www.directoryprogramming.net
The idea behind looping through the groups is just for debug purposes to
see
what's actually in the user's token. That will give you a better clue
what's
going on and you can go from there.

ah...my initial thought was that by looping thru the current
WindowsIdentity's Groups and translating to NTAccounts as I am doing
(first post) was doing exactly that. but now i see the User.Identity
is NOT the same as the WindowsIdentity.GetCurrent(). (seems the
WindowsIdentity represents the thread running the ASP.NET code,
whereas User.Identity just represents the "client" identity. im still
learning the diffs!)

thus youre suggesting I "translate" the User.Identity to a
WindowsIdentity. so i did this:

WindowsIdentity winIdentity2 = (WindowsIdentity)User.Identity;

.....and re-created winIdentity2's groups collection, translating to
NTAccount. results -- group membership is *the same* as when i used:

WindowsIdentity.GetCurrent(true); //true = app is using
impersonation

....same exact groups when looped thru.


the plot thickens!!


btw i really appreciate your knowledge & help.
sm
 
S

SpaceMarine

WindowsIdentity.GetCurrent is only the same as User.Identity when you have
impersonation enabled.

i see. i do have impersonation enabled -- enabling it and disabling
Anonymous Access seemed the only way to get ASP.NET apps to pickup
*anything* from AD. when these werent set my User.Identity.Name was
empty. by enabling impersonation and disabling anonymous
User.Identity.Name was filled w/ the currently-authenticated user.

The question is still whether or not Context.User.Identity belongs to the
group in question or not.  If it does and the spelling is correct, then
Context.User.IsInRole *should* give you the behavior you want (as should
checks with the <authorization> element or PrincipalPermission.Demand
checks).  It still isn't clear to me what the story is there from your
reply.

well, if my code is right, the answer is "Yes", the
Context.User.Identity does belong -- its translated group memberships
are exactly the same as the WindowsIdentity's groups. but it sounds
like this is expected as im using impersonation.

the code performing this check:

WindowsIdentity winIdentity2 = (WindowsIdentity)Context.User.Identity;

IdentityReferenceCollection usersGroups2 =
winIdentity2.Groups.Translate(System.Type.GetType
("System.Security.Principal.NTAccount"));

sb = new StringBuilder(200);

foreach (IdentityReference group in usersGroups2)
sb.Append(group.Value + "<br/>");

litGroups2.Text = sb.ToString();


.....there in the Literal i see my OURDOMAIN\FOO_BAR listed.


sm
 
S

SpaceMarine

It should work fine.  Normally a problem like this is that either:

 - You have an incorrect name and the string match is failing as a result
 - You have a domain local group from a domain in a different domain than
the web server
 - You have a nested group and are still in Win2K mixed mode with AD
 - The group isn't security enabled

on #2 and #3, my admin suggests those arent the case. he sent me a
screenshot that says:

Domain name:
ourdomain.com

Current domain functional level:
Windows Server 2003

....the "ourdomain.com" is the same as what my webserver reports. and
my take-away from the current-functional-level is that its not W2K
mode.

darn. this is puzzling and frustrating..


sm
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top