Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F1426576
CentralAuthSessionManager.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
7 KB
Referenced Files
None
Subscribers
None
CentralAuthSessionManager.php
View Options
<?php
/**
* 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
*/
namespace
MediaWiki\Extension\CentralAuth
;
use
MediaWiki\Config\ServiceOptions
;
use
MediaWiki\MediaWikiServices
;
use
MediaWiki\Session\Session
;
use
MediaWiki\Session\SessionManager
;
use
MWCryptRand
;
use
Wikimedia\ObjectCache\BagOStuff
;
use
Wikimedia\ObjectCache\CachedBagOStuff
;
use
Wikimedia\Stats\IBufferingStatsdDataFactory
;
use
Wikimedia\Stats\StatsFactory
;
class
CentralAuthSessionManager
{
/**
* @internal Only public for service wiring use
*/
public
const
CONSTRUCTOR_OPTIONS
=
[
'CentralAuthSessionCacheType'
,
'SessionCacheType'
,
];
/** @var BagOStuff|null Session cache */
private
$sessionStore
=
null
;
private
ServiceOptions
$options
;
private
IBufferingStatsdDataFactory
$statsdDataFactory
;
private
StatsFactory
$statsFactory
;
public
function
__construct
(
ServiceOptions
$options
,
IBufferingStatsdDataFactory
$statsdDataFactory
,
StatsFactory
$statsFactory
)
{
$options
->
assertRequiredOptions
(
self
::
CONSTRUCTOR_OPTIONS
);
$this
->
options
=
$options
;
$this
->
statsdDataFactory
=
$statsdDataFactory
;
$this
->
statsFactory
=
$statsFactory
;
}
/**
* @return string db name, for session key creation
* Note that if there is more than one CentralAuth database
* in use for the same session key store, the database names
* MUST be unique.
*/
private
function
getCentralAuthDBForSessionKey
()
{
return
MediaWikiServices
::
getInstance
()
->
getDBLoadBalancerFactory
()->
getPrimaryDatabase
(
'virtual-centralauth'
)->
getDomainID
();
}
/**
* @param string $keygroup
* @param string ...$components
* @return string The global session key (with proper escaping)
*/
public
function
makeSessionKey
(
string
$keygroup
,
...
$components
):
string
{
return
$this
->
getSessionStore
()->
makeGlobalKey
(
$keygroup
,
$this
->
getCentralAuthDBForSessionKey
(),
...
$components
);
}
/**
* Get a cache for storage of central sessions
* @return BagOStuff
*/
public
function
getSessionStore
():
BagOStuff
{
if
(
!
$this
->
sessionStore
)
{
$sessionCacheType
=
$this
->
options
->
get
(
'CentralAuthSessionCacheType'
)
??
$this
->
options
->
get
(
'SessionCacheType'
);
$cache
=
MediaWikiServices
::
getInstance
()->
getObjectCacheFactory
()->
getInstance
(
$sessionCacheType
);
$this
->
sessionStore
=
$cache
instanceof
CachedBagOStuff
?
$cache
:
new
CachedBagOStuff
(
$cache
);
}
return
$this
->
sessionStore
;
}
/**
* Get the central session data associated with the given local session.
*
* When the session is not centrally logged in, an empty array is returned.
*
* @param Session|null $session The local session. If omitted, uses the global session.
* @return array
*/
public
function
getCentralSession
(
$session
=
null
)
{
if
(
!
$session
)
{
$session
=
SessionManager
::
getGlobalSession
();
}
$id
=
$session
->
get
(
'CentralAuth::centralSessionId'
);
if
(
$id
!==
null
)
{
return
$this
->
getCentralSessionById
(
$id
);
}
else
{
return
[];
}
}
/**
* Get the central session data.
*
* The shape of the data is not enforced by this class, but in practice it will contain these keys:
* - sessionId: string, the central session ID
* - expiry: int, timestamp when the session expires
* - user: string, the username
* - token: string, the central token (gu_auth_token)
* - remember: bool, the "keep me logged in" flag.
*
* When $id is not found in the central session store, an empty array is returned.
*
* During central login, the session is a provisional "stub session" (which will be seen
* by the session provider as an anonymous session) with the following keys:
* - pending_name: string, the username
* - pending_guid: string, the central user ID
* - sessionId, expiry: as above
* @param string $id
* @return array
*/
public
function
getCentralSessionById
(
$id
)
{
$key
=
$this
->
makeSessionKey
(
'session'
,
$id
);
$stime
=
microtime
(
true
);
$data
=
$this
->
getSessionStore
()->
get
(
$key
)
?:
[];
$real
=
microtime
(
true
)
-
$stime
;
// Stay backward compatible with the dashboard feeding on
// this data. NOTE: $real is in second with microsecond-level
// precision. This is reconciled on the grafana dashboard.
$this
->
statsdDataFactory
->
timing
(
'centralauth.session.read'
,
$real
);
$this
->
statsFactory
->
withComponent
(
'CentralAuth'
)
->
getTiming
(
'session_read_seconds'
)
->
observe
(
$real
*
1000
);
return
$data
;
}
/**
* Set data in the central session. Uses the central session ID stored in the local session
* to find the data; if not present (or $reset is used), creates a new object under a new ID
* and stores the ID in the local session.
*
* When not overridden in $data, the following keys in the central session data are preserved:
* expiry, user, token. (Expiry will be extended if the session is beyond half its lifetime.)
* sessionId will be updated as needed. Other data (ie. the remember flag or the stub session
* fields) will be lost if not explicitly included in $data. This is true regardless of whether
* $reset is used.
*
* @param array $data New session data.
* @param bool|string $reset Reset the session ID. If a string, this is the new ID.
* @param Session|null $session Local session. When omitted, uses the global session.
* @return string|null Session ID
*/
public
function
setCentralSession
(
array
$data
,
$reset
=
false
,
$session
=
null
)
{
$keepKeys
=
[
'user'
=>
true
,
'token'
=>
true
,
'expiry'
=>
true
];
$session
??=
SessionManager
::
getGlobalSession
();
$id
=
$session
->
get
(
'CentralAuth::centralSessionId'
);
if
(
$reset
||
$id
===
null
)
{
$id
=
is_string
(
$reset
)
?
$reset
:
MWCryptRand
::
generateHex
(
32
);
}
$data
[
'sessionId'
]
=
$id
;
$sessionStore
=
$this
->
getSessionStore
();
$key
=
$this
->
makeSessionKey
(
'session'
,
$id
);
// Copy certain keys from the existing session, if any (T124821)
$existing
=
$sessionStore
->
get
(
$key
);
if
(
is_array
(
$existing
)
)
{
$data
+=
array_intersect_key
(
$existing
,
$keepKeys
);
}
$isDirty
=
(
$data
!==
$existing
);
if
(
$isDirty
||
!
isset
(
$data
[
'expiry'
]
)
||
$data
[
'expiry'
]
<
time
()
+
32100
)
{
$data
[
'expiry'
]
=
time
()
+
$sessionStore
::
TTL_DAY
;
$stime
=
microtime
(
true
);
$sessionStore
->
set
(
$key
,
$data
,
$sessionStore
::
TTL_DAY
);
$real
=
microtime
(
true
)
-
$stime
;
// Stay backward compatible with the dashboard feeding on
// this data. NOTE: $real is in second with microsecond-level
// precision. This is reconciled on the grafana dashboard.
$this
->
statsdDataFactory
->
timing
(
'centralauth.session.write'
,
$real
);
$this
->
statsFactory
->
withComponent
(
'CentralAuth'
)
->
getTiming
(
'session_write_seconds'
)
->
observe
(
$real
*
1000
);
}
if
(
$session
)
{
$session
->
set
(
'CentralAuth::centralSessionId'
,
$id
);
}
return
$id
;
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Sat, May 16, 13:24 (1 d, 18 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
b4/86/8210309c66f8888d4b82a2ec275e
Default Alt Text
CentralAuthSessionManager.php (7 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment