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