PHP 7.3 doesn't like it if session_id() is called when the session has
been started, so we need to be sure to close it first in a few tests.
Bug: T207112
Change-Id: Ief36c1bb7b5c9066f158b5bb0d6d785a7f7ddd3c
This is a test mock exclusively used in tests. All code I'm removing here
is unused and neither needed nor covered by any test.
Change-Id: Ifd010c49973460f6fbb2cd83f8fd63488f5fd291
Replaces \TestingAccessWrapper (defined in core) with
\Wikimedia\TestingAccessWrapper (defined in the composer package
wikimedia/testing-access-wrapper).
See https://gerrit.wikimedia.org/r/#/q/topic:librarize-testing-access-wrapper
for downstream patches.
The core version of the class is kept around for a while to avoid
circular dependency problems.
Bug: T163434
Change-Id: I52cc257e593da3d6c3b01a909e554a950225aec8
The default will remain PHPUnit 4.x due to PHP 5.5 support.
But, we should allow developers to run tests with newer PHPUnit
versions which are noticably faster (especially for code coverage
reports).
* <https://github.com/sebastianbergmann/phpunit/wiki/Release-Announcement-for-PHPUnit-5.4.0>
PHPUnit 5 deprecates the getMock() shortcut for getMockBuilder()->getMock().
It instead introduces the shortcut createMock() which has better defaults
than getMockBuilder(). For example, it sets 'disableArgumentCloning' and
other things by default.
Going forward, code should either use getMockBuilder directly and configure
it using the setter methods (instead of the confusing variadic arguments
of getMock) or simply use the new minimalistic createMock method. This patch
backports the createMock method to MediaWikiTestCase so that we can start
using it.
Change-Id: I091c0289b21d2b1c876adba89529dc3e72b99af2
Validating this should be as simple as it can be: if the tests run,
this change should be fine. :-)
Change-Id: I8e4a3dfc83fdc9b8c8d7f5bbd067e088ebd2133d
This implements the AuthManager class and its needed interfaces and
subclasses, and integrates them into the backend portion of MediaWiki.
Integration with frontend portions of MediaWiki (e.g. ApiLogin,
Special:Login) is left for a followup.
Bug: T91699
Bug: T71589
Bug: T111299
Co-Authored-By: Gergő Tisza <gtisza@wikimedia.org>
Change-Id: If89d24838e326fe25fe867d02181eebcfbb0e196
Most of the time calling User::setToken() is enough, but CentralAuth
needs to be able to call CentralAuthUser::resetAuthToken() on command.
Change-Id: Iad2ae914a81481f040e047b550f3fd3437277626
A provider that uses SessionProvider::hashToSessionId() will likely have
issues if something such as a call to $user->setToken() causes
SessionManager::loadSessionInfoFromStore() to fail, since the provider
can't just arbitrarily change the session ID it returns.
The two solutions to this problem are:
* Somehow include everything that could cause loadSessionInfoFromStore
to fail in the data hashed by hashToSessionId.
* Flag the SessionInfo so that, if stored data and the SessionInfo
conflict, it should delete the stored data instead of discarding the
SessionInfo.
Since the second is less complexity overall due to the lack of need to
define "everything", this patch takes that approach.
Change-Id: I8c6fab2ec295e71242bbcb19d0ee5ade6bd655df
We already save all open SessionBackends when shutdown handlers are run,
which *should* make the Session object destructors that run during
global shutdown not have anything to save. But it can get fooled if the
Session data contains other objects that have already gotten destroyed
during the global shutdown, leading to spurious warnings and errors as
it tries to access partically-destroyed objects.
The solution is to set a flag when we do the shutdown handlers and just
ignore the last gasps from Session::__destruct() that might come after.
Change-Id: Ic3eb0bac2d29a30488c84b6525ad796a7f1c9ce9
This fixes a bug where SessionBackend::resetId() of the PHP session will
fail to properly load $_SESSION because the new session ID hasn't been
saved to the store yet. It's also a reasonable performance improvement,
no need to call loadSessionInfoFromStore() when we already have the
session loaded.
Change-Id: I30f159ef1267442a6325aabbbdfaf69defc10ed6
There's no point in keeping broken cookies around, it just means all
future requests will continue to flood the logs.
Change-Id: Ib10c9ed9049b71ed434950fc731ea77960ceca0c
Add the data values and types to the exception raised when mismatched
session data is processed. This is done by passing the old and new
values on via a new MetadataMergeException class. The attached data is
added to the debug logging context info when caught.
Change-Id: If8a7174399289bc284ca1b36052ba515c8857c50
As an attempt to detect SessionManager errors that log people into
the wrong account, log multiple IPs using the same session, or the same
user account.
Bug: T125455
Change-Id: I27468a3f6d582d9b46984227b9307dc71190fd6a
* Use PSR-3 templates and context where applicable
* Add log coverage for exceptional events
Bug: T125452
Change-Id: I8f96fa1c5766c739a21219abcae2dbb76de53e2a
To avoid having to have SessionManager try to reset sessions on every
request, we set the user_token to a special value. When that value is
present, User::getToken() returns a different value every time (so
existing checks will fail) and User::setToken() refuses to alter it.
Bug: T124414
Change-Id: Ie4c84ce993e40a081288cf5a543f8ba99f98806a
Ie161e0f was done in a hurry, and so didn't do things in the best ways.
This introduces a new "CachedBagOStuff" that transparently handles all
the logic that had been copy-pasted all over in Ie161e0f.
The differences between CachedBagOStuff and MultiWriteBagOStuff are:
* CachedBagOStuff supports only one "backend".
* There's a flag for writes to only go to the in-memory cache.
* The in-memory cache is always updated.
* Locks go to the backend cache (with MultiWriteBagOStuff, it would wind
up going to the HashBagOStuff used for the in-memory cache).
Change-Id: Iea494729bd2e8c6c5ab8facf4c241232e31e8215
The plan here is to take it out of 1.27.0-wmf.12 and put it back in
1.27.0-wmf.13.
Since BotPasswords depends on SessionManager, that's getting temporarily
removed too.
This reverts the following commits:
* 6acd424e0d SessionManager: Notify AuthPlugin before calling hooks
* 4d1ad32d8a Close a loophole in CookieSessionProvider
* fcdd643a46 SessionManager: Don't save non-persisted sessions to backend storage
* 058aec4c76 MessageCache: Don't get a ParserOptions for $wgUser before the end of Setup.php
* b5c0c03bb7 SessionManager: Save user name to metadata even if the user doesn't exist locally
* 13f2f09a19 SECURITY: Fix User::setToken() call on User::newSystemUser
* 305bc75b27 SessionManager: Don't generate user tokens when checking the tokens
* 7c4bd85d21 RequestContext::exportSession() should only export persisted session IDs
* 296ccfd4a9 SessionManager: Save 'persisted' flag in session metadata
* 94ba53f677 Move CSRF token handling into MediaWiki\Session\Session
* 46a565d6b0 Avoid false "added in both Session and $_SESSION" when value is null
* c00d0b5d94 Log backtrace for "User::loadFromSession called before the end of Setup.php"
* 4eeff5b559 Use $wgSecureCookie to decide whether to actually mark secure cookies as 'secure'
* 7491b52f70 Call session_cache_limiter() before starting a session
* 2c34aeea72 SessionManager: Abstract forceHTTPS cookie setting
* 9aa53627a5 Ignore auth cookies with value 'deleted'
* 43f904b51a SessionManager: Kill getPersistedSessionId()
* 50c5256352 SessionManager: Add SessionBackend::setProviderMetadata()
* f640d40315 SessionManager: Notify AuthPlugin when auto-creating accounts
* 70b05d1ac1 Add checks of $wgEnableBotPasswords in more places
* bfed32eb78 Do not raise a PHP warning when session write fails
* 722a7331ad Only check LoggedOut timestamp on the user loaded from session
* 4f5057b84b SessionManager: Change behavior of getSessionById()
* 66e82e614e Fix typo in [[MediaWiki:Botpasswords-editexisting/en]]
* f9fd9516d9 Add "bot passwords"
* d7716f1df0 Add missing argument for wfDebugLog
* a73c5b7395 Add SessionManager
Change-Id: I2389a8133e25ab929e9f27f41fa9a05df8147a50
This introduces an in-process cache (using a HashBagOStuff) for session
data, and only saves to the external cache when the session is
persisted.
Bug: T125267
Change-Id: Ie161e0f7522cd68515b060ad8cf8c151b7198b0b
This allows SessionManager::getSessionById()->isPersisted() to be
reliably set. Otherwise it depends on whether the SessionBackend is
still loaded or not.
Change-Id: I17733559ac5d8fff13881664333f61d36f610b6d
It's not guaranteed that loadSessionFromStore() will succeed after
whatever alterations the SessionProvider might have made later in the
request.
So instead, let's make a new global object that stores the SessionId
of the persistent session that was loaded during Setup.php, if any. Then
we can check that when we need to know whether the session was
persisted.
Bug: T124468
Change-Id: I1e8e616c83b16aadd86b0a0a40826d40f6e8abe4
It's easily possible for SessionManager::getSessionById() to not be
able to load the specified session and to not be able to create an empty
one by that ID, for example if the user's token changed. So change this
from an exceptional condition to an expected one, and adjust callers to
deal with it appropriately.
Let's also make the checks for invalid data structure when loading the
session from the store delete the bogus data entirely.
At the same time, let's change the silly "$noEmpty" parameter to
"$create" and make the default behavior be not to create an empty
session.
Bug: T124126
Change-Id: I085d2026d1b366b1af9fd0e8ca3d815fd8288030
SessionManager is a general-purpose session management framework, rather
than the cookie-based sessions that PHP wants to provide us.
While fallback is provided for using $_SESSION and other PHP session
management functions, they should be avoided in favor of using
SessionManager directly.
For proof-of-concept extensions, see OAuth change Ib40b221 and
CentralAuth change I27ccabdb.
Bug: T111296
Change-Id: Ic1ffea74f3ccc8f93c8a23b795ecab6f06abca72