1<?php
2
3/**
4 * Class action_plugin_usermanagerextended_extend
5 */
6class action_plugin_usermanagerextended_extend extends DokuWiki_Action_Plugin
7{
8
9    /**
10     * @param \Doku_Event_Handler $controller
11     */
12    public function register(\Doku_Event_Handler $controller)
13    {
14        $controller->register_hook('ADMINPLUGIN_ACCESS_CHECK', 'AFTER', $this, 'handleAccess');
15        $controller->register_hook('AUTH_USER_CHANGE', 'BEFORE', $this, 'handlePermissions');
16    }
17
18    /**
19     * Grant managers access to user manager
20     *
21     * @param \Doku_Event $event
22     */
23    public function handleAccess(\Doku_Event $event)
24    {
25        if ($event->data['instance'] instanceof \admin_plugin_usermanager) {
26            $event->data['hasAccess'] = auth_ismanager();
27        }
28    }
29
30    /**
31     * Prevent managers from making changes beyond their privileges:
32     * - do not modify superusers
33     * - do not create superusers or managers (by adding users or groups)
34     *
35     * @param \Doku_Event $event
36     * @return bool
37     */
38    public function handlePermissions(\Doku_Event $event)
39    {
40        // preliminary checks
41        global $INPUT;
42        if ($INPUT->str('page') !== 'usermanager') return true;
43        if (auth_isadmin()) return true;
44        if (!auth_ismanager()) return $this->deny($event);
45
46        $modUser = $event->data['params'][0];
47
48        // more checks
49        if (is_array($modUser)) {
50            foreach ($modUser as $user) {
51                $this->checkModUser($user, $event);
52            }
53        } else {
54            $this->checkModUser($modUser, $event);
55        }
56
57        return true;
58    }
59
60    /**
61     * Check if modification of given user is allowed
62     *
63     * @param string $modUser
64     * @param \Doku_Event $event
65     * @return bool
66     */
67    protected function checkModUser($modUser, \Doku_Event $event)
68    {
69        global $auth, $conf;
70
71        // rule: don't touch admins
72        // auth_isadmin() needs to receive groups or it will match against the groups of REMOTE_USER!
73        $existingUser = $auth->getUserData($modUser);
74        if ($existingUser && auth_isadmin($modUser, $existingUser['grps'])) return $this->deny($event);
75
76        // rule: don't create admins or managers
77        // check groups in modification parameters
78        if ($event->data['type'] === 'create') {
79            $groups = $event->data['params'][4];
80        } elseif ($event->data['type'] === 'modify') {
81            $groups = $event->data['params'][1]['grps'];
82        }
83
84        // those new groups should be enough because we do not prevent demoting managers
85        // like we did with admins
86        if (
87            !empty($groups) &&
88            auth_isMember(
89                join(',', [$conf['superuser'], $conf['manager']]),
90                $modUser,
91                $groups
92            )
93        ) {
94            return $this->deny($event);
95        }
96
97        return true;
98    }
99
100    /**
101     * Wrap up modification denial
102     *
103     * @param \Doku_Event $event
104     * @return false
105     */
106    protected function deny(\Doku_Event $event)
107    {
108        $event->preventDefault();
109
110        msg($this->getLang('error_forbidden'), -1);
111        return false;
112    }
113}
114