ASP.NET Security – Securing Access to Files using the ASP.NET IHttpHandler
The IHttpHandler interface is an underused interface in my humble opinion. It gives the developer the ability to process HTTP requests with custom HTTP handlers. Have you ever wondered why aspx pages are processed by ASP.NET?
To answer that question, you need to open the Application Configuration dialog in IIS. This example uses IIS 6. The Application Configuration is located on the Home Directory tab in IIS. Clicking the configuration button opens the Application Configuration dialog shown below. Highlighted is the .aspx Application Extension. The executable path for this extension is c:\windows\microsoft.net\framework\v2.0.50727\aspnet_isapi.dll.
When IIS receives a request and the extension is .aspx, it directs the request to the aspnet_isapi.dll. The aspnet_isapi.dll will check the web.config file located in C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG to see what class will handle the request. The following code is a small extract of the web.config file:
<httpHandlers>
<add path="*.aspx" verb="*" type="System.Web.UI.PageHandlerFactory" validate="True"/></httpHandlers>
In the code above, the httpHanders section has an entry for *.aspx. All *.aspx requests will be processed by the System.Web.UI.PagehandlerFactory class.
You as the developer have the ability to process HTTP requests with customer HTTP handlers. In the following article I’ll take you through a typical business scenario where custom HTTP handlers are great. Here are the business rules we must follow:
· *.ceo files can only be viewed by the CEO
· The CEO must be logged into the website
Open Visual Studio 2008 and choose File > New > Web > ASP.NET Web Application. C# users can name the application as ‘HttpHandler’. VB.NET users can call it ‘HttpHandlerVB’
Right click the project and choose Add > New Folder. Rename the folder to SecuredFiles. This is where the CEO files will be. Add a new text file to this folder and rename the extension to *.ceo.
Right click the project and choose Add > New Item > Generic Handler.
Open the CustomHandler.ashx file and add the following code:
C#
public class CustomHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
if (context.User.Identity.IsAuthenticated &&
context.User.Identity.Name.ToUpper() == "CEO")
{
DownloadFile(context);
}
else
{
context.Response.Write("No access unless you’re the CEO!!!");
}
}
protected void DownloadFile(HttpContext context)
{
context.Response.Buffer = true;
context.Response.Clear();
context.Response.AddHeader("content-disposition", context.Request.Url.AbsolutePath);
context.Response.ContentType = "text/plain";
context.Response.WriteFile(context.Server.MapPath(context.Request.Url.AbsolutePath));
}
public override string ToString()
{
return "Some generic description to define what this class does..";
}
public bool IsReusable
{
get
{
return false;
}
}
}
VB.NET
Public Class CustomHandler
Implements System.Web.IHttpHandler
Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
If context.User.Identity.IsAuthenticated AndAlso context.User.Identity.Name.ToUpper() = "CEO" Then
DownloadFile(context)
Else
context.Response.Write("No access unless you're the CEO!!!")
End If
End Sub
Protected Sub DownloadFile(ByVal context As HttpContext)
context.Response.Buffer = True
context.Response.Clear()
context.Response.AddHeader("content-disposition", context.Request.Url.AbsolutePath)
context.Response.ContentType = "text/plain"
context.Response.WriteFile(context.Server.MapPath(context.Request.Url.AbsolutePath))
End Sub
Public Overrides Function ToString() As String
Return "Some generic description to define what this class does.."
End Function
ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
Get
Return False
End Get
End Property
End Class
The CustomHandler class implements the IHttpHandler interface. Implementing this interface allows you to create custom HTTP handlers. The two methods that we must implement are ProcessRequest and IsReusable. ProcessRequest accepts the HttpContext as a parameter, which contains all the information about the HTTP request. We want this HTTP handler to check HttpContext to ensure the HTTP request is from an authenticated user and they’re username is CEO.
Next you must update the web.config file and add a new entry to the httpHandlers section. The following xml is required:
<httpHandlers>
<add verb="*" path="*.ceo" type="WebApplication1.CustomHandler"/>
This tells our website that if there are any HTTP requests for pages that have a *.ceo extension, they will be processed by the WebApplication1.CustomHandler class.
To complete this demo you’ll need to update the web.config file to use Forms authentication. The following xml is required:
<authentication mode="Forms">
<forms loginUrl="~/Login.aspx" defaultUrl="~/Default.aspx" />
</authentication>
<authorization>
<deny users="?"/>
<allow users="*"/>
</authorization>
Right click on the project and choose Add > New Item > Web Form. Add a Login control to the page and add the following code to the Authenticate event:
C#
FormsAuthentication.Authenticate(Login1.UserName, Login1.Password);
FormsAuthentication.RedirectFromLoginPage(Login1.UserName, true);
VB.NET
Protected Sub Login1_Authenticate(ByVal sender As Object, ByVal e As AuthenticateEventArgs)
FormsAuthentication.Authenticate(Login1.UserName, Login1.Password)
FormsAuthentication.RedirectFromLoginPage(Login1.UserName, True)
End Sub
The authentication would normally be verified against a database, but for this example we’ll let everyone through. Type in any username and password of your choice. Once the user has logged in they’ll be redirected to the Default.aspx page. There is a link to the CEO file. Clicking on that link will direct the HTTP request to the CustomerHandler class. If the user has logged in as CEO (username: Ceo) they will be able to download the file. If not, they will see a message on the screen that says No access unless you’re the CEO!!!.
HTTP handlers are a great way to write generic functions to handle HTTP requests. You can utilize HTTP handlers to process both GET and POST requests. I’ve found them useful for the scenario above and I’m positive you can take this example and come up with other ways to utilize this powerful tool.
The entire source code of this article in C# and VB.NET can be downloaded over here.
This article has been editorially reviewed by Suprotim Agarwal.
C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.
We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).
Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.
Click here to Explore the Table of Contents or Download Sample Chapters!
Was this article worth reading? Share it with fellow developers too. Thanks!
Malcolm Sheridan is a Microsoft awarded MVP in ASP.NET, a Telerik Insider and a regular presenter at conferences and user groups throughout Australia and New Zealand. Being an ASP.NET guy, his focus is on web technologies and has been for the past 10 years. He loves working with ASP.NET MVC these days and also loves getting his hands dirty with jQuery and JavaScript. He also writes technical articles on ASP.NET for SitePoint and other various websites. Follow him on twitter @
malcolmsheridan