Building in security capabilities.
This commit is contained in:
parent
0a6c124302
commit
9fe5ce72d4
7 changed files with 282 additions and 29 deletions
|
@ -115,14 +115,12 @@ class Config extends Object
|
|||
*
|
||||
* Prohibits the direct modification of module variables.
|
||||
*
|
||||
* @param string $name name of the variable to be set
|
||||
* @param mixed $value value of the variable to be set
|
||||
* @return boolean false
|
||||
* @param string $name name of the variable to be set
|
||||
* @param mixed $value value of the variable to be set
|
||||
*/
|
||||
public function __set($name, $value)
|
||||
{
|
||||
trigger_error('Cannot set config variables directly', E_USER_ERROR);
|
||||
return false;
|
||||
throw new Exception('Cannot set config variables directly', E_USER_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -40,13 +40,13 @@ class Controller extends Object
|
|||
// Generate a generic "site down" message
|
||||
if ($this->config->pickles['disabled'])
|
||||
{
|
||||
Error::fatal($_SERVER['SERVER_NAME'] . ' is currently<br />down for maintenance');
|
||||
throw new Exception($_SERVER['SERVER_NAME'] . ' is currently<br />down for maintenance');
|
||||
}
|
||||
|
||||
// Ack, not sure what page to load, throw an error
|
||||
if (!isset($_REQUEST['request']) && (empty($this->config->pickles['default']) || $this->config->pickles['default'] == null))
|
||||
{
|
||||
Error::fatal('Unable complete this request because no URI was provided and there is no default module specified in config.ini');
|
||||
throw new Exception('Unable complete this request because no URI was provided and there is no default module specified in config.ini');
|
||||
}
|
||||
// Loads the requested module's information
|
||||
if (isset($_REQUEST['request']) && trim($_REQUEST['request']) != '')
|
||||
|
@ -83,7 +83,7 @@ class Controller extends Object
|
|||
|
||||
unset($basename);
|
||||
|
||||
$module_exists = (isset($module_filename) && $module_filename != null && file_exists($module_filename));
|
||||
$module_exists = (isset($module_filename) && $module_filename != null && file_exists($module_filename));
|
||||
|
||||
// Instantiates an instance of the module
|
||||
if ($module_exists)
|
||||
|
@ -120,6 +120,20 @@ class Controller extends Object
|
|||
}
|
||||
}
|
||||
|
||||
// Validates security level
|
||||
if ($module->security !== false)
|
||||
{
|
||||
// @todo If no type is set, default to isLevel (safer)
|
||||
// @todo If array is present and no type set, validate against each level there
|
||||
// @todo Is array is present under type, validate against each level accordingly
|
||||
if (Security::isLevel($module->security) == false)
|
||||
{
|
||||
// @todo Redirect to login page, potentially configured in the config, else /login
|
||||
// @todo Set variable for the destination, perhaps $_SESSION['__pickles']['login']['destination']
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
// Validates the rendering engine
|
||||
// @todo Need to validate against the module's return type(s)
|
||||
$engine = $module->engine;
|
||||
|
@ -149,7 +163,7 @@ class Controller extends Object
|
|||
{
|
||||
if (!isset($_REQUEST['request']))
|
||||
{
|
||||
Error::fatal('Way to go, you\'ve successfully created an infinite redirect loop. Good thing I was here or you would have been served with a pretty ugly browser error.<br /><br />So here\'s the deal, no templates were able to be loaded. Make sure your parent and child templates actually exist and if you\'re using non-default values, make sure they\'re defined correctly in your config.');
|
||||
throw new Exception('Way to go, you\'ve successfully created an infinite redirect loop. Good thing I was here or you would have been served with a pretty ugly browser error.<br /><br />So here\'s the deal, no templates were able to be loaded. Make sure your parent and child templates actually exist and if you\'re using non-default values, make sure they\'re defined correctly in your config.');
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -165,6 +179,7 @@ class Controller extends Object
|
|||
}
|
||||
}
|
||||
|
||||
$meta_data = null;
|
||||
$module_return = null;
|
||||
|
||||
$profiler = (isset($this->config->pickles['profiler']) && $this->config->pickles['profiler'] == true);
|
||||
|
@ -182,6 +197,13 @@ class Controller extends Object
|
|||
Profiler::log($module, '__default');
|
||||
}
|
||||
|
||||
// Sets meta data from the module
|
||||
$display->setMetaData(array(
|
||||
'title' => $module->title,
|
||||
'description' => $module->description,
|
||||
'keywords' => $module->keywords
|
||||
));
|
||||
|
||||
/**
|
||||
* Note to Self: When building in caching will need to let the
|
||||
* module know to use the cache, either passing in a variable
|
||||
|
|
|
@ -63,6 +63,14 @@ abstract class Display_Common extends Object
|
|||
*/
|
||||
protected $js_basename = '';
|
||||
|
||||
/**
|
||||
* Meta Data
|
||||
*
|
||||
* @access protected
|
||||
* @var array
|
||||
*/
|
||||
protected $meta_data = null;
|
||||
|
||||
/**
|
||||
* Module Return Data
|
||||
*
|
||||
|
@ -135,6 +143,18 @@ abstract class Display_Common extends Object
|
|||
$this->js_basename = $js_basename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Meta Data
|
||||
*
|
||||
* Sets the meta data from the module so the display class can use it
|
||||
*
|
||||
* @param array $meta_data key/value array of data
|
||||
*/
|
||||
public function setMetaData($meta_data)
|
||||
{
|
||||
$this->meta_data = $meta_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Module Return
|
||||
*
|
||||
|
|
|
@ -64,6 +64,7 @@ class Display_PHP extends Display_Common
|
|||
$form_class = (isset($this->config->pickles['form']) ? $this->config->pickles['form'] : 'Form');
|
||||
|
||||
$__config = $this->config;
|
||||
$__meta = $this->meta_data;
|
||||
$__module = $this->module_return;
|
||||
$__css_class = $this->css_class;
|
||||
$__js_file = $this->js_basename;
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
class Module extends Object
|
||||
{
|
||||
/**
|
||||
* Database
|
||||
* Database object
|
||||
*
|
||||
* @access protected
|
||||
* @var object
|
||||
|
@ -59,14 +59,6 @@ class Module extends Object
|
|||
*/
|
||||
protected $keywords = null;
|
||||
|
||||
/**
|
||||
* Access level of the page
|
||||
*
|
||||
* @access protected
|
||||
* @var boolean, null by default
|
||||
*/
|
||||
protected $access = null;
|
||||
|
||||
/**
|
||||
* Secure
|
||||
*
|
||||
|
@ -78,6 +70,14 @@ class Module extends Object
|
|||
*/
|
||||
protected $secure = null;
|
||||
|
||||
/**
|
||||
* Security settings of the page
|
||||
*
|
||||
* @access protected
|
||||
* @var boolean, null by default
|
||||
*/
|
||||
protected $security = null;
|
||||
|
||||
/**
|
||||
* Session
|
||||
*
|
||||
|
@ -133,6 +133,7 @@ class Module extends Object
|
|||
* @access protected
|
||||
* @var array, null by default
|
||||
* @todo Currently the super globals are not being cleared out
|
||||
* @todo Not even sure I want to implement this at this point
|
||||
*/
|
||||
protected $request = null;
|
||||
|
||||
|
@ -177,14 +178,12 @@ class Module extends Object
|
|||
*
|
||||
* Prohibits the direct modification of module variables.
|
||||
*
|
||||
* @param string $name name of the variable to be set
|
||||
* @param mixed $value value of the variable to be set
|
||||
* @return boolean false
|
||||
* @param string $name name of the variable to be set
|
||||
* @param mixed $value value of the variable to be set
|
||||
*/
|
||||
public function __set($name, $value)
|
||||
{
|
||||
trigger_error('Cannot set module variables directly', E_USER_ERROR);
|
||||
return false;
|
||||
throw new Exception('Cannot set module variables directly');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -230,8 +229,7 @@ class Module extends Object
|
|||
}
|
||||
else
|
||||
{
|
||||
trigger_error('Only Controller can perform setRequest()', E_USER_ERROR);
|
||||
return false;
|
||||
throw new Exception('Only Controller can perform setRequest()');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
183
classes/Security.php
Normal file
183
classes/Security.php
Normal file
|
@ -0,0 +1,183 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Security System for PICKLES
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* Licensed under the GNU General Public License Version 3
|
||||
* Redistribution of these files must retain the above copyright notice.
|
||||
*
|
||||
* @package PICKLES
|
||||
* @author Josh Sherman <josh@phpwithpickles.org>
|
||||
* @copyright Copyright 2007-2010, Gravity Boulevard, LLC
|
||||
* @license http://www.gnu.org/licenses/gpl.html GPL v3
|
||||
* @link http://phpwithpickles.org
|
||||
*/
|
||||
|
||||
/**
|
||||
* Security Class
|
||||
*
|
||||
* Collection of static methods for handling security within a website running
|
||||
* on PICKLES. Requires sessions to be enabled.
|
||||
*
|
||||
* @usage <code>Security::setLevel('level');</code>
|
||||
* @usage <code>Security::isLevel('level');</code>
|
||||
*/
|
||||
class Security
|
||||
{
|
||||
/**
|
||||
* Check Session
|
||||
*
|
||||
* Checks if sessions are enabled.
|
||||
*
|
||||
* @return boolean whether or not sessions are enabled
|
||||
*/
|
||||
private static function checkSession()
|
||||
{
|
||||
if (session_id() == '')
|
||||
{
|
||||
throw new Exception('Sessions must be enabled to use Security class');
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check Level
|
||||
*
|
||||
* Checks if a passed level is an integer and/or properly defined in the
|
||||
* site's configuration file.
|
||||
*
|
||||
* @param mixed access level to validate
|
||||
* @return whether ot not the access level is valid
|
||||
*/
|
||||
private static function checkLevel(&$access_level)
|
||||
{
|
||||
if (is_int($access_level))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$config = Config::getInstance();
|
||||
|
||||
// Attempts to validate the string passed
|
||||
if (isset($config->security[$access_level]))
|
||||
{
|
||||
if (is_numeric($config->security[$access_level]))
|
||||
{
|
||||
$access_level = (int)$config->security[$access_level];
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception('Level "' . $access_level . '" is not numeric in config.ini');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception('Level "' . $access_level . '" is not defined in config.ini');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Level
|
||||
*
|
||||
* Sets the security level.
|
||||
*
|
||||
* @param mixed $access_level access level to set this session to
|
||||
* @return boolean true on success, thrown exception on error
|
||||
*/
|
||||
public static function setLevel($access_level)
|
||||
{
|
||||
if (self::checkSession() && self::checkLevel($access_level))
|
||||
{
|
||||
$_SESSION['__pickles']['security']['level'] = $access_level;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear Level
|
||||
*
|
||||
* Clears out the security level.
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
public static function clearLevel()
|
||||
{
|
||||
if (isset($_SESSION['__pickles']['security']['level']))
|
||||
{
|
||||
$_SESSION['__pickles']['security']['level'] = null;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is Level
|
||||
*
|
||||
* Checks the user's access level is exactly the passed level
|
||||
*
|
||||
* @param mixed $access_level access level to be checked against
|
||||
* @param mixed $user_level optional user's access level
|
||||
* @return boolean whether or not the user is that level
|
||||
*/
|
||||
public static function isLevel($access_level, $user_level = null)
|
||||
{
|
||||
if (self::checkSession() && self::checkLevel($access_level) && ($user_level == null || ($user_level != null && self::checkLevel($user_level))))
|
||||
{
|
||||
if ($user_level != null)
|
||||
{
|
||||
return ($user_level == $access_level);
|
||||
}
|
||||
elseif (isset($_SESSION['__pickles']['security']['level']))
|
||||
{
|
||||
return ($_SESSION['__pickles']['security']['level'] == $access_level);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception('Security level has not been set');
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Has Level
|
||||
*
|
||||
* Checks the user's access level against the passed level.
|
||||
*
|
||||
* @param integer $access_level access level to be checked against
|
||||
* @param integer $user_level optional user's access level
|
||||
* @return boolean whether or not the user has access
|
||||
*/
|
||||
public static function hasLevel($access_level, $user_level = null)
|
||||
{
|
||||
if (self::checkSession() && self::checkLevel($access_level) && ($user_level == null || ($user_level != null && self::checkLevel($user_level))))
|
||||
{
|
||||
if ($user_level != null)
|
||||
{
|
||||
return ($user_level >= $access_level);
|
||||
}
|
||||
elseif (isset($_SESSION['__pickles']['security']['level']))
|
||||
{
|
||||
return ($_SESSION['__pickles']['security']['level'] >= $access_level);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception('Security level has not been set');
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
39
pickles.php
39
pickles.php
|
@ -53,13 +53,16 @@ define('JSON_AVAILABLE', function_exists('json_encode'));
|
|||
|
||||
// }}}
|
||||
|
||||
// {{{ Defaults some important configuration options
|
||||
|
||||
// Error reporting is not modified initially
|
||||
// Feel free to uncomment these lines if you want error reporting on before the config is loaded
|
||||
ini_set('display_errors', true);
|
||||
error_reporting(-1);
|
||||
// ini_set('display_errors', true);
|
||||
// error_reporting(-1);
|
||||
|
||||
// Sets the error handler
|
||||
// Sets the error and exceptios handlers
|
||||
set_error_handler('__handleError');
|
||||
set_exception_handler('__handleException');
|
||||
|
||||
// Defaults timezone to UTC if not set
|
||||
if (ini_get('date.timezone') == '')
|
||||
|
@ -67,6 +70,10 @@ if (ini_get('date.timezone') == '')
|
|||
ini_set('date.timezone', 'Etc/UTC');
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
// {{{ Loads the configuration file(1)
|
||||
|
||||
// Loads the base config
|
||||
$config = Config::getInstance();
|
||||
|
||||
|
@ -91,6 +98,10 @@ if ($config->environment != false && is_array($config->environment))
|
|||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
// {{{ Sets any configurable options
|
||||
|
||||
// Configures any available PHP configuration options
|
||||
if (isset($config->php['display_error']))
|
||||
{
|
||||
|
@ -102,7 +113,7 @@ if (isset($config->php['error_reporting']))
|
|||
error_reporting($config->php['error_reporting']);
|
||||
}
|
||||
|
||||
// Sets the timezone to avoid warnings
|
||||
// Sets the timezone
|
||||
if (isset($config->php['date.timezone']))
|
||||
{
|
||||
ini_set('date.timezone', $config->php['date.timezone']);
|
||||
|
@ -114,6 +125,14 @@ if (isset($config->php['error_handler']))
|
|||
set_error_handler($config->php['error_handler']);
|
||||
}
|
||||
|
||||
// Sets the exception handler
|
||||
if (isset($config->php['exception_handler']))
|
||||
{
|
||||
set_exception_handler($config->php['exception_handler']);
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
/**
|
||||
* Magic function to automatically load classes
|
||||
*
|
||||
|
@ -170,4 +189,16 @@ function __handleError($number, $string, $file, $line, array $context)
|
|||
throw new ErrorException($string, 0, $number, $file, $line);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception handling function
|
||||
*
|
||||
* Catches thrown exceptions and displays them.
|
||||
*
|
||||
* @param object $exception the exception
|
||||
*/
|
||||
function __handleException($exception)
|
||||
{
|
||||
Error::fatal($exception->getMessage());
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue