MediaWiki REL1_31
ApiLoginTest.php
Go to the documentation of this file.
1<?php
2
3use Wikimedia\TestingAccessWrapper;
4
13
17 public function testApiLoginNoName() {
18 $session = [
19 'wsTokenSecrets' => [ 'login' => 'foobar' ],
20 ];
21 $data = $this->doApiRequest( [ 'action' => 'login',
22 'lgname' => '', 'lgpassword' => self::$users['sysop']->getPassword(),
23 'lgtoken' => (string)( new MediaWiki\Session\Token( 'foobar', '' ) )
24 ], $session );
25 $this->assertEquals( 'Failed', $data[0]['login']['result'] );
26 }
27
28 public function testApiLoginBadPass() {
29 global $wgServer;
30
31 $user = self::$users['sysop'];
32 $userName = $user->getUser()->getName();
33 $user->getUser()->logout();
34
35 if ( !isset( $wgServer ) ) {
36 $this->markTestIncomplete( 'This test needs $wgServer to be set in LocalSettings.php' );
37 }
38 $ret = $this->doApiRequest( [
39 "action" => "login",
40 "lgname" => $userName,
41 "lgpassword" => "bad",
42 ] );
43
44 $result = $ret[0];
45
46 $this->assertNotInternalType( "bool", $result );
47 $a = $result["login"]["result"];
48 $this->assertEquals( "NeedToken", $a );
49
50 $token = $result["login"]["token"];
51
52 $ret = $this->doApiRequest(
53 [
54 "action" => "login",
55 "lgtoken" => $token,
56 "lgname" => $userName,
57 "lgpassword" => "badnowayinhell",
58 ],
59 $ret[2]
60 );
61
62 $result = $ret[0];
63
64 $this->assertNotInternalType( "bool", $result );
65 $a = $result["login"]["result"];
66
67 $this->assertEquals( 'Failed', $a );
68 }
69
70 public function testApiLoginGoodPass() {
71 global $wgServer;
72
73 if ( !isset( $wgServer ) ) {
74 $this->markTestIncomplete( 'This test needs $wgServer to be set in LocalSettings.php' );
75 }
76
77 $user = self::$users['sysop'];
78 $userName = $user->getUser()->getName();
79 $password = $user->getPassword();
80 $user->getUser()->logout();
81
82 $ret = $this->doApiRequest( [
83 "action" => "login",
84 "lgname" => $userName,
85 "lgpassword" => $password,
86 ]
87 );
88
89 $result = $ret[0];
90 $this->assertNotInternalType( "bool", $result );
91 $this->assertNotInternalType( "null", $result["login"] );
92
93 $a = $result["login"]["result"];
94 $this->assertEquals( "NeedToken", $a );
95 $token = $result["login"]["token"];
96
97 $ret = $this->doApiRequest(
98 [
99 "action" => "login",
100 "lgtoken" => $token,
101 "lgname" => $userName,
102 "lgpassword" => $password,
103 ],
104 $ret[2]
105 );
106
107 $result = $ret[0];
108
109 $this->assertNotInternalType( "bool", $result );
110 $a = $result["login"]["result"];
111
112 $this->assertEquals( "Success", $a );
113 }
114
118 public function testApiLoginGotCookie() {
119 $this->markTestIncomplete( "The server can't do external HTTP requests, "
120 . "and the internal one won't give cookies" );
121
122 global $wgServer, $wgScriptPath;
123
124 if ( !isset( $wgServer ) ) {
125 $this->markTestIncomplete( 'This test needs $wgServer to be set in LocalSettings.php' );
126 }
127 $user = self::$users['sysop'];
128 $userName = $user->getUser()->getName();
129 $password = $user->getPassword();
130
131 $req = MWHttpRequest::factory( self::$apiUrl . "?action=login&format=xml",
132 [ "method" => "POST",
133 "postData" => [
134 "lgname" => $userName,
135 "lgpassword" => $password
136 ]
137 ],
138 __METHOD__
139 );
140 $req->execute();
141
142 libxml_use_internal_errors( true );
143 $sxe = simplexml_load_string( $req->getContent() );
144 $this->assertNotInternalType( "bool", $sxe );
145 $this->assertThat( $sxe, $this->isInstanceOf( SimpleXMLElement::class ) );
146 $this->assertNotInternalType( "null", $sxe->login[0] );
147
148 $a = $sxe->login[0]->attributes()->result[0];
149 $this->assertEquals( ' result="NeedToken"', $a->asXML() );
150 $token = (string)$sxe->login[0]->attributes()->token;
151
152 $req->setData( [
153 "lgtoken" => $token,
154 "lgname" => $userName,
155 "lgpassword" => $password ] );
156 $req->execute();
157
158 $cj = $req->getCookieJar();
159 $serverName = parse_url( $wgServer, PHP_URL_HOST );
160 $this->assertNotEquals( false, $serverName );
161 $serializedCookie = $cj->serializeToHttpRequest( $wgScriptPath, $serverName );
162 $this->assertNotEquals( '', $serializedCookie );
163 $this->assertRegExp(
164 '/_session=[^;]*; .*UserID=[0-9]*; .*UserName=' . $user->userName . '; .*Token=/',
165 $serializedCookie
166 );
167 }
168
169 public function testRunLogin() {
170 $user = self::$users['sysop'];
171 $userName = $user->getUser()->getName();
172 $password = $user->getPassword();
173
174 $data = $this->doApiRequest( [
175 'action' => 'login',
176 'lgname' => $userName,
177 'lgpassword' => $password ] );
178
179 $this->assertArrayHasKey( "login", $data[0] );
180 $this->assertArrayHasKey( "result", $data[0]['login'] );
181 $this->assertEquals( "NeedToken", $data[0]['login']['result'] );
182 $token = $data[0]['login']['token'];
183
184 $data = $this->doApiRequest( [
185 'action' => 'login',
186 "lgtoken" => $token,
187 "lgname" => $userName,
188 "lgpassword" => $password ], $data[2] );
189
190 $this->assertArrayHasKey( "login", $data[0] );
191 $this->assertArrayHasKey( "result", $data[0]['login'] );
192 $this->assertEquals( "Success", $data[0]['login']['result'] );
193 }
194
195 public function testBotPassword() {
197
198 if ( !isset( $wgServer ) ) {
199 $this->markTestIncomplete( 'This test needs $wgServer to be set in LocalSettings.php' );
200 }
201
202 $this->setMwGlobals( [
203 'wgSessionProviders' => array_merge( $wgSessionProviders, [
204 [
205 'class' => MediaWiki\Session\BotPasswordSessionProvider::class,
206 'args' => [ [ 'priority' => 40 ] ],
207 ]
208 ] ),
209 'wgEnableBotPasswords' => true,
210 'wgBotPasswordsDatabase' => false,
211 'wgCentralIdLookupProvider' => 'local',
212 'wgGrantPermissions' => [
213 'test' => [ 'read' => true ],
214 ],
215 ] );
216
217 // Make sure our session provider is present
218 $manager = TestingAccessWrapper::newFromObject( MediaWiki\Session\SessionManager::singleton() );
219 if ( !isset( $manager->sessionProviders[MediaWiki\Session\BotPasswordSessionProvider::class] ) ) {
220 $tmp = $manager->sessionProviders;
221 $manager->sessionProviders = null;
222 $manager->sessionProviders = $tmp + $manager->getProviders();
223 }
224 $this->assertNotNull(
225 MediaWiki\Session\SessionManager::singleton()->getProvider(
226 MediaWiki\Session\BotPasswordSessionProvider::class
227 ),
228 'sanity check'
229 );
230
231 $user = self::$users['sysop'];
232 $centralId = CentralIdLookup::factory()->centralIdFromLocalUser( $user->getUser() );
233 $this->assertNotEquals( 0, $centralId, 'sanity check' );
234
235 $password = 'ngfhmjm64hv0854493hsj5nncjud2clk';
236 $passwordFactory = new PasswordFactory();
237 $passwordFactory->init( RequestContext::getMain()->getConfig() );
238 // A is unsalted MD5 (thus fast) ... we don't care about security here, this is test only
239 $passwordHash = $passwordFactory->newFromPlaintext( $password );
240
241 $dbw = wfGetDB( DB_MASTER );
242 $dbw->insert(
243 'bot_passwords',
244 [
245 'bp_user' => $centralId,
246 'bp_app_id' => 'foo',
247 'bp_password' => $passwordHash->toString(),
248 'bp_token' => '',
249 'bp_restrictions' => MWRestrictions::newDefault()->toJson(),
250 'bp_grants' => '["test"]',
251 ],
252 __METHOD__
253 );
254
255 $lgName = $user->getUser()->getName() . BotPassword::getSeparator() . 'foo';
256
257 $ret = $this->doApiRequest( [
258 'action' => 'login',
259 'lgname' => $lgName,
260 'lgpassword' => $password,
261 ] );
262
263 $result = $ret[0];
264 $this->assertNotInternalType( 'bool', $result );
265 $this->assertNotInternalType( 'null', $result['login'] );
266
267 $a = $result['login']['result'];
268 $this->assertEquals( 'NeedToken', $a );
269 $token = $result['login']['token'];
270
271 $ret = $this->doApiRequest( [
272 'action' => 'login',
273 'lgtoken' => $token,
274 'lgname' => $lgName,
275 'lgpassword' => $password,
276 ], $ret[2] );
277
278 $result = $ret[0];
279 $this->assertNotInternalType( 'bool', $result );
280 $a = $result['login']['result'];
281
282 $this->assertEquals( 'Success', $a );
283 }
284
286 $this->setTemporaryHook( 'RequestHasSameOriginSecurity',
287 function () {
288 return false;
289 }
290 );
291
292 $result = $this->doApiRequest( [
293 'action' => 'login',
294 ] )[0]['login'];
295
296 $this->assertSame( [
297 'result' => 'Aborted',
298 'reason' => 'Cannot log in when the same-origin policy is not applied.',
299 ], $result );
300 }
301}
$wgSessionProviders
MediaWiki\Session\SessionProvider configuration.
$wgScriptPath
The path we should point to.
$wgServer
URL of the server.
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
API Database medium.
testApiLoginGotCookie()
Broken.
testLoginWithNoSameOriginSecurity()
testApiLoginNoName()
Test result of attempted login with an empty username.
doApiRequest(array $params, array $session=null, $appendModule=false, User $user=null, $tokenType=null)
Does the API request and returns the result.
setMwGlobals( $pairs, $value=null)
Sets a global, maintaining a stashed version of the previous global to be restored in tearDown.
setTemporaryHook( $hookName, $handler)
Create a temporary hook handler which will be reset by tearDown.
Factory class for creating and checking Password objects.
static getMain()
Get the RequestContext object associated with the main request.
this hook is for auditing only $req
Definition hooks.txt:990
This code would result in ircNotify being run twice when an article is and once for brion Hooks can return three possible true was required This is the default since MediaWiki *some string
Definition hooks.txt:181
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses & $ret
Definition hooks.txt:2005
A helper class for throttling authentication attempts.
const DB_MASTER
Definition defines.php:29