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