Localisation updates from https://translatewiki.net.
[mediawiki.git] / tests / phpunit / includes / auth / AbstractPasswordPrimaryAuthenticationProviderTest.php
blob06a3442bcbcdf65f870fe361b4390130e6374233
1 <?php
3 namespace MediaWiki\Tests\Auth;
5 use MediaWiki\Auth\AbstractPasswordPrimaryAuthenticationProvider;
6 use MediaWiki\Auth\AuthenticationResponse;
7 use MediaWiki\Auth\AuthManager;
8 use MediaWiki\Auth\PasswordAuthenticationRequest;
9 use MediaWiki\Config\HashConfig;
10 use MediaWiki\Config\MultiConfig;
11 use MediaWiki\MainConfigNames;
12 use MediaWiki\Password\Password;
13 use MediaWiki\Password\PasswordFactory;
14 use MediaWiki\Request\FauxRequest;
15 use MediaWiki\Status\Status;
16 use MediaWiki\Tests\Unit\Auth\AuthenticationProviderTestTrait;
17 use MediaWiki\User\User;
18 use MediaWiki\User\UserFactory;
19 use MediaWikiIntegrationTestCase;
20 use Wikimedia\TestingAccessWrapper;
22 /**
23 * @group AuthManager
24 * @covers \MediaWiki\Auth\AbstractPasswordPrimaryAuthenticationProvider
26 class AbstractPasswordPrimaryAuthenticationProviderTest extends MediaWikiIntegrationTestCase {
27 use AuthenticationProviderTestTrait;
29 public function testConstructor() {
30 $provider = $this->getMockForAbstractClass(
31 AbstractPasswordPrimaryAuthenticationProvider::class
33 $providerPriv = TestingAccessWrapper::newFromObject( $provider );
34 $this->assertTrue( $providerPriv->authoritative );
36 $provider = $this->getMockForAbstractClass(
37 AbstractPasswordPrimaryAuthenticationProvider::class,
38 [ [ 'authoritative' => false ] ]
40 $providerPriv = TestingAccessWrapper::newFromObject( $provider );
41 $this->assertFalse( $providerPriv->authoritative );
44 public function testGetPasswordFactory() {
45 $provider = $this->getMockForAbstractClass(
46 AbstractPasswordPrimaryAuthenticationProvider::class
48 $this->initProvider( $provider, $this->getServiceContainer()->getMainConfig() );
49 $providerPriv = TestingAccessWrapper::newFromObject( $provider );
51 $obj = $providerPriv->getPasswordFactory();
52 $this->assertInstanceOf( PasswordFactory::class, $obj );
53 $this->assertSame( $obj, $providerPriv->getPasswordFactory() );
56 public function testGetPassword() {
57 $provider = $this->getMockForAbstractClass(
58 AbstractPasswordPrimaryAuthenticationProvider::class
60 $this->initProvider( $provider, $this->getServiceContainer()->getMainConfig() );
61 $providerPriv = TestingAccessWrapper::newFromObject( $provider );
63 $obj = $providerPriv->getPassword( null );
64 $this->assertInstanceOf( Password::class, $obj );
66 $obj = $providerPriv->getPassword( 'invalid' );
67 $this->assertInstanceOf( Password::class, $obj );
70 public function testGetNewPasswordExpiry() {
71 $userName = 'TestGetNewPasswordExpiry';
72 $config = new HashConfig;
73 $provider = $this->getMockForAbstractClass(
74 AbstractPasswordPrimaryAuthenticationProvider::class
76 $this->initProvider( $provider, new MultiConfig( [ $config, $this->getServiceContainer()->getMainConfig() ] ) );
77 $providerPriv = TestingAccessWrapper::newFromObject( $provider );
79 $config->set( MainConfigNames::PasswordExpirationDays, 0 );
80 $this->assertNull( $providerPriv->getNewPasswordExpiry( $userName ) );
82 $config->set( MainConfigNames::PasswordExpirationDays, 5 );
83 $this->assertEqualsWithDelta(
84 time() + 5 * 86400,
85 wfTimestamp( TS_UNIX, $providerPriv->getNewPasswordExpiry( $userName ) ),
86 2 /* Fuzz */
89 $this->initProvider(
90 $provider,
91 new MultiConfig( [ $config, $this->getServiceContainer()->getMainConfig() ] ),
92 null,
93 null,
94 $this->createHookContainer( [
95 'ResetPasswordExpiration' => function ( $user, &$expires ) use ( $userName ) {
96 $this->assertSame( $userName, $user->getName() );
97 $expires = '30001231235959';
99 ] )
101 $this->assertSame( '30001231235959', $providerPriv->getNewPasswordExpiry( $userName ) );
104 public function testCheckPasswordValidity() {
105 $uppCalled = 0;
106 $uppStatus = Status::newGood( [] );
107 $this->overrideConfigValue(
108 MainConfigNames::PasswordPolicy,
110 'policies' => [
111 'default' => [
112 'Check' => true,
115 'checks' => [
116 'Check' => static function () use ( &$uppCalled, &$uppStatus ) {
117 $uppCalled++;
118 return $uppStatus;
123 $this->clearHook( 'PasswordPoliciesForUser' );
125 $provider = $this->getMockForAbstractClass(
126 AbstractPasswordPrimaryAuthenticationProvider::class
128 $this->initProvider( $provider, $this->getServiceContainer()->getMainConfig() );
129 $providerPriv = TestingAccessWrapper::newFromObject( $provider );
131 $username = '127.0.0.1';
132 $anon = new User();
133 $anon->setName( $username );
134 $userFactory = $this->createMock( UserFactory::class );
135 $userFactory->method( 'newFromName' )->with( $username )->willReturn( $anon );
136 $this->setService( 'UserFactory', $userFactory );
138 $this->assertEquals( $uppStatus, $providerPriv->checkPasswordValidity( $username, 'bar' ) );
140 $uppStatus->fatal( 'arbitrary-warning' );
141 $this->assertEquals( $uppStatus, $providerPriv->checkPasswordValidity( $username, 'bar' ) );
144 public function testSetPasswordResetFlag() {
145 $config = new HashConfig( [
146 MainConfigNames::InvalidPasswordReset => true,
147 ] );
149 $services = $this->getServiceContainer();
150 $manager = new AuthManager(
151 new FauxRequest(),
152 $services->getMainConfig(),
153 $services->getObjectFactory(),
154 $services->getHookContainer(),
155 $services->getReadOnlyMode(),
156 $services->getUserNameUtils(),
157 $services->getBlockManager(),
158 $services->getWatchlistManager(),
159 $services->getDBLoadBalancer(),
160 $services->getContentLanguage(),
161 $services->getLanguageConverterFactory(),
162 $services->getBotPasswordStore(),
163 $services->getUserFactory(),
164 $services->getUserIdentityLookup(),
165 $services->getUserOptionsManager()
168 $provider = $this->getMockForAbstractClass(
169 AbstractPasswordPrimaryAuthenticationProvider::class
171 $this->initProvider( $provider, $config, null, $manager, $services->getHookContainer() );
172 $providerPriv = TestingAccessWrapper::newFromObject( $provider );
174 $manager->removeAuthenticationSessionData( null );
175 $status = Status::newGood();
176 $providerPriv->setPasswordResetFlag( 'Foo', $status );
177 $this->assertNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
179 $manager->removeAuthenticationSessionData( null );
180 $status = Status::newGood( [ 'suggestChangeOnLogin' => true ] );
181 $status->error( 'testing' );
182 $providerPriv->setPasswordResetFlag( 'Foo', $status );
183 $ret = $manager->getAuthenticationSessionData( 'reset-pass' );
184 $this->assertNotNull( $ret );
185 $this->assertSame( 'resetpass-validity-soft', $ret->msg->getKey() );
186 $this->assertFalse( $ret->hard );
188 $config->set( MainConfigNames::InvalidPasswordReset, false );
189 $manager->removeAuthenticationSessionData( null );
190 $providerPriv->setPasswordResetFlag( 'Foo', $status );
191 $ret = $manager->getAuthenticationSessionData( 'reset-pass' );
192 $this->assertNull( $ret );
195 public function testFailResponse() {
196 $provider = $this->getMockForAbstractClass(
197 AbstractPasswordPrimaryAuthenticationProvider::class,
198 [ [ 'authoritative' => false ] ]
200 $providerPriv = TestingAccessWrapper::newFromObject( $provider );
202 $req = new PasswordAuthenticationRequest;
204 $ret = $providerPriv->failResponse( $req );
205 $this->assertSame( AuthenticationResponse::ABSTAIN, $ret->status );
207 $provider = $this->getMockForAbstractClass(
208 AbstractPasswordPrimaryAuthenticationProvider::class,
209 [ [ 'authoritative' => true ] ]
211 $providerPriv = TestingAccessWrapper::newFromObject( $provider );
213 $req->password = '';
214 $ret = $providerPriv->failResponse( $req );
215 $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
216 $this->assertSame( 'wrongpasswordempty', $ret->message->getKey() );
218 $req->password = 'X';
219 $ret = $providerPriv->failResponse( $req );
220 $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
221 $this->assertSame( 'wrongpassword', $ret->message->getKey() );
225 * @dataProvider provideGetAuthenticationRequests
226 * @param string $action
227 * @param array $response
229 public function testGetAuthenticationRequests( $action, $response ) {
230 $provider = $this->getMockForAbstractClass(
231 AbstractPasswordPrimaryAuthenticationProvider::class
234 $this->assertEquals( $response, $provider->getAuthenticationRequests( $action, [] ) );
237 public static function provideGetAuthenticationRequests() {
238 return [
239 [ AuthManager::ACTION_LOGIN, [ new PasswordAuthenticationRequest() ] ],
240 [ AuthManager::ACTION_CREATE, [ new PasswordAuthenticationRequest() ] ],
241 [ AuthManager::ACTION_LINK, [] ],
242 [ AuthManager::ACTION_CHANGE, [ new PasswordAuthenticationRequest() ] ],
243 [ AuthManager::ACTION_REMOVE, [ new PasswordAuthenticationRequest() ] ],
247 public function testProviderRevokeAccessForUser() {
248 $req = new PasswordAuthenticationRequest;
249 $req->action = AuthManager::ACTION_REMOVE;
250 $req->username = 'foo';
251 $req->password = null;
253 $provider = $this->getMockForAbstractClass(
254 AbstractPasswordPrimaryAuthenticationProvider::class
256 $provider->expects( $this->once() )
257 ->method( 'providerChangeAuthenticationData' )
258 ->with( $req );
260 $provider->providerRevokeAccessForUser( 'foo' );