Merge "Revert "Log the reason why revision->getContent() returns null""
[lhc/web/wiklou.git] / tests / phpunit / includes / api / ApiLoginTest.php
1 <?php
2
3 use Wikimedia\TestingAccessWrapper;
4
5 /**
6 * @group API
7 * @group Database
8 * @group medium
9 *
10 * @covers ApiLogin
11 */
12 class ApiLoginTest extends ApiTestCase {
13
14 /**
15 * Test result of attempted login with an empty username
16 */
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
115 /**
116 * @group Broken
117 */
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() {
196 global $wgServer, $wgSessionProviders;
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
285 }