It was asked in a patch review to apply fully import InvalidArgumentException where possible. I was guessing some of my other already merged patches have but turned out such thing exists other places style so for the sake of consistency I've turned rest of inline import of the specific exception at top of the file. There are instances of source files that aren't in any namespace but have fully qualified import which this patch doesn't touch. Change-Id: I4071fc698b65746d9594cf4d5f45bae82843d436
179 lines
5.2 KiB
PHP
179 lines
5.2 KiB
PHP
<?php
|
|
/**
|
|
* MediaWiki session provider base class
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
* http://www.gnu.org/copyleft/gpl.html
|
|
*
|
|
* @file
|
|
* @ingroup Session
|
|
*/
|
|
|
|
namespace MediaWiki\Session;
|
|
|
|
use InvalidArgumentException;
|
|
use MediaWiki\MainConfigNames;
|
|
use MediaWiki\Request\WebRequest;
|
|
|
|
/**
|
|
* An ImmutableSessionProviderWithCookie doesn't persist the user, but
|
|
* optionally can use a cookie to support multiple IDs per session.
|
|
*
|
|
* As mentioned in the documentation for SessionProvider, many methods that are
|
|
* technically "cannot persist ID" could be turned into "can persist ID but
|
|
* not changing User" using a session cookie. This class implements such an
|
|
* optional session cookie.
|
|
*
|
|
* @stable to extend
|
|
* @ingroup Session
|
|
* @since 1.27
|
|
*/
|
|
abstract class ImmutableSessionProviderWithCookie extends SessionProvider {
|
|
|
|
/** @var string|null */
|
|
protected $sessionCookieName = null;
|
|
/** @var mixed[] */
|
|
protected $sessionCookieOptions = [];
|
|
|
|
/**
|
|
* @stable to call
|
|
* @param array $params Keys include:
|
|
* - sessionCookieName: Session cookie name, if multiple sessions per
|
|
* client are to be supported.
|
|
* - sessionCookieOptions: Options to pass to WebResponse::setCookie().
|
|
*/
|
|
public function __construct( $params = [] ) {
|
|
parent::__construct();
|
|
|
|
if ( isset( $params['sessionCookieName'] ) ) {
|
|
if ( !is_string( $params['sessionCookieName'] ) ) {
|
|
throw new InvalidArgumentException( 'sessionCookieName must be a string' );
|
|
}
|
|
$this->sessionCookieName = $params['sessionCookieName'];
|
|
}
|
|
if ( isset( $params['sessionCookieOptions'] ) ) {
|
|
if ( !is_array( $params['sessionCookieOptions'] ) ) {
|
|
throw new InvalidArgumentException( 'sessionCookieOptions must be an array' );
|
|
}
|
|
$this->sessionCookieOptions = $params['sessionCookieOptions'];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the session ID from the cookie, if any.
|
|
*
|
|
* Only call this if $this->sessionCookieName !== null. If
|
|
* sessionCookieName is null, do some logic (probably involving a call to
|
|
* $this->hashToSessionId()) to create the single session ID corresponding
|
|
* to this WebRequest instead of calling this method.
|
|
*
|
|
* @param WebRequest $request
|
|
* @return string|null
|
|
*/
|
|
protected function getSessionIdFromCookie( WebRequest $request ) {
|
|
if ( $this->sessionCookieName === null ) {
|
|
throw new \BadMethodCallException(
|
|
__METHOD__ . ' may not be called when $this->sessionCookieName === null'
|
|
);
|
|
}
|
|
|
|
$prefix = $this->sessionCookieOptions['prefix']
|
|
?? $this->getConfig()->get( MainConfigNames::CookiePrefix );
|
|
$id = $request->getCookie( $this->sessionCookieName, $prefix );
|
|
return SessionManager::validateSessionId( $id ) ? $id : null;
|
|
}
|
|
|
|
/**
|
|
* @inheritDoc
|
|
* @stable to override
|
|
*/
|
|
public function persistsSessionId() {
|
|
return $this->sessionCookieName !== null;
|
|
}
|
|
|
|
/**
|
|
* @inheritDoc
|
|
* @stable to override
|
|
*/
|
|
public function canChangeUser() {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @inheritDoc
|
|
* @stable to override
|
|
*/
|
|
public function persistSession( SessionBackend $session, WebRequest $request ) {
|
|
if ( $this->sessionCookieName === null ) {
|
|
return;
|
|
}
|
|
|
|
$response = $request->response();
|
|
if ( $response->headersSent() ) {
|
|
// Can't do anything now
|
|
$this->logger->debug( __METHOD__ . ': Headers already sent' );
|
|
return;
|
|
}
|
|
|
|
$options = $this->sessionCookieOptions;
|
|
if ( $session->shouldForceHTTPS() || $session->getUser()->requiresHTTPS() ) {
|
|
// Send a cookie unless $wgForceHTTPS is set (T256095)
|
|
if ( !$this->getConfig()->get( MainConfigNames::ForceHTTPS ) ) {
|
|
$response->setCookie( 'forceHTTPS', 'true', null,
|
|
[ 'prefix' => '', 'secure' => false ] + $options );
|
|
}
|
|
$options['secure'] = true;
|
|
}
|
|
|
|
$response->setCookie( $this->sessionCookieName, $session->getId(), null, $options );
|
|
}
|
|
|
|
/**
|
|
* @inheritDoc
|
|
* @stable to override
|
|
*/
|
|
public function unpersistSession( WebRequest $request ) {
|
|
if ( $this->sessionCookieName === null ) {
|
|
return;
|
|
}
|
|
|
|
$response = $request->response();
|
|
if ( $response->headersSent() ) {
|
|
// Can't do anything now
|
|
$this->logger->debug( __METHOD__ . ': Headers already sent' );
|
|
return;
|
|
}
|
|
|
|
$response->clearCookie( $this->sessionCookieName, $this->sessionCookieOptions );
|
|
}
|
|
|
|
/**
|
|
* @inheritDoc
|
|
* @stable to override
|
|
*/
|
|
public function getVaryCookies() {
|
|
if ( $this->sessionCookieName === null ) {
|
|
return [];
|
|
}
|
|
|
|
$prefix = $this->sessionCookieOptions['prefix'] ??
|
|
$this->getConfig()->get( MainConfigNames::CookiePrefix );
|
|
return [ $prefix . $this->sessionCookieName ];
|
|
}
|
|
|
|
public function whyNoSession() {
|
|
return wfMessage( 'sessionprovider-nocookies' );
|
|
}
|
|
}
|