WindowsTokenRoleProvider & Domain Groups

C

Craig Wagner

I've been researching using Domain Groups within our application. I found a
code sample that I've been experimenting with, but need confirmation on one
behavioral thing that I've noticed.

My web.config contains the following:

<system.web>
<authentication mode="Windows" />
<roleManager enabled="true"
defaultProvider="AspNetWindowsTokenRoleProvider" />
</system.web>

The IIS vdir has anonymous access turned off and Integrated Windows
Authentication turned on.

In my web page, I execute:

string[] members = Roles.GetRolesForUser();

The returned members include domain global groups and builtin groups. The
list does not include Domain Local groups to which I belong.

Is this expected behavior (the lack of domain local groups) or am I doing
something incorrectly?
 
J

Joe Kaplan

Are those domain local groups that are local to the domain the web server is
in? If the web server is in a different domain than the DLGs, then that is
the expected behavior.

Joe K.
 
J

Joe Kaplan

Well, the Windows token for you on the web server should contain the DLGs.
You might try getting the WindowsIdentity object associated with the user
and looking at the Groups property. If the DLGs aren't in there, then I
don't know what the problem is. On the other hand, I don't know why the
role provider method wouldn't return those if they were in the token, so
there is a mystery in general.

Joe K.
 
C

Craig Wagner

I'll take a look at that.

I'm wondering if it might have anything to do with the way I'm connecting to
AD. The connection string I'm using is LDAP://wagner.local, but in some of
the examples I've seen there's a bunch of CNs and UOs and other
two-letter-acronyms at the end of the string. Might that have anything to do
with not seeing the DLGs?

I may end up just switching the way I'm doing this and query AD for the user
info using the ActiveDirectoryMembershipProvider. It allows me to get
everything about the user, including their group memberships (and with that
code I am seeing the DLGs, an added bonus :)).
 
J

Joe Kaplan

There isn't actually an ActiveDirectoryRoleProvider to match the membership
provider (to my knowledge), so I'm not sure how you are getting the group
info. My co-author, Ryan, is actually working on an LDAP-based AD role
provider that we'll release at the website below when he's finished it.

Out of curiosity, how are you getting a Windows token for the logged on user
when you are using the ActiveDirectoryMembershipProvider? Normally, you get
a Windows token when you use Windows authentication.

Joe K.
 
S

Steven Cheng[MSFT]

Hi Craig,

As Joe said, the ActiveDirectoryMembershipProvider only help validate a
given user(username/password credentials) against the certain DC or get
list of users info from there. The return values are of
"ActiveDirectoryMembershipUser" which doesn't provide any role/group info.
How did you get the roles/groups through Membershipprovider?

For the "WindowsTokenRoleProvider", based on my local test, it seems with
an authenticated windows user, all the groups(domain ,local domain and
built-in ones) can be correctly retrieved. But my test is performed in VS
2005 test webserver which is running under my logon user(domain account).
So I think the behavior may be related to yoru ASP.NET application's worker
process identity(since the AD query is performed under process identity if
no impersonate is using). What's the current security identity of your
ASP.NET worker process, are you using IIS5 or IIS6. I suggest you also try
configure the ASP.NET application to running under a domain account to see
whether you can get all the correct groups.

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead


This posting is provided "AS IS" with no warranties, and confers no rights.
 
D

Dominick Baier

I wouldn't use the WTRP at all - it doesn't give you any advantages besides
making it even more confusing at times...

Just use no role provider with Windows authentication and you can find a
WindowsPrincipal sitting on Context.User which provides all the necessary
functionality.
 
D

Dominick Baier

ah - and this is how you retrieve groups then:

http://www.leastprivilege.com/GettingAllGroupsForAWindowsAccountInNET20.aspx
-----
Dominick Baier (http://www.leastprivilege.com)

Developing More Secure Microsoft ASP.NET 2.0 Applications (http://www.microsoft.com/mspress/books/9989.asp)
I wouldn't use the WTRP at all - it doesn't give you any advantages
besides making it even more confusing at times...

Just use no role provider with Windows authentication and you can find
a WindowsPrincipal sitting on Context.User which provides all the
necessary functionality.

-----
Dominick Baier (http://www.leastprivilege.com)
Developing More Secure Microsoft ASP.NET 2.0 Applications
(http://www.microsoft.com/mspress/books/9989.asp)
I've been researching using Domain Groups within our application. I
found a code sample that I've been experimenting with, but need
confirmation on one behavioral thing that I've noticed.

My web.config contains the following:

<system.web>
<authentication mode="Windows" />
<roleManager enabled="true"
defaultProvider="AspNetWindowsTokenRoleProvider" />
</system.web>
The IIS vdir has anonymous access turned off and Integrated Windows
Authentication turned on.
In my web page, I execute:

string[] members = Roles.GetRolesForUser();

The returned members include domain global groups and builtin groups.
The list does not include Domain Local groups to which I belong.

Is this expected behavior (the lack of domain local groups) or am I
doing something incorrectly?
 
C

Craig Wagner

I'm sorry. My mistake, I was using the ActiveDirectoryMembershipProvider
simply to validate the user's credentials. Then, once I knew the username and
password were valid I was using the DirectoryEntry & DirectorySearcher to get
information about the user. That's what I get for posting just as I'm trying
to leave the office.

I am using Windows authentication. My web.config contains:

<authentication mode="Windows" />

And the Directory Security for the vdir is set up such that the only option
checked is Integrated Windows authentication.
 
C

Craig Wagner

See my response to Joe about the ActiveDirectoryMembershipProvider.

My configuration is:

Windows XP Pro (IIS 5)
web.config contains <authentication mode="Windows" />
IIS vdir Directory Security is set to only Integrated Windows Authentication
Impersonation is turned on

I don't know how definitive this is, but when I display the values of
Environment.UserDomainName and Environment.UserName I get WAGNER\cwagner,
which is my domain credentials.

I also tried turning anonymous access back on and setting the anonymous user
account to my domain account and leaving impersonate on. Again
Environment.UserDomainName and Environment.UserName reported WAGNER\cwagner,
but GetRoles returned nothing.

Because ultimately I'm going to be able to need to get information about a
user other than the one that is logged in, the
DirectoryEntry/DirectorySearcher approach seems like the better one. In the
back of my mind I had always wondered how I would make GetRoles get me
information for other than the currently authenticated user, but I'm new to
working with AD and just kind of latched on to the first thing I found and
started experimenting with it.
 
J

Joe Kaplan

There is a nice sample that shows how to use the AD tokenGroups attribute to
retrieve a user's transitive security group membership in ch 10 of our book
which is a free download from our website (see link below). This technique
is the basis for which Ryan's ActiveDirectoryRoleProvider works. I'd
suggest checking that out.

If you need to do AD stuff and need to get up to speed with LDAP
programming, the book will likely help you.

It looks to me that if Windows auth in ASP.NET works for you, you should
just use Context.User.IsInRole to look at group membership. You really
don't need the WindowsTokenRoleProvider for this. I only think it is useful
in the context of an application that is coded to use the membership/roles
API and wants to provide flexibility to their customers as to which
providers they can use.

Joe K.
 
J

Joe Kaplan

I responded in another place in the thread, but you really don't need to do
this. If you are using Windows auth in IIS/ASP.NET, you don't need the
membership provider or the role provider. Just let Windows check the
credentials and let ASP.NET build you a token and a WindowsPrincipal that
will automatically be placed in Context.User.

If you need to look up additional attributes in AD, then the
DirectorySearcher will be needed.

Joe K.
 
C

Craig Wagner

"If you are using Windows auth in IIS/ASP.NET..."

Ah, there's the rub. The only reason I'm using Windows Authentication right
now is because that's the only way I could start experimenting with the
GetRoles method.

As I said in another post, ultimately the app needs to run with anonymous
access enabled and forms authentication. The current configuration (using
Windows Authentication) was only to get me started understanding a bit about
this stuff. Of course the first thing I ran into was not seeing the domain
local groups, which confused me.

Given that I ultimately need to use Forms Authentication and have the web
app run with anonymous access enabled, using the
ActiveDirectoryMembershipProvider for authentication and DirectorySearcher to
look up the user's name and groups seems the way to go.

I will take a look at your book for more hints.
 
J

Joe Kaplan

I don't understand why you need to use forms auth if you are going to use AD
as the auth store. What's the point? I realize that MS provided the AD
membership provider to address this need, but I still struggle to understand
when it is really needed.

If you do plan to use the AD membership provider, you will need an AD
LDAP-based role provider as well such as the one I mentioned that Ryan is
working on currently. To look up your additional attributes in AD, that
will require the DirectorySearcher as you've already been doing.

Definitely check out the book, especially the end of ch 10 to see how the
tokenGroups thing works to get a user's group membership via LDAP. That is
the query that the whole thing pivots around. The rest is just framework
code to make that data work within the provider model and provide
appropriate credentials and connection info to AD.

Joe K.
 
C

Craig Wagner

I don't understand why you need to use forms auth if you are going to use AD
as the auth store. What's the point?

We install our software at client sites. Some of them have AD and want to
use it, and others don't. There is also a requirement to allow a single
installation to work in a 'mixed mode' (think SQL Server).

We also deal with confidential health care data, and need to make sure our
application can time out the user and force them to re-authenticate, not just
let anyone who can access the machine launch the app.

The reason our clients are requesting support for AD as the auth store is
not to create a single sign-on environment, but only to allow our clients to
centralize their user and group membership maintenance.

Hope that answers the question.

I've already got the code from the end of chapter 10 returning the list of
groups to which the user belongs. Very sweet. The one thing I haven't quite
figured out all the way is that the RefreshCache needs to be called on a
DirectoryEntry object, but I've got a SearchResult object. What I'm doing for
the time being at least is the following:

DirectoryEntry entry =
new DirectoryEntry(
ConfigurationManager.ConnectionStrings["ADService"].ConnectionString, null,
null, AuthenticationTypes.Secure );

DirectorySearcher dsearch = new DirectorySearcher( entry );

string name = txtUserToFind.Text;

dsearch.Filter = "(&(sAMAccountType=805306368)(sAMAccountName="
+ name + "))";

SearchResult searchResult = dsearch.FindOne();

if( searchResult != null && searchResult.Properties.Contains(
"adspath" ) && searchResult.Properties["adspath"].Count > 0 )
{
DirectoryEntry user =
new DirectoryEntry(
searchResult.Properties["adspath"][0].ToString(), null, null,
AuthenticationTypes.Secure );

It may not be the most efficient approach in the world, but it seems like it
would work in a wide range of (if not all) installations. I'll be going out
after work today to try to find a copy of your book and see if I can find a
more efficient way of getting the info I need from AD.
 
J

Joe Kaplan

I see what you are doing. Coding to the membership APIs is probably you
best bet then as it gives your customers more flexibility.

The easiest way to get a DirectoryEntry from a SearchResult is just to call
GetDirectoryEntry. That's what I'd do.

You can also get the tokenGroups attribute from a SearchResult, but you have
to execute another search to do it, so it is easier just to use the
DirectoryEntry, as you need a DirectoryEntry pointing to the user itself to
use as the search root for the DirectorySearcher.

The reason for this is that tokenGroups is a special constructed attribute
that can only be requested when the scope of the query is "Base". When you
are searching the entire directory to find the user by their username, you
are doing a subtree query.

Under the hood, the DirectoryEntry fills its property cache by doing a base
level query to itself, so the net result is the same as if you did another
search with the DirectorySearcher.

Anyway, I hope this extra explanation is helpful and not distracting. :)

One other advantage to coding to the membership APIs is that it gives you
the ability to use ADFS as another way to sign into the application in the
future. This gives you a reasonable way to sell your app in the ASP model
where you host it yourself on the public internet and provide SSO back to
your clients. Your clients could also use this for SSO internally if they
are using ADFS.

Joe K.

--
Joe Kaplan-MS MVP Directory Services Programming
Co-author of "The .NET Developer's Guide to Directory Services Programming"
http://www.directoryprogramming.net
--
Craig Wagner said:
I don't understand why you need to use forms auth if you are going to use
AD
as the auth store. What's the point?

We install our software at client sites. Some of them have AD and want to
use it, and others don't. There is also a requirement to allow a single
installation to work in a 'mixed mode' (think SQL Server).

We also deal with confidential health care data, and need to make sure our
application can time out the user and force them to re-authenticate, not
just
let anyone who can access the machine launch the app.

The reason our clients are requesting support for AD as the auth store is
not to create a single sign-on environment, but only to allow our clients
to
centralize their user and group membership maintenance.

Hope that answers the question.

I've already got the code from the end of chapter 10 returning the list of
groups to which the user belongs. Very sweet. The one thing I haven't
quite
figured out all the way is that the RefreshCache needs to be called on a
DirectoryEntry object, but I've got a SearchResult object. What I'm doing
for
the time being at least is the following:

DirectoryEntry entry =
new DirectoryEntry(
ConfigurationManager.ConnectionStrings["ADService"].ConnectionString,
null,
null, AuthenticationTypes.Secure );

DirectorySearcher dsearch = new DirectorySearcher( entry );

string name = txtUserToFind.Text;

dsearch.Filter = "(&(sAMAccountType=805306368)(sAMAccountName="
+ name + "))";

SearchResult searchResult = dsearch.FindOne();

if( searchResult != null && searchResult.Properties.Contains(
"adspath" ) && searchResult.Properties["adspath"].Count > 0 )
{
DirectoryEntry user =
new DirectoryEntry(
searchResult.Properties["adspath"][0].ToString(), null, null,
AuthenticationTypes.Secure );

It may not be the most efficient approach in the world, but it seems like
it
would work in a wide range of (if not all) installations. I'll be going
out
after work today to try to find a copy of your book and see if I can find
a
more efficient way of getting the info I need from AD.
 
C

Craig Wagner

Yeah, I found that GetDirectoryEntry method about ten minutes after my last
post. It's been a learning experience. :)

Extra information is always helpful. Eventually it sinks in, even if I don't
get it initially.

ADFS = Active Directory Federated Services?
SSO = Single Sign-On?

I really appreciate all the assistance. You provide enough information so as
not to completely frustrate the reader but leave enough for the reader to
figure out on their own so it's still fun. That's a tough line to walk.
Thanks.
 
J

Joe Kaplan

Yes and yes and ADFS and SSO. ADFS and identity federation in general are
the future of authentication on the web, so I try to sneak that into every
post I can. :)

Joe K.
 
J

Joe Kaplan

Also, regarding the DLGs, it occurs to me to ask whether or not the groups
in question are actually security-enabled and also make sure the domain
isn't in Win2K mixed mode (instead of native mode). You won't get DLGs in
your access token unless the groups are security enabled and the domain in
2K native or higher.

Joe K.
 

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

Members online

Forum statistics

Threads
473,994
Messages
2,570,222
Members
46,810
Latest member
Kassie0918

Latest Threads

Top