Friday, 25 August 2006

Finding the Identity of the current user is one of those ASP.NET issues that causes confusion and consternation, especially given the different authentication schemes and application configurations available in ASP.NET.  In particular, HttpContext.Current.User, seems to be misunderstood.

Microsoft has provided a handy matrix outlining what can be expected under the different scenarios. Note that the last 3 tables are redundant -- they work exactly the same way no matter what form of Windows identification (Basic, Digest or Integrated) IIS is configured to use.  In any case, either this matrix is hard to find, or too confusing, so let's review the basics.

This post will cover ASP.NET 1.1.  Though the basics are the same in 2.0, there are some other things to discuss, which we'll tackle in a future post.

A freshly created web project in VS2003 (ASP.NET 1.1) has the following security settings in web.config...

<authentication mode="Windows" />
 
<authorization>
        <allow users="*" /> <!-- allow all users -->
</authorization>


The authorization element tells the app to let anyone in, making the authentication element pointless.

In this situation, the matrix tells us that we won't have any identity to look at since we'll have an anonymous user.  To test this, we build a web page that has a label that we will fill with the current user's name, using code like so....

CurrentUserIdentity.Text = HttpContext.Current.User.Identity.Name;

Run the app and sure enough,
HttpContext.Current.User.Identity.Name = ""

The user has no meaningful identity, so nothing is reported, we get the empty string.

Make a small change to the web.config file...

<authorization>
        <deny users="?" /> <!-- deny anonymous users -->
</authorization>

This tells the app to disallow ANONYMOUS users, it needs to authenitcate a user before it serves up the goodies.  Since our authentication mode is set for "windows", the user must have an account (domain or local) that can login to the server and has access to the web site.  Run the app again and now the app requests user credentials from the client's browser.  If the credentials are correct the page will be displayed, otherwise a prompt dialog box for the user id and password will be displayed.  Once correctly entered the page will be displayed, but this time it will show the user's domain and user name...

HttpContext.Current.User.Identity.Name = "somedomain\someuser"

Windows authentication is obviously useful for intranet sites where all the users are known to the server, but not so much for public sites. For public sites it makes sense to use Forms authentication. Under Forms Authentication the app will check a cookie (or a piece of the URL for a cookieless scheme) to see if the user has been authenticated.  This lets the developer implement a custom authentication scheme.  Putting the following in web.config tells the app to use Forms Authentication.

    <authentication mode="Forms">
        <forms name="FormsTicket"

          loginUrl="login.aspx"
          protection="All"
          timeout="20" path="/"
          requireSSL="false"
          slidingExpiration="true" />
    </authentication>

There are several ways user authentication can be implemented, the most common being looking up the user and a (hashed) password in a database.  But the key is setting the authentication cookie so the app knows that the user has been authenticated.  There are three methods in the FormsAuthentication class that will do this.  This one creates the cookie with the User's ID and redirects the user to the page they initially requested....

if(SomeMethodToAuthenticateUser(UserID, Password) == true)
{
FormsAuthentication.RedirectFromLoginPage(UserID, false);
}

This one sets the cookie and supplies the redirect URL, useful when redrection requires some more logic...

RedirectURL = FormsAuthentication.GetRedirectUrl(UserID, false);

This one just sets the cookie...

FormsAuthentication.SetAuthCookie(UserID, false);

All that matters is setting the cookie.  Without the cookie, the app thinks the user is anonymous and won't show itself.

So what shows up on our page?

HttpContext.Current.User.Identity.Name = UserID

Whatever the UserID set into the cookie was is what shows up as the User's name.  This is exactly what the matrix tells us it should be. Woo hoo.

So, there is one step to get the current user's identity no matter what authentication mode is being used.

1) Force authentication by denying access to anonymous users.

OK, three steps for Forms authentication:
2) Authenticate the user
3) Set the authentication cookie

So, if the user is not authenticated, the value of the HttpContext.Current.User.Identity.Name ="". For Authenticated users it just depends on the Authentication mode:
  • Windows =  domain\user (created and maintained by the app's server or its domain)
  • Forms = UserID (created and maintained by the app -- in DB, config file, etc. -- set in the Forms Authentication cookie)
  • Paspport = good question, does anybody outside of Redmond use this?
Now, another source of confusion is that each web app user has more than 1 identity, in fact, each user has 3 identities.  But even this isn't too horrid after a little investigation.

We've discussed the HttpContext Identity, which holds the user's identity as far as the application is concerned. There are also the
Windows Identity
and
Thread Identity

Odds are the Thread Identity is something that most developers will not have to concern themselves with. This is simply the identity tied to the currently executing .NET thread. The Windows Identity of the current user however, is something that every web developer has or will encounter at some point, because the Windows Identity is the actual Windows account that the current user is running under.  This is what gives the user the PERMISSIONS to access the file system and other resources on the server.  This is commonly referred to as the user's Security Context.

Let's go back to our previous examples and see what Windows accounts are being used in each situation:

HttpContext User Windows Account (XP, 2000) Windows Account (2003)
Anonymous MACHINE\ASPNET NT Authority\Network Service
Windows Authenticated MACHINE\ASPNET NT Authority\Network Service
Forms Authenticated MACHINE\ASPNET NT Authority\Network Service

Duh, that doesn't look complicated, all that matters is the OS, all the users use the same account! How can that cause confusion?

Well, like many mystery stories, we've left a character out until the end...

IMPERSONATE
 
ASP.NET applications have the ability to "impersonate" a windows account.  The above examples assumed the default of no impersonation.  Turn on impersonation, and it gets a little more complicated.

Impersonation is turned on like so...

<identity impersonate="true"><!-- default -->
OR

<identity impersonate="true" userName="SomeDomain\SomeUser" password="apassword"/><!-- specific account -->

Note that Impersonation can be set at any configuration level (machine, application, subdirectory).  If this is set in machine.config, it will affect all the web apps on a machine. Also note that putting a password and account in clear text isn't advised and there are ways to put encrypted versions in the registry. Finally note that allowing anonymous users to impersonate a real user account is a silly idea. In general, impersonation should only be used when necessary.


HttpContext User Windows Account (XP, 2000) Windows Account (2003)
Anonymous MACHINE\IUSR_MACHINE MACHINE\IUSR_MACHINE
Windows Authenticated SomeDomain\LoggedInUser SomeDomain\LoggedInUser
Forms Authenticated SomeDomain\SpecifiedUser SomeDomain\SpecifiedUser

 Let's put the info for our two identies of concern -- HttpContext and Windows -- into one table for easy reference.



Impersonation = False Impersonation = True
HttpContext User Name Win Acct (XP, 2000) Win Acct (2003) Name Win Acct
Anonymous   MACHINE\ASPNET Network Service   MACHINE\IUSR_MACHINE
Windows Authenticated Domain\LoggedInUser MACHINE\ASPNET Network Service Domain\LoggedInUser Domain\LoggedInUser
Forms Authenticated UserID
MACHINE\ASPNET Network Service UserID Domain\SpecifiedUser


As the table makes clear, the HttpContext Identity is only filled for authenticated users and the value it holds depends only on the authentication mode.  The name of the HttpContext user is controlled by Windows under Windows Authentication, the web application under Forms Authentication.  The HttpContext Identity is typically used by the application for personalization and application security.

The Windows Identity depends on the authentication mode and the impersonation settings. The Windows Identity the Windows Account the user is operating under, which  determines what files and resources the user can access on the SERVER. Without impersonation, a user will have access to the server resources via a very restricted account.  Impersonation can allow the user to have much broader access and should be used with care.

Hope this summary makes finding the current user's identities! easier. In the next post we'll look at what authentication wrinkles and new goodies there are in ASP.NET 2.0.  In the meantime, there's a new Yahoo Group to help decipher the more puzzling aspects of ASP.NET Security and Authentication.
Friday, 25 August 2006 13:42:57 (Eastern Standard Time, UTC-05:00)   #     Comments [0]  | 

Theme design by Dean Fiala

Pick a theme: