Do you find the Support WebCast transcripts helpful?
Let us know!
Microsoft Support WebCasts
Microsoft ASP.NET Security
November 20, 2001
Note This document is based on the original spoken Support WebCast transcript. It has been edited for clarity.
Venkat Chilakala: Hello, everyone. I am Venkat, and I welcome you all to the talk on ASP.NET security. For some of you, this may be your first look at the Microsoft® ASP.NET security model. For others, you may have heard a few things or played with a few features. For experts out there, some of this may just be a recap, but feel free to ask your questions at the end.
In today's talk, we'll briefly talk about why we need security for our applications (slide 2). We'll take a quick look at the classic ASP security model and compare it to the new security model in ASP.NET. We will also see how ASP.NET security works in conjunction with IIS security. Then, we will move on to authentication and look at different authentication providers that ASP.NET provides. After that, we'll turn on to authorization and see how that's implemented. Later, we will go on to role-based security and how you can implement role-based security in your ASP.NET applications for both Microsoft Windows® as well as non-Windows users. Finally, we'll talk about impersonation in ASP.NET and how to implement impersonation in your applications. At the end of the talk, we'll touch on some of the frequently asked questions. Then, we'll move on to some Q&A, if we have any time left.
So why do we need security for our applications? Security is one of the major concerns for both application architects and developers. Applications that store sensitive information need to be protected from malicious attacks, and from competitors attempting to steal information or intellectual property. When designing a security model for your application, you need to be aware of security requirements from a business perspective and the implications that a chosen security model can have on performance, scalability, and deployment. So basically knowing how the security works would help in making decisions to choose a security model for your applications.
Now, let's take a look at the old ASP security flow for a request (slide 3). Okay, a request for an ASP page, the request comes to IIS, and the IIS authenticates the user requesting this resource. Once authenticated, it then impersonates the authenticating user on the ASP worker thread that's going to serve this request. That means in ASP, both the authenticated user and the impersonated user are the same. Just to clarify what we mean by authenticating user, it's the actual user who is requesting the page. In case you have anonymous access enabled on IIS, that user will be IUSR_machine name by default. The impersonating user is the identity of the thread that is serving the request.
Now, let's take a look at the security flow for an ASP.NET page request (slide 4). When you make a request for an ASP.NET resource residing on the Internet Information Server, that request comes to IIS, and IIS authenticates the user requesting the resource and then passes on the request and the security token for the authenticating user to the ASP.NET worker process. Based on configuration settings for this application, ASP.NET worker process decides whether to impersonate the authenticated user supplied by IIS or not. If impersonation is turned on in the configuration settings in the web.config file, then the ASP.NET worker process impersonates the authenticated user provided by IIS. Otherwise, the thread will run under the ASP.NET worker process identity. After that is done, ASP.NET checks whether the authenticated user is authorized to access these resources. If they are allowed to, ASP.NET serves the request, or else it sends an "access denied" error message back to the user.
As we have seen in the last two slides, the request flow diagrams, the main difference between classic ASP and ASP.NET is that in ASP, IIS impersonates the authenticated user by default, and in ASP.NET, the developer has more control over configuring security at different levels.
Now, let's move on to authentication in detail (slide 5). Authentication is basically the process of obtaining identification credentials such as user name and password from a user, and validating those credentials against some authority. If the credentials are valid, the entity that submitted the credentials is considered to be an authenticated identity. In classic ASP, the authentication is done by IIS. Based on the result, it either forwards the request to ASP or returns an "HTTP 401 access denied" error message to the client. In ASP.NET, Authentication is done at two levels. IIS performs any required authentication first, then hands off the request to ASP.NET. Based on the ASP.NET configuration and security settings, ASP.NET may also be involved in authenticating the user. The user credentials that ASP.NET authenticates may be Windows or non-Windows user credentials. In the case of Forms Authentication and Passport Authentication, they are assumed to be non-Windows user accounts, and so ASP.NET authenticates those users. In the case of Windows Authentication, the user accounts are basically Windows accounts, and so there is really no need for ASP.NET to re-authenticate those users, because IIS has already authenticated them. After a user has been authenticated, ASP.NET checks to see if impersonation is enabled in the configuration pile. If impersonation is enabled, the thread serving the request takes the identity of the client. If impersonation is disabled, ASP.NET will serve this request with a process identity.
The authentication configuration section handler is basically responsible for handling the authentication support for ASP.NET. It can be declared at machine, site, or application level, but not the subdirectory level.
There are four different kinds of authentication providers that ASP.NET supports by default. They are basically Forms Authentication, Windows Authentication, Passport Authentication, Default Authentication, and Custom Authentication. Let's take a look at each of these Authentication methods and see how to implement each of them for your ASP.NET applications.
First, let's talk about Forms Authentication (slide 6). Forms Authentication refers to a system in which unauthenticated requests are redirected to an HTML form where users enter their credentials. After the user provides credentials and submits the form, the application authenticates the request, and the system issues an authentication ticket in the form of a cookie. This cookie contains a key for reacquiring the identity. Subsequent requests from the browser automatically include this cookie.
Because the Authentication cookie is the main key to the Forms Authentication process, you have to make sure this cookie is transmitted from the server to the client and the client to the server securely. It is suggested that you use SSL at least on the logon page to protect the user name and password from being transmitted in clear text. One thing to keep in mind is that Forms Authentication is often used for personalization where content is customized for a known user. In these cases, identification is the main issue rather than authentication. Some of those examples are MSN.com and Yahoo.com, etc.
Let's take a look at the Forms Authentication execution flow for a request (slide 7). A client generates a request for a protected resource first. Then, IIS receives the request, and if the requestor is authenticated by IIS or if IIS anonymous access is enabled, it gets asked to the ASP.NET application. ASP.NET checks to see if a valid authentication cookie is attached to the request. If it is attached, this means that the identity's credentials have been confirmed previously and the request is tested for authentication already. The authorization test is performed by ASP.NET. If the user is authorized to access these resources, access is granted to these protected resources, otherwise, the application sends an "access denied" message to the user. If there is no cookie attached to the request, ASP.NET redirects the request to a logon page, where the users can enter their credentials and resubmit for authentication. The application code checks the credentials that are submitted by the user to confirm their authenticity and if authenticated, attaches an authentication ticket (in the form of a cookie) to the response. If authentication fails, the user can be redirected back to the logon page saying that the authentication has failed.
Let's take a look at the configuring a Web application to implement Forms Authentication (slide 8). In general basically, setting up forms-based authentication involves four important steps. The first step is to enable anonymous access in IIS. This is because most of the forms users, in general, are assumed to be non-Windows users, so they have to get through IIS to get to ASP.NET. That's why you enable anonymous access in IIS. The second step is to configure the web.config file to use Forms Authentication, and we will see that later. The third step is configuring settings in the authorization section of the web.config file to deny access to the anonymous user of ASP.NET. Remember one thing, that ASP.NET will always allow anonymous access to the logon page though. The final step is basically creating a logon page. The logon page is where users without a valid authentication cookie will be redirected, so that they can supply their credentials and log on to the application. The logon page usually must validate the submitted credentials against a database of some custom method. If the credentials are valid, then it generates an authentication cookie and adds it to the response and redirects the user to where they came from.
Let's now talk about some of the important attributes of the forms tag that are used to configure the Forms Authentication process (slide 9). The forms tag supports several attributes that provide for advanced configuration of the Forms Authentication process. The important ones are the name attribute, which is basically the name of the HTTP cookie used for the authentication ticket. The next one is loginUrl. The requests are redirected to this particular URL, if the user is not authenticated; this is where they can supply their credentials to log on. We strongly suggest that this be an SSL URL to prevent credentials from being posted in clear text.
The next one is path. Path refers to the path of the cookie to be sent to the client. The fourth one is protection. The protection value specifies the method used to protect the cookie. The valid values for the protection attribute are All, None, Encryption, and Validation. If you specify All, it uses both validation and encryption to protect the cookie. If you specify None, it doesn't use either encryption or validation. This is the most performant way, and you can use this in scenarios where you have weaker requirements for security and need the most performance.
The third one is Encryption. Specifying this would encrypt the cookie using triple DES or DES encryption algorithms or the data validation is not done on the cookie. The last one is Validation. This specifies not to encrypt the contents of the cookie, but validate that the cookie data has not been altered in transit.
The last attribute of the forms tag is timeout. This is an important one. The timeout value is the amount of time, in minutes, after which the authentication cookie expires. Because the forms authentication cookie is passed as clear text over the wire, it's possible for someone to steal this cookie. One way of reducing the chances of someone stealing the forms authentication cookie is by configuring the timeout value of this cookie. By reducing this timeout, the cookie will be regenerated more often, thereby reducing the chances for someone to steal the cookie.
Here is a piece of code that you can use to validate the forms users (slide 10). This basically creates and sets the authentication cookie, and then redirects the user to the page where it came from. The authenticate method over here is used to validate the user credentials against the credentials section of the web.config file, if you're storing your user database in the credentials section of the web.config file. Based on where you store your user data, you could use your own mechanism to validate these users. After the user is validated, you can call the RedirectFromLoginPage, which basically does two things: create the authentication cookie and add it to the response, and then redirect the user to where they came from. The only client requirement to be able to access any application implementing Forms Authentication is to have cookies enabled on the client browser. If the client disables cookies, the cookie generated by Forms Authentication is lost, and it will not be able to authenticate. That completes the Forms Authentication provider.
The next one we'll see is Windows Authentication (slide 11). This can be used in combination with basic authentication, Digest, NTLM, or Kerberos Authentication on IIS. When Windows Authentication is specified in ASP.NET configuration file, ASP.NET uses the authenticated identity passed in from IIS. This is the easiest of all to implement. In this case, you do not have to write any code for validating the user, because Internet Information Server has already validated their Windows credentials. Usual scenarios where you would want to use Windows Authentication are when your end users are part of your Windows domain, and when you wish to impersonate the user account that IIS authenticates to execute the code in the same security context of the user's Windows account.
Let's walk through the flow of an ASP.NET request when Windows Authentication is used (slide 12). A request for a resource comes to IIS from the network client. IIS authenticates the client using Basic, Digest, or Windows NTLM authentication. The client is authenticated. IIS hands off the authenticated request to ASP.NET along with the security token for the authenticated user. If impersonation is turned on, then the ASP.NET application impersonates the requesting client using the access token passed from IIS and looks at the authorization section details in the configuration file to see if that user is allowed to access this page. Finally, it relies on NTFS file permissions for granting access. One thing to notice is that, if impersonation is not enabled, the application runs with the ASP.NET process identity. The ASP.NET process identity can be configured in the <processModel> section of the machine.config file. The default of this being local system account. If the access is granted to this resource, the ASP.NET application returns the requested page through IIS. Otherwise, it sends an "HTTP 401" error message back to the client. To implement Windows Authentication, you just have to set the authentication mode to Windows and deny access to the anonymous user in the configuration file or disable anonymous access for that virtual directory. If you wish to run your code under the same security context as that of the user account, then you will need to turn on the impersonation in the configuration file. We will see how to turn on this impersonation and different ways to impersonate a client later.
Let's now move on to Passport Authentication (slide 13). Passport Authentication is a centralized authentication service provider by Microsoft that offers a single sign-in and the code profiles a recess for member sites. Passport is architecturally similar to Kerberos security in the sense that clients are issued a ticket from the Passport service that will be presented to the Web server they are trying to access. Some of the scenarios in which you can use Passport Authentication are when you do not to maintain the user name and password database or a login page, and you need to provide personalized content, then your site or service will be used in conjunction with other Passport sites, and you want to give single sign-in capability to users.
Let's briefly take a look at what all we need to do to implement Passport Authentication (slide 14). To implement Passport, you need to install the Passport SDK on the server, and register with Microsoft Passport. In the web.config file for that application, the authentication mode needs to be set to Passport, as shown in the slide. Then, you will need to add the <passport> section. The Passport section supports a single attribute redirect URL. This attribute defaults to a value of internal, which causes unauthenticated requests to receive a generic error message. If this attribute contains a string other than internal, it's assumed to be a URL that unauthenticated requests will be redirected to.
The next one we'll talk about is Default and Custom Authentication (slide 15). First, we'll see Default Authentication and then move on to Custom Authentication.
This authentication is provided for two primary reasons. When you do not need any authentication for your site, you can use this method, and it gives maximum performance of all types of authentications. The second reason is when you want to implement Custom Authentication for your Web site; you set the authentication mode to "None" in your web.config file, and hook up your Custom Authentication module through a configuration file. Setting the authentication mode to none enables this Default Authentication. This setting causes ASP.NET to create a generic identity and assign that identity to the HTTP Context.User.Identity object. That's how that works.
The next one is Custom Authentication (slide 16). You can implement Custom Authentication in two ways. You can handle the authenticate request even in the global.asax, or you can implement IHttpModule to have your own authentication logic for every request. Some of the scenarios where you would use Custom Authentication are customize Forms Authentication to suit your requirements, or you could build an authentication scheme where your scheme uses munged URLs similar to cookie-less sessions.
After the authentication is done, the request basically goes through the Authorization process (slide 17). Authorization is basically the process of determining whether a user is allowed to perform a requested action. Authorization occurs after authentication, and it uses the information about the principal's identity to determine what resources the principal can access. The authorization configuration section handler is responsible for configuring the authorization support for ASP.NET. It can be declared at the mission level, site level, application level, and also subdirectory level. There are two fundamental methods that ASP.NET uses to authorize access to these resources. One is File Authorization. The second one is URL Authorization. You can also implement Custom Authorization.
First, let's take a look at File Authorization and then Custom Authorization. We'll save URL Authorization for the last.
Authorization is basically implemented in ASP.NET as HTTP modules. File Authorization is performed by the FileAuthorizationModule and is active when you use Windows Authentication. It's responsible for performing checks on Windows ACLs (that is access control lists), to determine whether a user should have access or not.
Next is Custom Authentication. You can do this in two ways. You can handle the AuthorizeRequest event handler in the global.asax, or implement an IHttpModule to have your own authorization logic for every request.
The last and important one is URL Authorization. URL Authorization controls authorization based on the URI name space, which can be quite different from the physical folder and the file paths used by NTFS permissions. The UrlAuthorizationModule implements both positive as well as negative authorization assertions. The module can be used to selectively allow or deny access to arbitrary parts of the "URI" namespace for different users, user roles, words like get, post, etc. The UrlAuthorizationModule is available for the user at any time. You only need to place a list of users and the roles in the "allow or deny" elements of the authorization section of the configuration file.
Let's take a look at what this looks like (slide 18). At run time, the Authorization module iterates through the "allow or deny" tags looking for the first access rule that fits a particular user. It decides to grant or reject access to the URL resource depending upon whether the first access rule satisfied is either an allow rule or a deny rule. By default, it rejects an access if no rule is found. The second shown in the example says to allow Admins and Web users and deny all others for all the pages of that application. You can use the <location> section of the configuration file to control permissions on different files and subdirectories individually in this virtual directory.
Now, let's take a look at the role-based security (slide 19). Role-based security in .NET is similar to that used by COM+ and MTS, but there are certain important differences. In .NET, role-based security supports authorization by making information about the principal available to the current thread. This principal can be constructed from an associated identity. The identity and the principal help to determine whether this user has access to a specific resource or not, based on the roles of a user or the user account. .NET applications can make authorization decisions based on the principal's identity or role membership or both. A role is a named set of principals that has the same privileges with respect to security. A principal can be a member of one or more roles. So applications can use role membership to determine whether a principal is authorized to perform a requested action or not. For example, if you're using Windows Authentication and impersonation is enabled, assuming anonymous access is disabled, the identity of the user will be a Windows identity. Identities can be checked for membership in specific roles and the access restricted accordingly. If the user identities are Windows identities, then the user roles map to the Windows groups. The code on slide 20 basically demonstrates how you can check users against their roles and the control program flow accordingly.
If you're using Forms Authentication and the identities are not necessarily Windows accounts, you can handle the AuthenticateRequest event in the global.asax and create a GenericPrincipal that attaches custom roles to the user identity and assigns that generic principal to the user object (slide 21). In your ASPX pages, basically you would check if the user belongs to your particular group, as shown in the code, and then control the program logic and permissions to the resources accordingly (slide 22).
Now, let's see the impersonation in detail (slide 23). Impersonation is the ability of the thread to execute in a security context that's different from the context of the process that owns the thread. One can use logon user, impersonate logged on user APIs to change the security context of the thread to another Windows account. Unlike classic ASP, the ASP.NET worker process, by default, does not perform any impersonation on a public list basis. It's important to remember that regardless of how ASP.NET is configured, Internet Information Server will always behave as it always has, including authenticating on the generating security tokens. Those security tokens can be based on a credential such as the authenticated user or, in the case of anonymous requests, the IIS anonymous accounts are user machine names. Impersonation in ASP.NET is configured using the identity tag in the ASP.NET configuration file.
Here are three different ways to control impersonation-related settings in the web.config file (slide 24). By setting the impersonate attribute in the <identity> section to false, you can turn off the impersonation in ASP.NET. When impersonation is disabled, the security context of a thread executing the request is going to be the same as that of the process identity that is, in ASP.NET, it's going to be system by default. By setting the impersonate attribute to true, you can enable impersonation. When impersonation is enabled, ASP.NET takes the security token passed by IIS and uses it to impersonate the thread that will serve this request. Because impersonation is performed using the security token provided by IIS, the method used by IIS to authenticate the user will determine whether the impersonation will allow delegation or not. This is extremely important because if the user is authenticated at the IIS using Windows challenged response mechanisms, then the security token is not delegatable, but if the authentication was performed using basic authentication, then the security token is delegatable. The third way of enabling impersonation is by specifying a valid Windows account and password in the <identity> section. If you do this, ASP.NET will impersonate those credentials for every thread that serves the pages of this application. This method does create a delegatable security token and forces all the requests to execute using a common security context.
You can also always perform impersonation within your code (slide 25). You can always program to run a specific piece of code in the security context of a specific user. You can do this by calling the Win32® LogonUser API, ImpersonateLoggedOnUser API, or you can also call LogonUser, DuplicateTokenEx methods and use the token returned by the DuplicateTokenEx to create a Windows identity and call the impersonate method on that Windows identity. That will do impersonation for you, and that creates a delegatable token too.
There's one special case that I wanted to point out, which is if your application is on a UNC share, ASP.NET will always impersonate the token provided by IIS to access that share unless a configured account is used. If an explicit configured account is provided in the <identity> section of the config file, ASP.NET will use that account in preference to the IIS UNC token.
Now, let's take a look at some of the common issues that we have been seeing (slide 26). When you query for the authenticating user by calling several variables, Logon_User or Auth_User, or by calling the User.Identity.Name function, you get an empty string. This occurs because the authenticated user here is an anonymous user. When the authenticated user is an anonymous user, this happens. To solve this problem, you can deny access to anonymous users in the web.config file. You can use the code snippet shown in the slide, which basically denies access to anonymous users and allows access to everyone else.
The next common scenario that we usually see is access denied to "NT Authority\System" or access denied to "NT Authority\Anonymous Logon" when you try to access resources on a remote machine, something like remote SQL Server™ with integrated Windows security or accessing a remote file system or similar situations (slide 27). This may be due to the fact that your application may be running into a delegation scenario. The solution here is to see to it that you have a primary security token when you request these resources. There are many ways to solve this issue based on your particular requirements and architecture of your application. One of them is to use basic authentication for your application, which creates a delegatable primary token. You can also impersonate a specific user who has access to these resources just before requesting these resources using LogonUser and ImpersonateLoggedOnUser by asking for a primary token.
Another common scenario that you see is when using Forms Authentication for a Web application, how do I allow anonymous access to certain pages like, let's say, default.aspx page but not to other pages in the same directory (slide 28). The answer to this is using the <location> section of the web.config file to allow anonymous access to default.aspx page only and then deny access to anonymous user on the rest of the pages. The piece of code is shown on slide 28.
That completes today's WebCast. I'll turn it over to Jason for the Q&A session. Thank you for attending the WebCast.
Jason Bennett: Thank you so much for that presentation, Venkat. I have just a couple of quick notes before we move on to the Q&A portion of this Support WebCast. If you'd like to have a copy of the PowerPoint® slides, you can download the file from the Past Support WebCast page. To access information on all upcoming Support WebCasts and the archived content from all past WebCasts, an easy to remember URL is http://support.microsoft.com/webcasts/.
The Q&A portion of the Support WebCast again is intended to encourage further discussion of the Support WebCast topic. One-on-one product support issues are outside the scope of what we're able to address here today. So if you need technical assistance, please submit an incident on the Web, or call Microsoft Product Support Services and speak to a Support Professional.
With all those details out of the way, we have gotten a few questions in already. The first question: What services on an IIS ASP box should be disabled, not installed, uninstalled, etc?
Venkat: The question is not clear, Jason. Could you give me details about what they are doing exactly and what they need so that they can disable this?
Jason: Okay, if that user wants to follow up with a little bit more information we'll try to answer it then.
The second question: I'm using forms-based security, and I need some pages that are restricted and some that are not. What is the best way to implement that?
Venkat: That has been answered in the last Frequently Asked Question (slide 28), but I will repeat it again. The answer to that is, using the location section in your web.config file to allow access to everyone for certain pages and restrict access to anonymous user for the rest of the pages that need security. The sample piece of code is shown in that slide, the slide for the third Frequently Asked Question that we had.
Jason: Slide number 28.
Venkat: Right. If you have any further questions, maybe you can follow it up later.
Jason: Why has ASP.NET maintained security configuration settings in XML configuration files?
Venkat: Why hasn't or why has?
Jason: Why has?
Venkat: One of the main reasons is that, in the ASP world, we have seen that the deployment was one of the major issues when you develop an application on development machines, and security settings are done on IIS. When you deploy it, it becomes very difficult to synchronize those IIS settings on the destination production server. By moving the security settings to the web.config file in the form of XML data, deployment becomes pretty easy. You don't have to really do anything on the destination machine except to just copy these files over to the destination machine, which is your production server, and everything should work fine. That's one of the major things.
The second thing is that the developers have been given more control over how you can configure security in ASP.NET. You can configure all these settings using your XML web.config file.
Jason: In what file is the <forms> section?
Venkat: The <forms> section goes in the web.config file within the <authentication> section. The <forms> section is a subsection of the <authentication> section basically. If Authentication mode is set to forms, then the <forms> section comes into play. I hope that's clear.
Jason: Our group is using a tool called Netegrity SiteMinder to handle the authentication piece. What should our ASP.NET app set in the web.config settings, Forms, Windows, or none? I'm assuming Windows is correct. We have impersonation turned on, because our ASP.NET needs to impersonate the logged on user. However, the ASP.NET app also needs to access a remote server via a UNC path on behalf of this user. From what I've read, this will require some form of delegation process; I think that's the term. Can you point to details about implementing a delegated process using multiple or remote machines?
Venkat: This is one of the Frequently Asked Questions for us, and we have addressed this in one our FAQs that's I think is the second of the Frequently Asked Questions or so. It depends on exactly what you are doing and what is the resource that you're trying to access from a remote machine. You could have many answers for this scenario.
A couple of things that always work are to enable basic authentication on IIS, which will give you a delegatable token so you can make one hop. Basically, you can go to one machine across the network. You can't make a second hop anyway. If you want to make a second hop, you have to use Kerberos security on your Windows 2000 domains. A couple of other ways are if you specify a valid Windows account in the <identity> section to impersonate, then that also creates a delegatable token. Remember that this user name and password are going to be in clear text in the web.config file, which may not be the right thing to do.
Another thing is, if you set your ASP.NET worker process to run under a valid Windows account that has access to these remote resources, then that also creates a delegatable token. Finally, one thing which might work well with your application is to use the LogonUser and the ImpersonateLoggedOnUser APIs to impersonate a specific user using that piece of code which accesses these remote resources from other machines. I hope that answers your question. Otherwise, you can follow up with me later, and I'll be able to provide some pieces of code and other solutions.
Follow-up answer: Based on what you have explained here, it looks to me that your end users are valid Windows users in your domain. If so, you can use "Windows" authentication in ASP.NET web.config file.
Since you need to impersonate the authenticating user, you need to do two things:
- Deny access to the anonymous user in the web.config file's authorization section.
- Set the Impersonate attribute to "true" in the <identity> section of the web.config file.
Coming to the point of accessing the resources on a remote computer (via an UNC path), you will get into delegation scenario. The trick here is to see to it that the identity of the thread requesting this source has a primary token so that it can access resources on a remote machine. In simple terms, a primary security token can be obtained only if the process has the username and password available for that user account that is impersonated on the thread that is making this request. Depending on what is acceptable for you, you can do this in many ways. One of the ways may be to call the LogonUser and DuplicateToken APIs, get a primary token, and then impersonate that user account before you access these network resources. When you are done with those resources, you can revert back to the original security context. KB article Q306158, "BETA-INFO: Implementing Impersonation in an ASP.NET Application" can help you do this.
An article titled "Authentication and Security for Internet Developers" is available on the Web at http://msdn.microsoft.com/library/en-us/dnauth/html/dnauth_security.asp?frame=true.
Jason: So you mentioned a little bit about Passport. Is Passport not something that you'd really use if you were focused on only internal development for a corporate intranet?
Venkat: No. Basically, its targeted users are totally different. It's not for internal intranet Web sites. Maybe Forms Authentication might go very well with your intranet Web sites. Passport is not the right thing to go with intranet Web sites, because all your users have to be Passport users, and probably most of those users, or maybe a lot of those users, are not Passport users already. You may find some information about that at http://www.passport.com/.
Jason: Can roles be accessed via LDAP or other, or are they limited to IIS? Would GenericPrincipal handle that?
Venkat: This question is not very clear, but I'll try to answer based on my understanding of the question, but you can follow up later. If the users are Windows users, the roles are mapped to the Windows groups. By default, they get added to the principal that gets created within ASP.NET. So you don't have to do anything special to add these roles, but if you are adding custom roles to existing Windows users, you will have to do something like creating GenericPrincipals and attaching those specific roles to the existing user. That's how you do it in Forms Authentication too, because in Forms Authentication, the users are not really Windows users. So you create a generic identity that attaches a particular user to roles that user belongs to. I hope that answers your question.
Jason: Can you use Forms Authentication and write code to authenticate against say a SQL database table or Active Directory®? Would you suggest this, or setting the options in web.config instead?
Venkat: No, you are right. Basically, using web.config to store your user database is not a realistic scenario. Probably it would work for a few static users or so, but that's not a realistic scenario. It's provided for developing some simple applications or just to test some simple scenarios and things like that, but a realistic application would go on something storing all your users in a SQL database and validating against a SQL database. There is a KB (Knowledge Base) article, on that, and I'm not exactly sure of the number. It is Q308157. You can search also on our Support Search site using keywords like "kbsecurity" and "kbaspnetbeta2" to find these kinds of articles. I hope that helps, and the best way to do it is using a SQL database to store these users or maybe if these users are Windows users, you can even validate these users against your Active Directory, LDAP, or whatever.
Jason: Can you define again what a primary security token is?
Venkat: There are different security tokens that you can get. A primary token is given only when a user name and password are available to the LogonUser API call. LogonUser API takes a few parameters. One of the parameters is the type of the token that you request. The primary token is the token that you get if you supply only your user name and password. If you don't have your user name and password available, then that means probably you will not get a primary token. Even if you get it, it's not going to be a delegatable token. I hope that is clear. Otherwise, you can take a look at LogonUser API in the LogonUser Win32 API in MSDN Help, and that is explained pretty clearly there.
Jason: In a simple summary, if you simply want to make sure that no visitor is ever running in the system account, do you just set an impersonation user and allow anonymous, or how would you suggest that this be done? If you allow anonymous, is the account for this still set in IIS, or does it go to the ASP.NET config file?
Venkat: Okay, when you understand how the security flow is, you can do this in many ways. Basically, if you don't want to run any piece of code under system identity, the best way to do it is go to your mission.config file and change the process model. There is a process model section in which you can specify what user account to use to run your ASP.NET worker process. If you change it to some restricted account other than system (by default this is system), and that account doesn't have extra privileges and a lot of resources on your machine, that will probably solve your problem. Otherwise, if you want to have it as system only, then you have to do a couple of things. One is, you can impersonate in the web.config file, and that would make sure that the code will be run under the impersonated user, which is the user who is requesting the page. For this, you can either enable anonymous access or disable anonymous access. It basically depends on what your security configuration is. If you're using Windows Authentication, you can probably disable anonymous access, because it really doesn't make sense to enable anonymous access when you're using Windows Authentication in ASP.NET, but if you're using Forms Authentication, you probably have to enable anonymous access, otherwise forms users cannot get to IIS, since they're not really Windows users.
Jason: I'm building a .NET Web site for a client. The site accepts credit card processing for subscriptions to services the site provides. Is there an automated way to set up certain pages to always ask for a user's ID and password irregardless of whether the user is already authenticated? If so, how do I do it? Is there a place you can point me to, to look at this?
Venkat: Yes. You might have to do this programmatically. There is no specific resource that I can point you to, but if you can contact us offline, I'll probably be able to provide some code snippets for this particular solution. But based on the architecture, the only solution could be to use some code snippet to redirect this user to some logon page or something like that.
Follow-up answer: If you are not using Session to store any information, you may be able to implement this in the code based on the logic that you need. But there is no existing solution for this. It is going to be your own custom solution based on the requirement of your application.
The following is an example of code:
If Session("page1")="First_time_coming_to_this_page" OR Session("page1")="" then
Session("page1")="Sent_back_a_401"
Response.StatusCode=401
Response.End
Else if Session("page1")="Sent_back_a_401" then
process the page and send the response back since he was sent a 401 when he initially came to this page.
Looks like he re-entered his credentials and authenticated specifically for this page.
At the end of the page set the above session variable to
Session("Page1")="First_time_coming_to_this_page"
End if
Jason: This answer will be included here. To reach the Past Support WebCast page, go to http://support.microsoft.com/webcasts/. When you get to that page, there's a link at the bottom to Past Support WebCast page. Just click on that link and it will take you to another page, and the page is arranged by product. Expand the Internet Technologies tree and click the Microsoft ASP.NET Security: Tuesday, November 20, 2001. Through that subsequent link, there'll be a link to download the PowerPoint files. There'll be a link for the transcript. There'll be a link for the streaming media. That will contain everything from today's WebCast.
Does ASP.NET automatically block access to the XML configuration files located in the Web directories?
Venkat: Yes, it does, and that is a security thing that's already put into ASP.NET. If you look at the application mappings for these .config files, it will tell you that it's mapped to a handler that doesn't allow these pages to be served. If you request a web.config file which resides on an IIS Server, it would just deny you the page. It will never serve that page.
Jason: I did want to take just a moment to solicit some feedback from our audience. If you've come in for the first time today, you've not been to one of our WebCasts before, or you've been to one, and you want to make a comment on how this one compares to an older one, or you just want to comment on the program in general, we are very interested in your feedback regarding this. You can send us an e-mail through feedback@microsoft.com, and make sure you put "Support WebCasts" in the subject line.
I'm not certain if it's referring back to another question, but it's definitely referring to delegation. Delegation was covered in the presentation, and that was much appreciated. I'll need a little bit more detail in order to implement this, particularly for accessing another server or UNC path. Finding articles on delegation is difficult. Additionally, IIS warns against using Basic Authentication, because that's a concern. Are there any comments you can give to this or any pointers you can send them to in terms of delegation?
Venkat: Yes. If that e-mail address is there, I will send a couple of resources. Probably in a few days from now, we will be writing a Knowledge Base article on delegation and related to ASP.NET, and that will be much more useful for you. Regarding your comment, actually using basic authentication is not a problem. The thing is that if you're using basic authentication, the user name and password that you're supplying to allow them to authenticate, are passed in clear text. That's why we suggest you use SSL on top of the pages that are secured by basic authentication. If you do that, there is no problem at all. You can always use that.
Regarding using Basic Authentication, I don't see any problem, as long as you use a secured protocol (https) when you enable Basic Authentication. If you use Basic Authentication, the user credentials are passed in Clear Text (base 64 encoded) over the wire and it is very easy to decrypt these details if someone decides to sniff this traffic. If you enable SSL on that application, you should be fine, even if you use Basic Authentication.
Jason: Okay, great. How can I create a forms-based authentication app that then impersonates Active Directory users?
Venkat: The only trick here is basically, you do the same as you do for any forms-based authentication, except that the validating the authenticating user is the only thing that's different here. In the code snippet that contains this validating the authenticating user, would go against the Active Directory and then get the user name and password, or just query for this particular user's credentials, and then check whether the supplied credentials match those credentials. Based on that, you can either allow or deny access to that page. It is similar to the way you can do it with the user database which is stored in a SQL Server or so that's very clearly mentioned in a Q article number Q308157. The only difference is that this article uses a SQL database to store users and validate users, whereas you would be using an Active Directory. The hint is basically here that you will use a LogonUser API to validate this particular user's credentials, a passing user name and password to this LogonUser API. If the call succeeds, the user is valid. If the call fails, the user is not a valid user. The only thing you have to remember is that this call is quite expensive. So use it scarcely; use it only when required.
Jason: Okay, we are down to our last few questions. Sometimes the value for user.identify.name is blank, and sometimes it contains the user name domain\fred. How would I go about debugging that problem?
Venkat: That's the first Frequently Asked Question that we had addressed in the slides, slide 26 actually. The problem with this is that it is the authenticated user that you are querying user.identity.name. It is blank when the authenticated user is an anonymous user. If you disable anonymous user to access these Web pages, then that user will come up as the user that you want it to be, probably domain\user name or something like that, or maybe if you're using forms or Passport authentication, it would be the forms user or the Passport user accordingly.
You can do this in two ways. Based on the authentication that you're using, if you're using Windows authentication in ASP.NET, you can disable anonymous access either on IIS, or you can disable access to the anonymous user in the web.config file. If you're using any other mechanism that's a forms-based authentication or Passport-based authentication, the best way to do it is in the web.config file, because you have to enable anonymous access in IIS to be able to get through these requests to ASP.NET, because forms users or Passport users are not really Windows users. They go through IIS as anonymous users only, but when they get to ASP.NET, it takes a look at the configuration section and sees whether the anonymous user of ASP.NET is allowed or not. Then accordingly, it behaves based on identity. The basic thing is that you have to then disable this anonymous user in the web.config file, and that works mostly for all types of authentications.
Venkat: There are two ways you can do this. One is for every request, you go to the database, query the database, get the roles for that user, and attach these roles to the identity as shown in the code snippet. I know this is quite expensive, because you have to go to the database for every request. The second thing is that you can query for these roles once, maybe when you authenticate this user, and then when you build the authentication cookie using forms authentication help for functions, there is a parameter called user data that's taken by the FormsAuthenticationTicket function. You can input the roles collection in the user data field and add it to the authentication cookie. From the subsequent requests, you can decrypt this cookie, and then read these user roles from the user data field, and then construct the user identity.
Follow-up answer: In ASP.NET, the flow of request is in such a way that Authentication takes place first and then based on the information from the user Identity that resulted from the authentication process of ASP.NET, Authorization is done by ASP.NET. The basic thing here is that before the execution flow reaches Authorization, you need to attach the Roles for a user to that user identity because these roles are used by the Authorization module to determine if this user has access to that resource that is being requested.
Because HTTP is a stateless protocol, this needs to happen for every request. You can retrieve the user roles from database (or wherever you stored) for the first request from a user (for example, when the user logs on to the application). After you retrieve these roles, you can store them in a session variable or as a part of the cookie to the user or as a part of the Authentication Ticket/cookie that you issue to the user or you could store them in the cache, using key-value pairs. You may use a unique id as the key and the value is a string of roles. But for each request you need to get these roles from wherever you store and attach them to the User Identity in the AuthenticateRequest Event handler.
Venkat: For one application, you can have only one type of authentication method. You cannot have two types of authentication methods for a single application. If you want to do what was just asked, then you have to split it into two different applications, or basically have a copy of the same application, and use one for Windows and the other for forms-based or Passport.
Jason: Okay, and this is the last question in the queue at this point. Does using one web.config file in the root Web have control over all the sub-Webs, i.e., do I need web.config files on all the sub-Webs?
Venkat: You really don't need to have them, if one is serving the purpose for you. It's basically provided because you can have more flexibility with settings for every application. You can have web.config files in every subdirectory, application level, or site level, but it's as you know already that the resultant configuration file for an application is constructed from the cumulative results of the config files in that hierarchy. So if one config file works for you, that's great, that's fine. You don't have to have another config file for each and every application, but it's provided because you can have more control over the settings that you want to set for each and every application.
Jason: Okay, that does answer all the questions in the queue. So we're going to wrap up our session. I want to thank everyone for joining us today. I hope this session was useful to you.
Again, you can give us feedback at any time. Relevant information for feedback is what you thought of the presentation, the presenter, the topic, future topics you'd like to see covered, what you think of the interface, sound quality, any of that is fair game. We're definitely interested in what you think about our program. You can always send it to us through the alias, feedback@microsoft.com. If you use that alias, please be sure to include "Support WebCasts" in the subject line.
We look forward to seeing you again in the near future. Thank you, and see you soon.