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