Merge "Don't use $wgContentNamespaces directly"
[lhc/web/wiklou.git] / tests / phpunit / includes / auth / ResetPasswordSecondaryAuthenticationProviderTest.php
1 <?php
2
3 namespace MediaWiki\Auth;
4
5 /**
6 * @group AuthManager
7 * @covers MediaWiki\Auth\ResetPasswordSecondaryAuthenticationProvider
8 */
9 class ResetPasswordSecondaryAuthenticationProviderTest extends \MediaWikiTestCase {
10 protected function setUp() {
11 global $wgDisableAuthManager;
12
13 parent::setUp();
14 if ( $wgDisableAuthManager ) {
15 $this->markTestSkipped( '$wgDisableAuthManager is set' );
16 }
17 }
18
19 /**
20 * @dataProvider provideGetAuthenticationRequests
21 * @param string $action
22 * @param array $response
23 */
24 public function testGetAuthenticationRequests( $action, $response ) {
25 $provider = new ResetPasswordSecondaryAuthenticationProvider();
26
27 $this->assertEquals( $response, $provider->getAuthenticationRequests( $action, [] ) );
28 }
29
30 public static function provideGetAuthenticationRequests() {
31 return [
32 [ AuthManager::ACTION_LOGIN, [] ],
33 [ AuthManager::ACTION_CREATE, [] ],
34 [ AuthManager::ACTION_LINK, [] ],
35 [ AuthManager::ACTION_CHANGE, [] ],
36 [ AuthManager::ACTION_REMOVE, [] ],
37 ];
38 }
39
40 public function testBasics() {
41 $user = \User::newFromName( 'UTSysop' );
42 $user2 = new \User;
43 $obj = new \stdClass;
44 $reqs = [ new \stdClass ];
45
46 $mb = $this->getMockBuilder( ResetPasswordSecondaryAuthenticationProvider::class )
47 ->setMethods( [ 'tryReset' ] );
48
49 $methods = [
50 'beginSecondaryAuthentication' => [ $user, $reqs ],
51 'continueSecondaryAuthentication' => [ $user, $reqs ],
52 'beginSecondaryAccountCreation' => [ $user, $user2, $reqs ],
53 'continueSecondaryAccountCreation' => [ $user, $user2, $reqs ],
54 ];
55 foreach ( $methods as $method => $args ) {
56 $mock = $mb->getMock();
57 $mock->expects( $this->once() )->method( 'tryReset' )
58 ->with( $this->identicalTo( $user ), $this->identicalTo( $reqs ) )
59 ->will( $this->returnValue( $obj ) );
60 $this->assertSame( $obj, call_user_func_array( [ $mock, $method ], $args ) );
61 }
62 }
63
64 public function testTryReset() {
65 $user = \User::newFromName( 'UTSysop' );
66
67 $provider = $this->getMockBuilder(
68 ResetPasswordSecondaryAuthenticationProvider::class
69 )
70 ->setMethods( [
71 'providerAllowsAuthenticationDataChange', 'providerChangeAuthenticationData'
72 ] )
73 ->getMock();
74 $provider->expects( $this->any() )->method( 'providerAllowsAuthenticationDataChange' )
75 ->will( $this->returnCallback( function ( $req ) {
76 $this->assertSame( 'UTSysop', $req->username );
77 return $req->allow;
78 } ) );
79 $provider->expects( $this->any() )->method( 'providerChangeAuthenticationData' )
80 ->will( $this->returnCallback( function ( $req ) {
81 $this->assertSame( 'UTSysop', $req->username );
82 $req->done = true;
83 } ) );
84 $config = new \HashConfig( [
85 'AuthManagerConfig' => [
86 'preauth' => [],
87 'primaryauth' => [],
88 'secondaryauth' => [
89 [ 'factory' => function () use ( $provider ) {
90 return $provider;
91 } ],
92 ],
93 ],
94 ] );
95 $manager = new AuthManager( new \FauxRequest, $config );
96 $provider->setManager( $manager );
97 $provider = \TestingAccessWrapper::newFromObject( $provider );
98
99 $msg = wfMessage( 'foo' );
100 $skipReq = new ButtonAuthenticationRequest(
101 'skipReset',
102 wfMessage( 'authprovider-resetpass-skip-label' ),
103 wfMessage( 'authprovider-resetpass-skip-help' )
104 );
105 $passReq = new PasswordAuthenticationRequest();
106 $passReq->action = AuthManager::ACTION_CHANGE;
107 $passReq->password = 'Foo';
108 $passReq->retype = 'Bar';
109 $passReq->allow = \StatusValue::newGood();
110 $passReq->done = false;
111
112 $passReq2 = $this->getMockBuilder( PasswordAuthenticationRequest::class )
113 ->enableProxyingToOriginalMethods()
114 ->getMock();
115 $passReq2->action = AuthManager::ACTION_CHANGE;
116 $passReq2->password = 'Foo';
117 $passReq2->retype = 'Foo';
118 $passReq2->allow = \StatusValue::newGood();
119 $passReq2->done = false;
120
121 $passReq3 = new PasswordAuthenticationRequest();
122 $passReq3->action = AuthManager::ACTION_LOGIN;
123 $passReq3->password = 'Foo';
124 $passReq3->retype = 'Foo';
125 $passReq3->allow = \StatusValue::newGood();
126 $passReq3->done = false;
127
128 $this->assertEquals(
129 AuthenticationResponse::newAbstain(),
130 $provider->tryReset( $user, [] )
131 );
132
133 $manager->setAuthenticationSessionData( 'reset-pass', 'foo' );
134 try {
135 $provider->tryReset( $user, [] );
136 $this->fail( 'Expected exception not thrown' );
137 } catch ( \UnexpectedValueException $ex ) {
138 $this->assertSame( 'reset-pass is not valid', $ex->getMessage() );
139 }
140
141 $manager->setAuthenticationSessionData( 'reset-pass', (object)[] );
142 try {
143 $provider->tryReset( $user, [] );
144 $this->fail( 'Expected exception not thrown' );
145 } catch ( \UnexpectedValueException $ex ) {
146 $this->assertSame( 'reset-pass msg is missing', $ex->getMessage() );
147 }
148
149 $manager->setAuthenticationSessionData( 'reset-pass', [
150 'msg' => 'foo',
151 ] );
152 try {
153 $provider->tryReset( $user, [] );
154 $this->fail( 'Expected exception not thrown' );
155 } catch ( \UnexpectedValueException $ex ) {
156 $this->assertSame( 'reset-pass msg is not valid', $ex->getMessage() );
157 }
158
159 $manager->setAuthenticationSessionData( 'reset-pass', [
160 'msg' => $msg,
161 ] );
162 try {
163 $provider->tryReset( $user, [] );
164 $this->fail( 'Expected exception not thrown' );
165 } catch ( \UnexpectedValueException $ex ) {
166 $this->assertSame( 'reset-pass hard is missing', $ex->getMessage() );
167 }
168
169 $manager->setAuthenticationSessionData( 'reset-pass', [
170 'msg' => $msg,
171 'hard' => true,
172 'req' => 'foo',
173 ] );
174 try {
175 $provider->tryReset( $user, [] );
176 $this->fail( 'Expected exception not thrown' );
177 } catch ( \UnexpectedValueException $ex ) {
178 $this->assertSame( 'reset-pass req is not valid', $ex->getMessage() );
179 }
180
181 $manager->setAuthenticationSessionData( 'reset-pass', [
182 'msg' => $msg,
183 'hard' => false,
184 'req' => $passReq3,
185 ] );
186 try {
187 $provider->tryReset( $user, [ $passReq ] );
188 $this->fail( 'Expected exception not thrown' );
189 } catch ( \UnexpectedValueException $ex ) {
190 $this->assertSame( 'reset-pass req is not valid', $ex->getMessage() );
191 }
192
193 $manager->setAuthenticationSessionData( 'reset-pass', [
194 'msg' => $msg,
195 'hard' => true,
196 ] );
197 $res = $provider->tryReset( $user, [] );
198 $this->assertInstanceOf( AuthenticationResponse::class, $res );
199 $this->assertSame( AuthenticationResponse::UI, $res->status );
200 $this->assertEquals( $msg, $res->message );
201 $this->assertCount( 1, $res->neededRequests );
202 $this->assertInstanceOf(
203 PasswordAuthenticationRequest::class,
204 $res->neededRequests[0]
205 );
206 $this->assertNotNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
207 $this->assertFalse( $passReq->done );
208
209 $manager->setAuthenticationSessionData( 'reset-pass', [
210 'msg' => $msg,
211 'hard' => false,
212 'req' => $passReq,
213 ] );
214 $res = $provider->tryReset( $user, [] );
215 $this->assertInstanceOf( AuthenticationResponse::class, $res );
216 $this->assertSame( AuthenticationResponse::UI, $res->status );
217 $this->assertEquals( $msg, $res->message );
218 $this->assertCount( 2, $res->neededRequests );
219 $expectedPassReq = clone $passReq;
220 $expectedPassReq->required = AuthenticationRequest::OPTIONAL;
221 $this->assertEquals( $expectedPassReq, $res->neededRequests[0] );
222 $this->assertEquals( $skipReq, $res->neededRequests[1] );
223 $this->assertNotNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
224 $this->assertFalse( $passReq->done );
225
226 $passReq->retype = 'Bad';
227 $manager->setAuthenticationSessionData( 'reset-pass', [
228 'msg' => $msg,
229 'hard' => false,
230 'req' => $passReq,
231 ] );
232 $res = $provider->tryReset( $user, [ $skipReq, $passReq ] );
233 $this->assertEquals( AuthenticationResponse::newPass(), $res );
234 $this->assertNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
235 $this->assertFalse( $passReq->done );
236
237 $passReq->retype = 'Bad';
238 $manager->setAuthenticationSessionData( 'reset-pass', [
239 'msg' => $msg,
240 'hard' => true,
241 ] );
242 $res = $provider->tryReset( $user, [ $skipReq, $passReq ] );
243 $this->assertSame( AuthenticationResponse::UI, $res->status );
244 $this->assertSame( 'badretype', $res->message->getKey() );
245 $this->assertCount( 1, $res->neededRequests );
246 $this->assertInstanceOf(
247 PasswordAuthenticationRequest::class,
248 $res->neededRequests[0]
249 );
250 $this->assertNotNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
251 $this->assertFalse( $passReq->done );
252
253 $manager->setAuthenticationSessionData( 'reset-pass', [
254 'msg' => $msg,
255 'hard' => true,
256 ] );
257 $res = $provider->tryReset( $user, [ $skipReq, $passReq3 ] );
258 $this->assertSame( AuthenticationResponse::UI, $res->status );
259 $this->assertEquals( $msg, $res->message );
260 $this->assertCount( 1, $res->neededRequests );
261 $this->assertInstanceOf(
262 PasswordAuthenticationRequest::class,
263 $res->neededRequests[0]
264 );
265 $this->assertNotNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
266 $this->assertFalse( $passReq->done );
267
268 $passReq->retype = $passReq->password;
269 $passReq->allow = \StatusValue::newFatal( 'arbitrary-fail' );
270 $res = $provider->tryReset( $user, [ $skipReq, $passReq ] );
271 $this->assertSame( AuthenticationResponse::UI, $res->status );
272 $this->assertSame( 'arbitrary-fail', $res->message->getKey() );
273 $this->assertCount( 1, $res->neededRequests );
274 $this->assertInstanceOf(
275 PasswordAuthenticationRequest::class,
276 $res->neededRequests[0]
277 );
278 $this->assertNotNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
279 $this->assertFalse( $passReq->done );
280
281 $passReq->allow = \StatusValue::newGood();
282 $res = $provider->tryReset( $user, [ $skipReq, $passReq ] );
283 $this->assertEquals( AuthenticationResponse::newPass(), $res );
284 $this->assertNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
285 $this->assertTrue( $passReq->done );
286
287 $manager->setAuthenticationSessionData( 'reset-pass', [
288 'msg' => $msg,
289 'hard' => false,
290 'req' => $passReq2,
291 ] );
292 $res = $provider->tryReset( $user, [ $passReq2 ] );
293 $this->assertEquals( AuthenticationResponse::newPass(), $res );
294 $this->assertNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
295 $this->assertTrue( $passReq2->done );
296
297 $passReq->done = false;
298 $passReq2->done = false;
299 $manager->setAuthenticationSessionData( 'reset-pass', [
300 'msg' => $msg,
301 'hard' => false,
302 'req' => $passReq2,
303 ] );
304 $res = $provider->tryReset( $user, [ $passReq ] );
305 $this->assertInstanceOf( AuthenticationResponse::class, $res );
306 $this->assertSame( AuthenticationResponse::UI, $res->status );
307 $this->assertEquals( $msg, $res->message );
308 $this->assertCount( 2, $res->neededRequests );
309 $expectedPassReq = clone $passReq2;
310 $expectedPassReq->required = AuthenticationRequest::OPTIONAL;
311 $this->assertEquals( $expectedPassReq, $res->neededRequests[0] );
312 $this->assertEquals( $skipReq, $res->neededRequests[1] );
313 $this->assertNotNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
314 $this->assertFalse( $passReq->done );
315 $this->assertFalse( $passReq2->done );
316 }
317 }