Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
90.38% covered (success)
90.38%
47 / 52
50.00% covered (danger)
50.00%
2 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
ServerParam
90.38% covered (success)
90.38%
47 / 52
50.00% covered (danger)
50.00%
2 / 4
19.32
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getPermissions
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 checkServerParam
87.50% covered (warning)
87.50%
28 / 32
0.00% covered (danger)
0.00%
0 / 1
11.24
 splitString
91.67% covered (success)
91.67%
11 / 12
0.00% covered (danger)
0.00%
0 / 1
4.01
1<?php
2
3/**
4 * ServerParam permission provider for VuFind.
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 * @author   Jochen Lienhard <lienhard@ub.uni-freiburg.de>
27 * @author   Bernd Oberknapp <bo@ub.uni-freiburg.de>
28 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
29 * @link     https://vufind.org Main Page
30 */
31
32namespace VuFind\Role\PermissionProvider;
33
34use Laminas\Http\PhpEnvironment\Request;
35
36use function count;
37use function in_array;
38
39/**
40 * ServerParam permission provider for VuFind.
41 *
42 * @category VuFind
43 * @package  Authorization
44 * @author   Demian Katz <demian.katz@villanova.edu>
45 * @author   Jochen Lienhard <lienhard@ub.uni-freiburg.de>
46 * @author   Bernd Oberknapp <bo@ub.uni-freiburg.de>
47 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
48 * @link     https://vufind.org Main Page
49 */
50class ServerParam implements
51    PermissionProviderInterface,
52    \Laminas\Log\LoggerAwareInterface
53{
54    use \VuFind\Log\LoggerAwareTrait;
55
56    /**
57     * Request object
58     *
59     * @var Request
60     */
61    protected $request;
62
63    /**
64     * Aliases for server param names (default: none)
65     *
66     * @var array
67     */
68    protected $aliases = [];
69
70    /**
71     * Delimiter for multi-valued server params (default: none)
72     *
73     * @var string
74     */
75    protected $serverParamDelimiter = '';
76
77    /**
78     * Escape character for delimiter in server param strings (default: none)
79     *
80     * @var string
81     */
82    protected $serverParamEscape = '';
83
84    /**
85     * Constructor
86     *
87     * @param Request $request Request object
88     */
89    public function __construct(Request $request)
90    {
91        $this->request = $request;
92    }
93
94    /**
95     * Return an array of roles which may be granted the permission based on
96     * the options.
97     *
98     * @param mixed $options Options provided from configuration.
99     *
100     * @return array
101     */
102    public function getPermissions($options)
103    {
104        // user only gets the permission if all options match (AND)
105        foreach ((array)$options as $option) {
106            $this->debug("getPermissions: option '{$option}'");
107            if (!$this->checkServerParam($option)) {
108                $this->debug('getPermissions: result = false');
109                return [];
110            }
111            $this->debug('getPermissions: result = true');
112        }
113        return ['guest', 'loggedin'];
114    }
115
116    /**
117     * Check if a server param matches the option.
118     *
119     * @param string $option Option
120     *
121     * @return bool true if a server param matches, false if not
122     */
123    protected function checkServerParam($option)
124    {
125        // split option on spaces unless escaped with backslash
126        $optionParts = $this->splitString($option, ' ', '\\');
127        if (count($optionParts) < 2) {
128            $this->logError("configuration option '{$option}' invalid");
129            return false;
130        }
131
132        // first part is the server param name
133        $serverParamName = array_shift($optionParts);
134        if (isset($this->aliases[$serverParamName])) {
135            $serverParamName = $this->aliases[$serverParamName];
136        }
137
138        // optional modifier follow server param name
139        $modifierMatch = in_array($optionParts[0], ['~', '!~']);
140        $modifierNot = in_array($optionParts[0], ['!', '!~']);
141        if ($modifierNot || $modifierMatch) {
142            array_shift($optionParts);
143        }
144
145        // remaining parts are the templates for checking the server params
146        $templates = $optionParts;
147        if (empty($templates)) {
148            $this->logError("configuration option '{$option}' invalid");
149            return false;
150        }
151
152        // server param values to check
153        $serverParamString = $this->request->getServer()->get($serverParamName);
154        if ($serverParamString === null) {
155            // check fails if server param is missing
156            return false;
157        }
158        $serverParams = $this->splitString(
159            $serverParamString,
160            $this->serverParamDelimiter,
161            $this->serverParamEscape
162        );
163
164        $result = false;
165        // check for each server param ...
166        foreach ($serverParams as $serverParam) {
167            // ... if it matches one of the templates (OR)
168            foreach ($templates as $template) {
169                if ($modifierMatch) {
170                    $result |= preg_match('/' . $template . '/', $serverParam);
171                } else {
172                    $result |= ($template === $serverParam);
173                }
174            }
175        }
176        if ($modifierNot) {
177            $result = !$result;
178        }
179
180        return $result;
181    }
182
183    /**
184     * Split string on delimiter unless dequalified with escape
185     *
186     * @param string $string    String to split
187     * @param string $delimiter Delimiter character
188     * @param string $escape    Escape character
189     *
190     * @return array split string parts
191     */
192    protected function splitString($string, $delimiter, $escape)
193    {
194        if ($delimiter === '') {
195            return [$string];
196        }
197
198        if ($delimiter === ' ') {
199            $pattern = ' +';
200        } else {
201            $pattern = preg_quote($delimiter, '/');
202        }
203
204        if ($escape === '') {
205            $pattern = '(?<!' . preg_quote($escape, '/') . ')' . $pattern;
206        }
207
208        return str_replace(
209            $escape . $delimiter,
210            $delimiter,
211            preg_split('/' . $pattern . '/', $string)
212        );
213    }
214}