<?php
// ------------------------------------------------------------
// Stratos PHP Framework
// Copyright (c) 2006-2007 Sephira Software, LLC
//
// This file is subject to the Stratos PHP Framework license
// which you should have received along with this file. The
// license is also accessible on the web at the following URI:
// http://www.stratosframework.com/wiki/Manual/License
// If you did not receive a copy of the Stratos PHP Framework
// license or you are unable to obtain it through the web,
// please send an e-mail to hide@address.com so a copy
// can be sent to you.
// ------------------------------------------------------------
/**
* This file contains the StratosAuth plugin class for the Stratos PHP Framework.
*
* @author Joshua Carnett
* @copyright Copyright (c) 2006-2007 Sephira Software, LLC
* @license http://www.stratosframework.com/wiki/Manual/License
* @package StratosAuth
*/
/**
*
*/
define('STRATOS_AUTH_MSG_DBERR', 'An error occurred while determining user privileges. You are not at fault.');
define('STRATOS_AUTH_MSG_NOAUTH', 'Unable to authenticate user.');
define('STRATOS_AUTH_MSG_AUTHERR', 'An error occurred while authenticating the user.');
define('STRATOS_AUTH_MSG_NOPRIVS', 'You do not have access to this resource.');
define('STRATOS_AUTH_MSG_AUTH_REQD', 'You must log in to access this resource.');
/**
* @package StratosAuth
*/
class StratosAuth extends StratosPlugin
{
// --------------------
// Private Variables
// --------------------
/**
* @access private
*/
var $_driver;
/**
* @access private
*/
var $_sdp;
/**
* @access private
*/
var $_dos;
/**
* @access private
*/
var $_roles;
/**
* @access private
*/
var $_anonymous_role_id;
/**
* @access private
*/
var $_logged_in_role_id;
/**
* @access private
*/
var $_super_role_id;
/**
* A list of actions that are never protected.
* @access private
*/
var $_always_unprotected;
/**
* @access private
*/
var $_user_session;
// --------------------
// Public Methods
// --------------------
/**
* StratosAuth class PHP 4 constructor.
*
* @access public
*/
function StratosAuth()
{
$this->__construct();
}
/**
* StratosAuth class PHP 5 constructor.
*
* @access public
*/
function __construct()
{
$this->_driver = null;
$this->_sdp = null;
$this->_dos = array(
'user-session' => 'UserSession',
'user' => 'User',
'user-property' => 'UserProperty',
'user-role' => 'UserRole',
'role' => 'Role',
'role-action' => 'RoleAction',
'action' => 'Action',
'action-group' => 'ActionGroup');
$this->_roles = array();
$this->_anonymous_role_id = null;
$this->_logged_in_role_id = null;
$this->_super_role_id = null;
$this->_always_unprotected = array();
$this->_user_session = null;
}
/**
* Starts the plugin.
*
* @access public
*/
function start()
{
$pman =& Stratos::getPluginManager();
if ( !$pman->isPluginEnabled('StratosData') ) return false;
$this->_sdp =& Stratos::getPlugin('StratosData');
if ( !$this->_sdp ) return false;
// Determine which dataset to use for authorizations either based
// on the "dataset" property in the configuration file or by using
// the default (first) dataset defined for StratosData
$this->_dataset_name = $this->_conf['dataset'];
if ( !in_array($this->_dataset_name, $this->_sdp->getDatasets()) )
{
$this->_dataset_name = array_head($this->_sdp->getDatasets());
}
// If no dataset is defined, do not start the plugin
if ( !$this->_dataset_name ) return false;
// Read the data object configuration and pass it along to StratosData
// to add all the data object definitions
$p_info = $pman->getPluginInfo('StratosAuth');
$this->_always_unprotected = $p_info->get('always-unprotected');
$dos = $p_info->get('dataobjects');
foreach ( $dos as $do_name => $do_conf )
{
if ( !$this->_sdp->isDataObject($do_name) )
{
$this->_sdp->addDataObject($do_conf, $this->_dataset_name);
}
}
$this->_anonymous_role_id = $this->_conf['anonymous-role-id'];
$this->_logged_in_role_id = $this->_conf['logged-in-role-id'];
$this->_super_role_id = $this->_conf['super-role-id'];
$driver = $this->_conf['driver'];
$driver_conf = $this->_conf['driver-conf'];
if ( $driver )
{
$driver = 'StratosAuthDriver_' . $driver;
if ( include_once("plugins/StratosAuth/drivers/$driver.php") )
{
$this->_driver =& new $driver($this, $driver_conf);
if ( $this->_driver->start() )
{
// Check if user is logged in
if ( isset($_SESSION['StratosAuth_token_' . STRATOS_SITE_ID])
&& $this->_driver->getUserId() )
{
$token = $_SESSION['StratosAuth_token_' . STRATOS_SITE_ID];
$user_id = $this->_driver->getUserId();
$user = null;
$user_session_query = $this->_sdp->query($this->_dos['user-session']);
$user_session_query->where('token', '=', $token);
$user_session_query->where('user_id', '=', $user_id);
$user_session_query->limit(1);
$user_session = $user_session_query->getFirst();
if ( $user_session )
{
$this->_user_session = $user_session;
$user = $this->_sdp->getById($this->_dos['user'],
$user_session->user_id);
}
if ( $user )
{
$this->_driver->setUser($user);
// Determine user roles
$user_role_query = $this->_sdp->query($this->_dos['user-role']);
$user_role_query->where('user_id', '=', $user->user_id);
$role_query = $this->_sdp->query($this->_dos['role']);
$role_query->referencedBy($user_role_query);
$roles = $role_query->getResults();
if ( $roles )
{
$this->_roles = $roles;
}
}
}
// Add the anonymous/default role to the list of user roles
if ( $this->_anonymous_role_id )
{
$role = $this->_sdp->getById($this->_dos['role'],
$this->_anonymous_role_id);
if ( $role )
{
$this->_roles[] = $role;
}
}
// If the user is authenticated, and a "logged in" role is
// configured, add it to the list of user roles
if ( $this->_driver->isAuthenticated() )
{
if ( $this->_logged_in_role_id )
{
$role = $this->_sdp->getById($this->_dos['role'],
$this->_logged_in_role_id);
if ( $role )
{
$this->_roles[] = $role;
}
}
}
return true;
}
}
Stratos::raiseError('StratosAuth::start(): An error '
. "occurred while loading the '$driver' driver.", PEAR_LOG_ERR);
return false;
}
Stratos::raiseError('StratosAuth::start(): The StratosAuth '
. 'plugin is not configured correctly. The \'driver\' property is '
. 'not set.', PEAR_LOG_ERR);
return false;
}
/**
* Stops the plugin.
*
* @access public
*/
function stop()
{
$res = true;
if ( $this->_driver )
{
$res = $this->_driver->stop();
$this->_driver = null;
}
unset($this->_sdp);
$this->_sdp = null;
$this->_roles = array();
return $res;
}
/**
* Notify the plugin of an event.
*
* @access public
*/
function notifyActionBegin( $action, $args )
{
if ( in_array($action, $this->_always_unprotected) )
{
return true;
}
$privs = $this->checkPrivileges($action);
if ( $privs )
{
return true;
}
$authd = $this->isAuthenticated();
if ( $authd )
{
Stratos::putFlash(STRATOS_AUTH_MSG_NOPRIVS, 'error');
Stratos::forward('StratosAuth/error');
return false;
}
else
{
$res = $this->authenticate();
if ( $res )
{
$privs = $this->checkPrivileges($action);
if ( $privs )
{
return true;
}
else
{
Stratos::putFlash(STRATOS_AUTH_MSG_NOPRIVS, 'error');
Stratos::forward('StratosAuth:error');
return false;
}
}
else
{
Stratos::putFlash(STRATOS_AUTH_MSG_NOAUTH, 'error');
Stratos::forward('StratosAuth:error');
return false;
}
}
}
/**
* Enter description here...
*
* @return unknown
*/
function isAuthenticated()
{
if ( isset($this) && is_a($this, 'StratosAuth') )
{
return $this->_driver->isAuthenticated();
}
else
{
$sap =& Stratos::getPlugin('StratosAuth');
return $sap->isAuthenticated();
}
}
/**
* Enter description here...
*
* @return unknown
*/
function authenticate()
{
if ( isset($this) && is_a($this, 'StratosAuth') )
{
return $this->_driver->authenticate();
}
else
{
$sap =& Stratos::getPlugin('StratosAuth');
return $sap->authenticate();
}
}
/**
* Enter description here...
*
* @return unknown
*/
function unauthenticate()
{
if ( isset($this) && is_a($this, 'StratosAuth') )
{
unset($_SESSION['StratosAuth_token_' . STRATOS_SITE_ID]);
$res = $this->_driver->unauthenticate();
$this->_driver->setUser(null);
return $res;
}
else
{
$sap =& Stratos::getPlugin('StratosAuth');
return $sap->unauthenticate();
}
}
/**
* Enter description here...
*
* @param unknown_type $action_name
* @return unknown
*/
function isActionProtected( $action_name = null )
{
if ( isset($this) && is_a($this, 'StratosAuth') )
{
if ( is_null($action_name) ) $action_name = Stratos::getAction();
$action = $this->_sdp->getWhere($this->_dos['action'],
new StratosDataWhere('name', '=', $action_name));
if ( $action )
{
return true;
}
else if ( !$action )
{
return false;
}
else
{
// error condition
return $action;
}
}
else
{
$sap =& Stratos::getPlugin('StratosAuth');
return $sap->isActionProtected($action_name);
}
}
/**
* Enter description here...
*
* @param unknown_type $action_name
* @return unknown
*/
function checkPrivileges( $action_name = null )
{
if ( isset($this) && is_a($this, 'StratosAuth') )
{
if ( !$action_name ) $action_name = Stratos::getAction();
$action = $this->_sdp->getByUnique(
$this->_dos['action'], 'name', $action_name);
if ( $action )
{
if ( $this->_roles )
{
// If a super role is set and the user has that role, we can
// simply return true
if ( $this->_super_role_id
&& $this->userHasRole($this->_super_role_id) )
{
return true;
}
// Check if the user has a role that is authorized to access
// the action
$auth_query = $this->_sdp->query($this->_dos['role-action']);
foreach ( $this->_roles as $role )
{
$auth_query->orWhere('role_id', '=', $role->role_id);
}
$auth_query->andWhere('action_id', '=', $action->action_id);
$auths = $auth_query->getResults();
if ( $auths )
{
// User has a role that is authorized to access the
// action, so allow access
return true;
}
else
{
return false;
}
}
else
{
// User has no roles, but action is protected, so deny access
return false;
}
}
// Action is not protected, allow access
return true;
}
else
{
$sap =& Stratos::getPlugin('StratosAuth');
return $sap->checkPrivileges($action_name);
}
}
/**
* Enter description here...
*
* @return unknown
*/
function getUserId()
{
if ( isset($this) && is_a($this, 'StratosAuth') )
{
return $this->_driver->getUserId();
}
else
{
$sap =& Stratos::getPlugin('StratosAuth');
return $sap->getUserId();
}
}
/**
* Enter description here...
*
* @return unknown
*/
function getUser()
{
if ( isset($this) && is_a($this, 'StratosAuth') )
{
return $this->_driver->getUser();
}
else
{
$sap =& Stratos::getPlugin('StratosAuth');
return $sap->getUser();
}
}
/**
* Enter description here...
*
* @return unknown
*/
function getUserRoles()
{
if ( isset($this) && is_a($this, 'StratosAuth') )
{
return $this->_roles;
}
else
{
$sap =& Stratos::getPlugin('StratosAuth');
return $sap->getUserRoles();
}
}
/**
* Enter description here...
*
* @param unknown_type $role
* @return unknown
*/
function userHasRole( $role )
{
if ( isset($this) && is_a($this, 'StratosAuth') )
{
if ( $this->_roles )
{
if ( is_string($role) )
{
// Lookup the role by abbreviation
$unq_attr = 'abbr';
}
else if ( is_int($role) )
{
// Lookup the role by id
$unq_attr = 'role_id';
}
else
{
return false;
}
foreach ( $this->_roles as $r )
{
if ( $r->$unq_attr == $role ) return true;
}
}
return false;
}
else
{
$sap =& Stratos::getPlugin('StratosAuth');
return $sap->userHasRole($role);
}
}
/**
* Enter description here...
*
* @param unknown_type $name
* @return unknown
*/
function getUserProperty( $name, $user_id = null )
{
if ( isset($this) && is_a($this, 'StratosAuth') )
{
if ( is_null($user_id) )
{
$user_id = $this->getUserId();
}
if ( $user_id )
{
$user_prop_query = $this->_sdp->query($this->_dos['user-property']);
$user_prop_query->where('user_id', '=', $user_id);
$user_prop_query->where('name', '=', $name);
$user_prop_query->limit(1);
$user_prop = $user_prop_query->getFirst();
if ( $user_prop )
{
return $user_prop;
}
}
return null;
}
else
{
$sap =& Stratos::getPlugin('StratosAuth');
return $sap->getUserProperty($name, $user_id);
}
}
/**
* Enter description here...
*
* @param unknown_type $name
* @param unknown_type $value
* @return unknown
*/
function setUserProperty( $name, $value, $user_id = null )
{
if ( isset($this) && is_a($this, 'StratosAuth') )
{
if ( is_null($user_id) )
{
$user_id = $this->getUserId();
}
if ( $user_id )
{
$user_prop = $this->getUserProperty($name, $user_id);
if ( !$user_prop )
{
$user_prop = new $this->_dos['user-property']();
$user_prop->user_id = $user_id;
$user_prop->name = $name;
$user_prop->value = $value;
$res = $user_prop->add();
}
else
{
$user_prop->value = $value;
$res = $user_prop->update();
}
return $res;
}
return false;
}
else
{
$sap =& Stratos::getPlugin('StratosAuth');
return $sap->setUserProperty($name, $value, $user_id);
}
}
function getUserToken()
{
if ( isset($this) && is_a($this, 'StratosAuth') )
{
if ( $this->_user_session )
{
return $this->_user_session->token;
}
else if ( isset($_SESSION['StratosAuth_token_' . STRATOS_SITE_ID])
&& $this->_driver->getUserId() )
{
return $_SESSION['StratosAuth_token_' . STRATOS_SITE_ID];
}
return null;
}
else
{
$sap =& Stratos::getPlugin('StratosAuth');
return $sap->getUserToken();
}
}
/**
* Enter description here...
*
* @return unknown
*/
function &getDriver()
{
if ( isset($this) && is_a($this, 'StratosAuth') )
{
return $this->_driver;
}
else
{
$sap =& Stratos::getPlugin('StratosAuth');
return $sap->getDriver();
}
}
/**
* Returns the first user found matching all of the given attributes.
*
* @static
*
* @param array $properties attribute => value pairs to use for looking up
* the user.
* @return object The first user object found matching all of the given
* attributes.
*/
function lookupUser( $properties )
{
if ( isset($this) && is_a($this, 'StratosAuth') )
{
$user_query = $this->_sdp->query($this->_dos['user']);
foreach ( $properties as $name => $value )
{
if ( $name == 'username' )
{
$user_query->where($name, '=', $value);
}
else
{
$user_props_query = $this->_sdp->query($this->_dos['user-property']);
$user_props_query->where('name', '=', $name);
$user_props_query->where('value', '=', $value);
$user_query->referencedBy($user_props_query);
}
}
return $user_query->getFirst();
}
else
{
$sap =& Stratos::getPlugin('StratosAuth');
return $sap->lookupUser($properties);
}
}
/**
* Enter description here...
*
*/
function updateUserToken()
{
$new_session = false;
if ( !$this->_user_session )
{
$new_session = true;
$this->_user_session = new $this->_dos['user-session']();
}
$user = $this->_driver->getUser();
$this->_user_session->user_id = $user->user_id;
// while token is not unique
do
{
$this->_user_session->token
= $_SESSION['StratosAuth_token_' . STRATOS_SITE_ID] = md5(
uniqid(rand(), true));
$check_token = $this->_sdp->getByUnique($this->_dos['user-session'],
'token', $this->_user_session->token);
} while ( $check_token );
if ( $new_session )
{
// The time at which the session is started is stored in ISO
// format: "YYYY-MM-DD HH:MM:SS"
$this->_user_session->session_time = strftime('%Y-%m-%d %H:%M:%S');
$this->_user_session->add();
}
else
{
$this->_user_session->update();
}
$this->_driver->setUser($user);
}
/**
* Enter description here...
*
* @access public
*
* @return array An array of available drivers.
*/
function getDriverList( $driver_path = null )
{
if ( isset($this) && is_a($this, 'StratosAuth') )
{
// Method is being called on an instance
if ( is_null($driver_path) )
{
$drivers = $this->getDriverList('./plugins/StratosAuth/drivers');
$stratos_path = Stratos::getStratosPath();
if ( $stratos_path )
{
$drivers = array_merge($drivers,
$this->getDriverList(
$stratos_path . 'plugins/StratosAuth/drivers'));
}
sort($drivers);
return array_unique($drivers);
}
else
{
$drivers = array();
if ( file_exists($driver_path) && is_dir($driver_path) )
{
$d = dir($driver_path);
while ( false !== ($entry = $d->read()) )
{
if ( strpos($entry, 'StratosAuthDriver_') === 0 )
{
$tmp = substr($entry, 18);
$drivers[] = substr($tmp, 0, strrpos($tmp, '.'));
}
}
$d->close();
}
return $drivers;
}
}
else
{
// Method is being called statically
$sap =& Stratos::getPlugin('StratosAuth');
return $sap->getDriverList($driver_path);
}
}
/**
* Enter description here...
*
* @param string $do
* @return string
*/
function getDataObjectName( $do )
{
if ( isset($this->_dos[$do]) )
{
return $this->_dos[$do];
}
return null;
}
/**
* Enter description here...
*
* @return array
*/
function getDataObjectNames()
{
return $this->_dos;
}
}
?>