Exemple #1
0
 /**
  * Start an account creation flow
  * @param User $creator User doing the account creation
  * @param AuthenticationRequest[] $reqs
  * @param string $returnToUrl Url that REDIRECT responses should eventually
  *  return to.
  * @return AuthenticationResponse
  */
 public function beginAccountCreation(User $creator, array $reqs, $returnToUrl)
 {
     $session = $this->request->getSession();
     if (!$this->canCreateAccounts()) {
         // Caller should have called canCreateAccounts()
         $session->remove('AuthManager::accountCreationState');
         throw new \LogicException('Account creation is not possible');
     }
     try {
         $username = AuthenticationRequest::getUsernameFromRequests($reqs);
     } catch (\UnexpectedValueException $ex) {
         $username = null;
     }
     if ($username === null) {
         $this->logger->debug(__METHOD__ . ': No username provided');
         return AuthenticationResponse::newFail(wfMessage('noname'));
     }
     // Permissions check
     $status = $this->checkAccountCreatePermissions($creator);
     if (!$status->isGood()) {
         $this->logger->debug(__METHOD__ . ': {creator} cannot create users: {reason}', ['user' => $username, 'creator' => $creator->getName(), 'reason' => $status->getWikiText(null, null, 'en')]);
         return AuthenticationResponse::newFail($status->getMessage());
     }
     $status = $this->canCreateAccount($username, User::READ_LOCKING);
     if (!$status->isGood()) {
         $this->logger->debug(__METHOD__ . ': {user} cannot be created: {reason}', ['user' => $username, 'creator' => $creator->getName(), 'reason' => $status->getWikiText(null, null, 'en')]);
         return AuthenticationResponse::newFail($status->getMessage());
     }
     $user = User::newFromName($username, 'creatable');
     foreach ($reqs as $req) {
         $req->username = $username;
         $req->returnToUrl = $returnToUrl;
         if ($req instanceof UserDataAuthenticationRequest) {
             $status = $req->populateUser($user);
             if (!$status->isGood()) {
                 $status = Status::wrap($status);
                 $session->remove('AuthManager::accountCreationState');
                 $this->logger->debug(__METHOD__ . ': UserData is invalid: {reason}', ['user' => $user->getName(), 'creator' => $creator->getName(), 'reason' => $status->getWikiText(null, null, 'en')]);
                 return AuthenticationResponse::newFail($status->getMessage());
             }
         }
     }
     $this->removeAuthenticationSessionData(null);
     $state = ['username' => $username, 'userid' => 0, 'creatorid' => $creator->getId(), 'creatorname' => $creator->getName(), 'reqs' => $reqs, 'returnToUrl' => $returnToUrl, 'primary' => null, 'primaryResponse' => null, 'secondary' => [], 'continueRequests' => [], 'maybeLink' => [], 'ranPreTests' => false];
     // Special case: converting a login to an account creation
     $req = AuthenticationRequest::getRequestByClass($reqs, CreateFromLoginAuthenticationRequest::class);
     if ($req) {
         $state['maybeLink'] = $req->maybeLink;
         // If we get here, the user didn't submit a form with any of the
         // usual AuthenticationRequests that are needed for an account
         // creation. So we need to determine if there are any and return a
         // UI response if so.
         if ($req->createRequest) {
             // We have a createRequest from a
             // PrimaryAuthenticationProvider, so don't ask.
             $providers = $this->getPreAuthenticationProviders() + $this->getSecondaryAuthenticationProviders();
         } else {
             // We're only preserving maybeLink, so ask for primary fields
             // too.
             $providers = $this->getPreAuthenticationProviders() + $this->getPrimaryAuthenticationProviders() + $this->getSecondaryAuthenticationProviders();
         }
         $reqs = $this->getAuthenticationRequestsInternal(self::ACTION_CREATE, [], $providers);
         // See if we need any requests to begin
         foreach ((array) $reqs as $r) {
             if (!$r instanceof UsernameAuthenticationRequest && !$r instanceof UserDataAuthenticationRequest && !$r instanceof CreationReasonAuthenticationRequest) {
                 // Needs some reqs, so request them
                 $reqs[] = new CreateFromLoginAuthenticationRequest($req->createRequest, []);
                 $state['continueRequests'] = $reqs;
                 $session->setSecret('AuthManager::accountCreationState', $state);
                 $session->persist();
                 return AuthenticationResponse::newUI($reqs, wfMessage('authmanager-create-from-login'));
             }
         }
         // No reqs needed, so we can just continue.
         $req->createRequest->returnToUrl = $returnToUrl;
         $reqs = [$req->createRequest];
     }
     $session->setSecret('AuthManager::accountCreationState', $state);
     $session->persist();
     return $this->continueAccountCreation($reqs);
 }
 public function testForAuthentication(array $reqs)
 {
     if (!$this->passwordAttemptThrottle) {
         return \StatusValue::newGood();
     }
     $ip = $this->manager->getRequest()->getIP();
     try {
         $username = AuthenticationRequest::getUsernameFromRequests($reqs);
     } catch (\UnexpectedValueException $e) {
         $username = '';
     }
     // Get everything this username could normalize to, and throttle each one individually.
     // If nothing uses usernames, just throttle by IP.
     $usernames = $this->manager->normalizeUsername($username);
     $result = false;
     foreach ($usernames as $name) {
         $r = $this->passwordAttemptThrottle->increase($name, $ip, __METHOD__);
         if ($r && (!$result || $result['wait'] < $r['wait'])) {
             $result = $r;
         }
     }
     if ($result) {
         $message = wfMessage('login-throttled')->durationParams($result['wait']);
         return \StatusValue::newFatal($message);
     } else {
         $this->manager->setAuthenticationSessionData('LoginThrottle', ['users' => $usernames, 'ip' => $ip]);
         return \StatusValue::newGood();
     }
 }
Exemple #3
0
 /**
  * Start an account creation flow
  *
  * In addition to the AuthenticationRequests returned by
  * $this->getAuthenticationRequests(), a client might include a
  * CreateFromLoginAuthenticationRequest from a previous login attempt. If
  * <code>
  * $createFromLoginAuthenticationRequest->hasPrimaryStateForAction( AuthManager::ACTION_CREATE )
  * </code>
  * returns true, any AuthenticationRequest::PRIMARY_REQUIRED requests
  * should be omitted. If the CreateFromLoginAuthenticationRequest has a
  * username set, that username must be used for all other requests.
  *
  * @param User $creator User doing the account creation
  * @param AuthenticationRequest[] $reqs
  * @param string $returnToUrl Url that REDIRECT responses should eventually
  *  return to.
  * @return AuthenticationResponse
  */
 public function beginAccountCreation(User $creator, array $reqs, $returnToUrl)
 {
     $session = $this->request->getSession();
     if (!$this->canCreateAccounts()) {
         // Caller should have called canCreateAccounts()
         $session->remove('AuthManager::accountCreationState');
         throw new \LogicException('Account creation is not possible');
     }
     try {
         $username = AuthenticationRequest::getUsernameFromRequests($reqs);
     } catch (\UnexpectedValueException $ex) {
         $username = null;
     }
     if ($username === null) {
         $this->logger->debug(__METHOD__ . ': No username provided');
         return AuthenticationResponse::newFail(wfMessage('noname'));
     }
     // Permissions check
     $status = $this->checkAccountCreatePermissions($creator);
     if (!$status->isGood()) {
         $this->logger->debug(__METHOD__ . ': {creator} cannot create users: {reason}', ['user' => $username, 'creator' => $creator->getName(), 'reason' => $status->getWikiText(null, null, 'en')]);
         return AuthenticationResponse::newFail($status->getMessage());
     }
     $status = $this->canCreateAccount($username, ['flags' => User::READ_LOCKING, 'creating' => true]);
     if (!$status->isGood()) {
         $this->logger->debug(__METHOD__ . ': {user} cannot be created: {reason}', ['user' => $username, 'creator' => $creator->getName(), 'reason' => $status->getWikiText(null, null, 'en')]);
         return AuthenticationResponse::newFail($status->getMessage());
     }
     $user = User::newFromName($username, 'creatable');
     foreach ($reqs as $req) {
         $req->username = $username;
         $req->returnToUrl = $returnToUrl;
         if ($req instanceof UserDataAuthenticationRequest) {
             $status = $req->populateUser($user);
             if (!$status->isGood()) {
                 $status = Status::wrap($status);
                 $session->remove('AuthManager::accountCreationState');
                 $this->logger->debug(__METHOD__ . ': UserData is invalid: {reason}', ['user' => $user->getName(), 'creator' => $creator->getName(), 'reason' => $status->getWikiText(null, null, 'en')]);
                 return AuthenticationResponse::newFail($status->getMessage());
             }
         }
     }
     $this->removeAuthenticationSessionData(null);
     $state = ['username' => $username, 'userid' => 0, 'creatorid' => $creator->getId(), 'creatorname' => $creator->getName(), 'reqs' => $reqs, 'returnToUrl' => $returnToUrl, 'primary' => null, 'primaryResponse' => null, 'secondary' => [], 'continueRequests' => [], 'maybeLink' => [], 'ranPreTests' => false];
     // Special case: converting a login to an account creation
     $req = AuthenticationRequest::getRequestByClass($reqs, CreateFromLoginAuthenticationRequest::class);
     if ($req) {
         $state['maybeLink'] = $req->maybeLink;
         if ($req->createRequest) {
             $reqs[] = $req->createRequest;
             $state['reqs'][] = $req->createRequest;
         }
     }
     $session->setSecret('AuthManager::accountCreationState', $state);
     $session->persist();
     return $this->continueAccountCreation($reqs);
 }