MediaWiki REL1_37
UserPasswordPolicy.php
Go to the documentation of this file.
1<?php
25
32
36 private $policies;
37
45
51 public function __construct( array $policies, array $checks ) {
52 if ( !isset( $policies['default'] ) ) {
53 throw new InvalidArgumentException(
54 'Must include a \'default\' password policy'
55 );
56 }
57 $this->policies = $policies;
58
59 foreach ( $checks as $statement => $check ) {
60 if ( !is_callable( $check ) ) {
61 throw new InvalidArgumentException(
62 "Policy check functions must be callable. '$statement' isn't callable."
63 );
64 }
65 $this->policyCheckFunctions[$statement] = $check;
66 }
67 }
68
79 public function checkUserPassword( UserIdentity $user, $password ) {
80 $effectivePolicy = $this->getPoliciesForUser( $user );
81 return $this->checkPolicies(
82 $user,
83 $password,
84 $effectivePolicy,
85 $this->policyCheckFunctions
86 );
87 }
88
102 public function checkUserPasswordForGroups( UserIdentity $user, $password, array $groups ) {
103 $effectivePolicy = self::getPoliciesForGroups(
104 $this->policies,
105 $groups,
106 $this->policies['default']
107 );
108 return $this->checkPolicies(
109 $user,
110 $password,
111 $effectivePolicy,
112 $this->policyCheckFunctions
113 );
114 }
115
123 private function checkPolicies( UserIdentity $user, $password, $policies, $policyCheckFunctions ) {
124 $status = Status::newGood( [] );
125 $forceChange = false;
126 $suggestChangeOnLogin = false;
127 $legacyUser = MediaWikiServices::getInstance()
128 ->getUserFactory()
129 ->newFromUserIdentity( $user );
130 foreach ( $policies as $policy => $settings ) {
131 if ( !isset( $policyCheckFunctions[$policy] ) ) {
132 throw new DomainException( "Invalid password policy config. No check defined for '$policy'." );
133 }
134 if ( !is_array( $settings ) ) {
135 // legacy format
136 $settings = [ 'value' => $settings ];
137 }
138 if ( !array_key_exists( 'value', $settings ) ) {
139 throw new DomainException( "Invalid password policy config. No value defined for '$policy'." );
140 }
141 $value = $settings['value'];
143 $policyStatus = call_user_func(
144 $policyCheckFunctions[$policy],
145 $value,
146 $legacyUser,
147 $password
148 );
149
150 if ( !$policyStatus->isGood() ) {
151 if ( !empty( $settings['forceChange'] ) ) {
152 $forceChange = true;
153 }
154
155 if ( !empty( $settings['suggestChangeOnLogin'] ) ) {
156 $suggestChangeOnLogin = true;
157 }
158 }
159 $status->merge( $policyStatus );
160 }
161
162 if ( $status->isOK() ) {
163 if ( $forceChange ) {
164 $status->value['forceChange'] = true;
165 } elseif ( $suggestChangeOnLogin ) {
166 $status->value['suggestChangeOnLogin'] = true;
167 }
168 }
169
170 return $status;
171 }
172
179 public function getPoliciesForUser( UserIdentity $user ) {
180 $effectivePolicy = self::getPoliciesForGroups(
181 $this->policies,
182 MediaWikiServices::getInstance()
183 ->getUserGroupManager()
184 ->getUserEffectiveGroups( $user ),
185 $this->policies['default']
186 );
187
188 $legacyUser = MediaWikiServices::getInstance()
189 ->getUserFactory()
190 ->newFromUserIdentity( $user );
191 Hooks::runner()->onPasswordPoliciesForUser( $legacyUser, $effectivePolicy );
192
193 return $effectivePolicy;
194 }
195
204 public static function getPoliciesForGroups( array $policies, array $userGroups,
205 array $defaultPolicy
206 ) {
207 $effectivePolicy = $defaultPolicy;
208 foreach ( $policies as $group => $policy ) {
209 if ( in_array( $group, $userGroups ) ) {
210 $effectivePolicy = self::maxOfPolicies(
211 $effectivePolicy,
212 $policy
213 );
214 }
215 }
216
217 return $effectivePolicy;
218 }
219
228 public static function maxOfPolicies( array $p1, array $p2 ) {
229 $ret = [];
230 $keys = array_merge( array_keys( $p1 ), array_keys( $p2 ) );
231 foreach ( $keys as $key ) {
232 if ( !isset( $p1[$key] ) ) {
233 $ret[$key] = $p2[$key];
234 } elseif ( !isset( $p2[$key] ) ) {
235 $ret[$key] = $p1[$key];
236 } elseif ( !is_array( $p1[$key] ) && !is_array( $p2[$key] ) ) {
237 $ret[$key] = max( $p1[$key], $p2[$key] );
238 } else {
239 if ( !is_array( $p1[$key] ) ) {
240 $p1[$key] = [ 'value' => $p1[$key] ];
241 } elseif ( !is_array( $p2[$key] ) ) {
242 $p2[$key] = [ 'value' => $p2[$key] ];
243 }
244 $ret[$key] = self::maxOfPolicies( $p1[$key], $p2[$key] );
245 }
246 }
247 return $ret;
248 }
249
250}
MediaWikiServices is the service locator for the application scope of MediaWiki.
Check if a user's password complies with any password policies that apply to that user,...
getPoliciesForUser(UserIdentity $user)
Get the policy for a user, based on their group membership.
checkUserPasswordForGroups(UserIdentity $user, $password, array $groups)
Check if a password meets the effective password policy for a User, using a set of groups they may or...
checkUserPassword(UserIdentity $user, $password)
Check if a password meets the effective password policy for a User.
static getPoliciesForGroups(array $policies, array $userGroups, array $defaultPolicy)
Utility function to get the effective policy from a list of policies, based on a list of groups.
__construct(array $policies, array $checks)
checkPolicies(UserIdentity $user, $password, $policies, $policyCheckFunctions)
static maxOfPolicies(array $p1, array $p2)
Utility function to get a policy that is the most restrictive of $p1 and $p2.
array $policyCheckFunctions
Mapping of statements to the function that will test the password for compliance.
Interface for objects representing user identity.