Wednesday, November 15, 2006

Quick and easy passwords for ASP.NET

There are quite a few samples on the net which will provide alternate password protection schemes for ASP.NET. There are also built in authentication and authorization mechanisms which are great at what they do, are robust, proven, and super flexible. Occasionally, however, you need something a little simpler.

In my case, I generally need to provide a basic password protection for simple admin/reporting tools or development environments I want to keep away from prying eyes. The optimal solution for me would be something that I can simply set up in web.config and forget about.

This article will outline the basics of getting something as simple as that set up and how you'd configure your web application once the code is running.

Setting up browser-based authentication involves the following steps:

  • Derive from the HttpModule base class
  • Interpret the appropriate HTTP Headers
  • Validate against a configuration or data store
  • Modify the appropriate HTTP Headers based on the result

Code

In setting up our HttpModule, the event that we are most interested in is Application.AuthenticateRequest. We need to setup a handler for it in the HttpModule.Init() method.

Once that's done, we can handle the bulk of the HTTP work that needs to be done. This little bit of code sets up the variables and tests to see if we can even handle this request.

HttpApplication app = (HttpApplication)source;
string authStr = app.Request.Headers["Authorization"];

/* If there's nothing in the header, then it's an anonymous request */
if (authStr == null || authStr.Length == 0)  return;

/* If the authtype isn't Basic, then assume someone else will handle it. */
authStr = authStr.Trim();
if (authStr.IndexOf("Basic",0) != 0) return;

Next, we need to interpret the header information which is stored in Base64 for basic authentication.

string encodedCredentials = authStr.Substring(6);
byte[] decodedBytes = Convert.FromBase64String(encodedCredentials);

string s = new ASCIIEncoding().GetString(decodedBytes);
string[] userPass = s.Split(new char[] {":"});
string username = userPass[0];
string password = userPass[1];

Finally, authenticate the user using the credentials we were presented with and modify the headers to reflect the results. If we are successful, give the current context a Principal based on our credentials in case that information is needed further down the line.

if (AuthenticateUser(app, username, password, out roles))
{
    string realm = "dieselrover";
    app.Context.User = new GenericPrincipal(new GenericIdentity(username, realm),
roles);
}
else
{
    DenyAccess(app);
}

The AuthenticateUser method simply checks the credentials against some settings in the web.config. If you are interested in seeing that, just download the project and browse through it. You can easily override that method with your own if you want a more complicated data store for usernames and passwords, but I would strongly suggest evaluting a more robust solution if you need "real" authentication.

Configuration

Now lets look at how to set this up and get it running. For those of you not interested in how it really works, you can just download the binary, put it in your bin folder, and edit the web.config file.

First, set up the configuration handler:

<configSections>
   <section name="MonoSite.Authentication"
type
="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089"
/>
</configSections>

Second, configure the authentication settings by setting the username, password, and realm. The realm is used by the client to organize saved passwords.

<MonoSite.Authentication>
  <add key="username" value="admin" />
  <add key="password" value="admin1234" />
  <add key="realm" value="dieselrover" />
</MonoSite.Authentication>

Third, setup the HttpModule.

<httpModules>
  <add name="Authentication"
type
="MonoSite.Http.AuthenticationModule,MonoSite.Http.Authentication" />
</httpModules>

Lastly, tell ASP.NET that you want there to be some sort of authentication.

<system.web>
 <authorization>
  <deny users="?"/>
 </authorization>
</system.web>

If you want to only password protect certain subfolders of your application, you can do that easily by using the location tag.

<location path="admin">
 <system.web>
  <authorization>
   <deny users="?"/>
  </authorization>
 </system.web>
</location>

Source code and binaries

#    Comments [0] |

-