Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
19.40% |
52 / 268 |
|
21.05% |
4 / 19 |
CRAP | |
0.00% |
0 / 1 |
CentralAuthSessionProvider | |
19.40% |
52 / 268 |
|
21.05% |
4 / 19 |
3778.16 | |
0.00% |
0 / 1 |
__construct | |
75.00% |
9 / 12 |
|
0.00% |
0 / 1 |
2.06 | |||
postInitSetup | |
100.00% |
15 / 15 |
|
100.00% |
1 / 1 |
2 | |||
returnParentSessionInfo | |
21.05% |
4 / 19 |
|
0.00% |
0 / 1 |
7.43 | |||
provideSessionInfo | |
3.85% |
3 / 78 |
|
0.00% |
0 / 1 |
452.27 | |||
refreshSessionInfo | |
7.14% |
2 / 28 |
|
0.00% |
0 / 1 |
90.07 | |||
sessionIdWasReset | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 | |||
sessionDataToExport | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 | |||
cookieDataToExport | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
persistSession | |
0.00% |
0 / 41 |
|
0.00% |
0 / 1 |
156 | |||
unpersistSession | |
25.00% |
3 / 12 |
|
0.00% |
0 / 1 |
6.80 | |||
invalidateSessionsForUser | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
20 | |||
preventSessionsForUser | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
30 | |||
setForceHTTPSCookie | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
setLoggedOutCookie | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
12 | |||
getVaryCookies | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 | |||
suggestLoginUsername | |
87.50% |
7 / 8 |
|
0.00% |
0 / 1 |
5.05 | |||
getCentralCookieDomain | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getExtendedLoginCookies | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
getRememberUserDuration | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
2 |
1 | <?php |
2 | |
3 | use MediaWiki\Extension\CentralAuth\CentralAuthSessionManager; |
4 | use MediaWiki\Extension\CentralAuth\User\CentralAuthUser; |
5 | use MediaWiki\MainConfigNames; |
6 | use MediaWiki\Request\FauxRequest; |
7 | use MediaWiki\Request\WebRequest; |
8 | use MediaWiki\Session\SessionBackend; |
9 | use MediaWiki\Session\SessionInfo; |
10 | use MediaWiki\Session\SessionManager; |
11 | use MediaWiki\Session\UserInfo; |
12 | use MediaWiki\User\User; |
13 | use MediaWiki\User\UserIdentityLookup; |
14 | use MediaWiki\User\UserNameUtils; |
15 | |
16 | /** |
17 | * CentralAuth cookie-based sessions. |
18 | * |
19 | * This is intended to completely replace the core CookieSessionProvider. |
20 | * |
21 | * @warning Due to the complicated way CentralAuth has historically interacted with core |
22 | * sessions, this is somewhat complicated and is probably not a good example to |
23 | * copy if you're writing your own SessionProvider. |
24 | */ |
25 | class CentralAuthSessionProvider extends MediaWiki\Session\CookieSessionProvider { |
26 | |
27 | /** @var bool */ |
28 | protected $enable = false; |
29 | |
30 | /** @var array */ |
31 | protected $centralCookieOptions = []; |
32 | |
33 | private UserIdentityLookup $userIdentityLookup; |
34 | private CentralAuthSessionManager $sessionManager; |
35 | |
36 | /** |
37 | * @param UserIdentityLookup $userIdentityLookup |
38 | * @param CentralAuthSessionManager $sessionManager |
39 | * @param array $params In addition to the parameters for |
40 | * CookieSessionProvider, the following are |
41 | * recognized: |
42 | * - enable: Whether to set CentralAuth-specific features. Defaults to |
43 | * $wgCentralAuthCookies. |
44 | * - centralSessionName: Central session cookie name. Defaults to |
45 | * centralCookieOptions['prefix'] . 'Session'. Note this does not |
46 | * replace the parent class's 'sessionName', it's a different cookie. |
47 | * - centralCookieOptions: Settings for central cookies |
48 | * - prefix: Cookie prefix, defaults to $wgCentralAuthCookiePrefix |
49 | * - path: Cookie path, defaults to $wgCentralAuthCookiePath |
50 | * - domain: Cookie domain, defaults to $wgCentralAuthCookieDomain |
51 | * - secure: Cookie secure flag, defaults to $wgCookieSecure |
52 | * - httpOnly: Cookie httpOnly flag, defaults to $wgCookieHttpOnly |
53 | * - sameSite: Cookie SameSite attribute, defaults to $wgCookieSameSite |
54 | */ |
55 | public function __construct( |
56 | UserIdentityLookup $userIdentityLookup, |
57 | CentralAuthSessionManager $sessionManager, |
58 | $params = [] |
59 | ) { |
60 | $this->userIdentityLookup = $userIdentityLookup; |
61 | $this->sessionManager = $sessionManager; |
62 | |
63 | $params += [ |
64 | 'centralCookieOptions' => [], |
65 | ]; |
66 | |
67 | if ( !is_array( $params['centralCookieOptions'] ) ) { |
68 | throw new \InvalidArgumentException( |
69 | __METHOD__ . ': centralCookieOptions must be an array' |
70 | ); |
71 | } |
72 | |
73 | $this->centralCookieOptions = $params['centralCookieOptions']; |
74 | unset( $params['centralCookieOptions'] ); |
75 | |
76 | parent::__construct( $params ); |
77 | } |
78 | |
79 | protected function postInitSetup() { |
80 | parent::postInitSetup(); |
81 | |
82 | $this->centralCookieOptions += [ |
83 | 'prefix' => $this->getConfig()->get( 'CentralAuthCookiePrefix' ), |
84 | 'path' => $this->getConfig()->get( 'CentralAuthCookiePath' ), |
85 | 'domain' => $this->getConfig()->get( 'CentralAuthCookieDomain' ), |
86 | 'secure' => $this->getConfig()->get( 'CookieSecure' ) || $this->getConfig()->get( 'ForceHTTPS' ), |
87 | 'httpOnly' => $this->getConfig()->get( 'CookieHttpOnly' ), |
88 | 'sameSite' => $this->getConfig()->get( 'CookieSameSite' ) |
89 | ]; |
90 | |
91 | $params = [ |
92 | 'enable' => $this->getConfig()->get( 'CentralAuthCookies' ), |
93 | 'centralSessionName' => $this->centralCookieOptions['prefix'] . 'Session', |
94 | ]; |
95 | $this->params += $params; |
96 | |
97 | $this->enable = (bool)$params['enable']; |
98 | } |
99 | |
100 | /** |
101 | * Get the local session info, with CentralAuthSource metadata. |
102 | * |
103 | * @param WebRequest $request |
104 | * @param bool $forceEmptyPersist If this is true and there is no local |
105 | * session, return a persistent empty local session to override the |
106 | * non-functional CentralAuth one. This prevents the deletion of global |
107 | * cookies, allowing the user to retain their central login elsewhere |
108 | * in the same cookie domain. It makes sense to do this for problems with |
109 | * the central session that are specific to the local wiki. (T342475) |
110 | * @return SessionInfo|null |
111 | */ |
112 | private function returnParentSessionInfo( WebRequest $request, $forceEmptyPersist = false ) { |
113 | $info = parent::provideSessionInfo( $request ); |
114 | if ( $info ) { |
115 | return new SessionInfo( $info->getPriority(), [ |
116 | 'copyFrom' => $info, |
117 | 'metadata' => [ |
118 | 'CentralAuthSource' => 'Local', |
119 | ], |
120 | ] ); |
121 | } elseif ( $forceEmptyPersist ) { |
122 | return new SessionInfo( $this->priority, [ |
123 | 'id' => null, |
124 | 'provider' => $this, |
125 | 'idIsSafe' => true, |
126 | 'persisted' => true, |
127 | 'metadata' => [ |
128 | 'CentralAuthSource' => 'Local', |
129 | ], |
130 | ] ); |
131 | } else { |
132 | return null; |
133 | } |
134 | } |
135 | |
136 | /** |
137 | * @param WebRequest $request |
138 | * @return SessionInfo|null |
139 | */ |
140 | public function provideSessionInfo( WebRequest $request ) { |
141 | if ( !$this->enable ) { |
142 | $this->logger->debug( __METHOD__ . ': Not enabled, falling back to core sessions' ); |
143 | return self::returnParentSessionInfo( $request ); |
144 | } |
145 | |
146 | $info = [ |
147 | 'id' => $this->getCookie( $request, $this->params['sessionName'], '' ) |
148 | ]; |
149 | if ( !SessionManager::validateSessionId( $info['id'] ) ) { |
150 | unset( $info['id'] ); |
151 | } |
152 | |
153 | $userName = null; |
154 | $token = null; |
155 | $from = null; |
156 | |
157 | $prefix = $this->centralCookieOptions['prefix']; |
158 | $userCookie = $this->getCookie( $request, 'User', $prefix ); |
159 | $tokenCookie = $this->getCookie( $request, 'Token', $prefix ); |
160 | if ( $userCookie !== null && $tokenCookie !== null ) { |
161 | $userName = $userCookie; |
162 | $token = $tokenCookie; |
163 | $from = 'cookies'; |
164 | } else { |
165 | $id = $this->getCookie( $request, $this->params['centralSessionName'], '' ); |
166 | if ( $id !== null ) { |
167 | $data = $this->sessionManager->getCentralSessionById( $id ); |
168 | if ( isset( $data['pending_name'] ) || isset( $data['pending_guid'] ) ) { |
169 | $this->logger->debug( __METHOD__ . ': uninitialized session' ); |
170 | } elseif ( isset( $data['token'] ) && isset( $data['user'] ) ) { |
171 | $token = $data['token']; |
172 | $userName = $data['user']; |
173 | $from = 'session'; |
174 | } else { |
175 | $this->logger->debug( __METHOD__ . ': uninitialized session' ); |
176 | } |
177 | } |
178 | } |
179 | if ( $userName === null || $token === null ) { |
180 | return self::returnParentSessionInfo( $request ); |
181 | } |
182 | |
183 | // Sanity check to avoid session ID collisions, as reported on T21158 |
184 | if ( $userCookie === null ) { |
185 | $this->logger->debug( |
186 | __METHOD__ . ': no User cookie, so unable to check for session mismatch' |
187 | ); |
188 | return self::returnParentSessionInfo( $request ); |
189 | } elseif ( $userCookie != $userName ) { |
190 | $this->logger->debug( |
191 | __METHOD__ . ': Session ID/User mismatch. Possible session collision. ' . |
192 | "Expected: $userName; actual: $userCookie" |
193 | ); |
194 | return self::returnParentSessionInfo( $request ); |
195 | } |
196 | |
197 | // Clean up username |
198 | $userName = $this->userNameUtils->getCanonical( $userName, UserNameUtils::RIGOR_VALID ); |
199 | if ( !$userName ) { |
200 | $this->logger->debug( __METHOD__ . ': invalid username' ); |
201 | return self::returnParentSessionInfo( $request ); |
202 | } |
203 | if ( !$this->userNameUtils->isUsable( $userName ) ) { |
204 | $this->logger->warning( |
205 | __METHOD__ . ': username {username} is not usable on this wiki', [ |
206 | 'username' => $userName, |
207 | ] |
208 | ); |
209 | return self::returnParentSessionInfo( $request, true ); |
210 | } |
211 | |
212 | // Try the central user |
213 | $centralUser = CentralAuthUser::getInstanceByName( $userName ); |
214 | |
215 | // Skip if they're being renamed |
216 | if ( $centralUser->renameInProgress() ) { |
217 | $this->logger->debug( __METHOD__ . ': rename in progress' ); |
218 | // No fallback here, just fail it because our SessionCheckMetadata |
219 | // hook will do so anyway. |
220 | return null; |
221 | } |
222 | |
223 | if ( !$centralUser->exists() ) { |
224 | $this->logger->debug( __METHOD__ . ': global account doesn\'t exist' ); |
225 | return self::returnParentSessionInfo( $request ); |
226 | } |
227 | if ( !$centralUser->isAttached() ) { |
228 | $userIdentity = $this->userIdentityLookup->getUserIdentityByName( $userName ); |
229 | if ( $userIdentity && $userIdentity->isRegistered() ) { |
230 | $this->logger->debug( __METHOD__ . ': not attached and local account exists' ); |
231 | return self::returnParentSessionInfo( $request, true ); |
232 | } |
233 | } |
234 | if ( $centralUser->authenticateWithToken( $token ) != 'ok' ) { |
235 | $this->logger->debug( __METHOD__ . ': token mismatch' ); |
236 | // At this point, don't log in with a local session anymore |
237 | return null; |
238 | } |
239 | |
240 | $this->logger->debug( __METHOD__ . ": logged in from $from" ); |
241 | |
242 | $info += [ |
243 | 'userInfo' => UserInfo::newFromName( $userName, true ), |
244 | 'provider' => $this, |
245 | // CA sessions are always persistent |
246 | 'persisted' => true, |
247 | 'remembered' => $tokenCookie !== null, |
248 | 'metadata' => [ |
249 | 'CentralAuthSource' => 'CentralAuth', |
250 | ], |
251 | ]; |
252 | |
253 | return new SessionInfo( $this->priority, $info ); |
254 | } |
255 | |
256 | /** @inheritDoc */ |
257 | public function refreshSessionInfo( SessionInfo $info, WebRequest $request, &$metadata ) { |
258 | // Sanity check on the metadata, to avoid T124409 |
259 | if ( isset( $metadata['CentralAuthSource'] ) ) { |
260 | $name = $info->getUserInfo()->getName(); |
261 | if ( $name !== null ) { |
262 | if ( !$this->enable ) { |
263 | $source = 'Local'; |
264 | } else { |
265 | $centralUser = CentralAuthUser::getInstanceByName( $name ); |
266 | $centralUserExists = $centralUser->exists(); |
267 | if ( $centralUserExists && $centralUser->isAttached() ) { |
268 | $source = 'CentralAuth'; |
269 | } elseif ( $centralUserExists ) { |
270 | $userIdentity = $this->userIdentityLookup |
271 | ->getUserIdentityByName( $name, IDBAccessObject::READ_LATEST ); |
272 | if ( !$userIdentity || !$userIdentity->isRegistered() ) { |
273 | $source = 'CentralAuth'; |
274 | } else { |
275 | $source = 'Local'; |
276 | } |
277 | } else { |
278 | $source = 'Local'; |
279 | } |
280 | } |
281 | if ( $metadata['CentralAuthSource'] !== $source ) { |
282 | $this->logger->warning( |
283 | 'Session "{session}": CentralAuth saved source {saved} ' . |
284 | '!= expected source {expected}', |
285 | [ |
286 | 'session' => $info->__toString(), |
287 | 'saved' => $metadata['CentralAuthSource'], |
288 | 'expected' => $source, |
289 | ] |
290 | ); |
291 | return false; |
292 | } |
293 | } |
294 | } |
295 | |
296 | return true; |
297 | } |
298 | |
299 | /** @inheritDoc */ |
300 | public function sessionIdWasReset( SessionBackend $session, $oldId ) { |
301 | if ( !$this->enable ) { |
302 | return; |
303 | } |
304 | |
305 | // We need a Session to pass to CentralAuthSessionManager::setCentralSession() |
306 | // to reset the session ID, so create one on a new FauxRequest. |
307 | $s = $session->getSession( new FauxRequest() ); |
308 | |
309 | // We also need to fetch the current central data to pass to |
310 | // CentralAuthSessionManager::setCentralSession() when resetting the ID. |
311 | $data = $this->sessionManager->getCentralSession( $s ); |
312 | |
313 | $this->sessionManager->setCentralSession( $data, true, $s ); |
314 | } |
315 | |
316 | /** @inheritDoc */ |
317 | protected function sessionDataToExport( $user ) { |
318 | $data = parent::sessionDataToExport( $user ); |
319 | |
320 | // CentralAuth needs to prevent core login-from-session to |
321 | // avoid bugs like T124409 |
322 | $centralUser = CentralAuthUser::getInstance( $user ); |
323 | if ( $centralUser->isAttached() ) { |
324 | unset( $data['wsToken'] ); |
325 | } |
326 | |
327 | return $data; |
328 | } |
329 | |
330 | /** @inheritDoc */ |
331 | protected function cookieDataToExport( $user, $remember ) { |
332 | // If we're going to set CA cookies, don't remember in core cookies. |
333 | if ( $remember ) { |
334 | $centralUser = CentralAuthUser::getInstance( $user ); |
335 | $remember = !$centralUser->isAttached(); |
336 | } |
337 | |
338 | return parent::cookieDataToExport( $user, $remember ); |
339 | } |
340 | |
341 | /** |
342 | * @param SessionBackend $session |
343 | * @param WebRequest $request |
344 | */ |
345 | public function persistSession( SessionBackend $session, WebRequest $request ) { |
346 | parent::persistSession( $session, $request ); |
347 | |
348 | if ( !$this->enable ) { |
349 | return; |
350 | } |
351 | |
352 | $response = $request->response(); |
353 | if ( $response->headersSent() ) { |
354 | // Can't do anything now |
355 | return; |
356 | } |
357 | |
358 | $s = $session->getSession( $request ); |
359 | |
360 | $user = $session->getUser(); |
361 | $centralUser = CentralAuthUser::getInstance( $user ); |
362 | |
363 | if ( $centralUser->exists() && ( $centralUser->isAttached() || !$user->getId() ) ) { |
364 | // CentralAuth needs to prevent core login-from-session to |
365 | // avoid bugs like T124409 |
366 | $data = &$session->getData(); |
367 | if ( array_key_exists( 'wsToken', $data ) ) { |
368 | unset( $data['wsToken'] ); |
369 | $session->dirty(); |
370 | } |
371 | unset( $data ); |
372 | |
373 | $metadata = $session->getProviderMetadata(); |
374 | $metadata['CentralAuthSource'] = 'CentralAuth'; |
375 | $session->setProviderMetadata( $metadata ); |
376 | |
377 | $remember = $session->shouldRememberUser(); |
378 | |
379 | $options = $this->centralCookieOptions; |
380 | |
381 | // We only save the user into the central session if it's not a |
382 | // "pending" session, but we still need the ID to set the cookie. |
383 | $data = $this->sessionManager->getCentralSession( $s ); |
384 | if ( isset( $data['pending_name'] ) ) { |
385 | $remember = false; |
386 | } else { |
387 | $data['user'] = $centralUser->getName(); |
388 | $data['token'] = $centralUser->getAuthToken(); |
389 | } |
390 | $centralSessionId = $this->sessionManager->setCentralSession( $data, false, $s ); |
391 | |
392 | $cookies = [ |
393 | 'User' => (string)$centralUser->getName(), |
394 | 'Token' => $remember ? (string)$centralUser->getAuthToken() : false, |
395 | ]; |
396 | foreach ( $cookies as $name => $value ) { |
397 | if ( $value === false ) { |
398 | $response->clearCookie( $name, $options ); |
399 | } else { |
400 | $expirationDuration = $this->getLoginCookieExpiration( $name, $remember ); |
401 | $expiration = $expirationDuration ? $expirationDuration + time() : null; |
402 | $response->setCookie( $name, (string)$value, $expiration, $options ); |
403 | } |
404 | } |
405 | |
406 | $response->setCookie( $this->params['centralSessionName'], $centralSessionId, null, |
407 | [ 'prefix' => '' ] + $options ); |
408 | } else { |
409 | $metadata = $session->getProviderMetadata(); |
410 | $metadata['CentralAuthSource'] = 'Local'; |
411 | $session->setProviderMetadata( $metadata ); |
412 | } |
413 | } |
414 | |
415 | /** |
416 | * @param WebRequest $request |
417 | */ |
418 | public function unpersistSession( WebRequest $request ) { |
419 | parent::unpersistSession( $request ); |
420 | |
421 | if ( !$this->enable ) { |
422 | return; |
423 | } |
424 | |
425 | $response = $request->response(); |
426 | if ( $response->headersSent() ) { |
427 | // Can't do anything now |
428 | $this->logger->debug( __METHOD__ . ': Headers already sent' ); |
429 | return; |
430 | } |
431 | |
432 | $expiry = time() - 86400; |
433 | $response->clearCookie( 'User', $this->centralCookieOptions ); |
434 | $response->clearCookie( 'Token', $this->centralCookieOptions ); |
435 | $response->clearCookie( $this->params['centralSessionName'], |
436 | [ 'prefix' => '' ] + $this->centralCookieOptions ); |
437 | } |
438 | |
439 | /** @inheritDoc */ |
440 | public function invalidateSessionsForUser( User $user ) { |
441 | $centralUser = CentralAuthUser::getPrimaryInstance( $user ); |
442 | if ( $centralUser->exists() && ( $centralUser->isAttached() || !$user->isRegistered() ) ) { |
443 | $centralUser->resetAuthToken(); |
444 | } |
445 | } |
446 | |
447 | /** @inheritDoc */ |
448 | public function preventSessionsForUser( $username ) { |
449 | $username = $this->userNameUtils->getCanonical( $username, UserNameUtils::RIGOR_VALID ); |
450 | if ( !$username ) { |
451 | return; |
452 | } |
453 | |
454 | $centralUser = CentralAuthUser::getPrimaryInstanceByName( $username ); |
455 | if ( !$centralUser->exists() ) { |
456 | return; |
457 | } |
458 | |
459 | // Reset the user's password to something invalid and reset the token, |
460 | // if it's not already invalid. |
461 | $config = RequestContext::getMain()->getConfig(); |
462 | $passwordFactory = new PasswordFactory( |
463 | $config->get( MainConfigNames::PasswordConfig ), |
464 | $config->get( MainConfigNames::PasswordDefault ) |
465 | ); |
466 | |
467 | try { |
468 | $password = $passwordFactory->newFromCiphertext( $centralUser->getPassword() ); |
469 | } catch ( PasswordError $e ) { |
470 | return; |
471 | } |
472 | if ( !$password instanceof InvalidPassword ) { |
473 | $centralUser->setPassword( null, true ); |
474 | } |
475 | } |
476 | |
477 | /** |
478 | * @inheritDoc |
479 | */ |
480 | protected function setForceHTTPSCookie( $set, ?SessionBackend $backend, WebRequest $request ) { |
481 | // Do nothing. We don't support mixed-protocol HTTP/HTTPS wikis in CentralAuth, |
482 | // so this cookie is not needed. |
483 | } |
484 | |
485 | /** @inheritDoc */ |
486 | protected function setLoggedOutCookie( $loggedOut, WebRequest $request ) { |
487 | if ( $loggedOut + 86400 > time() && |
488 | $loggedOut !== (int)$this->getCookie( |
489 | $request, 'LoggedOut', $this->centralCookieOptions['prefix'] ) |
490 | ) { |
491 | $request->response()->setCookie( 'LoggedOut', (string)$loggedOut, $loggedOut + 86400, |
492 | $this->centralCookieOptions ); |
493 | } |
494 | } |
495 | |
496 | /** |
497 | * @return string[] |
498 | */ |
499 | public function getVaryCookies() { |
500 | $cookies = parent::getVaryCookies(); |
501 | |
502 | if ( $this->enable ) { |
503 | $prefix = $this->centralCookieOptions['prefix']; |
504 | $cookies[] = $prefix . 'Token'; |
505 | $cookies[] = $prefix . 'LoggedOut'; |
506 | $cookies[] = $this->params['centralSessionName']; |
507 | } |
508 | |
509 | return $cookies; |
510 | } |
511 | |
512 | /** @inheritDoc */ |
513 | public function suggestLoginUsername( WebRequest $request ) { |
514 | $name = $this->getCookie( $request, 'User', $this->centralCookieOptions['prefix'] ); |
515 | if ( $name !== null ) { |
516 | if ( $this->userNameUtils->isTemp( $name ) ) { |
517 | $name = false; |
518 | } else { |
519 | $name = $this->userNameUtils->getCanonical( $name, UserNameUtils::RIGOR_USABLE ); |
520 | } |
521 | } |
522 | return ( $name === false || $name === null ) |
523 | ? parent::suggestLoginUsername( $request ) |
524 | : $name; |
525 | } |
526 | |
527 | /** |
528 | * Fetch the central cookie domain |
529 | * @return string |
530 | */ |
531 | public function getCentralCookieDomain() { |
532 | return $this->centralCookieOptions['domain']; |
533 | } |
534 | |
535 | /** @inheritDoc */ |
536 | protected function getExtendedLoginCookies() { |
537 | $cookies = parent::getExtendedLoginCookies(); |
538 | $cookies[] = 'User'; |
539 | return $cookies; |
540 | } |
541 | |
542 | /** @inheritDoc */ |
543 | public function getRememberUserDuration() { |
544 | // CentralAuth needs User and Token cookies to remember the user. The fallback to |
545 | // sessions needs UserID as well, so if that one has shorter expiration, the remember |
546 | // duration will depend on whether the account is attached; let's return the shorter |
547 | // duration in that case. |
548 | |
549 | return min( |
550 | $this->getLoginCookieExpiration( 'User', true ), |
551 | $this->getLoginCookieExpiration( 'Token', true ), |
552 | $this->getLoginCookieExpiration( 'UserID', true ) |
553 | ) ?: null; |
554 | } |
555 | } |