Location: PHPKode > projects > Stratos > stratos-1.0rc1/plugins/StratosAuth/StratosAuth.php
<?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;
    }
}

?>
Return current item: Stratos