3 namespace MediaWiki\Auth
;
5 use Wikimedia\TestingAccessWrapper
;
9 * @covers MediaWiki\Auth\ResetPasswordSecondaryAuthenticationProvider
11 class ResetPasswordSecondaryAuthenticationProviderTest
extends \MediaWikiTestCase
{
13 * @dataProvider provideGetAuthenticationRequests
14 * @param string $action
15 * @param array $response
17 public function testGetAuthenticationRequests( $action, $response ) {
18 $provider = new ResetPasswordSecondaryAuthenticationProvider();
20 $this->assertEquals( $response, $provider->getAuthenticationRequests( $action, [] ) );
23 public static function provideGetAuthenticationRequests() {
25 [ AuthManager
::ACTION_LOGIN
, [] ],
26 [ AuthManager
::ACTION_CREATE
, [] ],
27 [ AuthManager
::ACTION_LINK
, [] ],
28 [ AuthManager
::ACTION_CHANGE
, [] ],
29 [ AuthManager
::ACTION_REMOVE
, [] ],
33 public function testBasics() {
34 $user = \User
::newFromName( 'UTSysop' );
37 $reqs = [ new \stdClass
];
39 $mb = $this->getMockBuilder( ResetPasswordSecondaryAuthenticationProvider
::class )
40 ->setMethods( [ 'tryReset' ] );
43 'beginSecondaryAuthentication' => [ $user, $reqs ],
44 'continueSecondaryAuthentication' => [ $user, $reqs ],
45 'beginSecondaryAccountCreation' => [ $user, $user2, $reqs ],
46 'continueSecondaryAccountCreation' => [ $user, $user2, $reqs ],
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 ) );
57 public function testTryReset() {
58 $user = \User
::newFromName( 'UTSysop' );
60 $provider = $this->getMockBuilder(
61 ResetPasswordSecondaryAuthenticationProvider
::class
64 'providerAllowsAuthenticationDataChange', 'providerChangeAuthenticationData'
67 $provider->expects( $this->any() )->method( 'providerAllowsAuthenticationDataChange' )
68 ->will( $this->returnCallback( function ( $req ) {
69 $this->assertSame( 'UTSysop', $req->username
);
72 $provider->expects( $this->any() )->method( 'providerChangeAuthenticationData' )
73 ->will( $this->returnCallback( function ( $req ) {
74 $this->assertSame( 'UTSysop', $req->username
);
77 $config = new \
HashConfig( [
78 'AuthManagerConfig' => [
82 [ 'factory' => function () use ( $provider ) {
88 $manager = new AuthManager( new \FauxRequest
, $config );
89 $provider->setManager( $manager );
90 $provider = TestingAccessWrapper
::newFromObject( $provider );
92 $msg = wfMessage( 'foo' );
93 $skipReq = new ButtonAuthenticationRequest(
95 wfMessage( 'authprovider-resetpass-skip-label' ),
96 wfMessage( 'authprovider-resetpass-skip-help' )
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;
105 $passReq2 = $this->getMockBuilder( PasswordAuthenticationRequest
::class )
106 ->enableProxyingToOriginalMethods()
108 $passReq2->action
= AuthManager
::ACTION_CHANGE
;
109 $passReq2->password
= 'Foo';
110 $passReq2->retype
= 'Foo';
111 $passReq2->allow
= \StatusValue
::newGood();
112 $passReq2->done
= false;
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;
122 AuthenticationResponse
::newAbstain(),
123 $provider->tryReset( $user, [] )
126 $manager->setAuthenticationSessionData( 'reset-pass', 'foo' );
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() );
134 $manager->setAuthenticationSessionData( 'reset-pass', (object)[] );
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() );
142 $manager->setAuthenticationSessionData( 'reset-pass', [
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() );
152 $manager->setAuthenticationSessionData( 'reset-pass', [
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() );
162 $manager->setAuthenticationSessionData( 'reset-pass', [
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() );
174 $manager->setAuthenticationSessionData( 'reset-pass', [
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() );
186 $manager->setAuthenticationSessionData( 'reset-pass', [
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]
199 $this->assertNotNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
200 $this->assertFalse( $passReq->done
);
202 $manager->setAuthenticationSessionData( 'reset-pass', [
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
);
219 $passReq->retype
= 'Bad';
220 $manager->setAuthenticationSessionData( 'reset-pass', [
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
);
230 $passReq->retype
= 'Bad';
231 $manager->setAuthenticationSessionData( 'reset-pass', [
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]
243 $this->assertNotNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
244 $this->assertFalse( $passReq->done
);
246 $manager->setAuthenticationSessionData( 'reset-pass', [
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]
258 $this->assertNotNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
259 $this->assertFalse( $passReq->done
);
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]
271 $this->assertNotNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
272 $this->assertFalse( $passReq->done
);
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
);
280 $manager->setAuthenticationSessionData( 'reset-pass', [
285 $res = $provider->tryReset( $user, [ $passReq2 ] );
286 $this->assertEquals( AuthenticationResponse
::newPass(), $res );
287 $this->assertNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
288 $this->assertTrue( $passReq2->done
);
290 $passReq->done
= false;
291 $passReq2->done
= false;
292 $manager->setAuthenticationSessionData( 'reset-pass', [
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
);