add event to check access to admin plugins
This adds a new method that capsulates the access check that has to be done to decide if an admin plugin's page should be shown to the user. The default implementation is the same as before, relying only on the forAdminOnly() method and the users' isadmin or ismanager status. Admin plugins themselves can override the method to do additional checks. In this patch, I added that to the usermanager plugin which will only return true if the current auth backend can list users. However the real idea behind this change is that the new method emits a new event called ADMINPLUGIN_ACCESS_CHECK which would allow plugins to overwrite it. This way it could be possible to give certain user groups access to certain admin plugins without giving them admin or manager permissions. Note: this does not change how the "Admin" link is shown, it still depends on ismanager or isadmin. A plugin as mentioned above would need to influence the display via the MENU_ITEMS_ASSEMBLY event. Note: this only covers the basic access check. Admin plugins may need further adjustments for access to other parts of the plugin (like AJAX components). An additional commit will update this for the bundled plugins.
This commit is contained in:
parent
433bb3d9e3
commit
64cdf7793c
|
@ -41,7 +41,7 @@ class Admin extends AbstractUserAction {
|
|||
if(($page = $INPUT->str('page', '', true)) != '') {
|
||||
/** @var $plugin \DokuWiki_Admin_Plugin */
|
||||
if($plugin = plugin_getRequestAdminPlugin()) { // FIXME this method does also permission checking
|
||||
if($plugin->forAdminOnly() && !$INFO['isadmin']) {
|
||||
if(!$plugin->isAccessibleByCurrentUser()) {
|
||||
throw new ActionException('denied');
|
||||
}
|
||||
$plugin->handle();
|
||||
|
|
110
inc/Ui/Admin.php
110
inc/Ui/Admin.php
|
@ -12,6 +12,9 @@ namespace dokuwiki\Ui;
|
|||
*/
|
||||
class Admin extends Ui {
|
||||
|
||||
protected $forAdmins = array('usermanager', 'acl', 'extension', 'config', 'styling');
|
||||
protected $forManagers = array('revert', 'popularity');
|
||||
/** @var array[] */
|
||||
protected $menu;
|
||||
|
||||
/**
|
||||
|
@ -24,58 +27,30 @@ class Admin extends Ui {
|
|||
echo '<div class="ui-admin">';
|
||||
echo p_locale_xhtml('admin');
|
||||
$this->showSecurityCheck();
|
||||
$this->showAdminMenu();
|
||||
$this->showManagerMenu();
|
||||
$this->showMenu('admin');
|
||||
$this->showMenu('manager');
|
||||
$this->showVersion();
|
||||
$this->showPluginMenu();
|
||||
$this->showMenu('other');
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the standard admin tasks
|
||||
* Show the given menu of available plugins
|
||||
*
|
||||
* @param string $type admin|manager|other
|
||||
*/
|
||||
protected function showAdminMenu() {
|
||||
/** @var \DokuWiki_Auth_Plugin $auth */
|
||||
global $auth;
|
||||
global $INFO;
|
||||
protected function showMenu($type) {
|
||||
if (!$this->menu[$type]) return;
|
||||
|
||||
if(!$INFO['isadmin']) return;
|
||||
|
||||
// user manager only if the auth backend supports it
|
||||
if(!$auth || !$auth->canDo('getUsers') ) {
|
||||
if(isset($this->menu['usermanager'])) unset($this->menu['usermanager']);
|
||||
if ($type === 'other') {
|
||||
echo p_locale_xhtml('adminplugins');
|
||||
$class = 'admin_plugins';
|
||||
} else {
|
||||
$class = 'admin_tasks';
|
||||
}
|
||||
|
||||
echo '<ul class="admin_tasks">';
|
||||
foreach(array('usermanager','acl', 'extension', 'config', 'styling') as $plugin) {
|
||||
if(!isset($this->menu[$plugin])) continue;
|
||||
$this->showMenuItem($this->menu[$plugin]);
|
||||
unset($this->menu[$plugin]);
|
||||
}
|
||||
echo '</ul>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the standard manager tasks
|
||||
*/
|
||||
protected function showManagerMenu() {
|
||||
echo '<ul class="admin_tasks">';
|
||||
foreach(array('revert','popularity') as $plugin) {
|
||||
if(!isset($this->menu[$plugin])) continue;
|
||||
$this->showMenuItem($this->menu[$plugin]);
|
||||
unset($this->menu[$plugin]);
|
||||
}
|
||||
echo '</ul>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Display all the remaining plugins
|
||||
*/
|
||||
protected function showPluginMenu() {
|
||||
if(!count($this->menu)) return;
|
||||
echo p_locale_xhtml('adminplugins');
|
||||
echo '<ul class="admin_plugins">';
|
||||
foreach ($this->menu as $item) {
|
||||
echo "<ul class=\"$class\">";
|
||||
foreach ($this->menu[$type] as $item) {
|
||||
$this->showMenuItem($item);
|
||||
}
|
||||
echo '</ul>';
|
||||
|
@ -104,7 +79,9 @@ class Admin extends Ui {
|
|||
if(substr($conf['savedir'], 0, 2) !== './') return;
|
||||
echo '<a style="border:none; float:right;"
|
||||
href="http://www.dokuwiki.org/security#web_access_security">
|
||||
<img src="' . DOKU_URL . $conf['savedir'] . '/dont-panic-if-you-see-this-in-your-logs-it-means-your-directory-permissions-are-correct.png" alt="Your data directory seems to be protected properly."
|
||||
<img src="' . DOKU_URL . $conf['savedir'] .
|
||||
'/dont-panic-if-you-see-this-in-your-logs-it-means-your-directory-permissions-are-correct.png"
|
||||
alt="Your data directory seems to be protected properly."
|
||||
onerror="this.parentNode.style.display=\'none\'" /></a>';
|
||||
}
|
||||
|
||||
|
@ -136,19 +113,27 @@ class Admin extends Ui {
|
|||
* @return array list of plugins with their properties
|
||||
*/
|
||||
protected function getPluginList() {
|
||||
global $INFO;
|
||||
global $conf;
|
||||
|
||||
$pluginlist = plugin_list('admin');
|
||||
$menu = array();
|
||||
$menu = ['admin' => [], 'manager' => [], 'other' => []];
|
||||
|
||||
foreach($pluginlist as $p) {
|
||||
/** @var \DokuWiki_Admin_Plugin $obj */
|
||||
if(($obj = plugin_load('admin', $p)) === null) continue;
|
||||
if (($obj = plugin_load('admin', $p)) === null) continue;
|
||||
|
||||
// check permissions
|
||||
if($obj->forAdminOnly() && !$INFO['isadmin']) continue;
|
||||
if (!$obj->isAccessibleByCurrentUser()) continue;
|
||||
|
||||
$menu[$p] = array(
|
||||
if (in_array($p, $this->forAdmins, true)) {
|
||||
$type = 'admin';
|
||||
} elseif (in_array($p, $this->forManagers, true)){
|
||||
$type = 'manager';
|
||||
} else {
|
||||
$type = 'other';
|
||||
}
|
||||
|
||||
$menu[$type][$p] = array(
|
||||
'plugin' => $p,
|
||||
'prompt' => $obj->getMenuText($conf['lang']),
|
||||
'icon' => $obj->getMenuIcon(),
|
||||
|
@ -157,17 +142,26 @@ class Admin extends Ui {
|
|||
}
|
||||
|
||||
// sort by name, then sort
|
||||
uasort(
|
||||
$menu,
|
||||
function ($a, $b) {
|
||||
$strcmp = strcasecmp($a['prompt'], $b['prompt']);
|
||||
if($strcmp != 0) return $strcmp;
|
||||
if($a['sort'] == $b['sort']) return 0;
|
||||
return ($a['sort'] < $b['sort']) ? -1 : 1;
|
||||
}
|
||||
);
|
||||
uasort($menu['admin'], [$this, 'menuSort']);
|
||||
uasort($menu['manager'], [$this, 'menuSort']);
|
||||
uasort($menu['other'], [$this, 'menuSort']);
|
||||
|
||||
return $menu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom sorting for admin menu
|
||||
*
|
||||
* We sort alphabetically first, then by sort value
|
||||
*
|
||||
* @param array $a
|
||||
* @param array $b
|
||||
* @return int
|
||||
*/
|
||||
protected function menuSort ($a, $b) {
|
||||
$strcmp = strcasecmp($a['prompt'], $b['prompt']);
|
||||
if($strcmp != 0) return $strcmp;
|
||||
if($a['sort'] === $b['sort']) return 0;
|
||||
return ($a['sort'] < $b['sort']) ? -1 : 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,7 +123,7 @@ function plugin_getRequestAdminPlugin(){
|
|||
/** @var $admin_plugin DokuWiki_Admin_Plugin */
|
||||
$admin_plugin = plugin_load('admin', $page);
|
||||
// verify
|
||||
if ($admin_plugin && $admin_plugin->forAdminOnly() && !$INFO['isadmin']) {
|
||||
if ($admin_plugin && !$admin_plugin->isAccessibleByCurrentUser()) {
|
||||
$admin_plugin = null;
|
||||
$INPUT->remove('page');
|
||||
msg('For admins only',-1);
|
||||
|
|
|
@ -72,6 +72,29 @@ class DokuWiki_Admin_Plugin extends DokuWiki_Plugin {
|
|||
trigger_error('html() not implemented in '.get_class($this), E_USER_WARNING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if access should be granted to this admin plugin
|
||||
*
|
||||
* @return bool true if the current user may access this admin plugin
|
||||
*/
|
||||
public function isAccessibleByCurrentUser() {
|
||||
global $INFO;
|
||||
|
||||
$data['hasAccess'] = false;
|
||||
|
||||
$event = new Doku_Event('ADMINPLUGIN_ACCESS_CHECK', $data);
|
||||
if($event->advise_before()) {
|
||||
if ($this->forAdminOnly()) {
|
||||
$data['hasAccess'] = $INFO['isadmin'];
|
||||
} else {
|
||||
$data['hasAccess'] = $INFO['ismanager'];
|
||||
}
|
||||
}
|
||||
$event->advise_after();
|
||||
|
||||
return $data['hasAccess'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true for access only by admins (config:superuser) or false if managers are allowed as well
|
||||
*
|
||||
|
|
|
@ -297,6 +297,24 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* User Manager is only available if the auth backend supports it
|
||||
*
|
||||
* @inheritdoc
|
||||
* @return bool
|
||||
*/
|
||||
public function isAccessibleByCurrentUser()
|
||||
{
|
||||
/** @var DokuWiki_Auth_Plugin $auth */
|
||||
global $auth;
|
||||
if(!$auth || !$auth->canDo('getUsers') ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return parent::isAccessibleByCurrentUser();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Display form to add or modify a user
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue