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 / Session / SessionAuth.php
matomo / app / core / Session Last commit date
SaveHandler 6 years ago SessionAuth.php 6 years ago SessionFingerprint.php 6 years ago SessionInitializer.php 6 years ago SessionNamespace.php 6 years ago
SessionAuth.php
216 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
10 namespace Piwik\Session;
11
12 use Piwik\Auth;
13 use Piwik\AuthResult;
14 use Piwik\Config;
15 use Piwik\Date;
16 use Piwik\Plugins\UsersManager\Model as UsersModel;
17 use Piwik\Session;
18
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 /**
34 * @var UsersModel
35 */
36 private $userModel;
37
38 /**
39 * Set internally so it can be queried in FrontController.
40 *
41 * @var array
42 */
43 private $user;
44
45 public function __construct(UsersModel $userModel = null, $shouldDestroySession = true)
46 {
47 $this->userModel = $userModel ?: new UsersModel();
48 $this->shouldDestroySession = $shouldDestroySession;
49 }
50
51 public function getName()
52 {
53 // empty
54 }
55
56 public function setTokenAuth($token_auth)
57 {
58 // empty
59 }
60
61 public function getLogin()
62 {
63 return $this->user['login'];
64 }
65
66 public function getTokenAuthSecret()
67 {
68 // empty
69 }
70
71 public function setLogin($login)
72 {
73 // empty
74 }
75
76 public function setPassword($password)
77 {
78 // empty
79 }
80
81 public function setPasswordHash($passwordHash)
82 {
83 // empty
84 }
85
86 public function authenticate()
87 {
88 $sessionFingerprint = new SessionFingerprint();
89 $userModel = $this->userModel;
90
91 if ($this->isExpiredSession($sessionFingerprint)) {
92 $sessionFingerprint->clear();
93 return $this->makeAuthFailure();
94 }
95
96 $userForSession = $sessionFingerprint->getUser();
97 if (empty($userForSession)) {
98 return $this->makeAuthFailure();
99 }
100
101 $user = $userModel->getUser($userForSession);
102 if (empty($user)
103 || $user['login'] !== $userForSession // sanity check in case there's a bug in getUser()
104 ) {
105 return $this->makeAuthFailure();
106 }
107
108 $tsPasswordModified = !empty($user['ts_password_modified']) ? $user['ts_password_modified'] : null;
109 if ($this->isSessionStartedBeforePasswordChange($sessionFingerprint, $tsPasswordModified)) {
110 $this->destroyCurrentSession($sessionFingerprint);
111 return $this->makeAuthFailure();
112 }
113
114 $this->updateSessionExpireTime($sessionFingerprint);
115
116 return $this->makeAuthSuccess($user);
117 }
118
119 private function isSessionStartedBeforePasswordChange(SessionFingerprint $sessionFingerprint, $tsPasswordModified)
120 {
121 // sanity check, make sure users can still login if the ts_password_modified column does not exist
122 if ($tsPasswordModified === null) {
123 return false;
124 }
125
126 // if the session start time doesn't exist for some reason, log the user out
127 $sessionStartTime = $sessionFingerprint->getSessionStartTime();
128 if (empty($sessionStartTime)) {
129 return true;
130 }
131
132 return $sessionStartTime < Date::factory($tsPasswordModified)->getTimestampUTC();
133 }
134
135 private function makeAuthFailure()
136 {
137 return new AuthResult(AuthResult::FAILURE, null, null);
138 }
139
140 private function makeAuthSuccess($user)
141 {
142 $this->user = $user;
143
144 $isSuperUser = (int) $user['superuser_access'];
145 $code = $isSuperUser ? AuthResult::SUCCESS_SUPERUSER_AUTH_CODE : AuthResult::SUCCESS;
146
147 return new AuthResult($code, $user['login'], $user['token_auth']);
148 }
149
150 protected function initNewBlankSession(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
159 // regenerating the ID will create a new session w/ a new ID, but will
160 // copy over the existing session data. we want the new session for the
161 // unauthorized user to be different, so we clear the session fingerprint.
162 $sessionFingerprint->clear();
163 }
164
165 protected function destroyCurrentSession(SessionFingerprint $sessionFingerprint)
166 {
167 // Note: Piwik will attempt to create another session in the LoginController
168 // when rendering the login form (the nonce for the form is stored in the session).
169 // So we can't use Session::destroy() since Zend prohibits starting a new session
170 // after session_destroy() is called. Instead we clear the session fingerprint for
171 // the existing session and generate a new session. Both the old session &
172 // new session should have no stored data.
173 $sessionFingerprint->clear();
174 if ($this->shouldDestroySession) {
175 Session::regenerateId();
176 }
177 }
178
179 public function getTokenAuth()
180 {
181 return $this->user['token_auth'];
182 }
183
184 private function updateSessionExpireTime(SessionFingerprint $sessionFingerprint)
185 {
186 $sessionParams = session_get_cookie_params();
187
188 // we update the session cookie to make sure expired session cookies are not available client side...
189 $sessionCookieLifetime = Config::getInstance()->General['login_cookie_expire'];
190 Session::writeCookie(
191 session_name(),
192 session_id(),
193 time() + $sessionCookieLifetime,
194 $sessionParams['path'],
195 $sessionParams['domain'],
196 $sessionParams['secure'],
197 $sessionParams['httponly'],
198 Session::getSameSiteCookieValue()
199 );
200
201 // ...and we also update the expiration time stored server side so we can prevent expired sessions from being reused
202 $sessionFingerprint->updateSessionExpirationTime();
203 }
204
205 private function isExpiredSession(SessionFingerprint $sessionFingerprint)
206 {
207 $expirationTime = $sessionFingerprint->getExpirationTime();
208 if (empty($expirationTime)) {
209 return true;
210 }
211
212 $isExpired = Date::now()->getTimestampUTC() > $expirationTime;
213 return $isExpired;
214 }
215 }
216