Page MenuHomePhabricator

API:Login failed with Special:BotPasswords 
Closed, InvalidPublicBUG REPORT

Description

After an update (1.33.1), API:Login fails with credentials of Special:BotPasswords .

Steps to Reproduce:

  1. Install mediawiki 1.33.1 (via git, last version of the branch REL1.33)
  2. Create a login and a password with the form of Special:BotPasswords 
  3. Create the file test.php (first sample PHP code of the page https://www.mediawiki.org/wiki/API:Login )
  4. Replace the endpoint, the password and the login in the code.

File : test.php

<?php
$endPoint = "http://wiki/api.php";
$login_Token = getLoginToken(); // Step 1
loginRequest( $login_Token ); // Step 2

// Step 1: GET request to fetch login token
function getLoginToken() {
	global $endPoint;

	$params1 = [
		"action" => "query",
		"meta" => "tokens",
		"type" => "login",
		"format" => "json"
	];

	$url = $endPoint . "?" . http_build_query( $params1 );

	$ch = curl_init( $url );
	curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
	curl_setopt( $ch, CURLOPT_COOKIEJAR, "cookie.txt" );
	curl_setopt( $ch, CURLOPT_COOKIEFILE, "cookie.txt" );

	$output = curl_exec( $ch );
	curl_close( $ch );

	$result = json_decode( $output, true );
	return $result["query"]["tokens"]["logintoken"];
}

// Step 2: POST request to log in. Use of main account for login is not
// supported. Obtain credentials via Special:BotPasswords
// (https://www.mediawiki.org/wiki/Special:BotPasswords) for lgname & lgpassword
function loginRequest( $logintoken ) {
	global $endPoint;

	$params2 = [
		"action" => "login",
		"lgname" => "Test@bot",
		"lgpassword" => "PASSWORD",
		"lgtoken" => $logintoken,
		"format" => "json"
	];

	$ch = curl_init();

	curl_setopt( $ch, CURLOPT_URL, $endPoint );
	curl_setopt( $ch, CURLOPT_POST, true );
	curl_setopt( $ch, CURLOPT_POSTFIELDS, http_build_query( $params2 ) );
	curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
	curl_setopt( $ch, CURLOPT_COOKIEJAR, "cookie.txt" );
	curl_setopt( $ch, CURLOPT_COOKIEFILE, "cookie.txt" );

	$output = curl_exec( $ch );
	curl_close( $ch );

	echo( $output );
}

Actual Results:

The result is always the same (with a different token).

{
  "warnings": {
    "main": {
      "*": "Subscribe to the mediawiki-api-announce mailing list at <https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce> for notice of API deprecations and breaking changes."
    },
    "login": {
      "*": "Fetching a token via \"action=login\" is deprecated. Use \"action=query&meta=tokens&type=login\" instead."
    }
  },
  "login": {
    "result": "NeedToken",
    "token": "a94242ea5e82b694979787846c2b4cdd5db1e890+\\"
  }
}

Expected Results:

The page https://www.mediawiki.org/wiki/API:Login shows this expected results for this code.

{  
   "login": {  
      "lguserid": 21,
      "result": "Success",
      "lgusername": "William"
   }
}

Event Timeline

Restricted Application added a subscriber: Aklapper. · View Herald Transcript
Anomie subscribed.

Works fine for me. Most likely you somehow managed to change the cache used for session storage to something that doesn't persist the session data. You might check your logs for relevant messages on the 'session' channel, particularly for one along the lines of "SessionBackend "{ID}" is unsaved" on the second request.

You might also double check that the cookies are being sent correctly with the second request, with the session cookie corresponding to that returned by the first request.

Thanks @Anomie

I replace "cookie.txt" by "/tmp/cookie.txt" and it works now. I will update the doc on Mediawiki.

Sorry for the inconvenience
Bye

@Anomie can you help me ?

So with curl it's ok but I try to update an old extension and it uses MWHttpRequest to send HTTP requests.
I found the problem, it's also a problem about cookies. I don't know why the cookie changes after the function setCookieJar in this code. Have you an idea ?
If you have not the solution, I would remove MWHttpRequest of my extension.

                 $requestData = [
			'action' => 'login',
			'format' => 'json',
			'lgname' => $user,
			'lgpassword' => $password
		];
		
                $requestData['lgdomain'] = $domain;
		$requestData['lgtoken'] =  $token;

		$req = MWHttpRequest::factory( $target."/api.php",
			[
				'postData' => $requestData,
				'method' => 'POST',
				'timeout' => 'default'
			],
			__METHOD__
		);

		error_log(print_r($cookieJar, TRUE)); // ===> my_wiki_session=u2r90ouhdlcpmh0f0oju0ge0mkda7lk5

		$req->setCookieJar( $cookieJar );

		error_log(print_r($cookieJar, TRUE)); // ===> my_wiki_session=u2r90ouhdlcpmh0f0oju0ge0mkda7lk5

		$status = $req->execute();

		error_log(print_r($cookieJar, TRUE)); // ===> my_wiki_session=tprhpqfoupltka6kiebqk65671m8o4rj;

		error_log(print_r($req->getHeaderList() , TRUE)); / ===> my_wiki_session=tprhpqfoupltka6kiebqk65671m8o4rj;

It's presumably changing because the response includes a Set-Cookie header. You'll have to investigate yourself to determine why that is.

Note that a successful login will change the session cookie, as a defense against session fixation. Although since you're asking I'm guessing it's not a successful login.

@Anomie
I found the problem in my last code.

By default, the Guzzle engine is used by Mediawiki. I insert this code in my localsettings :

Http::$httpEngine = 'curl';

Now it works. For my, there are two problems :
"curl has to be the engine by default in Mediawiki"
"Guzzle engine has maybe a problem with setCookieJar"

I am a newbie with the API, I let you decide if there are or not problems.

It looks like the API is fine. If there's a bug in the Guzzle-backed HTTP request code, that's a bug in that rather than the API.