<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Chad Scharf&#039;s Weblog &#187; IIS</title>
	<atom:link href="http://www.chadscharf.com/index.php/categories/iis/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.chadscharf.com</link>
	<description>It&#039;s always time to upgrade!</description>
	<lastBuildDate>Fri, 28 Oct 2011 22:14:08 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>Protecting PDF files in IIS 6 using Forms Authentication</title>
		<link>http://www.chadscharf.com/index.php/2008/04/protecting-pdf-files-in-iis-6-using-forms-authentication/</link>
		<comments>http://www.chadscharf.com/index.php/2008/04/protecting-pdf-files-in-iis-6-using-forms-authentication/#comments</comments>
		<pubDate>Fri, 04 Apr 2008 03:32:00 +0000</pubDate>
		<dc:creator>Chad</dc:creator>
				<category><![CDATA[ASP.NET Development]]></category>
		<category><![CDATA[IIS]]></category>
		<category><![CDATA[ihttphandler]]></category>
		<category><![CDATA[iis 6]]></category>
		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://chadscharf.com/post.aspx?id=cb52d8b4-d442-418d-a5d3-d94c4ece3c86</guid>
		<description><![CDATA[Problem We have a very simple ASP.NET web site that uses the built in Forms Authentication provider out of the box for users, roles and security. Our internal business customers have hundreds of PDF documents that should only be accessible for specific users or roles within the company. A majority of users that need access [...]<p><a href="http://www.chadscharf.com/index.php/2008/04/protecting-pdf-files-in-iis-6-using-forms-authentication/">Protecting PDF files in IIS 6 using Forms Authentication</a> is a post from: <a href="http://www.chadscharf.com">Chad Scharf&#039;s Weblog</a>. For software consulting services please visit <a href="http://www.scharfholdings.com">Scharf Holdings, LLC</a></p>
]]></description>
			<content:encoded><![CDATA[<h2>Problem</h2>
<p>We have a very simple ASP.NET web site that uses the built in Forms Authentication provider out of the box for users, roles and security. Our internal business customers have hundreds of PDF documents that should only be accessible for specific users or roles within the company. A majority of users that need access to these files are outside the company firewall and do not have VPN access. The site must be hosted on Windows Server 2003 using IIS 6.</p>
<p>Although this problem could be solved in many ways, I wanted to make the site as dynamic as possible since our web master would need to make constant changes to files, structure, etc and we did not want a programmer having to make changes to specific code or a DBA maintaining a database of files, paths, etc. We also wanted to avoid using a network file share to host the files or wrap the site using Plain Text authentication.</p>
<p>The issue is Forms Authentication provides no security on the request stack within IIS 6 as it does in IIS 7. Because we can&#8217;t extend this, our files would be wide open to any attacker or malicious employee looking to download the file by figuring out the link or by users who had bookmarked certain files and later after they had been removed from that role, being able to still access them.</p>
<h2>The Solution</h2>
<p>The solution seemed easy. Some content management systems allow you to store files in databases, or use URL re-writing to accomplish this task, but I wanted something simpler and easier to extend or duplicate in the future. We&#8217;re all pretty familiar with IHttpHandler and it seemed since that&#8217;s the way the prior, more complex solutions perform this feat more often than not, why not give it a shot for this: <span id="more-9"></span></p>
<h3>Setup</h3>
<p>In order for ASP.NET to recognize the request for the PDF file and wrap it with the configured authentication method, we have to tell IIS to use the same ASAPI engine that is uses for ASPX, ASMX, etc.</p>
<p>I opened the properties for the web site/virtual directory in IIS Manager, clicked on the Configurationâ€¦ button located within the application settings section and the first tab contains my ISAPI extensions:</p>
<p><img src="/files/040408_0532_ProtectingP1.jpg" alt="" width="504" height="476" /></p>
<p>Then, I clicked the &#8220;Addâ€¦&#8221; button to add the new .pdf extension using the same ASP.NET ISAPI DLL, c:\windows\microsoft.net\framework\v2.0.50727\aspnet_isapi.dll for GET requests of .pdf:</p>
<p><img src="/files/040408_0532_ProtectingP2.jpg" alt="" width="504" height="293" /></p>
<p>I&#8217;m using the &#8220;Verify that file exists&#8221; because the file really will exists, it&#8217;s not in a database or remote location or anything fancy like that.</p>
<p>Once that&#8217;s done, you&#8217;ll notice if you have security set up on your site and in your web.config file around a PDF file, say for:</p>
<p>&lt;location path=&#8221;MyFile.pdf&#8221;&gt;&lt;web.config&gt;&lt;authorization&gt;&lt;deny users=&#8221;?&#8221; /&gt;&lt;/authorization&gt;&lt;/web.config&gt;&lt;/location&gt;</p>
<p>And you are not authenticated; you will immediately be taken to the login screen. Once you log in however you will get a compilation error page. This is because the ASP.NET CLR is trying to compile/execute your PDF as an ASP.NET extension file and it cannot for obvious reasons, it doesn&#8217;t know how to handle your file.</p>
<h3>IHttpHandler</h3>
<p>Now that security is taken care of, I needed to let ASP.NET know what to do with a PDF file. To do this I needed to create a simple IHttpHandler:</p>
<p><span style="font-size: 7pt; font-family: Courier New"><span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: #2b91af">PdfHandler</span> : IHttpHandler </span><br />
<span style="font-size: 7pt; font-family: Courier New">{ </span><br />
<span style="font-size: 7pt; font-family: Courier New">Â Â Â Â <span style="color: blue">public</span> PdfHandler() { } </span><br />
<span style="font-size: 7pt; font-family: Courier New">Â Â Â Â <span style="color: blue">public</span> <span style="color: blue">void</span> ProcessRequest(HttpContext context) </span><br />
<span style="font-size: 7pt; font-family: Courier New">Â Â Â Â { </span><br />
<span style="font-size: 7pt; font-family: Courier New">Â Â Â Â Â Â Â Â <span style="color: blue">string</span> path = context.Request.PhysicalPath; </span><br />
<span style="font-size: 7pt; font-family: Courier New">Â Â Â Â Â Â Â Â <span style="color: blue">string</span> name = path.Split(<span style="color: #a31515">&#8216;\\&#8217;</span>)[path.Split(<span style="color: #a31515">'\\'</span>).Length - 1]; </span><br />
<span style="font-size: 7pt; font-family: Courier New">Â Â Â Â Â Â Â Â <span style="color: blue">if</span> (!<span style="color: blue">string</span>.IsNullOrEmpty(path) &amp;&amp; path.ToLower().EndsWith(<span style="color: #a31515">&#8220;.pdf&#8221;</span>)) </span><br />
<span style="font-size: 7pt; font-family: Courier New">Â Â Â Â Â Â Â Â { </span><br />
<span style="font-size: 7pt; font-family: Courier New">Â Â Â Â Â Â Â Â Â Â Â Â context.Response.ClearHeaders(); </span><br />
<span style="font-size: 7pt; font-family: Courier New">Â Â Â Â Â Â Â Â Â Â Â Â context.Response.ClearContent(); </span><br />
<span style="font-size: 7pt; font-family: Courier New">Â Â Â Â Â Â Â Â Â Â Â Â context.Response.Clear(); </span></p>
<p><span style="font-size: 7pt; font-family: Courier New">Â Â Â Â Â Â Â Â Â Â Â Â context.Response.Charset = <span style="color: blue">null</span>; </span><br />
<span style="font-size: 7pt; font-family: Courier New">Â Â Â Â Â Â Â Â Â Â Â Â context.Response.ContentType = <span style="color: #a31515">&#8220;application/pdf&#8221;</span>; </span><br />
<span style="font-size: 7pt; font-family: Courier New">Â Â Â Â Â Â Â Â Â Â Â Â context.Response.AddHeader(<span style="color: #a31515">&#8220;Content-Type&#8221;</span>, <span style="color: #a31515">&#8220;application/pdf&#8221;</span>); </span><br />
<span style="font-size: 7pt; font-family: Courier New">Â Â Â Â Â Â Â Â Â Â Â Â context.Response.AppendHeader(<span style="color: #a31515">&#8220;Content-Disposition&#8221;</span>, <span style="color: blue">string</span>.Format(<span style="color: #a31515">&#8220;inline;filename={0}&#8221;</span>, name)); </span><br />
<span style="font-size: 7pt; font-family: Courier New">Â Â Â Â Â Â Â Â Â Â Â Â context.Response.WriteFile(path); </span><br />
<span style="font-size: 7pt; font-family: Courier New">Â Â Â Â Â Â Â Â } </span><br />
<span style="font-size: 7pt; font-family: Courier New">Â Â Â Â Â Â Â Â <span style="color: blue">else </span></span><br />
<span style="font-size: 7pt; font-family: Courier New">Â Â Â Â Â Â Â Â Â Â Â Â <span style="color: blue">throw</span> <span style="color: blue">new</span> <span style="color: #2b91af">FileNotFoundException</span>(<span style="color: #a31515">&#8220;The page requested is invalid&#8221;</span>, path); </span><br />
<span style="font-size: 7pt; font-family: Courier New">Â Â Â Â } </span><br />
<span style="font-size: 7pt; font-family: Courier New">Â Â Â Â <span style="color: blue">public</span> <span style="color: blue">bool</span> IsReusable { <span style="color: blue">get</span> { <span style="color: blue">return</span> <span style="color: blue">false</span>; } } </span><br />
<span style="font-size: 7pt; font-family: Courier New">} </span></p>
<p>This class, PdfHandler, implements the IHttpHandler interface which implements a proper, IsReuseable (which this one is not) and a method, ProcessRequest, which does the dirty work using the passed in HttpContext. In this case, I get the physcial path of the file being requested (remember that the file should always exist, otherwise IIS would have kicked the request back out) and then parse the name of the file, double check (using some sanity checking) that the file is indeed a PDF that we&#8217;re dealing with, clearing the response, setting the MIME type in the header and using the Response.WriteFile(filePath) method to output the file directly through the buffered response stream to the client. This would all be transparent to the user and the response time, although not as fast as IIS serving the file directly, is still acceptible for my means of use.</p>
<h3>Web.Config Changes</h3>
<p>Once I had the handler written for my PDF files, I just needed to let ASP.NET on the application level to use my handler for all PDF requests coming into the virtual directory/web site. I did this by using the configuration section under &lt;web.config&gt;, &lt;httpHandlers&gt;:</p>
<p><span style="font-size: 7pt; font-family: Courier New"><span style="color: blue">&lt;</span><span style="color: #a31515">httpHandlers</span><span style="color: blue">&gt; </span></span><br />
<span style="font-size: 7pt; font-family: Courier New"><span style="color: blue">Â Â Â Â &lt;</span><span style="color: #a31515">add</span><span style="color: blue"> </span><span style="color: red">verb</span><span style="color: blue">=</span>&#8220;<span style="color: blue">GET</span>&#8220;<span style="color: blue"> </span><span style="color: red">path</span><span style="color: blue">=</span>&#8220;<span style="color: blue">*.pdf</span>&#8220;<span style="color: blue"> </span><span style="color: red">type</span><span style="color: blue">=</span>&#8220;<span style="color: blue">PdfHandler</span>&#8220;<span style="color: blue"> </span><span style="color: red">validate</span><span style="color: blue">=</span>&#8220;<span style="color: blue">false</span>&#8220;<span style="color: blue">/&gt; </span></span><br />
<span style="font-size: 7pt; font-family: Courier New"><span style="color: blue">&lt;/</span><span style="color: #a31515">httpHandlers</span><span style="color: blue">&gt; </span></span></p>
<p>With this entry in there now, everything is working great and now my web master and I can manage security in the application simply by adding folders and new web.config files with an &lt;authorization/&gt; section along with the built-in membership/role management that comes standard in ASP.NET application services.</p>
<p>Now if only I can get them on IIS 7, this entire article would become obsolete, but life would definitely be better!</p>
<p><a href="http://www.chadscharf.com/index.php/2008/04/protecting-pdf-files-in-iis-6-using-forms-authentication/">Protecting PDF files in IIS 6 using Forms Authentication</a> is a post from: <a href="http://www.chadscharf.com">Chad Scharf&#039;s Weblog</a>. For software consulting services please visit <a href="http://www.scharfholdings.com">Scharf Holdings, LLC</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.chadscharf.com/index.php/2008/04/protecting-pdf-files-in-iis-6-using-forms-authentication/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
	</channel>
</rss>

