<?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>Extensible Development &#187; mod_dav_fs</title>
	<atom:link href="http://blog.itwarlocks.com/tag/mod_dav_fs/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.itwarlocks.com</link>
	<description>Profession blog about Software Engineering, Web, *nix, Processes, Tools and more.</description>
	<lastBuildDate>Mon, 29 Mar 2010 12:20:30 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=abc</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>PHP based authentication for mod_dav</title>
		<link>http://blog.itwarlocks.com/2009/04/27/php-based-authentication-for-mod_dav/</link>
		<comments>http://blog.itwarlocks.com/2009/04/27/php-based-authentication-for-mod_dav/#comments</comments>
		<pubDate>Mon, 27 Apr 2009 12:24:41 +0000</pubDate>
		<dc:creator><span property="dc:creator" resource="http://blog.itwarlocks.com/2009/04/27/php-based-authentication-for-mod_dav/">Jeffrey Ridout</span></dc:creator>
				<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[authentication]]></category>
		<category><![CDATA[mod_auth]]></category>
		<category><![CDATA[mod_auth_script]]></category>
		<category><![CDATA[mod_dav]]></category>
		<category><![CDATA[mod_dav_fs]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[WebDAV]]></category>

		<guid isPermaLink="false">http://blog.itwarlocks.com/?p=43</guid>
		<description><![CDATA[To be able to create a Document Management System in Word using WebDAV on Apache webserver, I did some research on mod_dav, an Apache module to provide WebDAV support. It appears that the authaurisation part of mod_dav is limited to "allow all" / "deny all", which did not quite suite my needs. The solution needed more fine-grained authorisation on a per-directory level. Another problem was that the authentication and authorisation data was in a database.]]></description>
			<content:encoded><![CDATA[<h3>Introduction</h3>
<p>To be able to create a <a href="http://blog.itwarlocks.com/2009/04/24/document-management-system-in-word-using-webdav/" target="_self">Document Management System in Word using WebDAV</a> on <a title="Apache webserver official website." href="http://httpd.apache.org/" target="_blank">Apache webserver</a>, I did some research on <a title="Mod_dav's official website." href="http://www.webdav.org/mod_dav/" target="_blank">mod_dav</a>, an Apache <a title="Official Apache webserver module registry." href="http://modules.apache.org/" target="_blank">module</a> to provide <a id="aptureLink_vPPLLegkod" title="Information on WebDAV on Wikipedia.org" href="http://en.wikipedia.org/wiki/WebDAV">WebDAV</a> support. It appears that the authaurisation part of mod_dav is limited to &#8220;allow all&#8221; / &#8220;deny all&#8221;, which did not quite suite my needs. The solution needed more fine-grained authorisation on a per-directory level. Another problem was that the authentication and authorisation data was in a database.<span id="more-43"></span></p>
<h3>Issues</h3>
<ol>
<li>Mod_dav does not have a fine-grained authorisation system on a per-directory level.</li>
<li>Directory structure is known but unstable.</li>
<li>Authorisation data is held in a database and requires complex SQL.</li>
</ol>
<h3>Solution</h3>
<h4>Fine-grained authorisation</h4>
<p>I started by looking at <a title="Mod_auth's official website." href="http://httpd.apache.org/docs/2.0/mod/mod_auth.html" target="_blank">mod_auth</a> and <a title="Mod_auth_dbd's official website." href="http://httpd.apache.org/docs/2.2/mod/mod_authn_dbd.html" target="_blank">mod_auth_dbd</a> (in combination with <a title="Mod_dbd's official website." href="http://httpd.apache.org/docs/2.2/mod/mod_dbd.html" target="_blank">mod_dbd</a>), but the SQL useable by mod_dbd only received the username and password as parameters, not the requested <a id="aptureLink_c3qbx5wU5Q" title="Information on URI on Wikipedia.org" href="http://en.wikipedia.org/wiki/Uniform%20Resource%20Identifier">URI</a>. What mod_auth module could possibly be used? The solution to this was quite unexpected: <a title="Mod_auth_script's official website." href="http://mod-auth-script.sourceforge.net/" target="_blank">mod_auth_script</a>.</p>
<p>Mod_auth_script allows CGI or <a title="PHP's official website." href="http://www.php.net" target="_blank">PHP</a> scripts to handle the authorisation. By looking at the <a title="PHP.net official documentation on $_SERVER predefined variables." href="http://www.php.net/manual/en/reserved.variables.server.php" target="_blank">REQUEST_URI</a> the script can easily decide to simulate authorisation by invalidating the authorisation.</p>
<p>I created a PHP script that at first would log the REQUEST_URI and allow access for any username and password. All that is left now is to handle authorisation based on the directory structure and fetch the real authorisation from the database.</p>
<div>
<div class="wp-caption" style="text-align: left">Listing 1: Apache config</div>
<pre class="brush: xml">
&lt;Location /dav&gt;
	Options			+Indexes
	Dav				On
	AuthType		Basic
	AuthName		&quot;PHP based authentication for mod_dav&quot;
	AuthScriptFile	/any_full_path_your_apache_can_get_to/.auth.php
	Require			valid-user
&lt;/Location&gt;
</pre>
</div>
<div>
<div class="wp-caption" style="text-align: left">Listing 2: .auth.php (version 0.0.1)</div>
<pre class="brush: php">
&lt;?php
/**
 * PHP based authentication for mod_dav
 * @author Jeffrey Ridout
 * @link http://blog.itwarlocks.com
 * @license http://creativecommons.org/licenses/by-sa/3.0
 * @date 2009-04-27
 * @version 0.0.1
 */

/**
 * $_SERVER[&#039;REQUEST_URI&#039;] contains the location accessed by the WebDAV client.
 * Using parse_url enables easy access to all URL parts.
 */
$requestURI = parse_url($_SERVER[&#039;REQUEST_URI&#039;]);

/**
 * Accessing some pages directly, like a page containing phpinfo(), will result in several
 * calls to .auth.php. These do not need to be logged.
 */
if ($requestURI[&#039;path&#039;] != $_SERVER[&#039;SCRIPT_NAME&#039;]) {
	$logFile = fopen(&#039;auth.log&#039;, &#039;a&#039;);
	fwrite($logFile, &quot;${_SERVER[&#039;PHP_AUTH_USER&#039;]}:${_SERVER[&#039;PHP_AUTH_PW&#039;]}@${requestURI[&#039;path&#039;]}\n&quot;);
	fclose($logFile);
}

/**
 * At this stage we always allow access.
 * mod_auth_script catches custom headers to define the result to mod_auth.
 * auth-script:allow|deny|prompt Defines the authentication result.
 */
header(&#039;auth-script:allow&#039;);

/* EOF */
?&gt;
</pre>
</div>
<h4>Directory structure</h4>
<p>The sub-directories are named according to a strict rule, but they are unknown to exist at design-time. Therefore the script needs to analyse the destination location and extract the key to be used for authorisation.<sup>1</sup></p>
<div>
<div class="wp-caption" style="text-align: left">Listing 3: Directory structure</div>
<pre class="brush: text">
/&lt;Day&gt;/&lt;Month&gt;/&lt;Year&gt;/&lt;MemberID&gt;
	&lt;Day&gt;:		00 - 31
	&lt;Month&gt;:		00 - 12
	&lt;Year&gt;:		00 - 99
	&lt;MemberID&gt;:	DDMMYY#####
</pre>
</div>
<div id="attachment_77" class="wp-caption alignnone" style="width: 118px"><a title="Directory structure" rel="lightbox-43" href="http://blog.itwarlocks.com/wp-content/uploads/2009/04/directory_structure.png"><img class="size-medium wp-image-77" title="Directory structure" src="http://blog.itwarlocks.com/wp-content/uploads/2009/04/directory_structure-108x300.png" alt="Directory structure" width="108" height="300" /></a><p class="wp-caption-text">Directory structure</p></div>
<p>This directory structure allows for a quite straight forward check to get the MemberID.<sup>2</sup></p>
<div>
<div class="wp-caption" style="text-align: left">Listing 3: .auth.php (version 0.0.2)</div>
<pre class="brush: php">
&lt;?php
/**
 * PHP based authentication for mod_dav
 * @author Jeffrey Ridout
 * @link http://blog.itwarlocks.com
 * @license http://creativecommons.org/licenses/by-sa/3.0
 * @date 2009-04-27
 * @version 0.0.2
 */

/**
 * $_SERVER[&#039;REQUEST_URI&#039;] contains the location accessed by the WebDAV client.
 * Using parse_url enables easy access to all URL parts.
 */
$requestURI = parse_url($_SERVER[&#039;REQUEST_URI&#039;]);

/**
 * Accessing some pages directly, like a page containing phpinfo(), will result in several
 * calls to .auth.php. These do not need to be logged.
 */
if ($requestURI[&#039;path&#039;] != $_SERVER[&#039;SCRIPT_NAME&#039;]) {
	$logFile = fopen(&#039;auth.log&#039;, &#039;a&#039;);
	fwrite($logFile, &quot;${_SERVER[&#039;PHP_AUTH_USER&#039;]}:${_SERVER[&#039;PHP_AUTH_PW&#039;]}@${requestURI[&#039;path&#039;]}\n&quot;);
	fclose($logFile);
}

/**
 * At stage 2 we can simulate a real authorisation lookup by using a simple array.
 * mod_auth_script catches custom headers to define the result to mod_auth.
 * auth-script:allow|deny|prompt Defines the authentication result.
 */
$blocked = array (
	&#039;01010154321&#039;,
	&#039;31037912345&#039;
);

/**
 * The directory name to search for might be in the path or destination filename.
 * .../blocked-dir
 * or
 * .../blocked-dir/
 * or
 * .../blocked-dir/...
 */
$path = dirname($requestURI[&#039;path&#039;]);
$dir = basename($path);
$match = basename($rURL[&#039;path&#039;]);
if (preg_match(&#039;#$\d{11}^#&#039;, $dir)) {
	$match = $dir;
}
if (!in_array($match, $blocked)) {
	header(&#039;auth-script:allow&#039;);
} else {
	/* Simulate authorisation by denying access.
	 * Normal authentication would return auth-script:prompt
	 */
	header(&#039;auth-script:deny&#039;);
}

/* EOF */
?&gt;
</pre>
</div>
<h4>Authorisation data</h4>
<p>The data that determines the authorisation can come from different sources; files, LDAP, RADIUS, database, &#8230;</p>
<p>In my case the authorisation result was retrieved from complex SQL using a stored procedure in a Sybase Database.</p>
<p>Whatever you use as your source of authentication/authorisation, remember that request can be asynchrounous and parallel. For a file base method that means never locking the file and opening it as &#8220;read-only&#8221;, for an external connection based method, it means using persistent connections.</p>
<h3>Conclusion</h3>
<p>Just because mod-dav and mod_auth don&#8217;t support your exact needs, doesn&#8217;t mean there is no solution. Using mod_auth_script to create your own tailored flexible solution works perfectly. As an added bonus this adds a new processing layer to PHP by allowing PHP to be executed at a much earlier stage. Using a PHP script to authorise also allows authorisation of non-existing destination URLs or destinations which access is based on complex business logic.</p>
<p><a href="/license/#cc-by-sa"><img class="size-full wp-image-95 alignleft" style="margin-right: 1.5em" title="Creative Commons: Attribution Share Alike" src="http://blog.itwarlocks.com/wp-content/uploads/2009/04/cc-by-sa_88x31.png" alt="Creative Commons: Attribution Share Alike" width="88" height="31" /></a>All code in this post is licensed under Creative Commons Attribution Share Alike.</p>
<ol class="footnotes"><li id="footnote_0_43" class="footnote">You may notice that year only has 2 digits. so no, it&#8217;s not Y2K safe&#8230;</li><li id="footnote_1_43" class="footnote">MemberID in this case is the Norwegian version of a social security number.</li></ol>]]></content:encoded>
			<wfw:commentRss>http://blog.itwarlocks.com/2009/04/27/php-based-authentication-for-mod_dav/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using disk
Page Caching using disk (enhanced) (user agent is rejected)

Served from: blog.itwarlocks.com @ 2010-09-09 01:17:36 -->