Localisation updates from https://translatewiki.net.
[mediawiki.git] / tests / phpunit / includes / auth / ResetPasswordSecondaryAuthenticationProviderTest.php
blob234b6d554b082e0a9a1e803acf0a57f53a1660c6
1 <?php
3 namespace MediaWiki\Tests\Auth;
5 use DynamicPropertyTestHelper;
6 use MediaWiki\Auth\AuthenticationRequest;
7 use MediaWiki\Auth\AuthenticationResponse;
8 use MediaWiki\Auth\AuthManager;
9 use MediaWiki\Auth\ButtonAuthenticationRequest;
10 use MediaWiki\Auth\PasswordAuthenticationRequest;
11 use MediaWiki\Auth\ResetPasswordSecondaryAuthenticationProvider;
12 use MediaWiki\Config\HashConfig;
13 use MediaWiki\MainConfigNames;
14 use MediaWiki\Request\FauxRequest;
15 use MediaWiki\Tests\Unit\Auth\AuthenticationProviderTestTrait;
16 use MediaWiki\Tests\Unit\DummyServicesTrait;
17 use MediaWiki\User\BotPasswordStore;
18 use MediaWiki\User\User;
19 use MediaWiki\User\UserNameUtils;
20 use MediaWikiIntegrationTestCase;
21 use StatusValue;
22 use stdClass;
23 use UnexpectedValueException;
24 use Wikimedia\TestingAccessWrapper;
26 /**
27 * @group AuthManager
28 * @covers \MediaWiki\Auth\ResetPasswordSecondaryAuthenticationProvider
30 class ResetPasswordSecondaryAuthenticationProviderTest extends MediaWikiIntegrationTestCase {
31 use AuthenticationProviderTestTrait;
32 use DummyServicesTrait;
34 /**
35 * @dataProvider provideGetAuthenticationRequests
36 * @param string $action
37 * @param array $response
39 public function testGetAuthenticationRequests( $action, $response ) {
40 $provider = new ResetPasswordSecondaryAuthenticationProvider();
42 $this->assertEquals( $response, $provider->getAuthenticationRequests( $action, [] ) );
45 public static function provideGetAuthenticationRequests() {
46 return [
47 [ AuthManager::ACTION_LOGIN, [] ],
48 [ AuthManager::ACTION_CREATE, [] ],
49 [ AuthManager::ACTION_LINK, [] ],
50 [ AuthManager::ACTION_CHANGE, [] ],
51 [ AuthManager::ACTION_REMOVE, [] ],
55 public function testBasics() {
56 $user = $this->createMock( User::class );
57 $user2 = new User;
58 $obj = new stdClass;
59 $reqs = [ new stdClass ];
61 $mb = $this->getMockBuilder( ResetPasswordSecondaryAuthenticationProvider::class )
62 ->onlyMethods( [ 'tryReset' ] );
64 $methods = [
65 'beginSecondaryAuthentication' => [ $user, $reqs ],
66 'continueSecondaryAuthentication' => [ $user, $reqs ],
67 'beginSecondaryAccountCreation' => [ $user, $user2, $reqs ],
68 'continueSecondaryAccountCreation' => [ $user, $user2, $reqs ],
70 foreach ( $methods as $method => $args ) {
71 $mock = $mb->getMock();
72 $mock->expects( $this->once() )->method( 'tryReset' )
73 ->with( $this->identicalTo( $user ), $this->identicalTo( $reqs ) )
74 ->willReturn( $obj );
75 $this->assertSame( $obj, $mock->$method( ...$args ) );
79 public function testTryReset() {
80 $username = 'TestTryReset';
81 $user = User::newFromName( $username );
83 $provider = $this->getMockBuilder(
84 ResetPasswordSecondaryAuthenticationProvider::class
86 ->onlyMethods( [
87 'providerAllowsAuthenticationDataChange', 'providerChangeAuthenticationData'
88 ] )
89 ->getMock();
90 $provider->method( 'providerAllowsAuthenticationDataChange' )
91 ->willReturnCallback( function ( $req ) use ( $username ) {
92 $this->assertSame( $username, $req->username );
93 return DynamicPropertyTestHelper::getDynamicProperty( $req, 'allow' );
94 } );
95 $provider->method( 'providerChangeAuthenticationData' )
96 ->willReturnCallback( function ( $req ) use ( $username ) {
97 $this->assertSame( $username, $req->username );
98 DynamicPropertyTestHelper::setDynamicProperty( $req, 'done', true );
99 } );
100 $config = new HashConfig( [
101 MainConfigNames::AuthManagerConfig => [
102 'preauth' => [],
103 'primaryauth' => [],
104 'secondaryauth' => [
105 [ 'factory' => static function () use ( $provider ) {
106 return $provider;
107 } ],
110 ] );
111 $mwServices = $this->getServiceContainer();
112 $manager = new AuthManager(
113 new FauxRequest,
114 $config,
115 $this->getDummyObjectFactory(),
116 $this->createHookContainer(),
117 $mwServices->getReadOnlyMode(),
118 $this->createNoOpMock( UserNameUtils::class ),
119 $mwServices->getBlockManager(),
120 $mwServices->getWatchlistManager(),
121 $mwServices->getDBLoadBalancer(),
122 $mwServices->getContentLanguage(),
123 $mwServices->getLanguageConverterFactory(),
124 $this->createMock( BotPasswordStore::class ),
125 $mwServices->getUserFactory(),
126 $mwServices->getUserIdentityLookup(),
127 $mwServices->getUserOptionsManager()
129 $this->initProvider( $provider, null, null, $manager );
130 $provider = TestingAccessWrapper::newFromObject( $provider );
132 $msg = wfMessage( 'foo' );
133 $skipReq = new ButtonAuthenticationRequest(
134 'skipReset',
135 wfMessage( 'authprovider-resetpass-skip-label' ),
136 wfMessage( 'authprovider-resetpass-skip-help' )
138 $passReq = new PasswordAuthenticationRequest();
139 $passReq->action = AuthManager::ACTION_CHANGE;
140 $passReq->password = 'Foo';
141 $passReq->retype = 'Bar';
142 DynamicPropertyTestHelper::setDynamicProperty( $passReq, 'allow', StatusValue::newGood() );
143 DynamicPropertyTestHelper::setDynamicProperty( $passReq, 'done', false );
145 $passReq2 = $this->getMockBuilder( PasswordAuthenticationRequest::class )
146 ->enableProxyingToOriginalMethods()
147 ->getMock();
148 $passReq2->action = AuthManager::ACTION_CHANGE;
149 $passReq2->password = 'Foo';
150 $passReq2->retype = 'Foo';
151 DynamicPropertyTestHelper::setDynamicProperty( $passReq2, 'allow', StatusValue::newGood() );
152 DynamicPropertyTestHelper::setDynamicProperty( $passReq2, 'done', false );
154 $passReq3 = new PasswordAuthenticationRequest();
155 $passReq3->action = AuthManager::ACTION_LOGIN;
156 $passReq3->password = 'Foo';
157 $passReq3->retype = 'Foo';
158 DynamicPropertyTestHelper::setDynamicProperty( $passReq3, 'allow', StatusValue::newGood() );
159 DynamicPropertyTestHelper::setDynamicProperty( $passReq3, 'done', false );
161 $this->assertEquals(
162 AuthenticationResponse::newAbstain(),
163 $provider->tryReset( $user, [] )
166 $manager->setAuthenticationSessionData( 'reset-pass', 'foo' );
167 try {
168 $provider->tryReset( $user, [] );
169 $this->fail( 'Expected exception not thrown' );
170 } catch ( UnexpectedValueException $ex ) {
171 $this->assertSame( 'reset-pass is not valid', $ex->getMessage() );
174 $manager->setAuthenticationSessionData( 'reset-pass', (object)[] );
175 try {
176 $provider->tryReset( $user, [] );
177 $this->fail( 'Expected exception not thrown' );
178 } catch ( UnexpectedValueException $ex ) {
179 $this->assertSame( 'reset-pass msg is missing', $ex->getMessage() );
182 $manager->setAuthenticationSessionData( 'reset-pass', [
183 'msg' => 'foo',
184 ] );
185 try {
186 $provider->tryReset( $user, [] );
187 $this->fail( 'Expected exception not thrown' );
188 } catch ( UnexpectedValueException $ex ) {
189 $this->assertSame( 'reset-pass msg is not valid', $ex->getMessage() );
192 $manager->setAuthenticationSessionData( 'reset-pass', [
193 'msg' => $msg,
194 ] );
195 try {
196 $provider->tryReset( $user, [] );
197 $this->fail( 'Expected exception not thrown' );
198 } catch ( UnexpectedValueException $ex ) {
199 $this->assertSame( 'reset-pass hard is missing', $ex->getMessage() );
202 $manager->setAuthenticationSessionData( 'reset-pass', [
203 'msg' => $msg,
204 'hard' => true,
205 'req' => 'foo',
206 ] );
207 try {
208 $provider->tryReset( $user, [] );
209 $this->fail( 'Expected exception not thrown' );
210 } catch ( UnexpectedValueException $ex ) {
211 $this->assertSame( 'reset-pass req is not valid', $ex->getMessage() );
214 $manager->setAuthenticationSessionData( 'reset-pass', [
215 'msg' => $msg,
216 'hard' => false,
217 'req' => $passReq3,
218 ] );
219 try {
220 $provider->tryReset( $user, [ $passReq ] );
221 $this->fail( 'Expected exception not thrown' );
222 } catch ( UnexpectedValueException $ex ) {
223 $this->assertSame( 'reset-pass req is not valid', $ex->getMessage() );
226 $manager->setAuthenticationSessionData( 'reset-pass', [
227 'msg' => $msg,
228 'hard' => true,
229 ] );
230 $res = $provider->tryReset( $user, [] );
231 $this->assertInstanceOf( AuthenticationResponse::class, $res );
232 $this->assertSame( AuthenticationResponse::UI, $res->status );
233 $this->assertEquals( $msg, $res->message );
234 $this->assertCount( 1, $res->neededRequests );
235 $this->assertInstanceOf(
236 PasswordAuthenticationRequest::class,
237 $res->neededRequests[0]
239 $this->assertNotNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
240 $this->assertFalse( DynamicPropertyTestHelper::getDynamicProperty( $passReq, 'done' ) );
242 $manager->setAuthenticationSessionData( 'reset-pass', [
243 'msg' => $msg,
244 'hard' => false,
245 'req' => $passReq,
246 ] );
247 $res = $provider->tryReset( $user, [] );
248 $this->assertInstanceOf( AuthenticationResponse::class, $res );
249 $this->assertSame( AuthenticationResponse::UI, $res->status );
250 $this->assertEquals( $msg, $res->message );
251 $this->assertCount( 2, $res->neededRequests );
252 $expectedPassReq = clone $passReq;
253 $expectedPassReq->required = AuthenticationRequest::OPTIONAL;
254 $this->assertEquals( $expectedPassReq, $res->neededRequests[0] );
255 $this->assertEquals( $skipReq, $res->neededRequests[1] );
256 $this->assertNotNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
257 $this->assertFalse( DynamicPropertyTestHelper::getDynamicProperty( $passReq, 'done' ) );
259 $passReq->retype = 'Bad';
260 $manager->setAuthenticationSessionData( 'reset-pass', [
261 'msg' => $msg,
262 'hard' => false,
263 'req' => $passReq,
264 ] );
265 $res = $provider->tryReset( $user, [ $skipReq, $passReq ] );
266 $this->assertEquals( AuthenticationResponse::newPass(), $res );
267 $this->assertNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
268 $this->assertFalse( DynamicPropertyTestHelper::getDynamicProperty( $passReq, 'done' ) );
270 $passReq->retype = 'Bad';
271 $manager->setAuthenticationSessionData( 'reset-pass', [
272 'msg' => $msg,
273 'hard' => true,
274 ] );
275 $res = $provider->tryReset( $user, [ $skipReq, $passReq ] );
276 $this->assertSame( AuthenticationResponse::UI, $res->status );
277 $this->assertSame( 'badretype', $res->message->getKey() );
278 $this->assertCount( 1, $res->neededRequests );
279 $this->assertInstanceOf(
280 PasswordAuthenticationRequest::class,
281 $res->neededRequests[0]
283 $this->assertNotNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
284 $this->assertFalse( DynamicPropertyTestHelper::getDynamicProperty( $passReq, 'done' ) );
286 $manager->setAuthenticationSessionData( 'reset-pass', [
287 'msg' => $msg,
288 'hard' => true,
289 ] );
290 $res = $provider->tryReset( $user, [ $skipReq, $passReq3 ] );
291 $this->assertSame( AuthenticationResponse::UI, $res->status );
292 $this->assertEquals( $msg, $res->message );
293 $this->assertCount( 1, $res->neededRequests );
294 $this->assertInstanceOf(
295 PasswordAuthenticationRequest::class,
296 $res->neededRequests[0]
298 $this->assertNotNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
299 $this->assertFalse( DynamicPropertyTestHelper::getDynamicProperty( $passReq, 'done' ) );
301 $passReq->retype = $passReq->password;
302 DynamicPropertyTestHelper::setDynamicProperty( $passReq, 'allow', StatusValue::newFatal( 'arbitrary-fail' ) );
303 $res = $provider->tryReset( $user, [ $skipReq, $passReq ] );
304 $this->assertSame( AuthenticationResponse::UI, $res->status );
305 $this->assertSame( 'arbitrary-fail', $res->message->getKey() );
306 $this->assertCount( 1, $res->neededRequests );
307 $this->assertInstanceOf(
308 PasswordAuthenticationRequest::class,
309 $res->neededRequests[0]
311 $this->assertNotNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
312 $this->assertFalse( DynamicPropertyTestHelper::getDynamicProperty( $passReq, 'done' ) );
314 DynamicPropertyTestHelper::setDynamicProperty( $passReq, 'allow', StatusValue::newGood() );
315 $res = $provider->tryReset( $user, [ $skipReq, $passReq ] );
316 $this->assertEquals( AuthenticationResponse::newPass(), $res );
317 $this->assertNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
318 $this->assertTrue( DynamicPropertyTestHelper::getDynamicProperty( $passReq, 'done' ) );
320 $manager->setAuthenticationSessionData( 'reset-pass', [
321 'msg' => $msg,
322 'hard' => false,
323 'req' => $passReq2,
324 ] );
325 $res = $provider->tryReset( $user, [ $passReq2 ] );
326 $this->assertEquals( AuthenticationResponse::newPass(), $res );
327 $this->assertNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
328 $this->assertTrue( DynamicPropertyTestHelper::getDynamicProperty( $passReq2, 'done' ) );
330 DynamicPropertyTestHelper::setDynamicProperty( $passReq, 'done', false );
331 DynamicPropertyTestHelper::setDynamicProperty( $passReq2, 'done', false );
332 $manager->setAuthenticationSessionData( 'reset-pass', [
333 'msg' => $msg,
334 'hard' => false,
335 'req' => $passReq2,
336 ] );
337 $res = $provider->tryReset( $user, [ $passReq ] );
338 $this->assertInstanceOf( AuthenticationResponse::class, $res );
339 $this->assertSame( AuthenticationResponse::UI, $res->status );
340 $this->assertEquals( $msg, $res->message );
341 $this->assertCount( 2, $res->neededRequests );
342 $expectedPassReq = clone $passReq2;
343 $expectedPassReq->required = AuthenticationRequest::OPTIONAL;
344 $this->assertEquals( $expectedPassReq, $res->neededRequests[0] );
345 $this->assertEquals( $skipReq, $res->neededRequests[1] );
346 $this->assertNotNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
347 $this->assertFalse( DynamicPropertyTestHelper::getDynamicProperty( $passReq, 'done' ) );
348 $this->assertFalse( DynamicPropertyTestHelper::getDynamicProperty( $passReq2, 'done' ) );