Protecting resources with HTTP auth

The Tonic resource and response classes have methods for sending HTTP auth response headers and for processing HTTP auth request headers. All we need to do to protect a resource is to add calls to these methods into the response handling methods we want to protect.

class BasicProtectedResource extends Resource {
	
	var $config = array();
	
	function basicDigestProtectedResource(&$adapter, $data = array()) {
		$this->config['username'] = 'user';
		$this->config['password'] = 'xyzzy';
		$this->config['realm'] = 'My Realm';
		parent::resource($adapter, $data);
	}
	
	function &get(&$request)
	{
		if (!$this->_authorisedByBasicAuth($request, $this->config)) {
			$response =& new Response(401);
			$response->sendBasicAuthHeader($this->config, $this);
			return $response;
		}
		return parent::get($request);
	}
	
}
lib/protectedResource.php

Our get() method above, checks to make sure that the username and password in the resource class match those given in the HTTP Basic auth request header. If not, we create a 401 response object and make it send Basic auth headers for the given realm.

class DigestProtectedResource extends Resource {
	
	var $config = array();
	
	function digestProtectedResource(&$adapter, $data = array()) {
		$this->config['username'] = 'user';
		$this->config['password'] = 'xyzzy';
		$this->config['realm'] = 'My Realm';
		$this->config['opaque'] = 'my opaque value';
		$this->config['privateKey'] = 'my secret key';
		$this->config['life'] = 5;
		$this->config['clientAddress'] = $_SERVER['HTTP_REMOTE_IP'];
		parent::resource($adapter, $data);
	}
	
	function &get(&$request)
	{
		if (!$this->_authorisedByDigestAuth($request, $this->config)) {
			$response =& new Response(401);
			$response->sendDigestAuthHeader($this->config, $this);
			return $response;
		}
		return parent::get($request);
	}
	
}
lib/digestProtectedResource.php

So Tonic allows us to easily protect our resources with HTTP auth and to control access from within PHP.

HTTP cookies

Some people aren't a fan of HTTP authentication, I don't know why, those Web browser auth dialogue boxes are awesome, but whatever the reasons, please like using HTML forms and cookies for authenticating people.

The problem with this of course is that people need to re-invent the wheel over and over again, and when it comes to making secure authentication, you want to make sure you've got it right.

So Tonic provides an easy way to use HTTP Cookies for authentication. It works pretty similar to HTTP Digest auth, identifying clients via a time and host dependent hash stored in a HTTP cookie. It is a little more involved than HTTP Basic or Digest auth due to the need to build a form resource and wire them together.

So let's build a form:

mimetype: text/html
class: SmartyResource

<h1>Cookie Auth</h1>

<form action="{$this->url}" method="post">
	<label>Username: <input type="text" name="username"></label>
	<label>Password: <input type="password" name="password"></label>
	<input type="submit">
</form>
resources/form.html

Now we need to protect our resource in a similar way to if we were using HTTP Digest, except on failure we send the form resource as the response, and on receiving a POST request containing the correct username and password we set a cookie containing an authorisation hash.

class CookieProtectedResource extends Resource {
	
	var $config = array();
	
	function CookieProtectedResource(&$adapter, $data = array()) {
		$this->config['username'] = 'user';
		$this->config['password'] = 'xyzzy';
		$this->config['realm'] = 'My Realm';
		$this->config['privateKey'] = 'my secret key';
		$this->config['life'] = 5;
		parent::resource($adapter, $data);
	}
	
	function &get(&$request)
	{
		if ($this->_authorisedByCookieAuth($request, $this->config)) {
			return parent::get($request);
		} else { // output login form
			$form =& Resource::find($this->_adapter, '/form.html');
			$response =& $form->get($request);
			if ($response->success()) {
				$response->statusCode = 401;
				$response->setDefaultHeaders($this, $request);
				$response->sendCookieAuthHeader($this->config, $this);
			}
			return $response;
		}
	}
	
	function &post(&$request)
	{
		if (
			isset($_POST['username']) && $_POST['username'] == $this->config['username'] &&
			isset($_POST['password']) && $_POST['password'] == $this->config['password']
		) {
			$response =& new Response(302, NULL, array('Location' => $request->rootUrl.$this->url)); // success, redirect to GET request on this resource
			$response->sendAuthCookie($this->config, $this);
			return $response;
		}
		return $this->get($request);
	}
}
lib/cookieProtectedResource.php

We need to pass in the HTTP method and the names of the fields used in our HTML form for the WWW-Authenticate header that will be sent in a failed HTTP response. Also, once we've generated our response from our form resource, we need to reset our response headers with a call to setDefaultHeaders() since we've changed our status code from a 200 success, to a 401 error response.

Back to documentation home
Created Feb 19, 2008, last modified Feb 19, 2008