Understanding Authentication for ASP.NET


This post comes from a question I answered in the newsgroup microsoft.public.dotnet.framework.aspnet. The first question was this:

Using Forms authentication.  After a user successfully logs in, if
they try to access a page to which they have not been granted
security, I expected an error page to be displayed.  Instead, the
Login Form is redisplayed.  I thought the login page was only
displayed if the user has not been authenticated.  Can someone please
explain?
  

The reason is the login mechanism works with authorization, not authentication. After answering, I got this in return.

Thanks for the quick reply and for your insight.  Unfortunately, I’ve not yet
reached the same conclusion. 

For example, if a user has not been authenticated and the deny="?" is set,
the login screen will appear.  In other words, the login screen is issued
because the user isn’t authenticated.  (It has nothing to do with his/her
authority?) 

Secondly, if the user does not have authority, what possible good can result
from forcing them to login again?  (If they didn’t have authority before,
logging them in again isn’t going to change anything.)  To make matters
worse, the login screen now has a returnUrl to a screen to which the user
does not have authority.  So, even if the user enters a valid
userid/password, a vicious circle occurs because they will be directed to a
screen to which they don’t have access which will cause the Login screen to
appear…  Surely, throwing an error would be a more sensible solution than
the Login screen vicious circle?

Finally, other web postings indicate the "Access is denied because of the
Web server’s configuration. Contact the Web server’s administrator for help."
error is issued when a user does not have authority.  That’s the error I
want!
 

I have answered this in the newsgroup, but this post is designed to further explain why we see this behavior in web applications and how you can get the application to behave the way you desire. Let’s start with Windows Authentication.

Windows Authentication

When you start up windows, there is one time authentication, which is done via your user name and password when you first log in. After this, you have a token that is used to determine whether or not you have access to resources. If this is a local login, as in your personal machine, you will have rights to everything on the machine, as you will be an administrator account. This changes slightly in Vista and Windows 7, of course, as you have a downgraded access token for your normal activities and have to accept a prompt for administrator access when you hit certain applications or tools. It is more complex than this, but that is a topic for another day.

If, instead, you are on a domain, the process is still essentially the same. You are logged into the domain and a token is issued by the domain controller instead of the local machine. Locally, access is still granted or denied for each resource based on local permissions for the domain login.

Resources, themselves, have an access control list or ACL. An ACL is a set of permissions stored in the file system. For each user, there is a bit masked value that contains different permissions. The permissions  range from no access to full control and can be visually seen for each file (if you have permissions to view the ACLs) by right clicking the file in Windows Explorer and going to properties, as seen below:

ControlList

Internet Information Server (IIS)

We now move to IIS. IIS is a server that runs on Windows. This means it adheres to the same ruleset as all other windows servers. Access to files still goes through the windows process. But many users are “anonymous”, meaning they do not log into your web application to see the resources. As windows requires an access check, IIS assigns an “anonymous” user to the request (for IIS access) and the ASP.NET user token for windows access.

What this means, to the web developer, is the browser request is assigned to the account that ASP.NET runs under. The user can “anonymously” see any resource the ASP.NET account has access to and cannot see anything it does not have access to. If he tries to get to a resource that ASP.NET cannot view, he gets an “access denied” error. I will get back to this in a minute.

There are two methods of authentication in a web application: forms authentication and windows authentication. As Windows Authentication works just like a normal windows login, let’s look at it first.

Windows Authentication

When you use Windows Authentication for your web application, each user will need rights to resources to see them. In Windows Authentication, the user is logged into the web server with his domain account, so all requests are not “anonymous”, they are assigned to the actual domain account. This can lead to a problem that you end up with resources that are linked on a menu that the user does not have rights to. With Windows Authentication, the user will then get a windows login popup which allows him to access the resource using another account. You can, optionally, have windows automagically remove the link from the menu using security trimmings on the provider the menu uses (very easy with the SiteMap provider, btw).

Windows Authentication is normally used with Intranet applications, and allows the web developer to ignore authorization rights (at least for the most part). It respects the rights the network admin assigns to the user.

Now to answer part of the question.

Finally, other web postings indicate the "Access is denied because of the
Web server’s configuration. Contact the Web server’s administrator for help."
error is issued when a user does not have authority.  That’s the error I
want!

This error occurs when the windows account does not have access. If you want this error, you deny rights to the ASP.NET account. But hold on a second before you do this, because all “anonymous” access attempts will get this error, including people logged in to your web application. Why? Let’s look at forms authentication.

Forms Authentication

Forms authentication is the normal method for authentication in ASP.NET for Internet applications. The user, from a windows standpoint, is always the ASP.NET user. From an application standpoint, however, he is identified via his login. We will now hit this part of the question:

For example, if a user has not been authenticated and the deny="?" is set,
the login screen will appear.  In other words, the login screen is issued
because the user isn’t authenticated.  (It has nothing to do with his/her
authority?) 

Secondly, if the user does not have authority, what possible good can result
from forcing them to login again?  (If they didn’t have authority before,
logging them in again isn’t going to change anything.)  To make matters
worse, the login screen now has a returnUrl to a screen to which the user
does not have authority.  So, even if the user enters a valid
userid/password, a vicious circle occurs because they will be directed to a
screen to which they don’t have access which will cause the Login screen to
appear…  Surely, throwing an error would be a more sensible solution than
the Login screen vicious circle?

Assumptions we have

  • Web.config set up to deny=”?”

When a user first hits a site, he is the ASP.NET user from a Windows perspective and the anonymous user from an ASP.NET application standpoint. Here is a matrix of what can happen.

ASP.NET user has windows access, IIS allows anonymous access
User views page

ASP.NET user has windows access, IIS does not allow anonymous access
User given login page

ASP.NET user does not have windows access
User given access denied message (in some cases a windows login prompt pops up as well)

Suppose the user logs into the web application and then hits a resource he does not have IIS permissions to hit. It will redirect him to the login page, as the account the user is using does not have rights. If he re-enters the same credentials, he goes through a loop and ends up back on login. It can get rather nasty, but the reason for this is IIS is giving the option to log in with another account.

Why? Because this is how it works. Initially, the “anonymous” user was asked to log in and when he (Mr. anonymous) hit a resource he did not have rights to, he was asked to log in as another account. He then logged in as User1 and can see the resource. Now, he clicks to a resource that User1 has no rights to. The cycle repeats, just as it did for anonymous. He does not have rights, so he has to log in as someone that has rights.

What this means is login in ASP.NET is an authentication method tied to authorization. the decision of whether or not to authenticate is not made based on whether or not the person has authenticated, but whether or not the user has authority to view a resource. If the user is already logged in, but does not have access, he is asked to log in again.

The appearance of it being authentication and authorization based is created as the user initially appears to be fully anonymous and non-authenticated. But, underneath the hood, he is authenticated using the anonymous token. This token is assigned to the windows ASP.NET account for windows access. When he first hits a resource that the anonymous token has no rights to, he is asked to log in.

Hopefully, this explains why we get into the dance of log in, log in, log in when a user does not have rights.

Solving the Dance

To get out of the log in dance, the first step is to not show a user anything he does not have rights to. The easiest way to do this is to set up one of two systems:

  1. Set up rights in the sitemap
  2. Set up access rights in web.config

In each case, you will end up using the site map to create the menu, as you can security trim using the site map provider. What the ASP.NET engine will do is check access rights before displaying a link.

What about links in pages? For these, the simplest solution is to use the loginView control and set the rights on it. Anything in this view will not be shown to a user that does not have rights. But, there is a downside to this solution, because you end up having to maintain bunches of links when you add groups/users that can view a particular page.

Another option is to go dynamic and have the page display a “no access” to a user without rights. You can then control access on the data layer, where it is configured in one place, outside the user interface layer. This is better, IMO, as you can easily transfer the code to other application types without recoding the user interface.

Summary

In ASP.NET, the login control is tied to authorization. It will attempt to authenticated any user that does not have rights by kicking them to the login page. When a user initially hits an app, he is “authenticated” using the anonymous token; he is not “non-authenticated” from the server standpoint. His anonymous token is tied to the ASP.NET user for windows rights.

If you want to give an access denied error, you can set windows rights, but this will affect all users that are not windows authenticated. This is a non option for most Internet applications. The other option is to set up your own access denied error, which can be declaratively coded on the user interface using a LoginView or can be dynamically created on the back end with an “exception” sent to the user interface to inform the user he does not have access.

Peace and Grace,
Greg

Twitter: @gbworld

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: