Services: Convert BlobStoreFactory's static to a const now HHVM is gone
[lhc/web/wiklou.git] / tests / phpunit / includes / user / PasswordResetTest.php
1 <?php
2
3 use MediaWiki\Auth\AuthManager;
4 use MediaWiki\Block\DatabaseBlock;
5 use MediaWiki\Block\CompositeBlock;
6 use MediaWiki\Block\SystemBlock;
7 use MediaWiki\Config\ServiceOptions;
8 use MediaWiki\Permissions\PermissionManager;
9 use Psr\Log\NullLogger;
10 use Wikimedia\Rdbms\ILoadBalancer;
11
12 /**
13 * @covers PasswordReset
14 * @group Database
15 */
16 class PasswordResetTest extends MediaWikiTestCase {
17 private function makeConfig( $enableEmail, array $passwordResetRoutes = [] ) {
18 $hash = new HashConfig( [
19 'EnableEmail' => $enableEmail,
20 'PasswordResetRoutes' => $passwordResetRoutes,
21 ] );
22
23 return new ServiceOptions( PasswordReset::$constructorOptions, $hash );
24 }
25
26 /**
27 * @dataProvider provideIsAllowed
28 */
29 public function testIsAllowed( $passwordResetRoutes, $enableEmail,
30 $allowsAuthenticationDataChange, $canEditPrivate, $block, $globalBlock, $isAllowed
31 ) {
32 $config = $this->makeConfig( $enableEmail, $passwordResetRoutes );
33
34 $authManager = $this->getMockBuilder( AuthManager::class )->disableOriginalConstructor()
35 ->getMock();
36 $authManager->expects( $this->any() )->method( 'allowsAuthenticationDataChange' )
37 ->willReturn( $allowsAuthenticationDataChange ? Status::newGood() : Status::newFatal( 'foo' ) );
38
39 $user = $this->getMockBuilder( User::class )->getMock();
40 $user->expects( $this->any() )->method( 'getName' )->willReturn( 'Foo' );
41 $user->expects( $this->any() )->method( 'getBlock' )->willReturn( $block );
42 $user->expects( $this->any() )->method( 'getGlobalBlock' )->willReturn( $globalBlock );
43
44 $permissionManager = $this->getMockBuilder( PermissionManager::class )
45 ->disableOriginalConstructor()
46 ->getMock();
47 $permissionManager->method( 'userHasRight' )
48 ->with( $user, 'editmyprivateinfo' )
49 ->willReturn( $canEditPrivate );
50
51 $loadBalancer = $this->getMockBuilder( ILoadBalancer::class )->getMock();
52
53 $passwordReset = new PasswordReset(
54 $config,
55 $authManager,
56 $permissionManager,
57 $loadBalancer,
58 new NullLogger()
59 );
60
61 $this->assertSame( $isAllowed, $passwordReset->isAllowed( $user )->isGood() );
62 }
63
64 public function provideIsAllowed() {
65 return [
66 'no routes' => [
67 'passwordResetRoutes' => [],
68 'enableEmail' => true,
69 'allowsAuthenticationDataChange' => true,
70 'canEditPrivate' => true,
71 'block' => null,
72 'globalBlock' => null,
73 'isAllowed' => false,
74 ],
75 'email disabled' => [
76 'passwordResetRoutes' => [ 'username' => true ],
77 'enableEmail' => false,
78 'allowsAuthenticationDataChange' => true,
79 'canEditPrivate' => true,
80 'block' => null,
81 'globalBlock' => null,
82 'isAllowed' => false,
83 ],
84 'auth data change disabled' => [
85 'passwordResetRoutes' => [ 'username' => true ],
86 'enableEmail' => true,
87 'allowsAuthenticationDataChange' => false,
88 'canEditPrivate' => true,
89 'block' => null,
90 'globalBlock' => null,
91 'isAllowed' => false,
92 ],
93 'cannot edit private data' => [
94 'passwordResetRoutes' => [ 'username' => true ],
95 'enableEmail' => true,
96 'allowsAuthenticationDataChange' => true,
97 'canEditPrivate' => false,
98 'block' => null,
99 'globalBlock' => null,
100 'isAllowed' => false,
101 ],
102 'blocked with account creation disabled' => [
103 'passwordResetRoutes' => [ 'username' => true ],
104 'enableEmail' => true,
105 'allowsAuthenticationDataChange' => true,
106 'canEditPrivate' => true,
107 'block' => new DatabaseBlock( [ 'createAccount' => true ] ),
108 'globalBlock' => null,
109 'isAllowed' => false,
110 ],
111 'blocked w/o account creation disabled' => [
112 'passwordResetRoutes' => [ 'username' => true ],
113 'enableEmail' => true,
114 'allowsAuthenticationDataChange' => true,
115 'canEditPrivate' => true,
116 'block' => new DatabaseBlock( [] ),
117 'globalBlock' => null,
118 'isAllowed' => true,
119 ],
120 'using blocked proxy' => [
121 'passwordResetRoutes' => [ 'username' => true ],
122 'enableEmail' => true,
123 'allowsAuthenticationDataChange' => true,
124 'canEditPrivate' => true,
125 'block' => new SystemBlock(
126 [ 'systemBlock' => 'proxy' ]
127 ),
128 'globalBlock' => null,
129 'isAllowed' => false,
130 ],
131 'globally blocked with account creation not disabled' => [
132 'passwordResetRoutes' => [ 'username' => true ],
133 'enableEmail' => true,
134 'allowsAuthenticationDataChange' => true,
135 'canEditPrivate' => true,
136 'block' => null,
137 'globalBlock' => new SystemBlock(
138 [ 'systemBlock' => 'global-block' ]
139 ),
140 'isAllowed' => true,
141 ],
142 'blocked via wgSoftBlockRanges' => [
143 'passwordResetRoutes' => [ 'username' => true ],
144 'enableEmail' => true,
145 'allowsAuthenticationDataChange' => true,
146 'canEditPrivate' => true,
147 'block' => new SystemBlock(
148 [ 'systemBlock' => 'wgSoftBlockRanges', 'anonOnly' => true ]
149 ),
150 'globalBlock' => null,
151 'isAllowed' => true,
152 ],
153 'blocked with an unknown system block type' => [
154 'passwordResetRoutes' => [ 'username' => true ],
155 'enableEmail' => true,
156 'allowsAuthenticationDataChange' => true,
157 'canEditPrivate' => true,
158 'block' => new SystemBlock( [ 'systemBlock' => 'unknown' ] ),
159 'globalBlock' => null,
160 'isAllowed' => false,
161 ],
162 'blocked with multiple blocks, all allowing password reset' => [
163 'passwordResetRoutes' => [ 'username' => true ],
164 'enableEmail' => true,
165 'allowsAuthenticationDataChange' => true,
166 'canEditPrivate' => true,
167 'block' => new CompositeBlock( [
168 'originalBlocks' => [
169 new SystemBlock( [ 'systemBlock' => 'wgSoftBlockRanges', 'anonOnly' => true ] ),
170 new Block( [] ),
171 ]
172 ] ),
173 'globalBlock' => null,
174 'isAllowed' => true,
175 ],
176 'blocked with multiple blocks, not all allowing password reset' => [
177 'passwordResetRoutes' => [ 'username' => true ],
178 'enableEmail' => true,
179 'allowsAuthenticationDataChange' => true,
180 'canEditPrivate' => true,
181 'block' => new CompositeBlock( [
182 'originalBlocks' => [
183 new SystemBlock( [ 'systemBlock' => 'wgSoftBlockRanges', 'anonOnly' => true ] ),
184 new SystemBlock( [ 'systemBlock' => 'proxy' ] ),
185 ]
186 ] ),
187 'globalBlock' => null,
188 'isAllowed' => false,
189 ],
190 'all OK' => [
191 'passwordResetRoutes' => [ 'username' => true ],
192 'enableEmail' => true,
193 'allowsAuthenticationDataChange' => true,
194 'canEditPrivate' => true,
195 'block' => null,
196 'globalBlock' => null,
197 'isAllowed' => true,
198 ],
199 ];
200 }
201
202 public function testExecute_email() {
203 $config = $this->makeConfig( true, [ 'username' => true, 'email' => true ] );
204
205 // Unregister the hooks for proper unit testing
206 $this->mergeMwGlobalArrayValue( 'wgHooks', [
207 'User::mailPasswordInternal' => [],
208 'SpecialPasswordResetOnSubmit' => [],
209 ] );
210
211 $authManager = $this->getMockBuilder( AuthManager::class )->disableOriginalConstructor()
212 ->getMock();
213 $authManager->expects( $this->any() )->method( 'allowsAuthenticationDataChange' )
214 ->willReturn( Status::newGood() );
215 $authManager->expects( $this->exactly( 2 ) )->method( 'changeAuthenticationData' );
216
217 $permissionManager = $this->getMockBuilder( PermissionManager::class )
218 ->disableOriginalConstructor()
219 ->getMock();
220 $permissionManager->method( 'userHasRight' )->willReturn( true );
221
222 $loadBalancer = $this->getMockBuilder( ILoadBalancer::class )
223 ->getMock();
224
225 $request = new FauxRequest();
226 $request->setIP( '1.2.3.4' );
227 $performingUser = $this->getMockBuilder( User::class )->getMock();
228 $performingUser->expects( $this->any() )->method( 'getRequest' )->willReturn( $request );
229 $performingUser->expects( $this->any() )->method( 'getName' )->willReturn( 'Performer' );
230
231 $permissionManager = $this->getMockBuilder( PermissionManager::class )
232 ->disableOriginalConstructor()
233 ->getMock();
234 $permissionManager->expects( $this->once() )
235 ->method( 'userHasRight' )
236 ->with( $performingUser, 'editmyprivateinfo' )
237 ->willReturn( true );
238
239 $targetUser1 = $this->getMockBuilder( User::class )->getMock();
240 $targetUser2 = $this->getMockBuilder( User::class )->getMock();
241 $targetUser1->expects( $this->any() )->method( 'getName' )->willReturn( 'User1' );
242 $targetUser2->expects( $this->any() )->method( 'getName' )->willReturn( 'User2' );
243 $targetUser1->expects( $this->any() )->method( 'getId' )->willReturn( 1 );
244 $targetUser2->expects( $this->any() )->method( 'getId' )->willReturn( 2 );
245 $targetUser1->expects( $this->any() )->method( 'getEmail' )->willReturn( 'foo@bar.baz' );
246 $targetUser2->expects( $this->any() )->method( 'getEmail' )->willReturn( 'foo@bar.baz' );
247
248 $passwordReset = $this->getMockBuilder( PasswordReset::class )
249 ->setMethods( [ 'getUsersByEmail' ] )
250 ->setConstructorArgs( [
251 $config,
252 $authManager,
253 $permissionManager,
254 $loadBalancer,
255 new NullLogger()
256 ] )
257 ->getMock();
258 $passwordReset->expects( $this->any() )->method( 'getUsersByEmail' )->with( 'foo@bar.baz' )
259 ->willReturn( [ $targetUser1, $targetUser2 ] );
260
261 $status = $passwordReset->isAllowed( $performingUser );
262 $this->assertTrue( $status->isGood() );
263
264 $status = $passwordReset->execute( $performingUser, null, 'foo@bar.baz' );
265 $this->assertTrue( $status->isGood() );
266 }
267 }