1
0
mirror of https://github.com/e107inc/e107.git synced 2025-08-04 13:47:31 +02:00

Admin menu 'userclass' option added;

Improved, simplified and detailed admin UI access control
Default admin controller 403 page added
This commit is contained in:
secretr
2012-01-20 15:53:59 +00:00
parent e639843ebf
commit 22f97b8674
3 changed files with 186 additions and 17 deletions

View File

@@ -422,7 +422,8 @@ if ($e107_popup != 1)
* $e107_vars['action']['text'] -> link title
* $e107_vars['action']['link'] -> if empty '#action' will be added as href attribute
* $e107_vars['action']['image'] -> (new) image tag
* $e107_vars['action']['perm'] -> permissions
* $e107_vars['action']['perm'] -> permissions via getperms()
* $e107_vars['action']['userclass'] -> user class permissions via check_class()
* $e107_vars['action']['include'] -> additional <a> tag attributes
* $e107_vars['action']['sub'] -> (new) array, exactly the same as $e107_vars' first level e.g. $e107_vars['action']['sub']['action2']['link']...
* $e107_vars['action']['sort'] -> (new) used only if found in 'sub' array - passed as last parameter (recursive call)
@@ -502,7 +503,13 @@ if ($e107_popup != 1)
$search[9] = '/\{LINK_IMAGE\}(.*?)/si';
foreach (array_keys($e107_vars) as $act)
{
if (vartrue($e107_vars[$act]['perm']) && !getperms($e107_vars[$act]['perm'])) // check perms first.
if (isset($e107_vars[$act]['perm']) && !getperms($e107_vars[$act]['perm'])) // check perms first.
{
continue;
}
// check class so that e.g. e_UC_NOBODY will result no permissions granted (even for main admin)
if (isset($e107_vars[$act]['userclass']) && !e107::getUser()->checkClass($e107_vars[$act]['userclass'], false)) // check userclass perms
{
continue;
}

View File

@@ -942,7 +942,25 @@ class e_admin_dispatcher
*
* @var array
*/
protected $modes;
protected $modes = array();
/**
* Optional - access restrictions per action
* Access array in format (similar to adminMenu)
* 'MODE/ACTION' => e_UC_* (userclass constant, or custom userclass ID if dynamically set)
*
* @var array
*/
protected $access = array();
/**
* Optional - generic entry point access restriction (via getperms())
* Value of this for plugins would be always 'P'.
* More detailed access control is granted with $access and $modes[MODE]['perm'] or $modes[MODE]['userclass'] settings
*
* @var string
*/
protected $perm;
/**
* @var string
@@ -964,6 +982,8 @@ class e_admin_dispatcher
* Optional (set by child class).
* Required for admin menu render
* Format: 'mode/action' => array('caption' => 'Link title'[, 'perm' => '0', 'url' => '{e_PLUGIN}plugname/admin_config.php'], ...);
* Note that 'perm' and 'userclass' restrictions are inherited from the $modes, $access and $perm, so you don't have to set that vars if
* you don't need any additional 'visual' control.
* All valid key-value pair (see e_admin_menu function) are accepted.
* @var array
*/
@@ -1009,12 +1029,14 @@ class e_admin_dispatcher
// register itself
e107::setRegistry('admin/ui/dispatcher', $this);
// permissions and restrictions
$this->checkAccess();
if($auto_observe)
{
$this->runObservers(true);
}
}
/**
@@ -1024,6 +1046,63 @@ class e_admin_dispatcher
public function init()
{
}
public function checkAccess()
{
$request = $this->getRequest();
$currentMode = $request->getMode();
// access based on mode setting - general controller access
if(!$this->checkModeAccess($currentMode))
{
$request->setAction('e403');
e107::getMessage()->addError('You don\'t have permissions to view this page.')
->addDebug('Mode access restriction triggered.');
return false;
}
// access based on $access settings - access per action
$currentAction = $request->getAction();
$route = $currentMode.'/'.$currentAction;
if(!$this->checkRouteAccess($route))
{
$request->setAction('e403');
e107::getMessage()->addError('You don\'t have permissions to view this page.')
->addDebug('Route access restriction triggered.');
return false;
}
return true;
}
public function checkModeAccess($mode)
{
// mode userclass (former check_class())
if(isset($this->modes[$mode]['userclass']) && !e107::getUser()->checkClass($this->modes[$mode]['userclass'], false))
{
return false;
}
// mode admin permission (former getperms())
if(isset($this->modes[$mode]['perm']) && !e107::getUser()->checkAdminPerms($this->modes[$mode]['perm']))
{
return false;
}
// generic dispatcher admin permission (former getperms())
if(null !== $this->perm && !e107::getUser()->checkAdminPerms($this->perm))
{
return false;
}
return true;
}
public function checkRouteAccess($route)
{
if(isset($this->access[$route]) && !e107::getUser()->checkClass($this->access[$route], false))
{
return false;
}
return true;
}
/**
* Retrieve missing default action/mode
@@ -1093,12 +1172,13 @@ class e_admin_dispatcher
/**
* Dispatch & render all
*
* @param boolean $return if true, array(title, body, render_mod) will be returned
* @param boolean $run_header see runObservers()
* @param boolean $return see runPage()
* @return string|array current admin page body
*/
public function run($return = false)
public function run($run_header = true, $return = 'render')
{
return $this->runObserver()->renderPage($return);
return $this->runObservers()->runPage($return);
}
/**
@@ -1275,7 +1355,6 @@ class e_admin_dispatcher
// Not known controller (not found in e_admin_dispatcher::$modes) exception
else
{
var_dump($this->getDefaultControllerName(), $this->modes);
// TODO - admin log
$this->_current_controller = $this->getDefaultController();
// add messages
@@ -1321,6 +1400,12 @@ class e_admin_dispatcher
{
$tmp = explode('/', trim($key, '/'), 3);
// sync with mode/route access
if(!$this->checkModeAccess($tmp[0]) || !$this->checkRouteAccess($tmp[0].'/'.$tmp[1]))
{
continue;
}
// custom 'selected' check
if(isset($val['selected']) && $val['selected']) $selected = $val['selected'] === true ? $key : $val['selected'];
@@ -1348,14 +1433,15 @@ class e_admin_dispatcher
break;
}
if($val['perm']!= null) // check perms
{
if(getperms($val['perm']))
{
$var[$key][$k2] = $v;
}
}
else
// Access check done above
// if($val['perm']!= null) // check perms
// {
// if(getperms($val['perm']))
// {
// $var[$key][$k2] = $v;
// }
// }
// else
{
$var[$key][$k2] = $v;
}
@@ -1371,7 +1457,9 @@ class e_admin_dispatcher
$var[$key]['link'] = (vartrue($val['url']) ? $tp->replaceConstants($val['url'], 'abs') : e_SELF).'?mode='.$tmp[0].'&action='.$tmp[1];
$var[$key]['perm'] = $val['perm']; */
}
if(empty($var)) return '';
$request = $this->getRequest();
if(!$selected) $selected = $request->getMode().'/'.$request->getAction();
$selected = vartrue($this->adminMenuAliases[$selected], $selected);
@@ -1400,6 +1488,22 @@ class e_admin_controller
* @var string default action name
*/
protected $_default_action = 'index';
/**
* List (numerical array) of only allowed for this controller actions
* Useful to grant access for certain pre-defined actions only
* XXX - we may move this in dispatcher (or even having it also there), still searching the most 'friendly' way
* @var array
*/
protected $allow = array();
/**
* List (numerical array) of only disallowed for this controller actions
* Useful to restrict access for certain pre-defined actions only
* XXX - we may move this in dispatcher (or even having it also there), still searching the most 'friendly' way
* @var array
*/
protected $disallow = array();
/**
* Constructor
@@ -1411,6 +1515,36 @@ class e_admin_controller
$this->setRequest($request)
->setResponse($response)
->setParams($params);
$this->checkAccess();
}
/**
* Check against allowed/disallowed actions
*/
public function checkAccess()
{
$request = $this->getRequest();
$currentAction = $request->getAction();
// access based on mode setting - general controller access
if(!empty($this->disallow) && in_array($currentAction, $this->disallow))
{
$request->setAction('e403');
e107::getMessage()->addError('You don\'t have permissions to view this page.')
->addDebug('Controller action disallowed restriction triggered.');
return false;
}
// access based on $access settings - access per action
if(!empty($this->allow) && !in_array($currentAction, $this->allow))
{
$request->setAction('e403');
e107::getMessage()->addError('You don\'t have permissions to view this page.')
->addDebug('Controller action not in allowed list restriction triggered.');
return false;
}
return true;
}
/**
@@ -1520,6 +1654,15 @@ class e_admin_controller
$this->_response = $response;
return $this;
}
/**
* Get current dispatcher object
* @return e_admin_dispatcher
*/
public function getDispatcher()
{
return e107::getRegistry('admin/ui/dispatcher');
}
/**
* Request proxy method
@@ -1841,6 +1984,23 @@ class e_admin_controller
{
exit;
}
public function E403Observer()
{
$this->getResponse()->setTitle(LAN_UI_403_TITLE_ERROR);
}
public function E403Page()
{
return '<div class="center">'.LAN_UI_403_BODY_ERROR.'</div>'; // TODO - lan
}
public function E403AjaxPage()
{
exit;
}
/**
* Generic redirect handler, it handles almost everything we would need.

View File

@@ -343,6 +343,8 @@ define('LAN_UI_BATCHDEL_ERROR', 'Batch delete not allowed!');
define('LAN_UI_404_BODY_ERROR', 'Requested page was not found!');
define('LAN_UI_404_TITLE_ERROR', 'Page Not Found');
define('LAN_UI_404_METHOD_ERROR', 'Action <strong>%1$s</strong> not found!');
define('LAN_UI_403_BODY_ERROR', 'Access to the requested page is denied.');
define('LAN_UI_403_TITLE_ERROR', 'Access denied');
define('LAN_UI_FORM_METHOD_ERROR', 'FATAL ERROR: The field name <strong>%1$s</strong> is not allowed. Please rename the key <strong>%1$s</strong> to something else in your fields array and database table (if required).');
define('LAN_UI_BATCH_UPDATE_SUCCESS', '<strong>%1$s</strong> set for <strong>%2$d</strong> record(s).');