Go to the documentation of this file.
32 use Psr\Log\LoggerAwareInterface;
33 use Psr\Log\LoggerAwareTrait;
34 use Psr\Log\LoggerInterface;
82 'AllowRequiringEmailForResets',
84 'PasswordResetRoutes',
102 LoggerInterface $logger,
114 $this->logger = $logger;
117 $this->hookRunner =
new HookRunner( $hookContainer );
134 $status = $this->permissionCache->get( $user->
getName() );
136 $resetRoutes = $this->config->get(
'PasswordResetRoutes' );
139 if ( !is_array( $resetRoutes ) || !in_array(
true, $resetRoutes,
true ) ) {
143 ( $providerStatus = $this->authManager->allowsAuthenticationDataChange(
145 && !$providerStatus->isGood()
149 $providerStatus->getMessage() );
150 } elseif ( !$this->config->get(
'EnableEmail' ) ) {
153 } elseif ( !$this->permissionManager->userHasRight( $user,
'editmyprivateinfo' ) ) {
163 $this->permissionCache->set( $user->
getName(), $status );
185 User $performingUser,
189 if ( !$this->
isAllowed( $performingUser )->isGood() ) {
190 throw new LogicException(
191 'User ' . $performingUser->
getName() .
' is not allowed to reset passwords'
197 if ( $performingUser->
pingLimiter(
'mailpassword' ) ) {
208 $username = $username ??
'';
209 $email = $email ??
'';
211 $resetRoutes = $this->config->get(
'PasswordResetRoutes' )
212 + [
'username' =>
false,
'email' => false ];
213 if ( $resetRoutes[
'username'] && $username ) {
214 $method =
'username';
215 $users = [ $this->userFactory->newFromName( $username ) ];
216 } elseif ( $resetRoutes[
'email'] && $email ) {
226 if ( $this->config->get(
'AllowRequiringEmailForResets' ) ) {
228 foreach ( $users as $index => $user ) {
229 if ( $optionsLookup->getBoolOption( $user,
'requireemail' ) ) {
230 unset( $users[$index] );
240 if ( $username && !$this->userNameUtils->getCanonical( $username ) ) {
247 'Username' => $username,
249 'Email' => $method ===
'email' ? $email :
null,
255 $users = array_values( $users );
257 if ( !$this->hookRunner->onSpecialPasswordResetOnSubmit( $users, $data, $error ) ) {
263 $firstUser = reset( $users );
265 $requireEmail = $this->config->get(
'AllowRequiringEmailForResets' )
266 && $method ===
'username'
268 && $this->userOptionsLookup->getBoolOption( $firstUser,
'requireemail' );
275 if ( $method ===
'email' ) {
287 if ( !$firstUser instanceof
User || !$firstUser->
getId() || !$firstUser->getEmail() ) {
292 if ( $requireEmail && $firstUser->getEmail() !== $email ) {
296 $this->hookRunner->onUser__mailPasswordInternal( $performingUser, $ip, $firstUser );
300 foreach ( $users as $user ) {
301 $req = TemporaryPasswordAuthenticationRequest::newRandom();
302 $req->username = $user->getName();
303 $req->mailpassword =
true;
304 $req->caller = $performingUser->
getName();
306 $status = $this->authManager->allowsAuthenticationDataChange( $req,
true );
310 if ( $status->isGood() && $status->getValue() ===
'throttled-mailpassword' ) {
314 if ( $status->isGood() && $status->getValue() !==
'ignored' ) {
316 } elseif ( $result->isGood() ) {
319 if ( $status->getValue() ===
'ignored' ) {
322 $result->merge( $status );
327 'requestingIp' => $ip,
328 'requestingUser' => $performingUser->
getName(),
329 'targetUsername' => $username,
330 'targetEmail' => $email,
333 if ( !$result->isGood() ) {
335 "{requestingUser} attempted password reset of {actualUser} but failed",
336 $logContext + [
'errors' => $result->getErrors() ]
343 DeferredUpdates::POSTSEND
361 return $block->appliesToPasswordReset();
373 $res = $this->loadBalancer->getConnectionRef(
DB_REPLICA )->select(
374 $userQuery[
'tables'],
375 $userQuery[
'fields'],
376 [
'user_email' => $email ],
384 throw new MWException(
'Unknown database error in ' . __METHOD__ );
388 foreach (
$res as $row ) {
389 $users[] = $this->userFactory->newFromRow( $row );
const CONSTRUCTOR_OPTIONS
UserNameUtils $userNameUtils
static newFromSpecifier( $value)
Transform a MessageSpecifier or a primitive value used interchangeably with specifiers (a message key...
static newFatal( $message,... $parameters)
Factory function for fatal errors.
__construct(ServiceOptions $config, LoggerInterface $logger, AuthManager $authManager, HookContainer $hookContainer, ILoadBalancer $loadBalancer, PermissionManager $permissionManager, UserFactory $userFactory, UserNameUtils $userNameUtils, UserOptionsLookup $userOptionsLookup)
This class is managed by MediaWikiServices, don't instantiate directly.
static addUpdate(DeferrableUpdate $update, $stage=self::POSTSEND)
Add an update to the pending update queue for execution at the appropriate time.
static validateEmail( $addr)
Does a string look like an e-mail address?
pingLimiter( $action='edit', $incrBy=1)
Primitive rate limits: enforce maximum actions per time period to put a brake on flooding.
getRequest()
Get the WebRequest object to use with this object.
MapCacheLRU $permissionCache
In-process cache for isAllowed lookups, by username.
ILoadBalancer $loadBalancer
Sends emails to all accounts associated with that email to reset the password.
Handles a simple LRU key/value map with a maximum number of entries.
getId( $wikiId=self::LOCAL)
Get the user's ID.
getBlock( $fromReplica=true, $disableIpBlockExemptChecking=false)
Get the block affecting the user, or null if the user is not blocked.
isAllowed(User $user)
Check if a given user has permission to use this functionality.
static newGood( $value=null)
Factory function for good results.
getGlobalBlock( $ip='')
Check if user is blocked on all wikis.
static getQueryInfo()
Return the tables, fields, and join conditions to be selected to create a new user object.
UserOptionsLookup $userOptionsLookup
PermissionManager $permissionManager
isBlocked(User $user)
Check whether the user is blocked.
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
execute(User $performingUser, $username=null, $email=null)
Do a password reset.
Helper class for the password reset functionality shared by the web UI and the API.
getName()
Get the user name, or the IP of an anonymous user.