using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Security.Principal;
using System.Configuration;
using System.Reflection;
namespace Smithfamily.Blog.Samples
{
/// <summary>
/// HttpModule that provides Basic authentication for asp.net applications
/// </summary>
public class BasicAuthenticationModule : IHttpModule
{
private static IAuthProvider authProvider;
#region IHttpModule Members
/// <summary>
/// Initializes the <see cref="BasicAuthenticationModule"/> class.
/// Instantiates the IAuthProvider configured in the web.config
/// </summary>
static BasicAuthenticationModule()
{
string provider =
ConfigurationManager.AppSettings["Smithfamily.Blog.Samples.BasicAuthenticationModule.AuthProvider"];
Type providerType = Type.GetType(provider, true);
authProvider = Activator.CreateInstance(providerType, false) as IAuthProvider;
}
/// <summary>
/// Disposes of the resources (other than memory) used by the module that implements <see cref="T:System.Web.IHttpModule"/>.
/// </summary>
public void Dispose()
{
authProvider.Dispose();
authProvider = null;
}
/// <summary>
/// Initializes a module and prepares it to handle requests.
/// </summary>
/// <param name="context">An <see cref="T:System.Web.HttpApplication"/> that provides access to the methods, properties, and events common to all application objects within an ASP.NET application</param>
public void Init(HttpApplication context)
{
context.AuthenticateRequest += new EventHandler(context_AuthenticateRequest);
context.AuthorizeRequest += new EventHandler(context_AuthorizeRequest);
context.BeginRequest += new EventHandler(context_BeginRequest);
}
/// <summary>
/// Handles the BeginRequest event of the context control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
void context_BeginRequest(object sender, EventArgs e)
{
HttpApplication context = sender as HttpApplication;
if (context.User == null)
{
if (!TryAuthenticate(context))
{
SendAuthHeader(context);
return;
}
}
BasicUser bu = context.User.Identity as BasicUser;
context.Response.Write(string.Format("Welcome {0} with the password:{1}", bu.UserName, bu.Password));
}
/// <summary>
/// Sends the Unauthorized header to the user, telling the user to provide a valid username and password
/// </summary>
/// <param name="context">The context.</param>
private void SendAuthHeader(HttpApplication context)
{
context.Response.Clear();
context.Response.StatusCode = 401;
context.Response.StatusDescription = "Unauthorized";
context.Response.AddHeader("WWW-Authenticate", "Basic realm=\"Secure Area\"");
context.Response.Write("401 baby, please authenticate");
context.Response.End();
}
/// <summary>
/// Handles the AuthorizeRequest event of the context control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
void context_AuthorizeRequest(object sender, EventArgs e)
{
HttpApplication context = sender as HttpApplication;
BasicUser bu = context.User.Identity as BasicUser;
if (!authProvider.IsRequestAllowed(context.Request, bu))
{
SendNotAuthorized(context);
}
}
/// <summary>
/// Sends the not authorized headers to the user
/// </summary>
/// <param name="context">The context.</param>
private void SendNotAuthorized(HttpApplication context)
{
context.Response.Clear();
context.Response.StatusCode = 403;
context.Response.StatusDescription = "Forbidden";
context.Response.Write("403 baby, You are not allowed to see this");
context.Response.End();
}
/// <summary>
/// Tries to authenticate the user
/// </summary>
/// <param name="context">The context.</param>
/// <returns></returns>
private bool TryAuthenticate(HttpApplication context)
{
string authHeader = context.Request.Headers["Authorization"];
if (!string.IsNullOrEmpty(authHeader))
{
if (authHeader.StartsWith("basic ", StringComparison.InvariantCultureIgnoreCase))
{
string userNameAndPassword = Encoding.Default.GetString(
Convert.FromBase64String(authHeader.Substring(6)));
string[] parts = userNameAndPassword.Split(':');
IBasicUser bu = null;
if (authProvider.IsValidUser(parts[0], parts[1], out bu))
{
context.Context.User = new GenericPrincipal(bu, new string[] { });
if (!authProvider.IsRequestAllowed(context.Request, bu))
{
SendNotAuthorized(context);
return false;
}
return true;
}
}
}
return false;
}
/// <summary>
/// Handles the AuthenticateRequest event of the context control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
void context_AuthenticateRequest(object sender, EventArgs e)
{
HttpApplication context = sender as HttpApplication;
TryAuthenticate(context);
}
#endregion
}
/// <summary>
/// Sample IAuthProvider that will authenticate all users, and only allow access to user with a username of bjorn
/// </summary>
public class BasicAuthProvider : IAuthProvider
{
#region IAuthProvider Members
/// <summary>
/// Validates the username and password and returns whether or not the combination is a valid user
/// </summary>
/// <param name="userName">The username to validate</param>
/// <param name="password">The password to match</param>
/// <param name="user">The user object created</param>
/// <returns>
/// true if the combination is a valid user;false otherwise
/// </returns>
public bool IsValidUser(string userName, string password, out IBasicUser user)
{
user = new BasicUser();
user.UserName = userName;
user.Password = password;
return true;
}
/// <summary>
/// Determines whether or not the current request is allowed to continue for the given user
/// </summary>
/// <param name="request">The request to check</param>
/// <param name="user">The user</param>
/// <returns>
/// true if request is authorized;false otherwise
/// </returns>
public bool IsRequestAllowed(HttpRequest request, IBasicUser user)
{
return user.UserName == "bjorn";
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
//This is intentional, since we don't have any resources to free in this very simple sample IAuthProvider
}
#endregion
}
public class BasicUser : IBasicUser
{
/// <summary>
/// Gets or sets the username of the user
/// </summary>
/// <value>The username of the user.</value>
public string UserName
{
get;
set;
}
/// <summary>
/// Gets or sets the password.
/// </summary>
/// <value>The password.</value>
public string Password
{
get;
set;
}
#region IIdentity Members
/// <summary>
/// Gets the type of authentication used.
/// </summary>
/// <value></value>
/// <returns>
/// The type of authentication used to identify the user.
/// </returns>
public string AuthenticationType
{
get
{
return "Custom";
}
}
/// <summary>
/// Gets a value that indicates whether the user has been authenticated.
/// </summary>
/// <value></value>
/// <returns>true if the user was authenticated; otherwise, false.
/// </returns>
public bool IsAuthenticated
{
get
{
return UserName != null;
}
}
/// <summary>
/// Gets the name of the current user.
/// </summary>
/// <value></value>
/// <returns>
/// The name of the user on whose behalf the code is running.
/// </returns>
public string Name
{
get
{
return UserName;
}
}
#endregion
}
}