xref: /plugin/elasticsearch/helper/acl.php (revision b30042c1e1ed4d5dd7667d1d25fccd0363de335f) !
1<?php
2/**
3 * DokuWiki Plugin elasticsearch (Helper Component)
4 *
5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6 * @author  Andreas Gohr <gohr@cosmocode.de>
7 * @author  Anna Dabrowska <dabrowska@cosmocode.de>
8 */
9
10// must be run within Dokuwiki
11if(!defined('DOKU_INC')) die();
12
13/**
14 * User-independent ACL methods
15 */
16class helper_plugin_elasticsearch_acl extends DokuWiki_Plugin
17{
18    /**
19     * Returns a full list of (read) permissions for users and groups whose access to a given page
20     * is defined in the ACLs.
21     * Traverses the whole rule set and resolves overrides and exclusions.
22     *
23     * @param string $id Page id
24     * @return array
25     */
26    public function getPageACL($id) {
27        $id    = cleanID($id);
28        $rules = [];
29
30        /** @var admin_plugin_acl $hlpACL */
31        $hlpACL = plugin_load('admin', 'acl');
32        $hlpACL->_init_acl_config();
33
34        // ACL lines as array
35        $acl = $hlpACL->acl;
36        ksort($acl);
37
38        // check for exact id
39        if (isset($acl[$id])) {
40            // process matched rule
41            $this->addRule($acl[$id], $rules);
42            // stop traversing if we reached a total access block for @ALL
43            if (isset($acl[$id]['@ALL'])) return $rules;
44        }
45
46        // walk namespace segments up
47        $ns = $id;
48        do {
49            $ns = getNS($ns);
50            // no namespace, check permissions for root
51            if (!$ns && isset($acl['*'])) {
52                $this->addRule($acl['*'], $rules);
53                // stop traversing if we reached a total access block for @ALL
54                if (isset($acl['*']['@ALL'])) {
55                    $ns = false;
56                    continue;
57                }
58            }
59            // check namespace
60            if (isset($acl[$ns . ':*'])) {
61                $this->addRule($acl[$ns . ':*'], $rules);
62                // stop traversing if we reached a total access block for @ALL
63                if (isset($acl[$ns . ':*']['@ALL'])) $ns = false;
64            }
65        } while ($ns);
66
67        return $rules;
68    }
69
70    /**
71     * Splits a rule set into query-digestible chunks
72     *
73     * @param array $rules
74     * @return array
75     */
76    public function splitRules($rules)
77    {
78        $splitACL = [
79            'groups_include' => [],
80            'groups_exclude' => [],
81            'users_include' => [],
82            'users_exclude' => [],
83        ];
84
85        foreach ($rules as $key => $perm) {
86            if (strpos($key, '@') === 0) {
87                $type = $perm ? 'groups_include' : 'groups_exclude';
88            } else {
89                $type = $perm ? 'users_include' : 'users_exclude';
90            }
91            $splitACL[$type][] = ltrim($key, '@');
92        }
93
94        return $splitACL;
95    }
96
97    /**
98     * Adds specific access rules to a rule set covering a full namespace path.
99     * Omit access block for @ALL since it is assumed.
100     *
101     * @param array $rule Collection of access permissions for a certain location
102     * @param array $rules Set of rules already
103     */
104    protected function addRule($rule, &$rules)
105    {
106        $localrules = [];
107
108        foreach ($rule as $key => $perm) {
109            // set read permissions for a given group or user
110            // but skip if already defined for a more specific path
111            if ($key !== '@ALL' && !array_key_exists($key, $rules)) {
112                $localrules[$key] = $perm > AUTH_NONE;
113            } elseif ($key === '@ALL' && $perm > AUTH_NONE) {
114                $localrules[$key] = true;
115            }
116        }
117
118        $rules = array_merge($rules, $localrules);
119    }
120}
121