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