Localisation updates from https://translatewiki.net.
[mediawiki.git] / tests / phpunit / includes / password / UserPasswordPolicyTest.php
blobdf82e49652e899fc1b3e8b1ed1c42500b17e5da0
1 <?php
2 /**
3 * Testing for password-policy enforcement, based on a user's groups.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * http://www.gnu.org/copyleft/gpl.html
20 * @file
23 use MediaWiki\Password\UserPasswordPolicy;
24 use MediaWiki\Status\Status;
25 use MediaWiki\User\User;
27 /**
28 * @group Database
29 * @covers \MediaWiki\Password\UserPasswordPolicy
31 class UserPasswordPolicyTest extends MediaWikiIntegrationTestCase {
33 private const POLICIES = [
34 'checkuser' => [
35 'MinimalPasswordLength' => [ 'value' => 10, 'forceChange' => true ],
36 'MinimumPasswordLengthToLogin' => 6,
38 'sysop' => [
39 'MinimalPasswordLength' => [ 'value' => 8, 'suggestChangeOnLogin' => true ],
40 'MinimumPasswordLengthToLogin' => 1,
42 'bureaucrat' => [
43 'MinimalPasswordLength' => [
44 'value' => 6,
45 'suggestChangeOnLogin' => false,
46 'forceChange' => true,
49 'default' => [
50 'MinimalPasswordLength' => 4,
51 'MinimumPasswordLengthToLogin' => 1,
52 'PasswordCannotMatchDefaults' => true,
53 'MaximalPasswordLength' => 4096,
54 'PasswordCannotBeSubstringInUsername' => true,
58 private const CHECKS = [
59 'MinimalPasswordLength' => 'MediaWiki\Password\PasswordPolicyChecks::checkMinimalPasswordLength',
60 'MinimumPasswordLengthToLogin' => 'MediaWiki\Password\PasswordPolicyChecks::checkMinimumPasswordLengthToLogin',
61 'PasswordCannotBeSubstringInUsername' =>
62 'MediaWiki\Password\PasswordPolicyChecks::checkPasswordCannotBeSubstringInUsername',
63 'PasswordCannotMatchDefaults' => 'MediaWiki\Password\PasswordPolicyChecks::checkPasswordCannotMatchDefaults',
64 'MaximalPasswordLength' => 'MediaWiki\Password\PasswordPolicyChecks::checkMaximalPasswordLength',
67 private function getUserPasswordPolicy() {
68 return new UserPasswordPolicy( self::POLICIES, self::CHECKS );
71 public function testGetPoliciesForUser() {
72 $upp = $this->getUserPasswordPolicy();
74 $user = $this->getTestUser( [ 'sysop' ] )->getUser();
75 $this->assertArrayEquals(
77 'MinimalPasswordLength' => [ 'value' => 8, 'suggestChangeOnLogin' => true ],
78 'MinimumPasswordLengthToLogin' => 1,
79 'PasswordCannotBeSubstringInUsername' => true,
80 'PasswordCannotMatchDefaults' => true,
81 'MaximalPasswordLength' => 4096,
83 $upp->getPoliciesForUser( $user )
86 $user = $this->getTestUser( [ 'sysop', 'checkuser' ] )->getUser();
87 $this->assertArrayEquals(
89 'MinimalPasswordLength' => [
90 'value' => 10,
91 'forceChange' => true,
92 'suggestChangeOnLogin' => true
94 'MinimumPasswordLengthToLogin' => 6,
95 'PasswordCannotBeSubstringInUsername' => true,
96 'PasswordCannotMatchDefaults' => true,
97 'MaximalPasswordLength' => 4096,
99 $upp->getPoliciesForUser( $user )
103 public function testGetPoliciesForGroups() {
104 $effective = UserPasswordPolicy::getPoliciesForGroups(
105 self::POLICIES,
106 [ 'user', 'checkuser', 'sysop' ],
107 self::POLICIES['default']
110 $this->assertArrayEquals(
112 'MinimalPasswordLength' => [
113 'value' => 10,
114 'forceChange' => true,
115 'suggestChangeOnLogin' => true
117 'MinimumPasswordLengthToLogin' => 6,
118 'PasswordCannotBeSubstringInUsername' => true,
119 'PasswordCannotMatchDefaults' => true,
120 'MaximalPasswordLength' => 4096,
122 $effective
127 * @dataProvider provideCheckUserPassword
129 public function testCheckUserPassword( $groups, $password, StatusValue $expectedStatus ) {
130 $upp = $this->getUserPasswordPolicy();
131 $user = $this->getTestUser( $groups )->getUser();
133 $status = $upp->checkUserPassword( $user, $password );
134 $this->assertSame( $expectedStatus->isGood(), $status->isGood(), 'password valid' );
135 $this->assertSame( $expectedStatus->isOK(), $status->isOK(), 'can login' );
136 $this->assertSame( $expectedStatus->getValue(), $status->getValue(), 'flags' );
139 public static function provideCheckUserPassword() {
140 $success = Status::newGood( [] );
141 $warning = Status::newGood( [] );
142 $forceChange = Status::newGood( [ 'forceChange' => true ] );
143 $suggestChangeOnLogin = Status::newGood( [ 'suggestChangeOnLogin' => true ] );
144 $fatal = Status::newGood( [] );
146 // the message does not matter, we only test for state and value
147 $warning->warning( 'invalid-password' );
148 $forceChange->warning( 'invalid-password' );
149 $suggestChangeOnLogin->warning( 'invalid-password' );
150 $warning->warning( 'invalid-password' );
151 $fatal->fatal( 'invalid-password' );
153 return [
154 'No groups, default policy, password too short to login' => [
157 $fatal,
159 'Default policy, short password' => [
160 [ 'user' ],
161 'aaa',
162 $warning,
164 'Sysop with good password' => [
165 [ 'sysop' ],
166 'abcdabcdabcd',
167 $success,
169 'Sysop with short password and suggestChangeOnLogin set to true' => [
170 [ 'sysop' ],
171 'abcd',
172 $suggestChangeOnLogin,
174 'Checkuser with short password' => [
175 [ 'checkuser' ],
176 'abcdabcd',
177 $forceChange,
179 'Bureaucrat bad password with forceChange true, suggestChangeOnLogin false' => [
180 [ 'bureaucrat' ],
181 'short',
182 $forceChange,
184 'Checkuser with too short password to login' => [
185 [ 'sysop', 'checkuser' ],
186 'abcd',
187 $fatal,
192 public function testCheckUserPassword_disallowed() {
193 $upp = $this->getUserPasswordPolicy();
194 $user = User::newFromName( 'Useruser' );
195 $user->addToDatabase();
197 $status = $upp->checkUserPassword( $user, 'Passpass' );
198 $this->assertStatusWarning( 'password-login-forbidden', $status );
202 * @dataProvider provideMaxOfPolicies
204 public function testMaxOfPolicies( $p1, $p2, $max ) {
205 $this->assertArrayEquals(
206 $max,
207 UserPasswordPolicy::maxOfPolicies( $p1, $p2 )
211 public static function provideMaxOfPolicies() {
212 return [
213 'Basic max in p1' => [
214 [ 'MinimalPasswordLength' => 8 ], // p1
215 [ 'MinimalPasswordLength' => 2 ], // p2
216 [ 'MinimalPasswordLength' => 8 ], // max
218 'Basic max in p2' => [
219 [ 'MinimalPasswordLength' => 2 ], // p1
220 [ 'MinimalPasswordLength' => 8 ], // p2
221 [ 'MinimalPasswordLength' => 8 ], // max
223 'Missing items in p1' => [
225 'MinimalPasswordLength' => 8,
226 ], // p1
228 'MinimalPasswordLength' => 2,
229 'PasswordCannotBeSubstringInUsername' => 1,
230 ], // p2
232 'MinimalPasswordLength' => 8,
233 'PasswordCannotBeSubstringInUsername' => 1,
234 ], // max
236 'Missing items in p2' => [
238 'MinimalPasswordLength' => 8,
239 'PasswordCannotBeSubstringInUsername' => 1,
240 ], // p1
242 'MinimalPasswordLength' => 2,
243 ], // p2
245 'MinimalPasswordLength' => 8,
246 'PasswordCannotBeSubstringInUsername' => 1,
247 ], // max
249 'complex value in p1' => [
251 'MinimalPasswordLength' => [
252 'value' => 8,
253 'foo' => 1,
255 ], // p1
257 'MinimalPasswordLength' => 2,
258 ], // p2
260 'MinimalPasswordLength' => [
261 'value' => 8,
262 'foo' => 1,
264 ], // max
266 'complex value in p2' => [
268 'MinimalPasswordLength' => 8,
269 ], // p1
271 'MinimalPasswordLength' => [
272 'value' => 2,
273 'foo' => 1,
275 ], // p2
277 'MinimalPasswordLength' => [
278 'value' => 8,
279 'foo' => 1,
281 ], // max
283 'complex value in both p1 and p2' => [
285 'MinimalPasswordLength' => [
286 'value' => 8,
287 'foo' => 1,
288 'baz' => false,
290 ], // p1
292 'MinimalPasswordLength' => [
293 'value' => 2,
294 'bar' => 2,
295 'baz' => true,
297 ], // p2
299 'MinimalPasswordLength' => [
300 'value' => 8,
301 'foo' => 1,
302 'bar' => 2,
303 'baz' => true,
305 ], // max
307 'complex value in both p1 and p2 #2' => [
309 'MinimalPasswordLength' => [
310 'value' => 8,
311 'foo' => 1,
312 'baz' => false,
314 ], // p1
316 'MinimalPasswordLength' => [
317 'value' => 2,
318 'bar' => true
320 ], // p2
322 'MinimalPasswordLength' => [
323 'value' => 8,
324 'foo' => 1,
325 'bar' => true,
326 'baz' => false,
328 ], // max