ASP.NET Security – Securing Access to Files using the ASP.NET IHttpHandler

Posted by: Malcolm Sheridan , on 2/10/2009, in Category ASP.NET
Views: 91960
Abstract: The following article demonstrates how to use the custom HTTP handler to implement security in an ASP.NET application.
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.
 
Config IIS
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’
New Project
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.
HttpHandler
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.

Absolutely Awesome Book on C# and .NET

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!

What Others Are Reading!
Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+

Author
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


Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!
Comment posted by Aview on Thursday, February 12, 2009 8:36 AM
Can this principle be applied on a folder with multiple files? So let us say that a CEO has to be granted access to files .ceo, .deo, .seo and so on. What would be the simplest way to achive this requirement using a handler?
Comment posted by Malcolm Sheridan on Thursday, February 12, 2009 5:47 PM
@Aview
The HttpHandler you create can be used with multiple extensions, so if you want to secure .deo or .seo files, you'd need to add them into the web.config file.
Comment posted by Aview on Friday, February 13, 2009 5:26 AM
You mean one line for each file? I work on an application that lets the user create his own extension files. So there are many files that could be created by a user(even though it has not happened yet)
Comment posted by Malcolm Sheridan on Friday, February 13, 2009 6:26 AM
@Aview
You can have a comma separated string with the extension, so for example you could have path="*.ceo,*.seo" and the HttpHandler will process both of them.
Comment posted by Umer Rasheed on Tuesday, March 17, 2009 4:11 AM
Nice and simple article to understand Custom HTTP Handlers, Thanks, great job
Comment posted by Malcolm Sheridan on Tuesday, March 17, 2009 6:37 PM
@Umer Rasheed
Thanks for the positive feedback!  Much appreciated.
Comment posted by Eric on Wednesday, March 18, 2009 4:56 AM
A small note: This works fine in cassini(the development server), but if you want to publish this to the IIS you need to add an application extension for .ceo files. It's quite simple, just click the Add... button in the first pictured dialogue. It's also possible to run ALL requests through an ISAPI dll(like asp.net) by adding a wildcard map(further down on the same dialogue). If you want to use virtual files, meaning running the asp.net engine even when there isn't any physical file match found, then just unclick Verify that file exists in the map properties.
Comment posted by Dan on Wednesday, March 18, 2009 6:30 AM
Hey ok I think I can do this now.
Thanks
Comment posted by Kris on Thursday, March 19, 2009 3:43 AM
Hello,

Please add your site at http://www.sweebs.com. Sweebs.com is a place where other people can find you among the best sites on the internet!
Its just started and we are collecting the best found on the net! We will be delighted to have you in the sweebs listings.

Regards
Kris
Comment posted by venkat on Tuesday, March 24, 2009 2:32 AM
hi i have worked the above sample code..
In my system i have .net 2.0 so i have the erron web.config file
Could not load type 'Sample_24_03_2009.CustomHandler'.

project name is Sample_24_03_2009
and generic handler file name CustomHandler

in web.config

<httpHandlers>
         <add verb="*" path="*.ceo" type="Sample_24_03_2009.CustomHandler"/>
      </httpHandlers>

Let me know what the problem.. ?
how to resolve this issue ..
Let you email pls..??
Thanks
Comment posted by NewSteve on Wednesday, August 26, 2009 10:19 AM
Nice job on this article!  I've seen a few good ones and this was the most helpful.  Thanks for taking the time to write it!
Comment posted by sandip on Tuesday, November 24, 2009 12:45 PM
@venkat, I faced same problem, it worked after I added aspnet_isapi.dll in IIS. see following link from microsoft

http://support.microsoft.com/kb/834270

tag: asp.net custom handler not working
Comment posted by Nguyen Lan on Tuesday, August 7, 2012 2:14 AM
Hi All,
I have many extension file as *.mp3, *.mp4, *.avi...How have I setup it?
Comment posted by Nguyen Lan on Tuesday, August 7, 2012 3:18 AM
Hi All,
I have many extension file as *.mp3, *.mp4, *.avi...How have I setup it?
Comment posted by Rahul on Wednesday, June 26, 2013 5:42 AM
Hi All,
In my application i am using http handlers to secure PDF attachments. In Local its working perfect. But in Server its not working perfectly. In server i have iis 6.0. I added the extensions also in the iis server. But its not working.
<add verb="GET,HEAD" path="Downloads/*.pdf" type="SecurityHandler"  validate="false"/>
But the above thing is working in local perfectly.

If i place Like below its working in server also.
<add verb="GET,HEAD" path="*.pdf" type="SecurityHandler"  validate="false"/>

But i want to specify the specific path like "Downloads/*.pdf".
Please help me friends



Comment posted by Prafulla on Tuesday, September 17, 2013 6:17 AM
It is not working properly. I am able to access through my URL directly without being authenticated
Comment posted by CECO on Thursday, June 5, 2014 8:00 AM
The code don`t work correctly Which name is on zip file in the links bellow HERE
"The entire source code of this article in C# and VB.NET can be downloaded over here."

bye