Walkthroughs: Advanced

C# and VB.NET Code is available
when installing the Samples package
Open this document in seperate window

In this walkthhrough, you will:

The more advanced possibility to implement Kabel .NET is to derive from the base HTTP Module and override its authentication functionality. From a developer's perspective, this gives you more control over the internals of your HTTP pipeline processing and it also allows you to customize other, more advanced Kabel .NET features, such as ticket generation and validation.

As with the basic implementation method, your code must provide an implementation for the authentication mechanism, which will then be called by the base Kabel .NET module.
Specifically, the HTTP Module (Type: uthentic.Web.Security.HttpDigest.DigestAuthenticationModule)
exposes the protected virtual (Overrideable) AuthenticateUser method for this purpose.

When called, your implementation of this function will need to validate the given username (return true) and supply the stored password associated with it - or reject the username if it is unknown or otherwise invalid (for example, if the associated account is disabled). See How Kabel .NET works to better understand this concept.

Getting Started

Before anything, two basic things need to be taken care of:

Overriding IIS Security settings

Lastly, it is necessary to disable the Integrated Windows authentication of IIS, because otherwise IIS will attempt to authenticate your HTTP Digest clients, which will only fail. Follow these simple steps:

  1. Open your IIS Virutal Directory settings and go to the Directory Security tab

  1. Click Edit... and the upcoming dialog, uncheck Integrated Windows Authentication

Adding a Reference to the global Kabel .NET assembly

You will need to do add a reference to the Kabel .NET assembly, which contains the necessary classes that you will be using in just a moment. To do this in Visual Studio .NET, simply follow these steps:

Implement Your Code!

Now we are ready to get coding. We will override the AuthenticateUser method, which the Kabel .NET base module calls whenever it needs to authenticate a client request. Let's first set-up our own HttpModule class that inherits from the base module:

Basic class declaration of Custom Module - C#

using System.Web;
using System.Security.Principal;
using uthentic.Web.Security.HttpDigest;
// for namespace abbreviations

namespace KabelAdvSample // your own namespace declaration
{

public class MyDigestAuthenticationModule : uthentic.Web.Security.HttpDigest.DigestAuthenticationModule [1]
{

override protected bool AuthenticateUser
(System.Web.HttpApplication app,
string username,
out
string password,
out
System.Security.Principal.IPrincipal user)
[2]
{

// Your Code will come here

}

}

}

Authenticate in global.asax - VB.NET

Imports System
Imports System.Security.Principal
Imports uthentic.Web.Security.HttpDigest
' for namespace abbreviations

Namespace KabelAdvSampleVB ' your own namespace declaration

Public Class MyDigestAuthenticationModule
Inherits uthentic.Web.Security.HttpDigest.DigestAuthenticationModule [1]

Protected Overrides Function AuthenticateUser [2]
(ByVal app As System.Web.HttpApplication,
ByVal username As String,
ByRef password
As String,
ByRef user
As System.Security.Principal.IPrincipal) As Boolean [2]

'Your Code will come here

End Function

End Class

End Namespace

The most important part: The Parameters

Let's disect the parameters of this function signature. As seen above,

Two parameters are always passed into the function:

and three parameters (including the boolean return value) should be returned

Bringing it together

This methodology will become clear when looking at the next code snippet. It implements the most simple Username validation, but it does not require much imagination to see a more sophisticated authentication being implemented instead (such as database lookups, or perhaps querying an XML configuration files, etc.)

Simple Username Validation - C#

using System.Web;
using System.Security.Principal;
using uthentic.Web.Security.HttpDigest;
// for namespace abbreviations

namespace KabelAdvSample // your own namespace declaration
{

public class MyDigestAuthenticationModule : uthentic.Web.Security.HttpDigest.DigestAuthenticationModule [1]
{

override protected bool AuthenticateUser
(System.Web.HttpApplication app,
string username,
out string password,
out System.Security.Principal.IPrincipal user) [2]
{

password = null;
user = null;

bool isValidUsername = false;
// it's a good security practice to be defensive
// and assume that the user is initially invalid

if (username.Equals("admin"))
{

password = "secret-password123";
isValidUsername = true;

user = DigestHelper.MakeSimpleUser("Administrator");

// 'admin' is a valid username for our application.
// The Client password should be 'secret-password123'

// We are also associating the name 'Administrator'
// with the identity of the Client

}
else if (username.Equals("mickey"))
{

password = "mouse-password";
isValidUsername = true;

user = DigestHelper.MakeSimpleUser("MickeyMouse");

// 'mickey' is also a valid username for our application.
// The Client password should be 'mouse-password'

// We are also associating the name 'MickeyMouse'
// with the identity of the Client

}
else
{

password = null;
isValidUsername = false;

user = null;

// We do not know any other users.
// Therefore, the Username is not valid!
// Therefore, password
= null and user = null

}

return isValidUsername;
// return the outcome of our simple validation

}

}

}

Nothing easier than that.

NOTE: With HTTP Digest, passwords are case-sensitive. This is an important detail on the client side.

Overriding other Module Methods

Authentication is not the only functionality that can be overriden for the Kabel .NET base module. You can use these other functions for greatest flexibility in your security and development needs. The following virtual (Overrideable) proctected methods are called by the base module in the sequence shown here.

Once per activated module instance:

  1. Initialize (HttpApplication application) - Called once during the initial initialization of the HTTP Module and before the first request is processed; use it to initialize any data/objects specific to each instance of your custom module (Note: ASP.NET may create several instances of your module to process concurrent requests). You also have full read/write access to the configuration settings which will be used to initialize the Kabel .NET base module instance (via the HttpDigestConfiguration instance member; you could thus load a custom ticket validation key, for example, without specifying it in the web.config file...).

And then for each authentication request (in sequence as shown):

  1. bool AuthenticateUser (...) - see above
  2. If true is returned, processing continues:
    1. bool ValidateTicket (string ticket, HttpApplication app) - Overwrite this method and the GenerateNewTicket method to implement your own ticket validation;
    2. string GenerateNewTicket (HttpApplication application) - return your custom ticket string here.
    3. string GenerateOpaqueValue (HttpApplication application) - return your custom opaque value here;
      Only called if useOpaque is enabled in the configuration; see Configuring Kabel .NET for more details on Opaque values.

Using Built-In Helper Functions

All classes deriving from the Kabel .NET base Module have access to a number of protected member methods, which can be used to simplify advanced development tasks. Refer to the API Documentation for details.

Use the DigestHelper class

The additional DigestHelper class exposes several static helper methods to simplify common Authentication processing and also Hashing functions. Please see the Basic Walkthrough for an example of how to use it; to learn more about its feature set, refer to the API Documentation.

Access the current DigestHeader

DigestHelper exposes one particular method, called GetCurrentDigestHeader, which returns a DigestHeader info structure when given a valid HttpContext instance for the current request. The DigestHeader contains all the HTTP Digest-specific information and parameters pertaining to the current request; it is provided for advanced development purposes and can be called from anywhere within your code (except from within Initialize [see above], which is called before processing the first request). Refer to the API Documentation for details.

Final Steps: Enabling the new custom Module for the ASP.NET application

After you have implemented your custom module to handle Kabel .NET authentication, we need to specify a few minimum configuration settings in the web.config file of your ASP.NET application to enable the newly derived module.

web.config

<configuration>
<system.web>

...

<httpModules> [3]

<add name="MyHttpDigestModule" [3.1]
type="KabelAdvSample.MyDigestAuthenticationModule, KabelAdvSample" /> [3.2]

</httpModules>

<authentication mode="None" /> [4]

</system.web>

<uthentic.HttpDigest>
<authentication realm="IBuySecurely" /> [5]
</uthentic.HttpDigest>

</configuration>

Additional Module Event Processing

Before jumping to the end, there is one more aspect about the Kabel .NET module that could be of interest to advanced developers and implementors: Like the built-in Authentication Modules of ASP.NET, Kabel .NET exposes two public events that are raised to indicate the outcome of a user's authetnication. Note that these events are available independently of your choice of implementation (Basic [via global.asax] or Advanced [via derived class, ie. this example]).

Module events are always captured in an application's global.asax file and in order to be hooked-up properly by the ASP.NET runtime, they must follow a certain naming pattern; see below for each event's specification.

AuthenticationSucceeded

The Kabel .NET base module will raise this event every time a user successfully authenticated to your application. For this to happen, these criteria must have been satisfied:

The following snippets illustrate the basic event handler signature:

AuthenticationSucceeded in global.asax - C#

using uthentic.Web.Security.HttpDigest.Events;
// for namespace abbreviations

...

protected void MyHttpDigestModule_AuthenticationSucceeded(object source, AuthenticationSucceededEventArgs e)
{

// Your addtional Code will come here

}

AuthenticationSucceeded in global.asax - VB.NET

Procted Sub MyHttpDigestModule_AuthenticationSucceeded(source As Object, e As AuthenticationSucceededEventArgs)
{

' Your addtional Code will come here

}

When implementing the event handler, make sure that it is named as follows:
FriendlyName_AuthenticationSucceeded where FriendlyName is the name assigned to the Module in the <httpModule> section of your web.config file (here: MyHttpDigestModule), as specified in [3.1] above.

AuthenticationSucceededEventArgs (parameter e, above) exposes the following properties:

If the User has been successfully authenticated (according to the above criteria) but the e.User property is still unassigned after the execution of the AuthenticateUser method and after this event completed, Kabel .NET will create a simple System.Security.Principal.GenericPrincipal user object for you, using the e.Username property as the identity's name.

AuthenticationFailed

The Kabel .NET base module will raise this event every time authentication for a request fails. Any one of the following criteria causes this to happen:

Use this event to customize the handling of bad requests and for advanced security auditing features.

NOTE: This event is not called when a Client ticket was stale / expired, as this does not indicate that the Client passed invalid credentials; rather, it means that the Client simply needs to re-authenticate using a new ticket. See About HTTP Digest, Tickets for more info.

The following snippets illustrate the basic event handler signature for AuthenticationFailed:

AuthenticationFailed in global.asax - C#

using uthentic.Web.Security.HttpDigest.Events;
// for namespace abbreviations

...

protected void MyHttpDigestModule_AuthenticationFailed(object source, AuthenticationFailedEventArgs e)
{

// Your addtional Code will come here

}

AuthenticationFailed in global.asax - VB.NET

Procted Sub MyHttpDigestModule_AuthenticationFailed(source As Object, e As AuthenticationFailedEventArgs)
{

' Your addtional Code will come here

}

When implementing the event handler, make sure that it is named as follows:
FriendlyName_AuthenticationFailed where FriendlyName is the name assigned to the Module in the <httpModule> section of your web.config file (here: MyHttpDigestModule), as specified in [3.1] above.

AuthenticationFailedEventArgs (parameter e, above) exposes the following members:

At last: Kabel .NET + Your Code in Action

So far, we have successfully

This means, we are ready to see Kabel .NET in action. Let's create a simple Web Service, which will only be accessible to successfully authenticated users and return the name of the current user (i.e. "Administrator" or "MickeyMouse", as seen above). The following snippet defines our public WebMethod:

Simple ASP.NET Web Service: RestrictedWs.asmx- C#

[WebMethod]
public string HelloCurrentUser()

{

return "Hello, " + Context.User.Identity.Name;
// This will return the name previously assigned to the Current User

}

Let's call this serivce RestrictedWs.asmx, and since it is restricted, let's configure the application so that only authenticated will be able to call it.

ASP.NET supports a powerful configuration mechanism, which allows you to authorize users according to their verified identity, roles, etc. on a ressource-specific basis. (Authorization happens after successful Authentication; at this stage, an application determines whether the authenticated user actually has the permission to access a given ressource.)

You can restrict all of your Web Application to authenticated users, by using the web.config <authorization> tag. Alternatively, you can use the <location> tag to specify different access criteria for individual pages and services.

The following web.config snippet configures the application so that all pages are restricted to authenticated users using the <authorization> tag:

web.config with <authorization> tag

<configuration>
<system.web>

...

<authorization>

<deny users="?" /> [6]

</authorization>

<httpModules> [3]

<add name="MyHttpDigestModule" [3.1]
type="KabelAdvSample.MyDigestAuthenticationModule, KabelAdvSample" /> [3.2]

</httpModules>

<authentication mode="None" /> [4]

</system.web>

<uthentic.HttpDigest>
<authentication realm="IBuySecurely" /> [5]
</uthentic.HttpDigest>

</configuration>

 

The next possible web.config code configures the application so that only RestrictedWs.asmx will be restricted; we are using the <location> tag:

web.config with <location> tag

<configuration>

<location path="RestrictedWs.asmx">

<sytem.web>
<authorization>
<deny users="?" /> [7]
</authorization>
</sytem.web>

</location>


<system.web>

...

<httpModules> [3]

<add name="MyHttpDigestModule" [3.1]
type="KabelAdvSample.MyDigestAuthenticationModule, KabelAdvSample" /> [3.2]

</httpModules>

<authentication mode="None" /> [4]

</system.web>

<uthentic.HttpDigest>
<authentication realm="IBuySecurely" /> [5]
</uthentic.HttpDigest>

</configuration>

Let's Launch

Let's test our simple but secure application: Open up Internet Explorer and point it to the location of RestrictedWs.asmx on your web server. The following screenshots illustrate a simple access scenario:

  1. When accessing the protected resource, Internet Explorer prompts for credentials.
    Notice the IBuySecurely identifier, as specified for the Web Application's Realm in [3] of the web.config file.

  1. First, when entering bad credentials (Username: i-am-a-hacker), we are denied access:

  1. Next, we try the accepted Username mickey with the password mouse-password. See there...

we're in!

  1. The HelloCurrentUser method of the Service then returns the following user-dependent string:

  1. Notice also that no additional re-authentication was required during the session; any possibly expired or stale tickets will be automatically renewed through the communication between Internet Explorer and Kabel .NET
  2. See the HTTP Digest Client Side Walkthrough for an example of how to automate authentication in your client applications.

Feedback on Help
Copyright © 2002, uthentic.net
All Rights Reserved