PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 4.0.2
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v4.0.2
5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / core / Access.php
matomo / app / core Last commit date
API 5 years ago Access 5 years ago Application 5 years ago Archive 5 years ago ArchiveProcessor 5 years ago Archiver 5 years ago AssetManager 5 years ago Auth 5 years ago Category 5 years ago CliMulti 5 years ago Columns 5 years ago Composer 5 years ago Concurrency 5 years ago Config 5 years ago Container 5 years ago CronArchive 5 years ago DataAccess 5 years ago DataFiles 5 years ago DataTable 5 years ago Db 5 years ago DeviceDetector 5 years ago Email 5 years ago Exception 5 years ago Http 5 years ago Intl 5 years ago Mail 5 years ago Measurable 5 years ago Menu 5 years ago Metrics 5 years ago Notification 5 years ago Period 5 years ago Plugin 5 years ago ProfessionalServices 5 years ago Report 5 years ago ReportRenderer 5 years ago Scheduler 5 years ago Segment 5 years ago Session 5 years ago Settings 5 years ago Tracker 5 years ago Translation 5 years ago UpdateCheck 5 years ago Updater 5 years ago Updates 5 years ago Validators 5 years ago View 5 years ago ViewDataTable 5 years ago Visualization 5 years ago Widget 5 years ago .htaccess 6 years ago Access.php 5 years ago Archive.php 5 years ago ArchiveProcessor.php 5 years ago AssetManager.php 5 years ago Auth.php 5 years ago AuthResult.php 5 years ago BaseFactory.php 5 years ago Cache.php 5 years ago CacheId.php 5 years ago CliMulti.php 5 years ago Common.php 5 years ago Config.php 5 years ago Console.php 5 years ago Context.php 5 years ago Cookie.php 5 years ago CronArchive.php 5 years ago DataArray.php 5 years ago DataTable.php 5 years ago Date.php 5 years ago Db.php 5 years ago DbHelper.php 5 years ago Development.php 5 years ago ErrorHandler.php 5 years ago EventDispatcher.php 5 years ago ExceptionHandler.php 5 years ago FileIntegrity.php 5 years ago Filechecks.php 5 years ago Filesystem.php 5 years ago FrontController.php 5 years ago Http.php 5 years ago IP.php 5 years ago Log.php 5 years ago LogDeleter.php 5 years ago Mail.php 5 years ago Metrics.php 5 years ago NoAccessException.php 5 years ago Nonce.php 5 years ago Notification.php 5 years ago NumberFormatter.php 5 years ago Option.php 5 years ago Period.php 5 years ago Piwik.php 5 years ago Plugin.php 5 years ago Profiler.php 5 years ago ProxyHeaders.php 5 years ago ProxyHttp.php 5 years ago QuickForm2.php 5 years ago RankingQuery.php 5 years ago ReportRenderer.php 5 years ago Segment.php 5 years ago Sequence.php 5 years ago Session.php 5 years ago SettingsPiwik.php 5 years ago SettingsServer.php 5 years ago Singleton.php 5 years ago Site.php 5 years ago TCPDF.php 5 years ago Theme.php 5 years ago Timer.php 5 years ago Tracker.php 5 years ago Twig.php 5 years ago Unzip.php 5 years ago UpdateCheck.php 5 years ago Updater.php 5 years ago UpdaterErrorException.php 5 years ago Updates.php 5 years ago Url.php 5 years ago UrlHelper.php 5 years ago Version.php 5 years ago View.php 5 years ago bootstrap.php 5 years ago dispatch.php 5 years ago testMinimumPhpVersion.php 5 years ago
Access.php
771 lines
1 <?php
2 /**
3 * Matomo - free/libre analytics platform
4 *
5 * @link https://matomo.org
6 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
7 *
8 */
9 namespace Piwik;
10
11 use Exception;
12 use Piwik\Access\CapabilitiesProvider;
13 use Piwik\API\Request;
14 use Piwik\Access\RolesProvider;
15 use Piwik\Container\StaticContainer;
16 use Piwik\Plugins\SitesManager\API as SitesManagerApi;
17 use Piwik\Session\SessionAuth;
18
19 /**
20 * Singleton that manages user access to Piwik resources.
21 *
22 * To check whether a user has access to a resource, use one of the {@link Piwik Piwik::checkUser...}
23 * methods.
24 *
25 * In Piwik there are four different access levels:
26 *
27 * - **no access**: Users with this access level cannot view the resource.
28 * - **view access**: Users with this access level can view the resource, but cannot modify it.
29 * - **admin access**: Users with this access level can view and modify the resource.
30 * - **Super User access**: Only the Super User has this access level. It means the user can do
31 * whatever they want.
32 *
33 * Super user access is required to set some configuration options.
34 * All other options are specific to the user or to a website.
35 *
36 * Access is granted per website. Uses with access for a website can view all
37 * data associated with that website.
38 *
39 */
40 class Access
41 {
42 /**
43 * Array of idsites available to the current user, indexed by permission level
44 * @see getSitesIdWith*()
45 *
46 * @var array
47 */
48 protected $idsitesByAccess = null;
49
50 /**
51 * Login of the current user
52 *
53 * @var string
54 */
55 protected $login = null;
56
57 /**
58 * token_auth of the current user
59 *
60 * @var string
61 */
62 protected $token_auth = null;
63
64 /**
65 * Defines if the current user is the Super User
66 * @see hasSuperUserAccess()
67 *
68 * @var bool
69 */
70 protected $hasSuperUserAccess = false;
71
72 /**
73 * Authentification object (see Auth)
74 *
75 * @var Auth
76 */
77 private $auth = null;
78
79 /**
80 * Gets the singleton instance. Creates it if necessary.
81 *
82 * @return self
83 */
84 public static function getInstance()
85 {
86 return StaticContainer::get('Piwik\Access');
87 }
88
89 /**
90 * @var CapabilitiesProvider
91 */
92 protected $capabilityProvider;
93
94 /**
95 * @var RolesProvider
96 */
97 private $roleProvider;
98
99 /**
100 * Constructor
101 */
102 public function __construct(RolesProvider $roleProvider = null, CapabilitiesProvider $capabilityProvider = null)
103 {
104 if (!isset($roleProvider)) {
105 $roleProvider = StaticContainer::get('Piwik\Access\RolesProvider');
106 }
107 if (!isset($capabilityProvider)) {
108 $capabilityProvider = StaticContainer::get('Piwik\Access\CapabilitiesProvider');
109 }
110 $this->roleProvider = $roleProvider;
111 $this->capabilityProvider = $capabilityProvider;
112
113 $this->resetSites();
114 }
115
116 private function resetSites()
117 {
118 $this->idsitesByAccess = array(
119 'view' => array(),
120 'write' => array(),
121 'admin' => array(),
122 'superuser' => array(),
123 );
124 }
125
126 /**
127 * Loads the access levels for the current user.
128 *
129 * Calls the authentication method to try to log the user in the system.
130 * If the user credentials are not correct we don't load anything.
131 * If the login/password is correct the user is either the SuperUser or a normal user.
132 * We load the access levels for this user for all the websites.
133 *
134 * @param null|Auth $auth Auth adapter
135 * @return bool true on success, false if reloading access failed (when auth object wasn't specified and user is not enforced to be Super User)
136 */
137 public function reloadAccess(Auth $auth = null)
138 {
139 $this->resetSites();
140
141 if (isset($auth)) {
142 $this->auth = $auth;
143 }
144
145 if ($this->hasSuperUserAccess()) {
146 $this->makeSureLoginNameIsSet();
147 return true;
148 }
149
150 $this->token_auth = null;
151 $this->login = null;
152
153 // if the Auth wasn't set, we may be in the special case of setSuperUser(), otherwise we fail TODO: docs + review
154 if (!isset($this->auth)) {
155 return false;
156 }
157
158 $result = null;
159
160 $forceApiSessionPost = Common::getRequestVar('force_api_session', 0, 'int', $_POST);
161 $forceApiSessionGet = Common::getRequestVar('force_api_session', 0, 'int', $_GET);
162 $isApiRequest = Piwik::getModule() === 'API' && (Piwik::getAction() === 'index' || !Piwik::getAction());
163 $apiMethod = Request::getMethodIfApiRequest(null);
164 $isGetApiRequest = 1 === substr_count($apiMethod, '.') && strpos($apiMethod, '.get') > 0;
165
166 if (($forceApiSessionPost && $isApiRequest) || ($forceApiSessionGet && $isApiRequest && $isGetApiRequest)) {
167 $request = ($forceApiSessionGet && $isApiRequest && $isGetApiRequest) ? $_GET : $_POST;
168 $tokenAuth = Common::getRequestVar('token_auth', '', 'string', $request);
169 Session::start();
170 $auth = StaticContainer::get(SessionAuth::class);
171 $auth->setTokenAuth($tokenAuth);
172 $result = $auth->authenticate();
173 if (!$result->wasAuthenticationSuccessful()) {
174 /**
175 * Ensures brute force logic to be executed
176 * @ignore
177 * @internal
178 */
179 Piwik::postEvent('API.Request.authenticate.failed');
180 }
181 Session::close();
182 // if not successful, we will fallback to regular auth
183 }
184
185 // access = array ( idsite => accessIdSite, idsite2 => accessIdSite2)
186 if (!$result || !$result->wasAuthenticationSuccessful()) {
187 $result = $this->auth->authenticate();
188 }
189
190 if (!$result->wasAuthenticationSuccessful()) {
191 return false;
192 }
193
194 $this->login = $result->getIdentity();
195 $this->token_auth = $result->getTokenAuth();
196
197 // case the superUser is logged in
198 if ($result->hasSuperUserAccess()) {
199 $this->setSuperUserAccess(true);
200 }
201
202 return true;
203 }
204
205 public function getRawSitesWithSomeViewAccess($login)
206 {
207 $sql = self::getSqlAccessSite("access, t2.idsite");
208
209 return Db::fetchAll($sql, $login);
210 }
211
212 /**
213 * Returns the SQL query joining sites and access table for a given login
214 *
215 * @param string $select Columns or expression to SELECT FROM table, eg. "MIN(ts_created)"
216 * @return string SQL query
217 */
218 public static function getSqlAccessSite($select)
219 {
220 $access = Common::prefixTable('access');
221 $siteTable = Common::prefixTable('site');
222
223 return "SELECT " . $select . " FROM " . $access . " as t1
224 JOIN " . $siteTable . " as t2 USING (idsite) WHERE login = ?";
225 }
226
227 /**
228 * Make sure a login name is set
229 *
230 * @return true
231 */
232 protected function makeSureLoginNameIsSet()
233 {
234 if (empty($this->login)) {
235 // flag to force non empty login so Super User is not mistaken for anonymous
236 $this->login = 'super user was set';
237 }
238 }
239
240 protected function loadSitesIfNeeded()
241 {
242 if ($this->hasSuperUserAccess) {
243 if (empty($this->idsitesByAccess['superuser'])) {
244 try {
245 $api = SitesManagerApi::getInstance();
246 $allSitesId = $api->getAllSitesId();
247 } catch (\Exception $e) {
248 $allSitesId = array();
249 }
250 $this->idsitesByAccess['superuser'] = $allSitesId;
251 }
252 } elseif (isset($this->login)) {
253 if (empty($this->idsitesByAccess['view'])
254 && empty($this->idsitesByAccess['write'])
255 && empty($this->idsitesByAccess['admin'])
256 ) {
257 // we join with site in case there are rows in access for an idsite that doesn't exist anymore
258 // (backward compatibility ; before we deleted the site without deleting rows in _access table)
259 $accessRaw = $this->getRawSitesWithSomeViewAccess($this->login);
260
261 foreach ($accessRaw as $access) {
262 $accessType = $access['access'];
263 $this->idsitesByAccess[$accessType][] = $access['idsite'];
264
265 if ($this->roleProvider->isValidRole($accessType)) {
266 foreach ($this->capabilityProvider->getAllCapabilities() as $capability) {
267 if ($capability->hasRoleCapability($accessType)) {
268 // we automatically add this capability
269 if (!isset($this->idsitesByAccess[$capability->getId()])) {
270 $this->idsitesByAccess[$capability->getId()] = array();
271 }
272 $this->idsitesByAccess[$capability->getId()][] = $access['idsite'];
273 }
274 }
275 }
276 }
277
278 /**
279 * Triggered after the initial access levels and permissions for the current user are loaded. Use this
280 * event to modify the current user's permissions (for example, making sure every user has view access
281 * to a specific site).
282 *
283 * **Example**
284 *
285 * function (&$idsitesByAccess, $login) {
286 * if ($login == 'somespecialuser') {
287 * return;
288 * }
289 *
290 * $idsitesByAccess['view'][] = $mySpecialIdSite;
291 * }
292 *
293 * @param array[] &$idsitesByAccess The current user's access levels for individual sites. Maps role and
294 * capability IDs to list of site IDs, eg:
295 *
296 * ```
297 * [
298 * 'view' => [1, 2, 3],
299 * 'write' => [4, 5],
300 * 'admin' => [],
301 * ]
302 * ```
303 * @param string $login The current user's login.
304 */
305 Piwik::postEvent('Access.modifyUserAccess', [&$this->idsitesByAccess, $this->login]);
306 }
307 }
308 }
309
310 /**
311 * We bypass the normal auth method and give the current user Super User rights.
312 * This should be very carefully used.
313 *
314 * @param bool $bool
315 */
316 public function setSuperUserAccess($bool = true)
317 {
318 $this->hasSuperUserAccess = (bool) $bool;
319
320 if ($bool) {
321 $this->makeSureLoginNameIsSet();
322 } else {
323 $this->resetSites();
324 }
325 }
326
327 /**
328 * Returns true if the current user is logged in as the Super User
329 *
330 * @return bool
331 */
332 public function hasSuperUserAccess()
333 {
334 return $this->hasSuperUserAccess;
335 }
336
337 /**
338 * Returns the current user login
339 *
340 * @return string|null
341 */
342 public function getLogin()
343 {
344 return $this->login;
345 }
346
347 /**
348 * Returns the token_auth used to authenticate this user in the API
349 *
350 * @return string|null
351 */
352 public function getTokenAuth()
353 {
354 return $this->token_auth;
355 }
356
357 /**
358 * Returns an array of ID sites for which the user has at least a VIEW access.
359 * Which means VIEW OR WRITE or ADMIN or SUPERUSER.
360 *
361 * @return array Example if the user is ADMIN for 4
362 * and has VIEW access for 1 and 7, it returns array(1, 4, 7);
363 */
364 public function getSitesIdWithAtLeastViewAccess()
365 {
366 $this->loadSitesIfNeeded();
367
368 return array_unique(array_merge(
369 $this->idsitesByAccess['view'],
370 $this->idsitesByAccess['write'],
371 $this->idsitesByAccess['admin'],
372 $this->idsitesByAccess['superuser'])
373 );
374 }
375
376 /**
377 * Returns an array of ID sites for which the user has at least a WRITE access.
378 * Which means WRITE or ADMIN or SUPERUSER.
379 *
380 * @return array Example if the user is WRITE for 4 and 8
381 * and has VIEW access for 1 and 7, it returns array(4, 8);
382 */
383 public function getSitesIdWithAtLeastWriteAccess()
384 {
385 $this->loadSitesIfNeeded();
386
387 return array_unique(array_merge(
388 $this->idsitesByAccess['write'],
389 $this->idsitesByAccess['admin'],
390 $this->idsitesByAccess['superuser'])
391 );
392 }
393
394 /**
395 * Returns an array of ID sites for which the user has an ADMIN access.
396 *
397 * @return array Example if the user is ADMIN for 4 and 8
398 * and has VIEW access for 1 and 7, it returns array(4, 8);
399 */
400 public function getSitesIdWithAdminAccess()
401 {
402 $this->loadSitesIfNeeded();
403
404 return array_unique(array_merge(
405 $this->idsitesByAccess['admin'],
406 $this->idsitesByAccess['superuser'])
407 );
408 }
409
410 /**
411 * Returns an array of ID sites for which the user has a VIEW access only.
412 *
413 * @return array Example if the user is ADMIN for 4
414 * and has VIEW access for 1 and 7, it returns array(1, 7);
415 * @see getSitesIdWithAtLeastViewAccess()
416 */
417 public function getSitesIdWithViewAccess()
418 {
419 $this->loadSitesIfNeeded();
420
421 return $this->idsitesByAccess['view'];
422 }
423
424 /**
425 * Returns an array of ID sites for which the user has a WRITE access only.
426 *
427 * @return array Example if the user is ADMIN for 4
428 * and has WRITE access for 1 and 7, it returns array(1, 7);
429 * @see getSitesIdWithAtLeastWriteAccess()
430 */
431 public function getSitesIdWithWriteAccess()
432 {
433 $this->loadSitesIfNeeded();
434
435 return $this->idsitesByAccess['write'];
436 }
437
438 /**
439 * Throws an exception if the user is not the SuperUser
440 *
441 * @throws \Piwik\NoAccessException
442 */
443 public function checkUserHasSuperUserAccess()
444 {
445 if (!$this->hasSuperUserAccess()) {
446 $this->throwNoAccessException(Piwik::translate('General_ExceptionPrivilege', array("'superuser'")));
447 }
448 }
449
450 /**
451 * Returns `true` if the current user has admin access to at least one site.
452 *
453 * @return bool
454 */
455 public function isUserHasSomeWriteAccess()
456 {
457 if ($this->hasSuperUserAccess()) {
458 return true;
459 }
460
461 $idSitesAccessible = $this->getSitesIdWithAtLeastWriteAccess();
462
463 return count($idSitesAccessible) > 0;
464 }
465
466 /**
467 * Returns `true` if the current user has admin access to at least one site.
468 *
469 * @return bool
470 */
471 public function isUserHasSomeAdminAccess()
472 {
473 if ($this->hasSuperUserAccess()) {
474 return true;
475 }
476
477 $idSitesAccessible = $this->getSitesIdWithAdminAccess();
478
479 return count($idSitesAccessible) > 0;
480 }
481
482 /**
483 * If the user doesn't have an WRITE access for at least one website, throws an exception
484 *
485 * @throws \Piwik\NoAccessException
486 */
487 public function checkUserHasSomeWriteAccess()
488 {
489 if (!$this->isUserHasSomeWriteAccess()) {
490 $this->throwNoAccessException(Piwik::translate('General_ExceptionPrivilegeAtLeastOneWebsite', array('write')));
491 }
492 }
493
494 /**
495 * If the user doesn't have an ADMIN access for at least one website, throws an exception
496 *
497 * @throws \Piwik\NoAccessException
498 */
499 public function checkUserHasSomeAdminAccess()
500 {
501 if (!$this->isUserHasSomeAdminAccess()) {
502 $this->throwNoAccessException(Piwik::translate('General_ExceptionPrivilegeAtLeastOneWebsite', array('admin')));
503 }
504 }
505
506 /**
507 * If the user doesn't have any view permission, throw exception
508 *
509 * @throws \Piwik\NoAccessException
510 */
511 public function checkUserHasSomeViewAccess()
512 {
513 if ($this->hasSuperUserAccess()) {
514 return;
515 }
516
517 $idSitesAccessible = $this->getSitesIdWithAtLeastViewAccess();
518
519 if (count($idSitesAccessible) == 0) {
520 $this->throwNoAccessException(Piwik::translate('General_ExceptionPrivilegeAtLeastOneWebsite', array('view')));
521 }
522 }
523
524 /**
525 * This method checks that the user has ADMIN access for the given list of websites.
526 * If the user doesn't have ADMIN access for at least one website of the list, we throw an exception.
527 *
528 * @param int|array $idSites List of ID sites to check
529 * @throws \Piwik\NoAccessException If for any of the websites the user doesn't have an ADMIN access
530 */
531 public function checkUserHasAdminAccess($idSites)
532 {
533 if ($this->hasSuperUserAccess()) {
534 return;
535 }
536
537 $idSites = $this->getIdSites($idSites);
538 $idSitesAccessible = $this->getSitesIdWithAdminAccess();
539
540 foreach ($idSites as $idsite) {
541 if (!in_array($idsite, $idSitesAccessible)) {
542 $this->throwNoAccessException(Piwik::translate('General_ExceptionPrivilegeAccessWebsite', array("'admin'", $idsite)));
543 }
544 }
545 }
546
547 /**
548 * This method checks that the user has VIEW or ADMIN access for the given list of websites.
549 * If the user doesn't have VIEW or ADMIN access for at least one website of the list, we throw an exception.
550 *
551 * @param int|array|string $idSites List of ID sites to check (integer, array of integers, string comma separated list of integers)
552 * @throws \Piwik\NoAccessException If for any of the websites the user doesn't have an VIEW or ADMIN access
553 */
554 public function checkUserHasViewAccess($idSites)
555 {
556 if ($this->hasSuperUserAccess()) {
557 return;
558 }
559
560 $idSites = $this->getIdSites($idSites);
561 $idSitesAccessible = $this->getSitesIdWithAtLeastViewAccess();
562
563 foreach ($idSites as $idsite) {
564 if (!in_array($idsite, $idSitesAccessible)) {
565 $this->throwNoAccessException(Piwik::translate('General_ExceptionPrivilegeAccessWebsite', array("'view'", $idsite)));
566 }
567 }
568 }
569
570 /**
571 * This method checks that the user has VIEW or ADMIN access for the given list of websites.
572 * If the user doesn't have VIEW or ADMIN access for at least one website of the list, we throw an exception.
573 *
574 * @param int|array|string $idSites List of ID sites to check (integer, array of integers, string comma separated list of integers)
575 * @throws \Piwik\NoAccessException If for any of the websites the user doesn't have an VIEW or ADMIN access
576 */
577 public function checkUserHasWriteAccess($idSites)
578 {
579 if ($this->hasSuperUserAccess()) {
580 return;
581 }
582
583 $idSites = $this->getIdSites($idSites);
584 $idSitesAccessible = $this->getSitesIdWithAtLeastWriteAccess();
585
586 foreach ($idSites as $idsite) {
587 if (!in_array($idsite, $idSitesAccessible)) {
588 $this->throwNoAccessException(Piwik::translate('General_ExceptionPrivilegeAccessWebsite', array("'write'", $idsite)));
589 }
590 }
591 }
592
593 public function checkUserIsNotAnonymous()
594 {
595 if ($this->hasSuperUserAccess()) {
596 return;
597 }
598 if (Piwik::isUserIsAnonymous()) {
599 $this->throwNoAccessException(Piwik::translate('General_YouMustBeLoggedIn'));
600 }
601 }
602
603 private function getSitesIdWithCapability($capability)
604 {
605 if (!empty($this->idsitesByAccess[$capability])) {
606 return $this->idsitesByAccess[$capability];
607 }
608 return array();
609 }
610
611 public function checkUserHasCapability($idSites, $capability)
612 {
613 if ($this->hasSuperUserAccess()) {
614 return;
615 }
616
617 $idSites = $this->getIdSites($idSites);
618 $idSitesAccessible = $this->getSitesIdWithCapability($capability);
619
620 foreach ($idSites as $idsite) {
621 if (!in_array($idsite, $idSitesAccessible)) {
622 $this->throwNoAccessException(Piwik::translate('ExceptionCapabilityAccessWebsite', array("'" . $capability ."'", $idsite)));
623 }
624 }
625
626 // a capability applies only when the user also has at least view access
627 $this->checkUserHasViewAccess($idSites);
628 }
629
630 /**
631 * @param int|array|string $idSites
632 * @return array
633 * @throws \Piwik\NoAccessException
634 */
635 protected function getIdSites($idSites)
636 {
637 if ($idSites === 'all') {
638 $idSites = $this->getSitesIdWithAtLeastViewAccess();
639 }
640
641 $idSites = Site::getIdSitesFromIdSitesString($idSites);
642
643 if (empty($idSites)) {
644 $this->throwNoAccessException("The parameter 'idSite=' is missing from the request.");
645 }
646
647 return $idSites;
648 }
649
650 /**
651 * Executes a callback with superuser privileges, making sure those privileges are rescinded
652 * before this method exits. Privileges will be rescinded even if an exception is thrown.
653 *
654 * @param callback $function The callback to execute. Should accept no arguments.
655 * @return mixed The result of `$function`.
656 * @throws Exception rethrows any exceptions thrown by `$function`.
657 * @api
658 */
659 public static function doAsSuperUser($function)
660 {
661 $isSuperUser = self::getInstance()->hasSuperUserAccess();
662
663 if ($isSuperUser) {
664 return $function();
665 }
666
667 $access = self::getInstance();
668 $login = $access->getLogin();
669 $shouldResetLogin = empty($login); // make sure to reset login if a login was set by "makeSureLoginNameIsSet()"
670 $access->setSuperUserAccess(true);
671
672 try {
673 $result = $function();
674 } catch (\Throwable $ex) {
675 $access->setSuperUserAccess($isSuperUser);
676 if ($shouldResetLogin) {
677 $access->login = null;
678 }
679
680 throw $ex;
681 }
682
683 if ($shouldResetLogin) {
684 $access->login = null;
685 }
686 $access->setSuperUserAccess($isSuperUser);
687
688 return $result;
689 }
690
691 /**
692 * Returns the level of access the current user has to the given site.
693 *
694 * @param int $idSite The site to check.
695 * @return string The access level, eg, 'view', 'admin', 'noaccess'.
696 */
697 public function getRoleForSite($idSite)
698 {
699 if ($this->hasSuperUserAccess
700 || in_array($idSite, $this->getSitesIdWithAdminAccess())
701 ) {
702 return 'admin';
703 }
704
705 if (in_array($idSite, $this->getSitesIdWithWriteAccess())) {
706 return 'write';
707 }
708
709 if (in_array($idSite, $this->getSitesIdWithViewAccess())) {
710 return 'view';
711 }
712
713 return 'noaccess';
714 }
715
716 /**
717 * Returns the capabilities the current user has for a given site.
718 *
719 * @param int $idSite The site to check.
720 * @return string[] The capabilities the user has.
721 */
722 public function getCapabilitiesForSite($idSite)
723 {
724 $result = [];
725 foreach ($this->capabilityProvider->getAllCapabilityIds() as $capabilityId) {
726 if (empty($this->idsitesByAccess[$capabilityId])) {
727 continue;
728 }
729
730 if (in_array($idSite, $this->idsitesByAccess[$capabilityId])) {
731 $result[] = $capabilityId;
732 }
733 }
734 return $result;
735 }
736
737 /**
738 * Throw a NoAccessException with the given message, or a more generic 'You need to log in' message if the
739 * user is not currently logged in (e.g. if session has expired).
740 *
741 * @param $message
742 * @throws NoAccessException
743 */
744 private function throwNoAccessException($message)
745 {
746 if (Piwik::isUserIsAnonymous() && !Request::isRootRequestApiRequest()) {
747 $message = Piwik::translate('General_YouMustBeLoggedIn');
748 }
749 // Try to detect whether user was previously logged in so that we can display a different message
750 $referrer = Url::getReferrer();
751 $matomoUrl = SettingsPiwik::getPiwikUrl();
752 if ($referrer && $matomoUrl && Url::isValidHost(Url::getHostFromUrl($referrer)) &&
753 strpos($referrer, $matomoUrl) === 0
754 ) {
755 $message = Piwik::translate('General_YourSessionHasExpired');
756 }
757
758 throw new NoAccessException($message);
759 }
760
761 /**
762 * Returns true if the current user is logged in or not.
763 *
764 * @return bool
765 */
766 public function isUserLoggedIn()
767 {
768 return !empty($this->login);
769 }
770 }
771