PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 1.3.1
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v1.3.1
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 6 years ago Access 6 years ago Application 6 years ago Archive 6 years ago ArchiveProcessor 6 years ago Archiver 6 years ago AssetManager 6 years ago Auth 6 years ago Category 6 years ago CliMulti 6 years ago Columns 6 years ago Composer 6 years ago Concurrency 6 years ago Config 6 years ago Container 6 years ago CronArchive 6 years ago DataAccess 5 years ago DataFiles 6 years ago DataTable 6 years ago Db 6 years ago DeviceDetector 5 years ago Email 6 years ago Exception 6 years ago Http 6 years ago Intl 6 years ago Mail 6 years ago Measurable 6 years ago Menu 6 years ago Metrics 6 years ago Notification 6 years ago Period 6 years ago Plugin 6 years ago ProfessionalServices 6 years ago Report 6 years ago ReportRenderer 6 years ago Scheduler 6 years ago Segment 6 years ago Session 6 years ago Settings 6 years ago Tracker 5 years ago Translation 6 years ago UpdateCheck 6 years ago Updater 6 years ago Updates 6 years ago Validators 6 years ago View 6 years ago ViewDataTable 6 years ago Visualization 6 years ago Widget 6 years ago .htaccess 6 years ago Access.php 6 years ago Archive.php 6 years ago ArchiveProcessor.php 6 years ago AssetManager.php 6 years ago Auth.php 6 years ago BaseFactory.php 6 years ago Cache.php 6 years ago CacheId.php 6 years ago CliMulti.php 6 years ago Common.php 6 years ago Config.php 6 years ago Console.php 6 years ago Context.php 6 years ago Cookie.php 5 years ago CronArchive.php 5 years ago DataArray.php 6 years ago DataTable.php 6 years ago Date.php 6 years ago Db.php 6 years ago DbHelper.php 6 years ago Development.php 6 years ago DeviceDetectorFactory.php 6 years ago ErrorHandler.php 6 years ago EventDispatcher.php 6 years ago ExceptionHandler.php 6 years ago FileIntegrity.php 6 years ago Filechecks.php 6 years ago Filesystem.php 6 years ago FrontController.php 6 years ago Http.php 6 years ago IP.php 6 years ago Log.php 6 years ago LogDeleter.php 6 years ago Mail.php 6 years ago Metrics.php 6 years ago MetricsFormatter.php 6 years ago Nonce.php 5 years ago Notification.php 6 years ago NumberFormatter.php 6 years ago Option.php 5 years ago Period.php 6 years ago Piwik.php 6 years ago Plugin.php 6 years ago Profiler.php 6 years ago ProxyHeaders.php 6 years ago ProxyHttp.php 6 years ago QuickForm2.php 6 years ago RankingQuery.php 6 years ago Registry.php 6 years ago ReportRenderer.php 6 years ago ScheduledTask.php 6 years ago Segment.php 6 years ago Sequence.php 6 years ago Session.php 6 years ago SettingsPiwik.php 6 years ago SettingsServer.php 6 years ago Singleton.php 6 years ago Site.php 6 years ago TCPDF.php 6 years ago TaskScheduler.php 6 years ago Theme.php 6 years ago Timer.php 6 years ago Tracker.php 6 years ago Translate.php 6 years ago Twig.php 6 years ago Unzip.php 6 years ago UpdateCheck.php 6 years ago Updater.php 6 years ago Updates.php 6 years ago Url.php 6 years ago UrlHelper.php 6 years ago Version.php 5 years ago View.php 6 years ago bootstrap.php 6 years ago dispatch.php 6 years ago testMinimumPhpVersion.php 6 years ago
Access.php
750 lines
1 <?php
2 /**
3 * Piwik - 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\Exception\InvalidRequestParameterException;
17 use Piwik\Plugins\SitesManager\API as SitesManagerApi;
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 // access = array ( idsite => accessIdSite, idsite2 => accessIdSite2)
159 $result = $this->auth->authenticate();
160
161 if (!$result->wasAuthenticationSuccessful()) {
162 return false;
163 }
164
165 $this->login = $result->getIdentity();
166 $this->token_auth = $result->getTokenAuth();
167
168 // case the superUser is logged in
169 if ($result->hasSuperUserAccess()) {
170 $this->setSuperUserAccess(true);
171 }
172
173 return true;
174 }
175
176 public function getRawSitesWithSomeViewAccess($login)
177 {
178 $sql = self::getSqlAccessSite("access, t2.idsite");
179
180 return Db::fetchAll($sql, $login);
181 }
182
183 /**
184 * Returns the SQL query joining sites and access table for a given login
185 *
186 * @param string $select Columns or expression to SELECT FROM table, eg. "MIN(ts_created)"
187 * @return string SQL query
188 */
189 public static function getSqlAccessSite($select)
190 {
191 $access = Common::prefixTable('access');
192 $siteTable = Common::prefixTable('site');
193
194 return "SELECT " . $select . " FROM " . $access . " as t1
195 JOIN " . $siteTable . " as t2 USING (idsite) WHERE login = ?";
196 }
197
198 /**
199 * Make sure a login name is set
200 *
201 * @return true
202 */
203 protected function makeSureLoginNameIsSet()
204 {
205 if (empty($this->login)) {
206 // flag to force non empty login so Super User is not mistaken for anonymous
207 $this->login = 'super user was set';
208 }
209 }
210
211 protected function loadSitesIfNeeded()
212 {
213 if ($this->hasSuperUserAccess) {
214 if (empty($this->idsitesByAccess['superuser'])) {
215 try {
216 $api = SitesManagerApi::getInstance();
217 $allSitesId = $api->getAllSitesId();
218 } catch (\Exception $e) {
219 $allSitesId = array();
220 }
221 $this->idsitesByAccess['superuser'] = $allSitesId;
222 }
223 } elseif (isset($this->login)) {
224 if (empty($this->idsitesByAccess['view'])
225 && empty($this->idsitesByAccess['write'])
226 && empty($this->idsitesByAccess['admin'])
227 ) {
228 // we join with site in case there are rows in access for an idsite that doesn't exist anymore
229 // (backward compatibility ; before we deleted the site without deleting rows in _access table)
230 $accessRaw = $this->getRawSitesWithSomeViewAccess($this->login);
231
232 foreach ($accessRaw as $access) {
233 $accessType = $access['access'];
234 $this->idsitesByAccess[$accessType][] = $access['idsite'];
235
236 if ($this->roleProvider->isValidRole($accessType)) {
237 foreach ($this->capabilityProvider->getAllCapabilities() as $capability) {
238 if ($capability->hasRoleCapability($accessType)) {
239 // we automatically add this capability
240 if (!isset($this->idsitesByAccess[$capability->getId()])) {
241 $this->idsitesByAccess[$capability->getId()] = array();
242 }
243 $this->idsitesByAccess[$capability->getId()][] = $access['idsite'];
244 }
245 }
246 }
247 }
248
249 /**
250 * Triggered after the initial access levels and permissions for the current user are loaded. Use this
251 * event to modify the current user's permissions (for example, making sure every user has view access
252 * to a specific site).
253 *
254 * **Example**
255 *
256 * function (&$idsitesByAccess, $login) {
257 * if ($login == 'somespecialuser') {
258 * return;
259 * }
260 *
261 * $idsitesByAccess['view'][] = $mySpecialIdSite;
262 * }
263 *
264 * @param array[] &$idsitesByAccess The current user's access levels for individual sites. Maps role and
265 * capability IDs to list of site IDs, eg:
266 *
267 * ```
268 * [
269 * 'view' => [1, 2, 3],
270 * 'write' => [4, 5],
271 * 'admin' => [],
272 * ]
273 * ```
274 * @param string $login The current user's login.
275 */
276 Piwik::postEvent('Access.modifyUserAccess', [&$this->idsitesByAccess, $this->login]);
277 }
278 }
279 }
280
281 /**
282 * We bypass the normal auth method and give the current user Super User rights.
283 * This should be very carefully used.
284 *
285 * @param bool $bool
286 */
287 public function setSuperUserAccess($bool = true)
288 {
289 $this->hasSuperUserAccess = (bool) $bool;
290
291 if ($bool) {
292 $this->makeSureLoginNameIsSet();
293 } else {
294 $this->resetSites();
295 }
296 }
297
298 /**
299 * Returns true if the current user is logged in as the Super User
300 *
301 * @return bool
302 */
303 public function hasSuperUserAccess()
304 {
305 return $this->hasSuperUserAccess;
306 }
307
308 /**
309 * Returns the current user login
310 *
311 * @return string|null
312 */
313 public function getLogin()
314 {
315 return $this->login;
316 }
317
318 /**
319 * Returns the token_auth used to authenticate this user in the API
320 *
321 * @return string|null
322 */
323 public function getTokenAuth()
324 {
325 return $this->token_auth;
326 }
327
328 /**
329 * Returns an array of ID sites for which the user has at least a VIEW access.
330 * Which means VIEW OR WRITE or ADMIN or SUPERUSER.
331 *
332 * @return array Example if the user is ADMIN for 4
333 * and has VIEW access for 1 and 7, it returns array(1, 4, 7);
334 */
335 public function getSitesIdWithAtLeastViewAccess()
336 {
337 $this->loadSitesIfNeeded();
338
339 return array_unique(array_merge(
340 $this->idsitesByAccess['view'],
341 $this->idsitesByAccess['write'],
342 $this->idsitesByAccess['admin'],
343 $this->idsitesByAccess['superuser'])
344 );
345 }
346
347 /**
348 * Returns an array of ID sites for which the user has at least a WRITE access.
349 * Which means WRITE or ADMIN or SUPERUSER.
350 *
351 * @return array Example if the user is WRITE for 4 and 8
352 * and has VIEW access for 1 and 7, it returns array(4, 8);
353 */
354 public function getSitesIdWithAtLeastWriteAccess()
355 {
356 $this->loadSitesIfNeeded();
357
358 return array_unique(array_merge(
359 $this->idsitesByAccess['write'],
360 $this->idsitesByAccess['admin'],
361 $this->idsitesByAccess['superuser'])
362 );
363 }
364
365 /**
366 * Returns an array of ID sites for which the user has an ADMIN access.
367 *
368 * @return array Example if the user is ADMIN for 4 and 8
369 * and has VIEW access for 1 and 7, it returns array(4, 8);
370 */
371 public function getSitesIdWithAdminAccess()
372 {
373 $this->loadSitesIfNeeded();
374
375 return array_unique(array_merge(
376 $this->idsitesByAccess['admin'],
377 $this->idsitesByAccess['superuser'])
378 );
379 }
380
381 /**
382 * Returns an array of ID sites for which the user has a VIEW access only.
383 *
384 * @return array Example if the user is ADMIN for 4
385 * and has VIEW access for 1 and 7, it returns array(1, 7);
386 * @see getSitesIdWithAtLeastViewAccess()
387 */
388 public function getSitesIdWithViewAccess()
389 {
390 $this->loadSitesIfNeeded();
391
392 return $this->idsitesByAccess['view'];
393 }
394
395 /**
396 * Returns an array of ID sites for which the user has a WRITE access only.
397 *
398 * @return array Example if the user is ADMIN for 4
399 * and has WRITE access for 1 and 7, it returns array(1, 7);
400 * @see getSitesIdWithAtLeastWriteAccess()
401 */
402 public function getSitesIdWithWriteAccess()
403 {
404 $this->loadSitesIfNeeded();
405
406 return $this->idsitesByAccess['write'];
407 }
408
409 /**
410 * Throws an exception if the user is not the SuperUser
411 *
412 * @throws \Piwik\NoAccessException
413 */
414 public function checkUserHasSuperUserAccess()
415 {
416 if (!$this->hasSuperUserAccess()) {
417 $this->throwNoAccessException(Piwik::translate('General_ExceptionPrivilege', array("'superuser'")));
418 }
419 }
420
421 /**
422 * Returns `true` if the current user has admin access to at least one site.
423 *
424 * @return bool
425 */
426 public function isUserHasSomeWriteAccess()
427 {
428 if ($this->hasSuperUserAccess()) {
429 return true;
430 }
431
432 $idSitesAccessible = $this->getSitesIdWithAtLeastWriteAccess();
433
434 return count($idSitesAccessible) > 0;
435 }
436
437 /**
438 * Returns `true` if the current user has admin access to at least one site.
439 *
440 * @return bool
441 */
442 public function isUserHasSomeAdminAccess()
443 {
444 if ($this->hasSuperUserAccess()) {
445 return true;
446 }
447
448 $idSitesAccessible = $this->getSitesIdWithAdminAccess();
449
450 return count($idSitesAccessible) > 0;
451 }
452
453 /**
454 * If the user doesn't have an WRITE access for at least one website, throws an exception
455 *
456 * @throws \Piwik\NoAccessException
457 */
458 public function checkUserHasSomeWriteAccess()
459 {
460 if (!$this->isUserHasSomeWriteAccess()) {
461 $this->throwNoAccessException(Piwik::translate('General_ExceptionPrivilegeAtLeastOneWebsite', array('write')));
462 }
463 }
464
465 /**
466 * If the user doesn't have an ADMIN access for at least one website, throws an exception
467 *
468 * @throws \Piwik\NoAccessException
469 */
470 public function checkUserHasSomeAdminAccess()
471 {
472 if (!$this->isUserHasSomeAdminAccess()) {
473 $this->throwNoAccessException(Piwik::translate('General_ExceptionPrivilegeAtLeastOneWebsite', array('admin')));
474 }
475 }
476
477 /**
478 * If the user doesn't have any view permission, throw exception
479 *
480 * @throws \Piwik\NoAccessException
481 */
482 public function checkUserHasSomeViewAccess()
483 {
484 if ($this->hasSuperUserAccess()) {
485 return;
486 }
487
488 $idSitesAccessible = $this->getSitesIdWithAtLeastViewAccess();
489
490 if (count($idSitesAccessible) == 0) {
491 $this->throwNoAccessException(Piwik::translate('General_ExceptionPrivilegeAtLeastOneWebsite', array('view')));
492 }
493 }
494
495 /**
496 * This method checks that the user has ADMIN access for the given list of websites.
497 * If the user doesn't have ADMIN access for at least one website of the list, we throw an exception.
498 *
499 * @param int|array $idSites List of ID sites to check
500 * @throws \Piwik\NoAccessException If for any of the websites the user doesn't have an ADMIN access
501 */
502 public function checkUserHasAdminAccess($idSites)
503 {
504 if ($this->hasSuperUserAccess()) {
505 return;
506 }
507
508 $idSites = $this->getIdSites($idSites);
509 $idSitesAccessible = $this->getSitesIdWithAdminAccess();
510
511 foreach ($idSites as $idsite) {
512 if (!in_array($idsite, $idSitesAccessible)) {
513 $this->throwNoAccessException(Piwik::translate('General_ExceptionPrivilegeAccessWebsite', array("'admin'", $idsite)));
514 }
515 }
516 }
517
518 /**
519 * This method checks that the user has VIEW or ADMIN access for the given list of websites.
520 * If the user doesn't have VIEW or ADMIN access for at least one website of the list, we throw an exception.
521 *
522 * @param int|array|string $idSites List of ID sites to check (integer, array of integers, string comma separated list of integers)
523 * @throws \Piwik\NoAccessException If for any of the websites the user doesn't have an VIEW or ADMIN access
524 */
525 public function checkUserHasViewAccess($idSites)
526 {
527 if ($this->hasSuperUserAccess()) {
528 return;
529 }
530
531 $idSites = $this->getIdSites($idSites);
532 $idSitesAccessible = $this->getSitesIdWithAtLeastViewAccess();
533
534 foreach ($idSites as $idsite) {
535 if (!in_array($idsite, $idSitesAccessible)) {
536 $this->throwNoAccessException(Piwik::translate('General_ExceptionPrivilegeAccessWebsite', array("'view'", $idsite)));
537 }
538 }
539 }
540
541 /**
542 * This method checks that the user has VIEW or ADMIN access for the given list of websites.
543 * If the user doesn't have VIEW or ADMIN access for at least one website of the list, we throw an exception.
544 *
545 * @param int|array|string $idSites List of ID sites to check (integer, array of integers, string comma separated list of integers)
546 * @throws \Piwik\NoAccessException If for any of the websites the user doesn't have an VIEW or ADMIN access
547 */
548 public function checkUserHasWriteAccess($idSites)
549 {
550 if ($this->hasSuperUserAccess()) {
551 return;
552 }
553
554 $idSites = $this->getIdSites($idSites);
555 $idSitesAccessible = $this->getSitesIdWithAtLeastWriteAccess();
556
557 foreach ($idSites as $idsite) {
558 if (!in_array($idsite, $idSitesAccessible)) {
559 $this->throwNoAccessException(Piwik::translate('General_ExceptionPrivilegeAccessWebsite', array("'write'", $idsite)));
560 }
561 }
562 }
563
564 public function checkUserIsNotAnonymous()
565 {
566 if ($this->hasSuperUserAccess()) {
567 return;
568 }
569 if (Piwik::isUserIsAnonymous()) {
570 $this->throwNoAccessException(Piwik::translate('General_YouMustBeLoggedIn'));
571 }
572 }
573
574 private function getSitesIdWithCapability($capability)
575 {
576 if (!empty($this->idsitesByAccess[$capability])) {
577 return $this->idsitesByAccess[$capability];
578 }
579 return array();
580 }
581
582 public function checkUserHasCapability($idSites, $capability)
583 {
584 if ($this->hasSuperUserAccess()) {
585 return;
586 }
587
588 $idSites = $this->getIdSites($idSites);
589 $idSitesAccessible = $this->getSitesIdWithCapability($capability);
590
591 foreach ($idSites as $idsite) {
592 if (!in_array($idsite, $idSitesAccessible)) {
593 $this->throwNoAccessException(Piwik::translate('ExceptionCapabilityAccessWebsite', array("'" . $capability ."'", $idsite)));
594 }
595 }
596
597 // a capability applies only when the user also has at least view access
598 $this->checkUserHasViewAccess($idSites);
599 }
600
601 /**
602 * @param int|array|string $idSites
603 * @return array
604 * @throws \Piwik\NoAccessException
605 */
606 protected function getIdSites($idSites)
607 {
608 if ($idSites === 'all') {
609 $idSites = $this->getSitesIdWithAtLeastViewAccess();
610 }
611
612 $idSites = Site::getIdSitesFromIdSitesString($idSites);
613
614 if (empty($idSites)) {
615 $this->throwNoAccessException("The parameter 'idSite=' is missing from the request.");
616 }
617
618 return $idSites;
619 }
620
621 /**
622 * Executes a callback with superuser privileges, making sure those privileges are rescinded
623 * before this method exits. Privileges will be rescinded even if an exception is thrown.
624 *
625 * @param callback $function The callback to execute. Should accept no arguments.
626 * @return mixed The result of `$function`.
627 * @throws Exception rethrows any exceptions thrown by `$function`.
628 * @api
629 */
630 public static function doAsSuperUser($function)
631 {
632 $isSuperUser = self::getInstance()->hasSuperUserAccess();
633
634 if ($isSuperUser) {
635 return $function();
636 }
637
638 $access = self::getInstance();
639 $login = $access->getLogin();
640 $shouldResetLogin = empty($login); // make sure to reset login if a login was set by "makeSureLoginNameIsSet()"
641 $access->setSuperUserAccess(true);
642
643 try {
644 $result = $function();
645 } catch (Exception $ex) {
646 $access->setSuperUserAccess($isSuperUser);
647 if ($shouldResetLogin) {
648 $access->login = null;
649 }
650
651 throw $ex;
652 }
653
654 if ($shouldResetLogin) {
655 $access->login = null;
656 }
657 $access->setSuperUserAccess($isSuperUser);
658
659 return $result;
660 }
661
662 /**
663 * Returns the level of access the current user has to the given site.
664 *
665 * @param int $idSite The site to check.
666 * @return string The access level, eg, 'view', 'admin', 'noaccess'.
667 */
668 public function getRoleForSite($idSite)
669 {
670 if ($this->hasSuperUserAccess
671 || in_array($idSite, $this->getSitesIdWithAdminAccess())
672 ) {
673 return 'admin';
674 }
675
676 if (in_array($idSite, $this->getSitesIdWithWriteAccess())) {
677 return 'write';
678 }
679
680 if (in_array($idSite, $this->getSitesIdWithViewAccess())) {
681 return 'view';
682 }
683
684 return 'noaccess';
685 }
686
687 /**
688 * Returns the capabilities the current user has for a given site.
689 *
690 * @param int $idSite The site to check.
691 * @return string[] The capabilities the user has.
692 */
693 public function getCapabilitiesForSite($idSite)
694 {
695 $result = [];
696 foreach ($this->capabilityProvider->getAllCapabilityIds() as $capabilityId) {
697 if (empty($this->idsitesByAccess[$capabilityId])) {
698 continue;
699 }
700
701 if (in_array($idSite, $this->idsitesByAccess[$capabilityId])) {
702 $result[] = $capabilityId;
703 }
704 }
705 return $result;
706 }
707
708 /**
709 * Throw a NoAccessException with the given message, or a more generic 'You need to log in' message if the
710 * user is not currently logged in (e.g. if session has expired).
711 * @param $message
712 * @throws NoAccessException
713 */
714 private function throwNoAccessException($message)
715 {
716 if (Piwik::isUserIsAnonymous() && !Request::isRootRequestApiRequest()) {
717 $message = Piwik::translate('General_YouMustBeLoggedIn');
718 }
719 // Try to detect whether user was previously logged in so that we can display a different message
720 $referrer = Url::getReferrer();
721 $matomoUrl = SettingsPiwik::getPiwikUrl();
722 if ($referrer && $matomoUrl && Url::isValidHost(Url::getHostFromUrl($referrer)) &&
723 strpos($referrer, $matomoUrl) === 0
724 ) {
725 $message = Piwik::translate('General_YourSessionHasExpired');
726 }
727
728 throw new NoAccessException($message);
729 }
730
731 /**
732 * Returns true if the current user is logged in or not.
733 *
734 * @return bool
735 */
736 public function isUserLoggedIn()
737 {
738 return !empty($this->login);
739 }
740 }
741
742 /**
743 * Exception thrown when a user doesn't have sufficient access to a resource.
744 *
745 * @api
746 */
747 class NoAccessException extends InvalidRequestParameterException
748 {
749 }
750