PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 5.13.0
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v5.13.0
5.13.0 5.12.1 5.12.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 3 months ago SessionAuth.php 1 week ago SessionFingerprint.php 2 months ago SessionInitializer.php 1 year ago SessionNamespace.php 1 year ago
SessionAuth.php
212 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 /**
44 * @var bool
45 */
46 private $sessionExpired = \false;
47 public function __construct(?UsersModel $userModel = null, $shouldDestroySession = \true)
48 {
49 $this->userModel = $userModel ?: new UsersModel();
50 $this->shouldDestroySession = $shouldDestroySession;
51 }
52 public function getName()
53 {
54 return null;
55 }
56 public function setTokenAuth(
57 #[\SensitiveParameter]
58 $token_auth)
59 {
60 $this->tokenAuth = $token_auth;
61 }
62 public function getLogin()
63 {
64 if (isset($this->user['login'])) {
65 return $this->user['login'];
66 }
67 return null;
68 }
69 public function getTokenAuthSecret()
70 {
71 return null;
72 }
73 public function setLogin($login)
74 {
75 // empty
76 }
77 public function setPassword(
78 #[\SensitiveParameter]
79 $password)
80 {
81 // empty
82 }
83 public function setPasswordHash(
84 #[\SensitiveParameter]
85 $passwordHash)
86 {
87 // empty
88 }
89 public function authenticate()
90 {
91 $this->sessionExpired = \false;
92 $sessionFingerprint = new \Piwik\Session\SessionFingerprint();
93 $userModel = $this->userModel;
94 $this->checkIfSessionFailedToRead();
95 if ($this->isExpiredSession($sessionFingerprint)) {
96 $sessionFingerprint->clear();
97 return $this->makeAuthFailure();
98 }
99 $userForSession = $sessionFingerprint->getUser();
100 if (empty($userForSession)) {
101 return $this->makeAuthFailure();
102 }
103 $user = $userModel->getUser($userForSession);
104 if (empty($user) || $user['login'] !== $userForSession) {
105 return $this->makeAuthFailure();
106 }
107 $tsPasswordModified = !empty($user['ts_password_modified']) ? $user['ts_password_modified'] : null;
108 if ($this->isSessionStartedBeforePasswordChange($sessionFingerprint, $tsPasswordModified)) {
109 $this->destroyCurrentSession($sessionFingerprint);
110 return $this->makeAuthFailure();
111 }
112 $this->updateSessionExpireTime($sessionFingerprint);
113 if ($this->tokenAuth !== null && $this->tokenAuth !== \false && $this->tokenAuth !== $sessionFingerprint->getSessionTokenAuth()) {
114 return $this->makeAuthFailure();
115 }
116 if ($sessionFingerprint->getSessionTokenAuth()) {
117 $tokenAuth = $sessionFingerprint->getSessionTokenAuth();
118 } else {
119 $tokenAuth = $this->userModel->generateRandomTokenAuth();
120 }
121 return $this->makeAuthSuccess($user, $tokenAuth);
122 }
123 private function isSessionStartedBeforePasswordChange(\Piwik\Session\SessionFingerprint $sessionFingerprint, $tsPasswordModified)
124 {
125 // sanity check, make sure users can still login if the ts_password_modified column does not exist
126 if ($tsPasswordModified === null) {
127 return \false;
128 }
129 // if the session start time doesn't exist for some reason, log the user out
130 $sessionStartTime = $sessionFingerprint->getSessionStartTime();
131 if (empty($sessionStartTime)) {
132 return \true;
133 }
134 return $sessionStartTime < Date::factory($tsPasswordModified)->getTimestampUTC();
135 }
136 private function makeAuthFailure()
137 {
138 return new AuthResult(AuthResult::FAILURE, null, null);
139 }
140 private function makeAuthSuccess($user,
141 #[\SensitiveParameter]
142 $tokenAuth)
143 {
144 $this->user = $user;
145 $this->tokenAuth = $tokenAuth;
146 $isSuperUser = (int) $user['superuser_access'];
147 $code = $isSuperUser ? AuthResult::SUCCESS_SUPERUSER_AUTH_CODE : AuthResult::SUCCESS;
148 return new AuthResult($code, $user['login'], $tokenAuth);
149 }
150 protected function initNewBlankSession(\Piwik\Session\SessionFingerprint $sessionFingerprint)
151 {
152 // this user should be using a different session, so generate a new ID
153 // NOTE: Zend_Session cannot be used since it will destroy the old
154 // session.
155 if ($this->shouldDestroySession) {
156 session_regenerate_id();
157 }
158 // regenerating the ID will create a new session w/ a new ID, but will
159 // copy over the existing session data. we want the new session for the
160 // unauthorized user to be different, so we clear the session fingerprint.
161 $sessionFingerprint->clear();
162 }
163 protected function destroyCurrentSession(\Piwik\Session\SessionFingerprint $sessionFingerprint)
164 {
165 // Note: Piwik will attempt to create another session in the LoginController
166 // when rendering the login form (the nonce for the form is stored in the session).
167 // So we can't use Session::destroy() since Zend prohibits starting a new session
168 // after session_destroy() is called. Instead we clear the session fingerprint for
169 // the existing session and generate a new session. Both the old session &
170 // new session should have no stored data.
171 $sessionFingerprint->clear();
172 if ($this->shouldDestroySession) {
173 Session::regenerateId();
174 }
175 }
176 public function getTokenAuth()
177 {
178 return $this->tokenAuth;
179 }
180 private function updateSessionExpireTime(\Piwik\Session\SessionFingerprint $sessionFingerprint)
181 {
182 $sessionParams = session_get_cookie_params();
183 // we update the session cookie to make sure expired session cookies are not available client side...
184 $sessionCookieLifetime = Config::getInstance()->General['login_cookie_expire'];
185 Session::writeCookie(session_name(), session_id(), time() + $sessionCookieLifetime, $sessionParams['path'], $sessionParams['domain'], $sessionParams['secure'], $sessionParams['httponly'], Session::getSameSiteCookieValue());
186 // ...and we also update the expiration time stored server side so we can prevent expired sessions from being reused
187 $sessionFingerprint->updateSessionExpirationTime();
188 }
189 private function isExpiredSession(\Piwik\Session\SessionFingerprint $sessionFingerprint)
190 {
191 $expirationTime = $sessionFingerprint->getExpirationTime();
192 if (empty($expirationTime)) {
193 return \true;
194 }
195 $isExpired = Date::now()->getTimestampUTC() > $expirationTime;
196 if ($isExpired) {
197 $this->sessionExpired = \true;
198 }
199 return $isExpired;
200 }
201 public function wasSessionExpired() : bool
202 {
203 return $this->sessionExpired;
204 }
205 private function checkIfSessionFailedToRead()
206 {
207 if (Session\SaveHandler\DbTable::$wasSessionToLargeToRead) {
208 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.");
209 }
210 }
211 }
212