Merge "Accept 'OK' status results from search engine"
[lhc/web/wiklou.git] / tests / phpunit / includes / auth / AbstractPasswordPrimaryAuthenticationProviderTest.php
1 <?php
2
3 namespace MediaWiki\Auth;
4
5 use MediaWiki\MediaWikiServices;
6
7 /**
8 * @group AuthManager
9 * @covers MediaWiki\Auth\AbstractPasswordPrimaryAuthenticationProvider
10 */
11 class AbstractPasswordPrimaryAuthenticationProviderTest extends \MediaWikiTestCase {
12 public function testConstructor() {
13 $provider = $this->getMockForAbstractClass(
14 AbstractPasswordPrimaryAuthenticationProvider::class
15 );
16 $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
17 $this->assertTrue( $providerPriv->authoritative );
18
19 $provider = $this->getMockForAbstractClass(
20 AbstractPasswordPrimaryAuthenticationProvider::class,
21 [ [ 'authoritative' => false ] ]
22 );
23 $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
24 $this->assertFalse( $providerPriv->authoritative );
25 }
26
27 public function testGetPasswordFactory() {
28 $provider = $this->getMockForAbstractClass(
29 AbstractPasswordPrimaryAuthenticationProvider::class
30 );
31 $provider->setConfig( MediaWikiServices::getInstance()->getMainConfig() );
32 $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
33
34 $obj = $providerPriv->getPasswordFactory();
35 $this->assertInstanceOf( 'PasswordFactory', $obj );
36 $this->assertSame( $obj, $providerPriv->getPasswordFactory() );
37 }
38
39 public function testGetPassword() {
40 $provider = $this->getMockForAbstractClass(
41 AbstractPasswordPrimaryAuthenticationProvider::class
42 );
43 $provider->setConfig( MediaWikiServices::getInstance()->getMainConfig() );
44 $provider->setLogger( new \Psr\Log\NullLogger() );
45 $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
46
47 $obj = $providerPriv->getPassword( null );
48 $this->assertInstanceOf( 'Password', $obj );
49
50 $obj = $providerPriv->getPassword( 'invalid' );
51 $this->assertInstanceOf( 'Password', $obj );
52 }
53
54 public function testGetNewPasswordExpiry() {
55 $config = new \HashConfig;
56 $provider = $this->getMockForAbstractClass(
57 AbstractPasswordPrimaryAuthenticationProvider::class
58 );
59 $provider->setConfig( new \MultiConfig( [
60 $config,
61 MediaWikiServices::getInstance()->getMainConfig()
62 ] ) );
63 $provider->setLogger( new \Psr\Log\NullLogger() );
64 $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
65
66 $this->mergeMwGlobalArrayValue( 'wgHooks', [ 'ResetPasswordExpiration' => [] ] );
67
68 $config->set( 'PasswordExpirationDays', 0 );
69 $this->assertNull( $providerPriv->getNewPasswordExpiry( 'UTSysop' ) );
70
71 $config->set( 'PasswordExpirationDays', 5 );
72 $this->assertEquals(
73 time() + 5 * 86400,
74 wfTimestamp( TS_UNIX, $providerPriv->getNewPasswordExpiry( 'UTSysop' ) ),
75 '',
76 2 /* Fuzz */
77 );
78
79 $this->mergeMwGlobalArrayValue( 'wgHooks', [
80 'ResetPasswordExpiration' => [ function ( $user, &$expires ) {
81 $this->assertSame( 'UTSysop', $user->getName() );
82 $expires = '30001231235959';
83 } ]
84 ] );
85 $this->assertEquals( '30001231235959', $providerPriv->getNewPasswordExpiry( 'UTSysop' ) );
86 }
87
88 public function testCheckPasswordValidity() {
89 $uppCalled = 0;
90 $uppStatus = \Status::newGood();
91 $this->setMwGlobals( [
92 'wgPasswordPolicy' => [
93 'policies' => [
94 'default' => [
95 'Check' => true,
96 ],
97 ],
98 'checks' => [
99 'Check' => function () use ( &$uppCalled, &$uppStatus ) {
100 $uppCalled++;
101 return $uppStatus;
102 },
103 ],
104 ]
105 ] );
106
107 $provider = $this->getMockForAbstractClass(
108 AbstractPasswordPrimaryAuthenticationProvider::class
109 );
110 $provider->setConfig( MediaWikiServices::getInstance()->getMainConfig() );
111 $provider->setLogger( new \Psr\Log\NullLogger() );
112 $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
113
114 $this->assertEquals( $uppStatus, $providerPriv->checkPasswordValidity( 'foo', 'bar' ) );
115
116 $uppStatus->fatal( 'arbitrary-warning' );
117 $this->assertEquals( $uppStatus, $providerPriv->checkPasswordValidity( 'foo', 'bar' ) );
118 }
119
120 public function testSetPasswordResetFlag() {
121 $config = new \HashConfig( [
122 'InvalidPasswordReset' => true,
123 ] );
124
125 $manager = new AuthManager(
126 new \FauxRequest(),
127 MediaWikiServices::getInstance()->getMainConfig()
128 );
129
130 $provider = $this->getMockForAbstractClass(
131 AbstractPasswordPrimaryAuthenticationProvider::class
132 );
133 $provider->setConfig( $config );
134 $provider->setLogger( new \Psr\Log\NullLogger() );
135 $provider->setManager( $manager );
136 $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
137
138 $manager->removeAuthenticationSessionData( null );
139 $status = \Status::newGood();
140 $providerPriv->setPasswordResetFlag( 'Foo', $status );
141 $this->assertNull( $manager->getAuthenticationSessionData( 'reset-pass' ) );
142
143 $manager->removeAuthenticationSessionData( null );
144 $status = \Status::newGood();
145 $status->error( 'testing' );
146 $providerPriv->setPasswordResetFlag( 'Foo', $status );
147 $ret = $manager->getAuthenticationSessionData( 'reset-pass' );
148 $this->assertNotNull( $ret );
149 $this->assertSame( 'resetpass-validity-soft', $ret->msg->getKey() );
150 $this->assertFalse( $ret->hard );
151
152 $config->set( 'InvalidPasswordReset', false );
153 $manager->removeAuthenticationSessionData( null );
154 $providerPriv->setPasswordResetFlag( 'Foo', $status );
155 $ret = $manager->getAuthenticationSessionData( 'reset-pass' );
156 $this->assertNull( $ret );
157 }
158
159 public function testFailResponse() {
160 $provider = $this->getMockForAbstractClass(
161 AbstractPasswordPrimaryAuthenticationProvider::class,
162 [ [ 'authoritative' => false ] ]
163 );
164 $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
165
166 $req = new PasswordAuthenticationRequest;
167
168 $ret = $providerPriv->failResponse( $req );
169 $this->assertSame( AuthenticationResponse::ABSTAIN, $ret->status );
170
171 $provider = $this->getMockForAbstractClass(
172 AbstractPasswordPrimaryAuthenticationProvider::class,
173 [ [ 'authoritative' => true ] ]
174 );
175 $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
176
177 $req->password = '';
178 $ret = $providerPriv->failResponse( $req );
179 $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
180 $this->assertSame( 'wrongpasswordempty', $ret->message->getKey() );
181
182 $req->password = 'X';
183 $ret = $providerPriv->failResponse( $req );
184 $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
185 $this->assertSame( 'wrongpassword', $ret->message->getKey() );
186 }
187
188 /**
189 * @dataProvider provideGetAuthenticationRequests
190 * @param string $action
191 * @param array $response
192 */
193 public function testGetAuthenticationRequests( $action, $response ) {
194 $provider = $this->getMockForAbstractClass(
195 AbstractPasswordPrimaryAuthenticationProvider::class
196 );
197
198 $this->assertEquals( $response, $provider->getAuthenticationRequests( $action, [] ) );
199 }
200
201 public static function provideGetAuthenticationRequests() {
202 return [
203 [ AuthManager::ACTION_LOGIN, [ new PasswordAuthenticationRequest() ] ],
204 [ AuthManager::ACTION_CREATE, [ new PasswordAuthenticationRequest() ] ],
205 [ AuthManager::ACTION_LINK, [] ],
206 [ AuthManager::ACTION_CHANGE, [ new PasswordAuthenticationRequest() ] ],
207 [ AuthManager::ACTION_REMOVE, [ new PasswordAuthenticationRequest() ] ],
208 ];
209 }
210
211 public function testProviderRevokeAccessForUser() {
212 $req = new PasswordAuthenticationRequest;
213 $req->action = AuthManager::ACTION_REMOVE;
214 $req->username = 'foo';
215 $req->password = null;
216
217 $provider = $this->getMockForAbstractClass(
218 AbstractPasswordPrimaryAuthenticationProvider::class
219 );
220 $provider->expects( $this->once() )
221 ->method( 'providerChangeAuthenticationData' )
222 ->with( $this->equalTo( $req ) );
223
224 $provider->providerRevokeAccessForUser( 'foo' );
225 }
226
227 }