ASP.NET - Windows authentication and local groups

Everyone has a pet project or two. One of mine is a little intranet website. The site is mostly information - not very interactive (yet) and in the past was mostly authored in ASP and FrontPage. For a while now I've been trying to migrate it to ASP.NET 2.0 mainly to give me a platform that I can use as a bit of a test bed for trying things out, such as the forthcoming Atlas technologies.

 

So the other day I was trying to revamp the security model for it. For certain reasons I need to restrict access to it to certain groups and then allow other users in once they have read certain terms and conditions. So my idea was simple - just use a machine local group to control who could access the site, add the necessary domain groups to my local group and then have a mechanism for adding individuals to the machine local group too. Easy? Well almost.

 

I added a section to my web.config thinking it would be just what I needed:

<authorization>
<allow roles="MACHINENAMESiteBrowsers"/>
<deny users="*"/>
</authorization>

This should allow in members of the SiteBrowsers group and keep everyone else out, I thought.  As I do my development against my local machine running IIS6 (on Windows Server 2003 x64 in 32-bit worker process mode) I added my domain account to the local group and browsed the site.

Access Denied

Hmm. That's strange.

<authorization>
<allow roles="BUILTINAdministrators"/>
<deny users="*"/>
</authorization>

That worked.  I quick surf around the net found some people getting similar problems with local groups. Some examples seemed to show the machine name prefix not being used:

<authorization>
<allow roles="Administrators"/>
<deny users="*"/>
</authorization>

That worked! That must be it, I just need to omit the machine name:

<authorization>
<allow roles="SiteBrowsers"/>
<deny users="*"/>
</authorization>

Nope:

Access Denied

This was starting to get annoying.

Maybe I should get a colleague to try it. So I persuade Paula, who sits next to me, to help me out. I add domainpaula to SiteBrowsers. She browses the site and it works! Aggh! So Paula can get in but I can't!  I remove her from the group and she is immediately denied access again. Paula then suggested that perhaps I need to log off and on again. So I logged off and back on and browse to localhost again and sure enough it worked! The plot thickens.

Now that I had it working I thought I would try a different syntax:

<authorization>
<allow roles="MACHINENAMESiteBrowsers"/>
<deny users="*"/>
</authorization>

Nope:

Access Denied

Ok, the MACHINENAME prefix is not respected by ASP.NET in parsing the <authorization> section, which is a shame because that is perfectly valid in most other contexts in Windows when you are dealing with security principals.  It seems happy with well know identifiers such as BUILTIN but not the machine name.

So my final working syntax was:

<authorization>
<allow roles="SiteBrowsers"/>
<deny users="*"/>
</authorization>

But the question still stands - why does adding (or indeed removing) myself from the local group not take effect until I log off and on again?

Now this is where my knowledge gets slightly vague so feel free to correct me by commenting this post.  When a remote user is authenticated by IIS, IIS asks Windows for an impersonation token for that user which it then passes to ASP.NET. ASP.NET then uses that token to authorize the user by checking the token against the groups defined in web.config. The token contains the SIDs of all the groups the user is a member of. These are enumerated by the Local Security Authority (LSA) at the time the impersonation token is created.  That impersonation token is then thrown away when the request is over. Therefore, if the user is added to a local group between one request and the next, the second request will use an impersonation token that contains the SID of the group they have just been added to so the request will succeed.

If on the other hand I am browsing my local server, when the request comes in IIS asks Windows for a token for the user. However because I am logged on locally Windows gives IIS my primary logon token from the LSA cache. (This is why, if your web site accesses some off-server resource like a file share or database that is secured with Windows authentication, it will work when you browse the server from a browser session on the server but may not if you are browsing from a remote client.)

As the primary token is created when I logged on the the server it only contains the SIDs of groups I was a member of at that point in time. For the token to contain the SID of the local group I have just been added to I have to log off and back on again.

Anyway, I hope my experience in getting this working saves you some time!

Cheers

Doug