11.2 Security in ASP.NET


As we will see, you can also require client authentication in ASP.NET applications by adding the appropriate elements to your application's web.config file. Once the client has been authenticated, whether it was specified by IIS or by ASP.NET, information about that client is available through the User property of the Page class. This property is a pass-through property pointing to the User property of the current HttpContext class on any given request. Listings 11-1 and 11-2 show the definition of this property in each class.

Listing 11-1 User Property in the Page Class
 Public Class Page   Inherits TemplateControl   Implements IHttpHandler     Public ReadOnly Property User As IPrincipal     '... End Class 
Listing 11-2 User Property in the HttpContext Class
 Public Class HttpContext        Implements IObjectServiceProvider     Public Property User As IPrincipal     '... End Class 

The User property points to an implementation of the IPrincipal interface. If the client was authenticated using Windows authentication, it points to an instance of the WindowsPrincipal class. Otherwise, it may point to a custom IPrincipal implementation or, more likely, an instance of the GenericPrincipal class. (We will show an example of using the GenericPrincipal class later to implement custom roles.) The IPrincipal interface is shown in Listing 11-3 and consists of a property and a method. The property ( Identity ) is an interface pointer to the identity of the current client, and the method ( IsInRole ) can be called to query whether the client is in a particular role. If the client was authenticated using Windows authentication, IsInRole simply checks group membership in the user's access token. If the client was authenticated in some other way (forms authentication, for example), this method should be able to tell you whether the client belongs to a particular named role, which is defined by the application.

Listing 11-3 The IPrincipal Interface
 Public Interface IPrincipal     ReadOnly Property Identity As IIdentity     Function IsInRole(role As string) As Boolean End Interface 

Listing 11-4 shows the IIdentity interface, consisting of three read-only properties: IsAuthenticated , Name , and AuthenticationType . You can use IsAuthenticated to distinguish between authenticated and anonymous clients , and you can use Name to query the identity of the client. If the client was authenticated, you can then use the AuthenticationType property of this interface to query the type of authentication that was used. Listing 11-5 shows an example of accessing an authenticated client's information. In this case, when the page loads, we extract the current client's name and type of authentication, and display them in labels on our page.

Listing 11-4 The IIdentity Interface
 Public Interface IIdentity    ReadOnly Property AuthenticationType As String    ReadOnly Property IsAuthenticated As Boolean    ReadOnly Property Name As String End Interface 
Listing 11-5 Accessing Authenticated Client Information
 <!-- File: AccessClientInfo.aspx --> <%@ Page language=VB %> <html> <script runat=server>   Sub Page_Load(src As Object, e As EventArgs)     AuthUser.Text = User.Identity.Name     AuthType.Text = User.Identity.AuthenticationType   End Sub </script> <body> <form runat="server"> <h1>My test security page</h1> <h2>Can you read this?</h2>   <h3>user:</h3><asp:label id=AuthUser runat=server />   <h3>authType: </h3><asp:label id=AuthType runat=server /> </form></body> </html> 

11.2.1 Client Authentication and Authorization

As we have seen, you can configure client authentication through IIS, and once that is in place, it applies to ASP.NET files as well. You can also specify authentication and authorization in ASP.NET via the web.config file of your application. You specify the client authentication type by using the authentication element, as shown in Listing 11-6. There are four possible values for the mode attribute of the authentication element: Windows (default), Forms , Passport , or None . If you use Windows authentication, you are shifting responsibility for authentication to the Web server, so you must pick an authentication mode in IIS, such as Integrated, Basic, Digest, or SSL client authentication.

Listing 11-6 Setting the Authentication Mode with web.config
 <!-- File: web.config --> <configuration>   <system.web>      <!-- mode can also be Forms, Passport, or None -->      <!-- the default is Windows -->      <authentication mode="Windows"/>   </system.web> </configuration> 

Once you have configured the type of authentication you would like ASP.NET to use, you need to give it a reason to authenticate clients. You do this by restricting access to all or portions of your application via the authorization element. To control access to your site, you add deny and allow subelements to the authorization element, specifically denying or allowing access to users or roles. The wildcard "*" is used to represent all users, and the wildcard "?" is used to represent anonymous users. For example, to deny anonymous users access to your site, you would specify an authorization element with a single deny subelement set to "?" , as shown in Listing 11-7.

Listing 11-7 Denying Anonymous Users
 <!-- File: web.config --> <configuration>   <system.web>       <authorization>              <deny users="?" />       </authorization>   </system.web> </configuration> 

Both the deny and allow elements provide three attributes ” users , roles , and verbs ”and the values of these attributes support comma-delimited lists of users, roles, or verbs. In Listing 11-7, we used the users attribute to deny anonymous users access to our application. We could also construct more complex authorization requirements by adding multiple deny and allow elements. For example, in Listing 11-8, we explicitly grant authenticated users MyDomain\bob and MyDomain\alice complete access to our application. The second allow element grants all users the right to issue GET requests to pages in our application, and the final element, deny , restricts access to unauthenticated users. When ASP.NET checks the authorization element, it traverses the list of allow and deny elements in declaration sequence, and the first element that matches the credentials of the client request determines whether access is granted or denied . In our example, if the incoming client has been authenticated as Bob or Alice, he (or she) will be granted complete access. If an anonymous user attempts to access our site with a GET request, the request will be serviced because of our second allow statement. However, if an anonymous client attempts to access a page in our application with a POST request, she will be either given a chance to authenticate or simply denied access.

Listing 11-8 A More Complex Authorization Declaration
 <configuration>   <system.web>       <authorization>         <allow users="MyDomain\bob, MyDomain\alice"/>         <allow users="*" verbs="GET" />         <deny users="?" />       </authorization>   </system.web> </configuration> 

One last question to ask about the example in Listing 11-8 is, What happens if Bob or Alice issues a GET request to one of our pages? Because GET requests are allowed via anonymous access by our second allow element, even the initial requests from Bob and Alice will typically be processed as anonymous requests. Only when the client attempts to do something that is prevented for anonymous users will authentication take place. In general, try to keep your authorization logic simple and obvious, because the more complex the rules become, the more likely you are to make a mistake and grant access where you should have denied it.

Authorization can be specified differently for different files and subdirectories in your application. To change the authorization settings for different directories in your application, you can add a web.config file to each subdirectory specifying authorization settings. Authorization is always applied with local web.config file settings first, and only if no match is found will it look in additional configuration files in the hierarchy above. Thus, if you grant anonymous users access to your top-level site but add a web.config file that denies anonymous users access to a particular subdirectory, clients must authenticate before they can access pages in that subdirectory. Alternatively, you can specify different authorization settings for different files (and subdirectories) from the top-level web.config file of your application using the location element. Listing 11-9 shows an example of restricting access to a top-level file called secret.aspx and a subdirectory called secret , while granting anonymous access to the remainder of the pages in the application.

Listing 11-9 Using the location Element for Fine-Grained Authorization
 <!-- File: web.config --> <configuration>   <system.web>       <authorization>         <!-- allow all users by default -->        <allow users="*" />       </authorization>   </system.web>     <!-- use location element to restrict access to a          particular file -->   <location path="secret.aspx">   <system.web>       <authorization>          <deny users="?" />       </authorization>   </system.web>   </location>     <!-- use location element to restrict access to a          subdirectory -->   <location path="secret">   <system.web>       <authorization>          <deny users="?" />       </authorization>   </system.web>   </location> </configuration> 

One final note on ASP.NET authentication to keep in mind is that ASP.NET can enforce authorization and authentication only when requests are dispatched to the ASP.NET worker process. This means that if you create an authorization scheme for your application using ASP.NET's configuration files, and a user requests a plain .htm file or .gif file, the ASP.NET authentication is not consulted, and whatever settings IIS has for your virtual directory are applied (typically granting anonymous access). The only work-around for this now is to route all file requests to the ASP.NET worker process by configuring the IIS metabase to use the aspnet_isapi.dll ISAPI extension as the handler for all Web file types (.htm,.gif, jpg, and so on). Keep in mind, however, that this also slows down access to these file types for your application.

11.2.2 Forms Authentication

As mentioned earlier, relying on Windows authentication is rarely what you want for an Internet application with a broad user base because it would require that each client have a valid Windows account on your server. Instead, in your web.config file, you can specify one of two cookie-based authentication models ( Passport or Forms ), which provide many of the details of managing application-level authentication. Passport mode uses a cookie-based authentication technique that relies on Microsoft's Passport authentication technology, which lets sites and clients register with Microsoft to have a central point for client authentication. Forms authentication also uses cookies but leaves the details of authentication in your hands. You do not have to build your own cookie-based authentication scheme, as developers have had to do in the past, because ASP.NET takes care of the details of enforcing authorization and managing an authentication cookie.

The idea behind forms-based authentication is shown in Figure 11-2. When a user first requests a resource that requires authentication, the server redirects him to a designated login page. This login page collects the user's name and password, PIN, or some other bit of proof, and the application then authenticates him (through some database of users and passwords, presumably). Once the user successfully logs in, the server grants him an authentication cookie (which should be a cryptographically secure value that is infeasible to guess). The user is then redirected to the original page that he requested , but this time he presents an authentication cookie with the request and is granted access to the page. This authentication cookie lasts throughout the session, and thus the client can access all pages allowed by the authorization policy by presenting this cookie with each access. If this cookie is made persistent on the client's machine, it can be used for subsequent sessions from that same machine as well (this is manifested in the commonly seen "remember my password" check box many sites provide). Be aware, however, that persistent authentication cookies can easily be hijacked by anyone with access to the client machine. Forms-based security works well for servers that intend to service a large number of clients and want to manage client registration and authentication at the application level rather than relying on system-provided authentication requiring much more setup.

Figure 11-2. Forms Authentication

graphics/11fig02.gif

ASP.NET provides much of the infrastructure necessary to put together a cookie-based authentication Web application. First, if you specify Forms authentication in your web.config file, you can specify a loginUrl attribute, which should point to the page you want users to be redirected to if they attempt unauthenticated access to your application. If you then explicitly deny anonymous users by using the authorization element, ASP.NET takes care of routing unauthenticated clients to your designated login page for authentication. An example of a web.config file configured for forms-based authentication is shown in Listing 11-10.

Listing 11-10 Specifying Forms Authentication
 <!-- File: web.config --> <configuration>   <system.web>     <authorization>       <deny users="?"/>     </authorization>     <authentication mode="Forms">       <forms loginUrl="login.aspx" />     </authentication>   </system.web> </configuration> 

Your only other major task to get cookie-based authentication working is to implement the login page to grant or deny the authentication cookie. ASP.NET provides the class FormsAuthentication , shown in Listing 11-11, so that you can do this. This class consists primarily of a number of static methods that control the authentication cookie. For example, to grant an authentication cookie to a client, you call the SetAuthCookie method, and ASP.NET makes sure that a new cookie is generated and set for the client. ASP.NET also checks incoming requests to verify that they are in fact presenting a valid authentication cookie, and if not, routes them to your designated login page. This class also gives a useful method called HashPass- wordForStoringInConfigFile , which takes a string and perform a one-way hash on it (using either SHA1 or MD5 algorithms). The next time a user presents her password to you, you can verify it by running the hash algorithm on it again and comparing the resultant string with the hash you stored earlier. This lets you avoid storing passwords in clear text in your database. We discuss password security in more detail later in this chapter.

Listing 11-11 FormsAuthentication Class
 Public Class FormsAuthentication   Public Shared ReadOnly Property FormsCookieName As String   Public Shared ReadOnly Property FormsCookiePath As String   Public Shared FunctionAuthenticate(Name As String, _                                   password As String) As Boolean   Public Shared Function Decrypt(s As String) _                 As FormsAuthenticationTicket   Public Shared Function Encrypt( _                   tk As FormsAuthenticationTicket) As String   Public Shared Function GetAuthCookie(userNm As String, _                                     bPersist As Boolean) As HttpCookie   Public Shared Function GetRedirectUrl(userNm As String, _                                         bPersist As Boolean) As String   Public Shared Function _                 HashPasswordForStoringInConfigFile( _                     psswd As String, Format As String) As String   Public Shared Sub RedirectFromLoginPage(userNm As String, _                             bPersist As Boolean)   Public Shared Sub SetAuthCookie(userNm As String, _                                   bPersist As Boolean)   Public Shared Sub SignOut()   '... End Class 

Listing 11-12 shows a sample login page implementation. Note that in this example, we are calling the FormsAuthentication.RedirectFromLoginPage method, which takes care of granting the authentication cookie to the client and then redirecting the client to the page she originally requested. In this example, we have hard-coded the user checks, but in a real application, this information would most likely live in a database.

Listing 11-12 Forms-Based Authentication Example ”login.aspx
 <!-- File: Login.aspx --> <%@ Page language=VB %> <html>   <script runat=server>   Public Sub OnClickLogin(src As Object, e As EventArgs)       If (_username.Text = "Bob" And _password.Text = "geek") _          Or (_username.Text = "Alice" And _password.Text = "geek") Then          FormsAuthentication.RedirectFromLoginPage( _                   _username.Text, _persistCookie.Checked)       Else        _message.Text = "Invalid login: Please try again"     End If   End Sub   </script>   <body>     <form runat=server> <h2>Login Page</h2>        User name:        <asp:TextBox id="_username" runat=server/><br/>        Password:        <asp:TextBox id="_password"                       TextMode="password" runat=server/>        <br/>        Remember password?:        <asp:CheckBox id=_persistCookie runat="server"/>        <br/>        <asp:Button text="Login" OnClick="OnClick_Login"                    runat=server/><br/>        <asp:Label id="_message" ForeColor="red"                   runat=server />     </form></body> </html> 

If you want further control over the authentication cookie used by the forms authentication module, there are several additional attributes that you can apply to the forms element, as listed in Table 11-1. First of all, by default the cookie will timeout after 30 minutes, so if you expect users of your application to submit requests more than 30 minutes apart, and you don't want to force them to reauthenticate, you can increase this value. On the other hand, it may often be wise to decrease this value to something closer to 5 or 10 minutes, because if someone were accessing private information from an Internet caf , for example, they wouldn't want someone else to come in within 30 minutes after they leave and be able to view that private data. The protection attribute lets you specify how much care is taken to protect the cookie. By default, the cookie is both encrypted and Message Authentication Code (MAC) verified so that it cannot be easily tampered with or read. If for some reason you want to decrease the amount of protection on the cookie, you can do so with this attribute. Unless you have a really good reason to change this setting, however, you should leave it alone. Finally, the path attribute lets you specify the path that will be prepended to the cookie. This defaults to "/" , which is the preferred setting, since some browsers treat cookie paths with case sensitivity and others without it; so leaving it as "/" works with the largest number of browsers.

Table 11-1. Attributes of the forms Authentication Element

Attribute

Values

Default

Description

name

String

.ASPXAUTH

Name of the cookie

loginUrl

URL

login.aspx

URL to redirect client to for authentication

protection

All, None, Encryption, Validation

All

Protection mode for data in cookie

timeout

Minutes

  30  

Duration for nonpersistent cookie to be valid (reset on each request)

path

Path

"/"

Path to use for cookie

11.2.3 Authentication Cookies in Web Farms

By default, authentication cookies used by the forms-based authentication module are both encrypted and MAC verified. The decryption and validation keys used to perform these tasks are automatically generated machine by machine. This means that if you are using forms-based authentication in a Web farm environment, where each request potentially can be served by a different machine in the farm, the key validation will quickly fail. To deal with this, you can use the machineKey element in your application's web.config file (or you can modify the one in the systemwide machine.config file) to use a fixed value for both keys. If all machines in a Web farm are configured to use the same pair of keys, the cookie protection in forms authentication will work properly. Listing 11-13 shows a sample web.config file that has explicitly set the machineKey element to use fixed key values for both the validation key and the decryption key.

Listing 11-13 Using Explicit Validation and Decryption keys
 <configuration>   <system.web>   <authentication mode="Forms"/>   <authorization>     <deny users="?"/>   </authorization> <machineKey validationKey="F18815BDA3E05869EEFA53C531A696B187DA31A0F298E0FAB869AC9 2E292F1008CD5EC1B5C887B39F9559C7ED6BE66242A42E028CC5B8306D0CD1F5784A4F BC9" decryptionKey="9F9E881DFCED3092FDE726CA286B0459375E42DFD3000C20"                validation="SHA1"/>   </system.web> </configuration> 

This example uses a 64-byte validation key and a 24-byte decryption key, the maximum length allowed by the encryption and validation algorithms in ASP.NET. It is wise to create these keys using strong random algorithms, such as those provided by the RNGCryptoServiceProvider . Listing 11-14 shows a sample console application that you can use to generate keys of arbitrary length by passing in the desired length on the command line to the program.

Listing 11-14 Program to Generate Strong Random Keys Using RNGCryptoServiceProvider
 ' File: genkey.vb Imports System Imports System.Text Imports System.Security Imports System.Security.Cryptography Class App   Shared Sub Main(argv As String())     Dim len As Integer = 48     If argv.Length > 0 Then       len = Integer.Parse(argv(0))     End If     Dim buff(len) As Byte     Dim rng As RNGCryptoServiceProvider     rng = New RNGCryptoServiceProvider()     rng.GetBytes(buff)     Dim sb As StringBuilder     sb = New StringBuilder(len)     Dim i As Integer     For i = 0 To buff.Length-1       sb.Append(string.Format("{0:X2}", buff(i)))     Next     Console.WriteLine(sb)   End Sub End Class 

11.2.4 Optional Authentication

Another scenario that comes up frequently is the need to let clients authenticate themselves if they want to or to let them simply use the site anonymously. Once a client has authenticated himself, you may elect to customize the contents of the site, or perhaps some subset of the pages of the site are available only if the client has been authenticated. In this scenario, we do not want to send every unauthenticated client to a default login form. More often, it makes sense to have a login form integrated into your main page. This way, the user can authenticate if he wishes or can remain anonymous.

ASP.NET supports this type of cookie authentication as well. Figure 11-3 shows an example of a client using an optional login form on a page. Once the client has been authenticated, the page displays additional information that is relevant to that client. The implementation is similar to the cookie authentication example discussed earlier, except that anonymous clients are not prevented from accessing the site. Instead, an integrated login form is shown on the main page. If a user logs in and authenticates successfully, she is granted an authentication cookie and can then potentially do additional things or view additional material on the site. Programmatically, our login form looks very similar to the one shown earlier, but instead of directly calling RedirectFromLoginPage , we explicitly grant the user an authentication cookie by calling SetAuthCookie and then redirect the user to the current page so that additional content may be displayed. Then, in any of the pages of our application, we can check the credentials of the current user and display elements of the page conditionally based on her login.

Figure 11-3. Forms-Based Authentication

graphics/11fig03.gif

11.2.5 Password Storage

One of the dangers of performing your own authentication, as is required by forms authentication, is that if a hacker manages to break into your database where the passwords are stored, she can then use the usernames and passwords freely , possibly at other Web sites if users established the same credentials elsewhere. To prevent this, you should avoid storing passwords in clear text altogether and instead prefer to store MD5 or SHA1 hashes of users' passwords. The FormsAuthentication class provides a method to perform MD5 and SHA1 hashes on arbitrary strings with the static method HashPasswordForStoringInConfigFile , as shown in Listing 11-15.

Listing 11-15 Hashing Passwords
 <%@ Page language=VB %> <html>   <script runat=server>   Public Sub OnClick_Login(src As Object, e As EventArgs)     ' Calculate hash of password to check against     ' database entry     Dim passHash As String     passHash =    FormsAuthentication.HashPasswordForStoringInConfigFile( _                            _password.Text, "sha1")     ' use passHash in a database query here to look up     ' password hash instead of clear text password     ' then call FormsAuthentication.RedirectFromLoginPage     ' if username and password hash are correct   End Sub   </script>   <body>     <form runat=server> <h2>Login Page</h2>        User name:        <asp:TextBox id="_username" runat=server/><br/>        Password:        <asp:TextBox id="_password"                       TextMode="password" runat=server/>        <br/>        Remember password?:        <asp:CheckBox id=_persistCookie runat="server"/>        <br/>        <asp:Button text="Login" OnClick="OnClick_Login"                    runat=server/><br/>     </form></body> </html> 

You might have noticed that the name of the function used to hash passwords is not just HashPassword but HashPasswordForStoringInConfigFile . This is not just because the Microsoft developer building this class wanted the title of "longest API function in .NET" but also because you can store user credentials directly in your web.config file. It is unlikely that you will want to take advantage of this feature in any reasonably sized application, because managing usernames and passwords is a task much better suited to a database. Listing 11-16 shows a sample web.config file that stores user credentials, and Listing 11-17 shows a sample page that uses the FormsAuthentication.Authenticate method to query those credentials.

Listing 11-16 Storing User Credentials in web.config
 <configuration>   <system.web>     <authorization>       <deny users="?"/>     </authorization>     <authentication mode="Forms">       <forms loginUrl="login.aspx">         <credentials passwordFormat="SHA1">           <user name="Alice" password="9402F2262..."/>           <user name="Bob"   password="EA9003E95..."/>         </credentials>       </forms>     </authentication>   </system.web> </configuration> 
Listing 11-17 Authenticating Users with web.config-Based Credentials
 <%@ Page language=VB %> <html>   <script runat=server>   Public Sub OnClick_Login(src As Object, e As EventArgs)     If FormsAuthentication.Authenticate(_username.Text, _                                          _password.Text) Then       FormsAuthentication.RedirectFromLoginPage( _                 _username.Text, _persistCookie.Checked)     Else       _message.Text = "Invalid login: Please try again"     End If   End Sub   </script>   <!-- body and form not shown - see earlier examples --> </html> 

11.2.6 Salted Hashes

In the previous examples, we performed one-way hashes on passwords to prevent anyone from viewing them should they somehow fall into the wrong hands. Unfortunately, this may not be enough to protect the passwords, because someone who gains access to the hashed passwords could run a dictionary attack against them. That is, a dictionary of prehashed words could be compared with all the passwords, and if there were any matches, the attacker would know one or more passwords.

To counter this, many password storage facilities use what are called "salted" hashes to store passwords. To perform a salted hash on a string, you prefix the string with a randomly generated string of fixed length (the "salt") before performing the hash. This ensures that comparisons with hashed strings drawn from a password dictionary will never match. To verify a client's password, you must prefix the password he sends you with the salt string used when the original password was hashed. This means that you need to store both the hash and the salt in your password database.

Although there is no direct support for performing salted hashes in ASP.NET, it is relatively straightforward to do. Listing 11-18 shows a function, HashWithSalt , that performs a salted hash. It takes as parameters the hashing algorithm, the password as plain text, and the salt string by reference (for which you pass null if this is the first time you are hashing a password), and the hash is returned as an out parameter. The function then creates a 16-byte salt string if no salt is passed in, prepends it to the password, and passes the resulting string onto the FormsAuthentication class's HashPasswordForStoringInConfigFile .

Listing 11-18 HashWithSalt Routine
 Shared Sub HashWithSalt(algName As String, _                         plaintext As String, _                         salt As String, hash As String)   Const SALT_BYTE_COUNT As Integer = 16   If salt = Nothing Or salt = "" Then     Dim saltBuf(SALT_BYTE_COUNT) As Byte     Dim rng As RNGCryptoServiceProvider = _                New RNGCryptoServiceProvider()     rng.GetBytes(saltBuf)     Dim sb As StringBuilder = _               New StringBuilder(saltBuf.Length)     Dim i As Integer     For i=0 To saltBuf.Length-1       sb.Append(string.Format("{0:X2}", saltBuf(i)))     Next     salt = sb.ToString()   End If   hash = FormsAuthentication. _  HashPasswordForStoringInConfigFile(salt+plaintext, algName) End Sub 

11.2.7 Role-Based Authentication

It is often useful to build Web applications in terms of roles. ASP.NET supports role-based authentication through the IsInRole() method of the IPrincipal interface. If Integrated Windows authentication is used, the IsInRole() method checks Windows group membership. If you are using cookie-based authentication and would like to use roles in your security checks, you must define those roles and create the mappings of users to roles. Fortunately, there is a convenient helper class called GenericPrincipal that implements IsInRole() for you when you give it a string of role names .

For an example of when roles might be useful in a Web application, consider the roles and code shown in Figure 11-4. This application defines five roles: Doctors, Nurses, Administrators, Patients, and Janitors. Each user that logs in to the application belongs to one or more roles, and within each page, you can specifically check to see which roles the current user belongs to, and grant access or display additional information based on role membership.

Figure 11-4. Role-Based Authentication

graphics/11fig04.gif

To implement role-based security checks, you must define the roles and the mapping of users to roles. You may have a registration form that assigns roles based on information that users check, or you may assign roles to users through some internal management page or some other technique. It is up to you how best to implement this. Once you have established the roles and user-to-role mapping, you must prepare a special IPrincipal implementation to be aware of these roles so that you can program against them in your pages.

The GenericPrincipal class is useful for this purpose. Its constructor takes an array of strings (role names) and a client Identity , and properly implements IsInRole of IPrincipal based on the array of strings. To use this class throughout the pages of your application, you need to prepare an instance of GenericPrincipal initialized with the appropriate array of role names for each request, and assign it to the User property of the current HttpContext .

The application-level event called AuthenticateRequest is your hook to perform these operations before any page requests information about the roles of the current client. Listing 11-19 shows an example global.asax file that defines a handler for the AuthenticateRequest event, prepares a GenericPrincipal class initialized with an array of role names based on the current user, and assigns the GenericPrincipal to the User property of the current HttpContext . After this event handler has set up the role-aware principal, your pages can successfully use the User.IsInRole() method to query whether a given user belongs to a particular role.

Listing 11-19 Role-Based Authentication Implementation (global.asax)
 <%! File: global.asax %> <%@ Application Language="VB" %> <%@ Import Namespace="System.Security" %> <%@ Import Namespace="System.Security.Principal" %> <script runat=server>   Sub Application_AuthenticateRequest(src As Object, _                                       e As EventArgs)     If Request.IsAuthenticated Then       Dim roles As ArrayList       roles = New ArrayList()       If Context.User.Identity.Name.ToLower() = "alice" Then         roles.Add("Doctors")         roles.Add("Administrators")     ElseIf Context.User.Identity.Name.ToLower() = "bob" Then            roles.Add("Doctors")            '...       End If       ' Assign a GenericPrincipal class initialized with       ' our custom roles for this user       Dim rgRoles() As String    rgRoles = CType(roles.ToArray(GetType(String)), String())       Context.User = _        New GenericPrincipal(Context.User.Identity, rgRoles)     End If   End Sub </script> 


Essential ASP.NET with Examples in Visual Basic .NET
Essential ASP.NET with Examples in Visual Basic .NET
ISBN: 0201760398
EAN: 2147483647
Year: 2003
Pages: 94
Authors: Fritz Onion

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net