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