When used with non-MySQL databases, SqlBagOStuff does not disable automatic transactions (DBO_TRX) and so can fail to commit the end-of-request save of session data when $wgSessionCacheType is CACHE_DB.
Original report:
I have MediaWiki 1.27.0 installed as a closed Wiki:
MediaWiki 1.27.0
PHP 5.6.20 (cgi-fcgi)
MS SQL Server 11.00.2100
IIS 7.5.7600
Windows 7 Enterprise, Servicepack 1, 64 Bit
In my own application (C#) I try to login using the API. First I fetch a login token and retrieve the cookies. Second I send a POST request with user, password, retrieved login token and retrieved cookies. The servers answer is NeedToken. When I try it outside of my application using Fiddler I have the same result:
- Request Fetch Login Token
GET http://localhost/mediawiki/api.php?action=query&meta=tokens&type=login&format=xml HTTP/1.1 User-Agent: Fiddler Host: localhost
- Response
HTTP/1.1 200 OK Cache-Control: private, must-revalidate, max-age=0 Content-Type: text/xml; charset=utf-8 Server: Microsoft-IIS/7.5 X-Powered-By: PHP/5.6.20 X-Content-Type-Options: nosniff Set-Cookie: Wiki_Standard_session=2p9esdd8h5veh46r3mipvuuar30jkqkk; path=/; httponly X-Frame-Options: DENY X-Powered-By: ASP.NET Date: Thu, 14 Jul 2016 07:44:23 GMT Content-Length: 130 <?xml version="1.0"?><api batchcomplete=""><query><tokens logintoken="12fa822ce9b537b855989d6a179ce346578742d7+\" /></query></api>
- Request Login
POST http://localhost/mediawiki/api.php?action=login&format=xml HTTP/1.1 User-Agent: Fiddler Host: localhost Content-Type: application/x-www-form-urlencoded Content-Length: 85 Cookie: Wiki_Standard_session=2p9esdd8h5veh46r3mipvuuar30jkqkk lgname=wiki&lgpassword=***&lgtoken=12fa822ce9b537b855989d6a179ce346578742d7%2B%5C
- Response
HTTP/1.1 200 OK Cache-Control: private, must-revalidate, max-age=0 Content-Type: text/xml; charset=utf-8 Server: Microsoft-IIS/7.5 X-Powered-By: PHP/5.6.20 X-Content-Type-Options: nosniff X-Frame-Options: DENY X-Powered-By: ASP.NET Date: Thu, 14 Jul 2016 07:49:41 GMT Content-Length: 359 <?xml version="1.0"?><api><warnings><login xml:space="preserve">Fetching a token via action=login is deprecated. Use action=query&meta=tokens&type=login instead.</login></warnings><login result="NeedToken" token="9082b41a22d33a9e0faf090edfd9672157874415+\" cookieprefix="Wiki_Standard" sessionid="2p9esdd8h5veh46r3mipvuuar30jkqkk" /></api>
I had a look into ApiQueryTokens.php, Session.php and ApiLogin.php. During the first request fetching the login token and the second request logging in is always the method getToken() of the class Session called. I made there some debug outputs seeing what’s wrong:
- Request Fetch Login Token
secrets: Session: sessionid=2p9esdd8h5veh46r3mipvuuar30jkqkk; Token: key=login, salt=, secret=2a28402e5c7d4f2c8464be81e9f85cab, new=1
- Request Login
secrets: Session: sessionid=2p9esdd8h5veh46r3mipvuuar30jkqkk; Token: key=login, salt=, secret=5d7b1d66014cde954aee9d83fad8b637, new=1
The sessionids are the same. The array $secrets from $this->get( 'wsTokenSecrets' ) is always empty. That’s why a new $secret and a new $token with the parameter $new = true will be created even during the second request where the $secret for the session should be exists. The check login token in the method execute() of class ApiLogin fails because the token of the session was just created ($token->wasNew()).