Commit 80bec815 authored by Taddeus Kroes's avatar Taddeus Kroes

Started implementing Security class, and added some documentation on what the result should be

parent 6fb07ae5
<?php
/**
* Security functions for user authentication and authorization.
*
* Usage example:
* <code>
* try {
* $security = webbasics\Security::getInstance();
*
* // Authentication: can the origin of the request be trusted?
*
* // Verify that a user is logged in
* $security->requireLogin();
*
* // Use a security token to verify that the request originated from a
* // trusted page. This is recommended if, for example, the script makes
* // changes to the database
* $security->requireToken($_REQUEST['token']);
*
* // Authorization: is the user allowed to request this page?
* $security->requireUserRole('admin');
*
* ...
*
* // Pass token to template so that it can be used in a submitted form or
* // AJAX request
* $template->set('token', $auth->generateToken());
*
* ...
*
* } catch(webbasics\AuthenticationFailed $e) {
* die('Get lost hacker!');
* } catch(webbasics\AuthorizationFailed $e) {
* http_response_code(403);
* die('You are not authorized to view this page.');
* }
* </code>
*
* Corresponding login controller example:
* <code>
* // Find the user using ActiveRecord (not part of the WebBasics library)
* $user = User::first(array('username' => $_POST['username']));
*
* if (!$user)
* die('Invalid username');
*
* // Current user is part of the
* $security = webbasics\Security::getInstance();
* $security->setUser($user);
*
* // Simple: use a plain password
* if (!$security->attemptPassword($user, $_POST['password']))
* die('Invalid password');
*
* // More secure: hash the password in a javascript function before
* // submitting the login form
* if (!$security->attemptPasswordHash($user, $_POST['password_hash']))
* die('Invalid password');
* </code>
*
* And the User model implementation used in the example above:
* <code>
* use PHPActiveRecord\Model;
* use webbasics\AuthenticatedUser;
* use webbasics\AuthorizedUser;
*
* class User extends Model implements AuthenticatedUser, AuthorizedUser {
* function getUsername() {
* return $this->username;
* }
*
* function getPasswordHash() {
* return $this->password;
* }
*
* function getCookieToken() {
* return $this->cookie_token;
* }
*
* function setCookieToken($token) {
* $this->update_attribute('cookie_token', $token);
* }
*
* function getRegistrationToken() {
* return $this->registration_token;
* }
*
* function setRegistrationToken($token) {
* $this->update_attribute('registration_token', $token);
* }
*
* function getRole() {
* return $this->role;
* }
* }
* </code>
*
* @author Taddeus Kroes
* @date 05-10-2012
*/
namespace webbasics;
require_once 'base.php';
interface AuthenticatedUser {
function getUsername();
function getPasswordHash();
function getCookieToken();
function setCookieToken($token);
function getRegistrationToken();
function setRegistrationToken($token);
}
interface AuthorizedUser {
function getRole();
}
class Security {
const SESSION_TOKEN_NAME = 'auth_token';
const SESSION_NAME_USERDATA = 'auth_userdata';
private static $instance;
private $user;
static function getInstance() {
if (self::$instance === null)
self::$instance = new self;
return self::$instance;
}
private function __construct() {}
function generateToken() {
$session = Session::getInstance();
$token = sha1(self::generateRandomString(10));
$session->set(self::SESSION_TOKEN_NAME, $token);
return $token;
}
function requireToken($request_token) {
if ($request_token != $this->getSavedToken())
throw new AuthenticationFailed('invalid token "%s"', $request_token);
}
private function getSavedToken() {
$session = Session::getInstance();
if (!$session->isRegistered(self::SESSION_TOKEN_NAME))
throw new AuthenticationError('no token saved in session');
return $session->get(self::SESSION_TOKEN_NAME);
}
function sessionDataExists() {
return Session::getInstance()->areRegistered(array(
self::SESSION_TOKEN_NAME, self::SESSION_NAME_USERDATA));
}
function requireLogin() {
}
function requireUserRole() {
}
//function setUser(AuthenticatedUser $user) {
// $this->user = $user;
//}
static function generateRandomString($length) {
$CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUWXYZ01234567890123456789';
$string = '';
srand(time());
for ($i = 0; $i < $length; $i++)
$string .= $CHARS[rand(0, strlen($CHARS) - 1)];
return $string;
}
}
class AuthenticationError extends FormattedException {}
class AuthenticationFailed extends FormattedException {}
class AuthorizationError extends FormattedException {}
class AuthorizationFailed extends FormattedException {}
?>
\ No newline at end of file
<?php
require_once 'SingletonTestCase.php';
require_once 'security.php';
use webbasics\Security;
class SecurityTest extends SingletonTestCase {
function getClassName() {
return 'webbasics\Security';
}
}
?>
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment