Regardless of what type of application you are creating in ASP.NET, the chances are very high that you will want to be able to identify the users who are connecting to your website. If you want to do something as simple as provide a personalized greeting or something as complex as identifying the user through some corporate single sign-on system, you will need to make use of some form of authentication. Authentication is the process of identifying who a particular user of your web application is by obtaining some set of credentials from the user and verifying those credentials against some authority. The authority can be a custom database, an Active Directory, or a single sign-on authority such as Microsoft Passport.
Authentication in ASP.NET works on the premise of providers. You choose which provider is providing authentication services for your application through a setting in the Web.config file.
You indicate the authentication provider within Web.config by setting the <authentication> element as follows:
Three authentication providers come with ASP.NET: Windows, Forms, and Passport. If you choose "None" for your authentication provider, ASP.NET will not do anything whatsoever to identify the person requesting each page. In the next few sections of this chapter you will see how to use the three authentication providers.
Two main interfaces are used by all of the authentication providers: IPrincipal and IIdentity. These two interfaces allow for a standard method of identifying authenticated users.
When a user has been authenticated (even if that authentication failed), an ASP.NET page has access to the user credentials and other authentication through the web context. All pages have access to the web context through an instance of the HttpContext class, which you can access via the HttpContext.Current property. To obtain an IPrincipal representing the current user, you can make use of the HttpContext.Current.User property.
Windows authentication for ASP.NET is provided by the WindowsAuthenticationModule class (found in the System.Web.Security namespace). When a user is authenticated using Windows authentication, the provider will create an instance of the WindowsPrincipal class and make it available through the web context.
Windows authentication works by taking whatever Windows-based credentials (clear text, integrated, and so on) were supplied by Internet Information Server (IIS) and providing them to the ASP.NET application through the WindowsPrincipal and WindowsIdentity classes.
Because Windows authentication is the default authentication provider for ASP.NET, it is extremely easy to create a sample application to test it out. To do so, create a new C# website called Authentication. After you've done this, add the following lines of code to the Page_Load event handler of the default Web Form that comes with the application:
Response.Write(User.Identity.Name + "<BR>"); Response.Write("User is authenticated? " + User.Identity.IsAuthenticated.ToString() + "<BR>"); Response.Write("Authentication Method: " + User.Identity.AuthenticationType.ToString() + "<BR>");
The User object is made available to all ASP.NET web pages. If you are writing a server control or a user control, you can access the User object by using Page.User or HttpContext.Current.User. Figure 28.1 shows the output of this page when run under Windows authentication. Obviously the name of the user will change, but everything else should look very similar in your own development environment.
Figure 28.1. The output of a page displaying Windows authentication information.
Passport authentication is handled by the Passport authentication provider. Passport is a centralized authentication service provided by Microsoft. Your application benefits in that users can reuse the same Passport on any number of sites while still maintaining their own privacy. Your application, by making use of Passport, can skip a lot of the process usually involved in creating an authentication scheme. If you are developing on Windows Server 2003, you already have all the tools you need in order to work with Passport authentication. If you are not using Windows Server 2003, you will need to download the Passport SDK. For information on the Passport SDK and how to support Passport authentication on your website, go to http://www.passport.com/business. In order to see the documentation you will have to have a Passport of your own.
Much like Forms authentication (covered in the next section), Passport authentication works with cookies. When a user opens a browser to a Passport-secured website, the client's cookies are examined for a valid Passport authentication ticket. If it is found, the user is seamlessly delivered to the secured resource. If no such ticket is found, the user is redirected to the Passport authentication page hosted by Microsoft. After authentication takes place, the user is then redirected to the original secured resource. Because the user now has a valid Passport authentication ticket, the client is then given access to the protected resource.
The PassportAuthenticationModule detects the presence of a valid Passport and then creates a PassportIdentity instance, which then becomes available from within the User object as shown in the preceding samples.
The PassportIdentity class offers several additional methods and properties that are useful when creating a Passport-secured website. For a full reference on the PassportIdentity class, consult the MSDN documentation at http://msdn.microsoft.com and the Passport SDK, which can be found at http://www.passport.com/business and is included with Windows Server 2003.
Forms authentication is the most commonly used means of authentication for public-facing websites. The reason for this is that there are often concerns with securing a website with Windows authentication that must be accessible to users who don't belong to a domain and to users accessing the site across any number of router configurations, as well as a need for protection of credentials.
As mentioned in the Passport section, Forms authentication is cookie-based. This means that when a user has authenticated to a website, that fact is stored in a cookie on the user's machine. If the website fails to find an authentication cookie, the user is redirected to a login page where they can supply their credentials (or in some cases they can register a new account).
Forms authentication has several options that can be configured through the Web.config file. The options for the <forms> element in the Web.config file are shown in the following code:
<authentication mode="Forms"> <forms name="name" cookieless=UseCookie|UseUri|AutoDetect|UseDeviceProfile defaultUrl=[URL] domain=domain name loginUrl="url" protection="All|None|Encryption|Validation" timeout="30" path="/" requireSSL="true|false" slidingExpiration="true|false"> <credentials passwordFormat="Clear|SHA1|MD5"> <user name="username" password="password"/> </credentials> </forms> </authentication>
The following is a quick summary of some of the options shown in the preceding example:
Also keep in mind that Visual Studio 2005 has a far more active and alert IntelliSense system than previous versionsyou will be able to see all of the options available to you while typing directly into the Web.config file.
The <forms> element only indicates how you are going to protect the pages on your website, not which locations you plan on protecting. To protect every page in your application except the login page, you can use a Web.config file that looks like this:
<?xml version="1.0"?> <configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0"> <appSettings/> <connectionStrings/> <location path="login.aspx"> <system.web> <authorization> <allow users="*"/> </authorization> </system.web> </location> <system.web> <compilation debug="true"/> <authentication mode="Forms"> <forms loginUrl="login.aspx" name="MyApp" protection="All"/> </authentication> <authorization> <deny users="?"/> </authorization> </system.web> </configuration>
The authorization section indicates who has been granted access and who has been denied access. The wildcards ? and * indicate anonymous (unauthenticated) users and all users, respectively. You will see more about the authorization element later in the chapter in the section "Security Through Authorization."
When you use the FormsAuthentication class, several static methods are available to you for dealing with Forms authentication, including the following:
With a quick change to the preceding application and a call to FormsAuthentication.RedirectFromLoginPage, you can create a quick sample of Forms authentication. The three lines of code you used to display the WindowsIdentity details can also be used to show the same information from Forms authentication, as shown in Figure 28.2.
Figure 28.2. Forms authentication in action.
If you have experience with Forms authentication in previous versions of ASP.NET, you may think that this section is a little small. I am deliberately leaving out some of the more tedious programming tasks associated with authentication such as creating login pages, status controls, and so that on. Later in this chapter there is a section ("The ASP.NET Security Controls") covering a host of new UI controls that automate a great deal of the common tasks associated with authentication that work with any authentication provider, not just Forms.
User Management with Membership
Authentication requires that a set of credentials supplied by the user be validated against some previously stored set of credentials. The means by which you store the user credentials is completely up to you. You can store them in a SQL Server instance, you can store them in an XML file, or an Access database, or even the Web.config file.
Every web application that requires a user to log in must deal with the issue of storing the information about the website's members and their credentials. ASP.NET 2.0 provides a new API, the Membership API. This API abstracts the management of user storage and credentials in a standard way. As you will find out later in this chapter, there is also a set of standard controls that are fully compatible with the membership API.
The Membership API consists of the set of classes provided by ASP.NET for dealing with Membership that reside in the System.Web.Security.Membership. This API provides the following functionality:
The bottom line is that now the majority of the tasks you had to code manually each time you created an ASP.NET v1.x website are now bundled for you in a secure, easy-to-use library that is available to every ASP.NET 2.0 web application.
The first step to using Membership on any application is to make sure that the ASP.NET Membership schemas are installed properly. These schemas are installed in an instance of SQL Server, or your default SQL Express instance. If this was not already done for you at the time ASP.NET was installed, you can use the command-line utility aspnet_regsql.exe to do the job for you. You can find this tool in [drive:]\windows\Microsoft.NET\Framework\v[version].
The next thing you need to do is create a connection string for the Membership provider to use. This connection string will be stored in the new <connectionStrings> element in Web.config. If you installed the full version of SQL Server 2005, you will have a standard connection string. If you are using the Express version of SQL 2005, you will have a slightly different connection string. The following is the line of XML I used for my Membership connection string after installing the schemas into my copy of SQL Express:
Note that if you're using a full version of SQL Server, you should replace the .\SQLExpress instance name with the server name (and possible instance name) of your full installation of SQL Server. Next, you need to configure the Membership API from within the Web.config file. The following is a sample Membership provider configuration:
<membership defaultProvider="SqlProvider" userIsOnlineTimeWindow="5"> <providers> <clear/> <add name="SqlProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="LocalSqlServer" applicationName="MembershipSample" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="true" requiresUniqueEmail="true" passwordFormat="Hashed" /> </providers> </membership>
When you look at this configuration, the individual attributes of the <add> element correspond directly to some of the static properties of the Membership class.
Before we get into any serious Membership coding, let's take a look at some of the properties and methods of the Membership class, which are shown in Tables 28.1 and 28.2.
The impact of a standardized membership API is extremely significant. This allows for developers of membership-enabled ASP.NET applications to learn one simple API for managing users, and the only difference between one application and the other is the Web.config setting for the provider and connection string. I can't stress enough how incredibly useful the new provider model is for ASP.NET developers. Later in this chapter you will see how to create your own Membership provider.
To recap, the following are the steps to take in order to enable Membership in your ASP.NET application: