Merge "Increase LocalFile lock() timeout and improve error message"
[lhc/web/wiklou.git] / tests / phpunit / includes / api / ApiLoginTest.php
1 <?php
2
3 /**
4 * @group API
5 * @group Database
6 * @group medium
7 *
8 * @covers ApiLogin
9 */
10 class ApiLoginTest extends ApiTestCase {
11
12 /**
13 * Test result of attempted login with an empty username
14 */
15 public function testApiLoginNoName() {
16 global $wgDisableAuthManager;
17
18 $session = [
19 'wsTokenSecrets' => [ 'login' => 'foobar' ],
20 ];
21 $data = $this->doApiRequest( [ 'action' => 'login',
22 'lgname' => '', 'lgpassword' => self::$users['sysop']->password,
23 'lgtoken' => (string)( new MediaWiki\Session\Token( 'foobar', '' ) )
24 ], $session );
25 $this->assertEquals( $wgDisableAuthManager ? 'NoName' : 'Failed', $data[0]['login']['result'] );
26 }
27
28 public function testApiLoginBadPass() {
29 global $wgServer, $wgDisableAuthManager;
30
31 $user = self::$users['sysop'];
32 $user->getUser()->logout();
33
34 if ( !isset( $wgServer ) ) {
35 $this->markTestIncomplete( 'This test needs $wgServer to be set in LocalSettings.php' );
36 }
37 $ret = $this->doApiRequest( [
38 "action" => "login",
39 "lgname" => $user->username,
40 "lgpassword" => "bad",
41 ] );
42
43 $result = $ret[0];
44
45 $this->assertNotInternalType( "bool", $result );
46 $a = $result["login"]["result"];
47 $this->assertEquals( "NeedToken", $a );
48
49 $token = $result["login"]["token"];
50
51 $ret = $this->doApiRequest(
52 [
53 "action" => "login",
54 "lgtoken" => $token,
55 "lgname" => $user->username,
56 "lgpassword" => "badnowayinhell",
57 ],
58 $ret[2]
59 );
60
61 $result = $ret[0];
62
63 $this->assertNotInternalType( "bool", $result );
64 $a = $result["login"]["result"];
65
66 $this->assertEquals( $wgDisableAuthManager ? 'WrongPass' : 'Failed', $a );
67 }
68
69 public function testApiLoginGoodPass() {
70 global $wgServer;
71
72 if ( !isset( $wgServer ) ) {
73 $this->markTestIncomplete( 'This test needs $wgServer to be set in LocalSettings.php' );
74 }
75
76 $user = self::$users['sysop'];
77 $user->getUser()->logout();
78
79 $ret = $this->doApiRequest( [
80 "action" => "login",
81 "lgname" => $user->username,
82 "lgpassword" => $user->password,
83 ]
84 );
85
86 $result = $ret[0];
87 $this->assertNotInternalType( "bool", $result );
88 $this->assertNotInternalType( "null", $result["login"] );
89
90 $a = $result["login"]["result"];
91 $this->assertEquals( "NeedToken", $a );
92 $token = $result["login"]["token"];
93
94 $ret = $this->doApiRequest(
95 [
96 "action" => "login",
97 "lgtoken" => $token,
98 "lgname" => $user->username,
99 "lgpassword" => $user->password,
100 ],
101 $ret[2]
102 );
103
104 $result = $ret[0];
105
106 $this->assertNotInternalType( "bool", $result );
107 $a = $result["login"]["result"];
108
109 $this->assertEquals( "Success", $a );
110 }
111
112 /**
113 * @group Broken
114 */
115 public function testApiLoginGotCookie() {
116 $this->markTestIncomplete( "The server can't do external HTTP requests, "
117 . "and the internal one won't give cookies" );
118
119 global $wgServer, $wgScriptPath;
120
121 if ( !isset( $wgServer ) ) {
122 $this->markTestIncomplete( 'This test needs $wgServer to be set in LocalSettings.php' );
123 }
124 $user = self::$users['sysop'];
125
126 $req = MWHttpRequest::factory( self::$apiUrl . "?action=login&format=xml",
127 [ "method" => "POST",
128 "postData" => [
129 "lgname" => $user->username,
130 "lgpassword" => $user->password
131 ]
132 ],
133 __METHOD__
134 );
135 $req->execute();
136
137 libxml_use_internal_errors( true );
138 $sxe = simplexml_load_string( $req->getContent() );
139 $this->assertNotInternalType( "bool", $sxe );
140 $this->assertThat( $sxe, $this->isInstanceOf( "SimpleXMLElement" ) );
141 $this->assertNotInternalType( "null", $sxe->login[0] );
142
143 $a = $sxe->login[0]->attributes()->result[0];
144 $this->assertEquals( ' result="NeedToken"', $a->asXML() );
145 $token = (string)$sxe->login[0]->attributes()->token;
146
147 $req->setData( [
148 "lgtoken" => $token,
149 "lgname" => $user->username,
150 "lgpassword" => $user->password ] );
151 $req->execute();
152
153 $cj = $req->getCookieJar();
154 $serverName = parse_url( $wgServer, PHP_URL_HOST );
155 $this->assertNotEquals( false, $serverName );
156 $serializedCookie = $cj->serializeToHttpRequest( $wgScriptPath, $serverName );
157 $this->assertNotEquals( '', $serializedCookie );
158 $this->assertRegExp(
159 '/_session=[^;]*; .*UserID=[0-9]*; .*UserName=' . $user->userName . '; .*Token=/',
160 $serializedCookie
161 );
162 }
163
164 public function testRunLogin() {
165 $sysopUser = self::$users['sysop'];
166 $data = $this->doApiRequest( [
167 'action' => 'login',
168 'lgname' => $sysopUser->username,
169 'lgpassword' => $sysopUser->password ] );
170
171 $this->assertArrayHasKey( "login", $data[0] );
172 $this->assertArrayHasKey( "result", $data[0]['login'] );
173 $this->assertEquals( "NeedToken", $data[0]['login']['result'] );
174 $token = $data[0]['login']['token'];
175
176 $data = $this->doApiRequest( [
177 'action' => 'login',
178 "lgtoken" => $token,
179 "lgname" => $sysopUser->username,
180 "lgpassword" => $sysopUser->password ], $data[2] );
181
182 $this->assertArrayHasKey( "login", $data[0] );
183 $this->assertArrayHasKey( "result", $data[0]['login'] );
184 $this->assertEquals( "Success", $data[0]['login']['result'] );
185 $this->assertArrayHasKey( 'lgtoken', $data[0]['login'] );
186 }
187
188 public function testBotPassword() {
189 global $wgServer, $wgSessionProviders;
190
191 if ( !isset( $wgServer ) ) {
192 $this->markTestIncomplete( 'This test needs $wgServer to be set in LocalSettings.php' );
193 }
194
195 $this->setMwGlobals( [
196 'wgSessionProviders' => array_merge( $wgSessionProviders, [
197 [
198 'class' => MediaWiki\Session\BotPasswordSessionProvider::class,
199 'args' => [ [ 'priority' => 40 ] ],
200 ]
201 ] ),
202 'wgEnableBotPasswords' => true,
203 'wgBotPasswordsDatabase' => false,
204 'wgCentralIdLookupProvider' => 'local',
205 'wgGrantPermissions' => [
206 'test' => [ 'read' => true ],
207 ],
208 ] );
209
210 // Make sure our session provider is present
211 $manager = TestingAccessWrapper::newFromObject( MediaWiki\Session\SessionManager::singleton() );
212 if ( !isset( $manager->sessionProviders[MediaWiki\Session\BotPasswordSessionProvider::class] ) ) {
213 $tmp = $manager->sessionProviders;
214 $manager->sessionProviders = null;
215 $manager->sessionProviders = $tmp + $manager->getProviders();
216 }
217 $this->assertNotNull(
218 MediaWiki\Session\SessionManager::singleton()->getProvider(
219 MediaWiki\Session\BotPasswordSessionProvider::class
220 ),
221 'sanity check'
222 );
223
224 $user = self::$users['sysop'];
225 $centralId = CentralIdLookup::factory()->centralIdFromLocalUser( $user->getUser() );
226 $this->assertNotEquals( 0, $centralId, 'sanity check' );
227
228 $passwordFactory = new PasswordFactory();
229 $passwordFactory->init( RequestContext::getMain()->getConfig() );
230 // A is unsalted MD5 (thus fast) ... we don't care about security here, this is test only
231 $passwordFactory->setDefaultType( 'A' );
232 $pwhash = $passwordFactory->newFromPlaintext( 'foobaz' );
233
234 $dbw = wfGetDB( DB_MASTER );
235 $dbw->insert(
236 'bot_passwords',
237 [
238 'bp_user' => $centralId,
239 'bp_app_id' => 'foo',
240 'bp_password' => $pwhash->toString(),
241 'bp_token' => '',
242 'bp_restrictions' => MWRestrictions::newDefault()->toJson(),
243 'bp_grants' => '["test"]',
244 ],
245 __METHOD__
246 );
247
248 $lgName = $user->username . BotPassword::getSeparator() . 'foo';
249
250 $ret = $this->doApiRequest( [
251 'action' => 'login',
252 'lgname' => $lgName,
253 'lgpassword' => 'foobaz',
254 ] );
255
256 $result = $ret[0];
257 $this->assertNotInternalType( 'bool', $result );
258 $this->assertNotInternalType( 'null', $result['login'] );
259
260 $a = $result['login']['result'];
261 $this->assertEquals( 'NeedToken', $a );
262 $token = $result['login']['token'];
263
264 $ret = $this->doApiRequest( [
265 'action' => 'login',
266 'lgtoken' => $token,
267 'lgname' => $lgName,
268 'lgpassword' => 'foobaz',
269 ], $ret[2] );
270
271 $result = $ret[0];
272 $this->assertNotInternalType( 'bool', $result );
273 $a = $result['login']['result'];
274
275 $this->assertEquals( 'Success', $a );
276 }
277
278 }