PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 5.2.0
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v5.2.0
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 / Session / SessionAuth.php
matomo / app / core / Session Last commit date
SaveHandler 1 year ago SessionAuth.php 1 year ago SessionFingerprint.php 1 year ago SessionInitializer.php 1 year ago SessionNamespace.php 1 year ago
SessionAuth.php
191 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\Session;
10
11 use Piwik\Auth;
12 use Piwik\AuthResult;
13 use Piwik\Config;
14 use Piwik\Container\StaticContainer;
15 use Piwik\Date;
16 use Piwik\Plugins\UsersManager\Model as UsersModel;
17 use Piwik\Session;
18 use Piwik\Log\LoggerInterface;
19 /**
20 * Validates already authenticated sessions.
21 *
22 * See {@link \Piwik\Session\SessionFingerprint} for more info.
23 */
24 class SessionAuth implements Auth
25 {
26 /**
27 * For tests, since there's no actual session there.
28 *
29 * @var bool
30 */
31 private $shouldDestroySession;
32 /**
33 * @var UsersModel
34 */
35 private $userModel;
36 /**
37 * Set internally so it can be queried in FrontController.
38 *
39 * @var array
40 */
41 private $user;
42 private $tokenAuth;
43 public function __construct(?UsersModel $userModel = null, $shouldDestroySession = \true)
44 {
45 $this->userModel = $userModel ?: new UsersModel();
46 $this->shouldDestroySession = $shouldDestroySession;
47 }
48 public function getName()
49 {
50 // empty
51 }
52 public function setTokenAuth($token_auth)
53 {
54 $this->tokenAuth = $token_auth;
55 }
56 public function getLogin()
57 {
58 if (isset($this->user['login'])) {
59 return $this->user['login'];
60 }
61 }
62 public function getTokenAuthSecret()
63 {
64 // empty
65 }
66 public function setLogin($login)
67 {
68 // empty
69 }
70 public function setPassword($password)
71 {
72 // empty
73 }
74 public function setPasswordHash($passwordHash)
75 {
76 // empty
77 }
78 public function authenticate()
79 {
80 $sessionFingerprint = new \Piwik\Session\SessionFingerprint();
81 $userModel = $this->userModel;
82 $this->checkIfSessionFailedToRead();
83 if ($this->isExpiredSession($sessionFingerprint)) {
84 $sessionFingerprint->clear();
85 return $this->makeAuthFailure();
86 }
87 $userForSession = $sessionFingerprint->getUser();
88 if (empty($userForSession)) {
89 return $this->makeAuthFailure();
90 }
91 $user = $userModel->getUser($userForSession);
92 if (empty($user) || $user['login'] !== $userForSession) {
93 return $this->makeAuthFailure();
94 }
95 $tsPasswordModified = !empty($user['ts_password_modified']) ? $user['ts_password_modified'] : null;
96 if ($this->isSessionStartedBeforePasswordChange($sessionFingerprint, $tsPasswordModified)) {
97 $this->destroyCurrentSession($sessionFingerprint);
98 return $this->makeAuthFailure();
99 }
100 $this->updateSessionExpireTime($sessionFingerprint);
101 if ($this->tokenAuth !== null && $this->tokenAuth !== \false && $this->tokenAuth !== $sessionFingerprint->getSessionTokenAuth()) {
102 return $this->makeAuthFailure();
103 }
104 if ($sessionFingerprint->getSessionTokenAuth()) {
105 $tokenAuth = $sessionFingerprint->getSessionTokenAuth();
106 } else {
107 $tokenAuth = $this->userModel->generateRandomTokenAuth();
108 }
109 return $this->makeAuthSuccess($user, $tokenAuth);
110 }
111 private function isSessionStartedBeforePasswordChange(\Piwik\Session\SessionFingerprint $sessionFingerprint, $tsPasswordModified)
112 {
113 // sanity check, make sure users can still login if the ts_password_modified column does not exist
114 if ($tsPasswordModified === null) {
115 return \false;
116 }
117 // if the session start time doesn't exist for some reason, log the user out
118 $sessionStartTime = $sessionFingerprint->getSessionStartTime();
119 if (empty($sessionStartTime)) {
120 return \true;
121 }
122 return $sessionStartTime < Date::factory($tsPasswordModified)->getTimestampUTC();
123 }
124 private function makeAuthFailure()
125 {
126 return new AuthResult(AuthResult::FAILURE, null, null);
127 }
128 private function makeAuthSuccess($user, $tokenAuth)
129 {
130 $this->user = $user;
131 $this->tokenAuth = $tokenAuth;
132 $isSuperUser = (int) $user['superuser_access'];
133 $code = $isSuperUser ? AuthResult::SUCCESS_SUPERUSER_AUTH_CODE : AuthResult::SUCCESS;
134 return new AuthResult($code, $user['login'], $tokenAuth);
135 }
136 protected function initNewBlankSession(\Piwik\Session\SessionFingerprint $sessionFingerprint)
137 {
138 // this user should be using a different session, so generate a new ID
139 // NOTE: Zend_Session cannot be used since it will destroy the old
140 // session.
141 if ($this->shouldDestroySession) {
142 session_regenerate_id();
143 }
144 // regenerating the ID will create a new session w/ a new ID, but will
145 // copy over the existing session data. we want the new session for the
146 // unauthorized user to be different, so we clear the session fingerprint.
147 $sessionFingerprint->clear();
148 }
149 protected function destroyCurrentSession(\Piwik\Session\SessionFingerprint $sessionFingerprint)
150 {
151 // Note: Piwik will attempt to create another session in the LoginController
152 // when rendering the login form (the nonce for the form is stored in the session).
153 // So we can't use Session::destroy() since Zend prohibits starting a new session
154 // after session_destroy() is called. Instead we clear the session fingerprint for
155 // the existing session and generate a new session. Both the old session &
156 // new session should have no stored data.
157 $sessionFingerprint->clear();
158 if ($this->shouldDestroySession) {
159 Session::regenerateId();
160 }
161 }
162 public function getTokenAuth()
163 {
164 return $this->tokenAuth;
165 }
166 private function updateSessionExpireTime(\Piwik\Session\SessionFingerprint $sessionFingerprint)
167 {
168 $sessionParams = session_get_cookie_params();
169 // we update the session cookie to make sure expired session cookies are not available client side...
170 $sessionCookieLifetime = Config::getInstance()->General['login_cookie_expire'];
171 Session::writeCookie(session_name(), session_id(), time() + $sessionCookieLifetime, $sessionParams['path'], $sessionParams['domain'], $sessionParams['secure'], $sessionParams['httponly'], Session::getSameSiteCookieValue());
172 // ...and we also update the expiration time stored server side so we can prevent expired sessions from being reused
173 $sessionFingerprint->updateSessionExpirationTime();
174 }
175 private function isExpiredSession(\Piwik\Session\SessionFingerprint $sessionFingerprint)
176 {
177 $expirationTime = $sessionFingerprint->getExpirationTime();
178 if (empty($expirationTime)) {
179 return \true;
180 }
181 $isExpired = Date::now()->getTimestampUTC() > $expirationTime;
182 return $isExpired;
183 }
184 private function checkIfSessionFailedToRead()
185 {
186 if (Session\SaveHandler\DbTable::$wasSessionToLargeToRead) {
187 StaticContainer::get(LoggerInterface::class)->warning("Too much data stored in the session so it could not be read properly. If you were logged out, this is why.");
188 }
189 }
190 }
191