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