Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
40 / 40
100.00% covered (success)
100.00%
6 / 6
CRAP
100.00% covered (success)
100.00%
1 / 1
DynamicRoleProvider
100.00% covered (success)
100.00%
40 / 40
100.00% covered (success)
100.00%
6 / 6
20
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getRoles
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getRole
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 populateRoles
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 getPermissionsArray
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
6
 getRolesForSettings
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
6
1<?php
2
3/**
4 * VuFind dynamic role provider.
5 *
6 * PHP version 8
7 *
8 * Copyright (C) Villanova University 2007.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2,
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22 *
23 * @category VuFind
24 * @package  Authorization
25 * @author   Demian Katz <demian.katz@villanova.edu>
26 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
27 * @link     https://vufind.org Main Page
28 */
29
30namespace VuFind\Role;
31
32use LmcRbacMvc\Role\RoleProviderInterface;
33use Rbac\Role\Role;
34
35/**
36 * VuFind dynamic role provider.
37 *
38 * @category VuFind
39 * @package  Authorization
40 * @author   Demian Katz <demian.katz@villanova.edu>
41 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
42 * @link     https://vufind.org Main Page
43 */
44class DynamicRoleProvider implements RoleProviderInterface
45{
46    /**
47     * Cache of role objects.
48     *
49     * @var array
50     */
51    protected $roles = false;
52
53    /**
54     * Permission provider manager
55     *
56     * @var PermissionProviderPluginManager
57     */
58    protected $manager;
59
60    /**
61     * Configuration for determining permissions.
62     *
63     * @var array
64     */
65    protected $config;
66
67    /**
68     * Constructor
69     *
70     * @param PermissionProvider\PluginManager $manager Permission provider manager
71     * @param array                            $config  Configuration for determining
72     * permissions
73     */
74    public function __construct(
75        PermissionProvider\PluginManager $manager,
76        array $config
77    ) {
78        $this->manager = $manager;
79        $this->config = $config;
80    }
81
82    /**
83     * Get the roles from the provider
84     *
85     * @param string[] $roleNames Role(s) to look up.
86     *
87     * @return \Rbac\Role\RoleInterface[]
88     */
89    public function getRoles(array $roleNames)
90    {
91        return array_map([$this, 'getRole'], $roleNames);
92    }
93
94    /**
95     * Get a role object by name.
96     *
97     * @param string $name Role name
98     *
99     * @return Role
100     */
101    protected function getRole($name)
102    {
103        // Retrieve permissions from providers if not already done:
104        if (false === $this->roles) {
105            $this->populateRoles();
106        }
107
108        // Create role object if missing:
109        if (!isset($this->roles[$name])) {
110            $this->roles[$name] = new Role($name);
111        }
112
113        return $this->roles[$name];
114    }
115
116    /**
117     * Populate the internal role array.
118     *
119     * @return void
120     */
121    protected function populateRoles()
122    {
123        // Reset internal role array:
124        $this->roles = [];
125
126        // Map permission configuration to the expected output format.
127        foreach ($this->getPermissionsArray() as $roleName => $permissionArr) {
128            $role = $this->getRole($roleName);
129            foreach ($permissionArr as $permission) {
130                $role->addPermission($permission);
131            }
132        }
133    }
134
135    /**
136     * Get an associative array of role name => permissions using the provided
137     * configuration.
138     *
139     * @return array
140     */
141    protected function getPermissionsArray()
142    {
143        // Loop through all of the permissions:
144        $retVal = [];
145        foreach ($this->config as $settings) {
146            $current = $this->getRolesForSettings($settings);
147            if (null !== $current['roles']) {
148                foreach ($current['roles'] as $role) {
149                    if (!isset($retVal[$role])) {
150                        $retVal[$role] = [];
151                    }
152                    foreach ($current['permissions'] as $permission) {
153                        $retVal[$role][] = $permission;
154                    }
155                }
156            }
157        }
158        return $retVal;
159    }
160
161    /**
162     * Given a settings array, return the appropriate roles.
163     *
164     * @param array $settings Settings for finding roles that allow a permission
165     *
166     * @return array
167     */
168    protected function getRolesForSettings($settings)
169    {
170        // Extract require setting:
171        if (isset($settings['require'])) {
172            $mode = strtoupper(trim($settings['require']));
173            unset($settings['require']);
174        } else {
175            $mode = 'ALL';
176        }
177
178        // Extract permission setting:
179        $permissions = isset($settings['permission'])
180            ? (array)$settings['permission'] : [];
181        unset($settings['permission']);
182
183        // Process everything:
184        $roles = null;
185        foreach ($settings as $provider => $options) {
186            $providerObj = $this->manager->get($provider);
187            $currentRoles = $providerObj->getPermissions($options);
188            if ($roles === null) {
189                $roles = $currentRoles;
190            } elseif ($mode == 'ANY') {
191                $roles = array_merge($roles, $currentRoles);
192            } else {
193                $roles = array_intersect($roles, $currentRoles);
194            }
195        }
196        return compact('permissions', 'roles');
197    }
198}