Authentication and AJAX

Getting Credentials and Sharing Tokens in AJAX Is Much the Same as in Classic ASP.NET

CoreCoder

LANGUAGES: C#

ASP.NET VERSIONS: 3.5

 

Authentication and AJAX

Getting Credentials and Sharing Tokens in AJAX Is Much the Same as in Classic ASP.NET

 

By Dino Esposito

 

Because of the statelessness of the HTTP protocol, Web applications have a lot to gain from server-side services that make up for the extreme simplicity of the protocol. On the other hand, the HTTP protocol was designed for an idea of the Web quite different from the one we have today. Such a simple protocol was just fine for sharing HTML-based and hyperlinked documents; it is less than ideal when we actually use HTML as an application delivery format and claim for security, state maintenance, and caching. At the end of the day, though, HTTP is still there and it forms the foundation of ASP.NET and AJAX.

 

To empower Web applications, virtually all server-side runtime environments build an abstraction layer and provide additional services to applications, such as session state, caching, user profiling, and, especially, authentication and role management.

 

In ASP.NET, the vast majority of these application services are incorporated in the runtime pipeline and use the HTTP module infrastructure. Services intercept pipeline events and kick in when appropriate. The page developer isn t involved in the services activity and passively deals with the results of the activity itself. What does it mean? For example, if a profiling service is in place, the page developer will find profile information for the current user ready to use. The same goes for the role management service. But what about authentication, instead?

 

Authentication is a key feature in ASP.NET. It ensures that only recognized users are granted access to a given resource be it a page, a folder, or a simple image. Authentication is implemented through an HTTP module that intercepts any request to a protected resource and directs the user to a log-in page first. Are authentication and other services compatible with ASP.NET AJAX?

 

How Authentication Works in ASP.NET

In the configuration file in classic ASP.NET, you declare which resources in which folder are off-limits for the anonymous user. At that point, the runtime pipeline automatically redirects the anonymous user to a log-in page, where the user is prompted for credentials. Next, if the user is successfully authenticated, an authentication token is generated as a cookie and appended to the response. Finally, the user is redirected to the originally requested page and passes any further check because of the attached token. Forms authentication is the ASP.NET built-in infrastructure that implements the log-in pattern. Forms authentication requires an additional log-in page and two HTTP redirect commands. Is it possible to save one redirect and authenticate the user from within an HTML page through an AJAX call?

 

An AJAX Infrastructure for Authentication

For ASP.NET AJAX clients, the infrastructure for authentication consists of two key components: a client-side JavaScript class and a system-provided HTTP handler. The same model is in place for other system services, such as role management and user profiles.

 

The JavaScript class supplies one method to send any user s credentials to a server-side endpoint. The HTTP handler internally invokes a system-provided scriptable Web service. As a result, you receive a Boolean answer that indicates whether the user has been authenticated or not. The Web service uses the server-side ASP.NET authentication and membership API to validate the user information. When you use a JavaScript proxy to command a remote authentication service, you check your users more quickly because you can incorporate a log-in form into any pages in the site that users visit regularly. The authentication essentially consists of a request, and doesn t force a redirect to a specialized log-in page.

 

From JavaScript, you invoke a proxy class implemented as a singleton. The original JavaScript class is instantiated in the Microsoft AJAX client library and is exposed as an object (as named here):

 

var proxy = Sys.Services.AuthenticationService;

 

The methods offered by the authentication JavaScript proxy class for ASP.NET AJAX are listed in Figure 1. Figure 2, instead, details the properties defined on the object. The underlying JavaScript class is a regular JavaScript proxy class nearly identical to any other JavaScript proxy class that the ScriptManager control generates for referenced Web and WCF services. The only difference is that such proxy classes for authentication, role management, and profile services are natively part of the Microsoft client library and downloaded as part of the MicrosoftAjax.js file.

 

Method

Description

login

Verifies credentials and issues an authentication ticket if the credentials are good.

logout

Clears the authentication ticket.

Figure 1: Methods of the Sys.Services.AuthenticationService object.

 

Property

Description

isLoggedIn

Boolean read-only property; indicates whether the current user is logged in.

path

Gets and sets the URL to reach the authentication Web service.

timeout

Gets and sets the timeout for the user authentication process.

Figure 2: Properties of the Sys.Services.AuthenticationService object.

 

The back-end of the authentication service is implemented in the AuthenticationWebService class, marked as sealed and internal. The class features a script service, as illustrated here:

 

[ScriptService]

class AuthenticationService

{

   // Methods

   public AuthenticationService();

    [WebMethod]

   public bool IsLoggedIn();

    [WebMethod]

   public bool Login(string userName, string password,

                      bool createPersistentCookie);

    [WebMethod]

   public void Logout();

}

 

Let s focus on the login method. The first two arguments set the credentials of the user. When you authenticate a user through Forms authentication, a cookie is created and attached to the response. This cookie is referred to as the authentication cookie and its name defaults to .ASPXAUTH. The final Boolean argument indicates whether a persistent cookie is required. If so, authenticated credentials will be in a persistent cookie saved across browser sessions.

 

What about the expiration of the authentication cookie? The cookie is simply given the expiration that you specify in the configuration file. So to set the timeout that is appropriate for your site, you simply set the timeout attribute in the <authentication> section of the application s web.config file to the desired number of minutes. You should note that the authentication service sets the cookie using the SetAuthCookie method on the FormsAuthentication class. This means that most settings defined in the <authentication> section of the configuration file are taken into proper account while creating the authentication ticket.

 

The Role of Membership Providers

Where would you specify the logic to check credentials? The AJAX authentication service takes advantage of the currently registered ASP.NET membership provider. The default membership provider checks username and password against the content of the users table in the aspnetdb.mdf file. However, both the database schema and the logic applied are a detail you can change at will.

 

If you want to apply an application-specific piece of logic or reuse an existing database of users, all you have to do is create a custom membership provider. Starting with ASP.NET 2.0, forms authentication is built atop a provider-based, extensible model that lets you easily change the underlying machinery, such as validation code and users management, while leaving the front-end API intact. Based on this model, you can easily adapt your existing code to connect to the authentication machinery of ASP.NET, also from an AJAX client.

 

A custom membership provider takes the form as shown in Figure 3. It is essentially a class that inherits from MembershipProvider and overrides a few members. The key member to override is ValidateUser. This method takes a username and password and returns a Boolean answer. It s within this member that you should place your custom logic for managing a user s credentials.

 

public class CustomMembershipProvider : MembershipProvider

{

   public CustomMembershipProvider()

   {

   }

   public override bool ValidateUser(string username, string password)

   {

       return AuthenticateUser(username, password);

   }

   private bool AuthenticateUser(string username, string password)

   {

       // Your authentication logic here

   }

   // Override all other abstract methods in MembershipProvider

   :

}

Figure 3: Skeleton for a custom membership provider.

 

Note also that MembershipProvider is an abstract class with a long list of members to override in any derived class. The complete list is shown in Figure 4.

 

public abstract class MembershipProvider : ProviderBase

{

 public abstract bool ChangePassword(

     string username, string oldPassword, string newPassword);

 public abstract bool ChangePasswordQuestionAndAnswer(

     string username, string password, string newPasswordQuestion,

      string newPasswordAnswer);

 public abstract MembershipUser CreateUser(

     string username, string password, string email, string passwordQuestion,

     string passwordAnswer, bool isApproved, object providerUserKey,

     out MembershipCreateStatus status);

 public abstract bool DeleteUser(

     string username, bool deleteAllRelatedData);

   public abstract MembershipUserCollection FindUsersByEmail(

     string emailToMatch, int pageIndex, int pageSize, out int totalRecords);

 public abstract MembershipUserCollection FindUsersByName(

     string usernameToMatch, int pageIndex, int pageSize, out int totalRecords);

 public abstract MembershipUserCollection GetAllUsers(

     int pageIndex, int pageSize, out int totalRecords);

 public abstract int GetNumberOfUsersOnline(

     );

 public abstract string GetPassword(

     string username, string answer);

 public abstract MembershipUser GetUser(

     object providerUserKey, bool userIsOnline);

 public abstract MembershipUser GetUser(

     string username, bool userIsOnline);

 public abstract string GetUserNameByEmail(

     string email);

 public abstract string ResetPassword(

     string username, string answer);

 public abstract bool UnlockUser(

     string userName);

 public abstract void UpdateUser(

     MembershipUser user);

 public abstract bool ValidateUser(

     string username, string password);

 // Properties

 public abstract string ApplicationName { get; set; }

 public abstract bool EnablePasswordReset { get; }

 public abstract bool EnablePasswordRetrieval { get; }

 public abstract int MaxInvalidPasswordAttempts { get; }

 public abstract int MinRequiredNonAlphanumericCharacters { get; }

 public abstract int MinRequiredPasswordLength { get; }

 public abstract int PasswordAttemptWindow { get; }

 public abstract MembershipPasswordFormat PasswordFormat { get; }

 public abstract string PasswordStrengthRegularExpression { get; }

 public abstract bool RequiresQuestionAndAnswer { get; }

 public abstract bool RequiresUniqueEmail { get; }

}

Figure 4: Definition of the MembershipProvider class.

 

You are not required to give an effective implementation to each member, but at the very minimum you should throw an exception, as shown here:

 

public override bool ChangePassword(string username,

   string oldPassword, string newPassword)

{

     throw new NotSupportedException();

}

 

For ASP.NET AJAX, though, there s a quicker way out you might want to consider. In the System.Web.ClientServices.Providers namespace you ll find the ClientFormsAuthenticationMembershipProvider class. This class is essentially an implementation of MembershipProvider that ASP.NET AJAX uses to perform default validation. At the end of the day, this class is a relatively thin wrapper around MembershipProvider that overrides ValidateUser and throws for any other method. You might seriously consider deriving your custom provider class from this instead of MembershipProvider.

 

Finally, to register the new membership provider, tweak the web.config file as shown here:

 

<membership defaultProvider="MyMembershipProvider">

  <providers>

    <add name="MyMembershipProvider"

         type="YourNamespace.CustomMembershipProvider" />

  </providers>

</membership>

 

Add the preceding code to the web.config file under the <system.web> node and you re done.

 

Performing Authentication

Using ASP.NET AJAX authentication requires a bunch of HTML input tags to collect username, password, and the optional checkbox for a persistent cookie. You also need a JavaScript button bound to the following code:

 

<script type="text/javascript">

   var username = $get("Login1_UserName");

    var password = $get("Login1_Password");

   function Login1_Click()

   {

       Sys.Services.AuthenticationService.login(

           username.value, password.value, false,

           null, null, onLoginCompleted);

       return false;

   }

   :

</script>

 

The authentication occurs asynchronously; when all is done, the callback (in this case, onLoginCompleted) is invoked to give you a chance to update the user interface.

 

What about the log-out process? To give users a chance to log out directly from the client, you must add another button to your client user interface and bind it to the following JavaScript code:

 

function Logout1_Click()

{

 Sys.Services.AuthenticationService.logout(

   onLogoutCompleted);

 return false;

}

 

The function originates a redirect and a full page reload. The final response doesn t include any more than the authentication cookie.

 

Brief Notes on AJAX Authentication

ASP.NET AJAX authentication needs to be explicitly enabled through a setting in the configuration file:

 

<system.web.extensions>

  <scripting>

    <webServices>

       <authenticationService enabled="true" />

    </webServices>

  </scripting>

</system.web.extensions>

 

In ASP.NET, forms authentication always sends credentials as clear text. This is nothing new, but a reminder is still useful. For a number of security-related reasons, it is recommended that log-in forms be placed in pages you reach through HTTPS. Clear text is not related to AJAX, but using AJAX for authentication certainly makes it easier for developers to place log-in forms everywhere.

 

Another point to keep in mind is that the AJAX authentication service doesn t work with applications that use a cookieless authentication scheme.

 

Conclusion

Forms authentication is the mechanism in ASP.NET applications that allows you to show a log-in page in front of users when they attempt to access a protected resource. In classic ASP.NET, forms authentication is based on a couple of HTTP redirects. In an ASP.NET AJAX scenario, you can use some JavaScript code to make at least the log-in process happen in a smoother way.

 

Dino Esposito is an architect at IDesign and specializes mainly in ASP.NET, AJAX, and RIA solutions. Dino is the author of Programming ASP.NET 3.5 Core Reference (Microsoft Press, 2008). He also wrote Introducing ASP.NET AJAX, also for Microsoft Press. Late-breaking news is available at http://weblogs.asp.net/despos.

 

 

 

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish