public function isEnabled()
 {
     // There's no sense in showing a change password panel if this install
     // doesn't support password authentication.
     if (!PhabricatorPasswordAuthProvider::getPasswordProvider()) {
         return false;
     }
     return true;
 }
 private function loadSetupAccount()
 {
     $provider = new PhabricatorPasswordAuthProvider();
     $provider->attachProviderConfig(id(new PhabricatorAuthProviderConfig())->setShouldAllowRegistration(1)->setShouldAllowLogin(1)->setIsEnabled(true));
     $account = $provider->getDefaultExternalAccount();
     $response = null;
     return array($account, $provider, $response);
 }
 public function handleRequest(AphrontRequest $request)
 {
     if (!PhabricatorPasswordAuthProvider::getPasswordProvider()) {
         return new Aphront400Response();
     }
     $e_email = true;
     $e_captcha = true;
     $errors = array();
     $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
     if ($request->isFormPost()) {
         $e_email = null;
         $e_captcha = pht('Again');
         $captcha_ok = AphrontFormRecaptchaControl::processCaptcha($request);
         if (!$captcha_ok) {
             $errors[] = pht('Captcha response is incorrect, try again.');
             $e_captcha = pht('Invalid');
         }
         $email = $request->getStr('email');
         if (!strlen($email)) {
             $errors[] = pht('You must provide an email address.');
             $e_email = pht('Required');
         }
         if (!$errors) {
             // NOTE: Don't validate the email unless the captcha is good; this makes
             // it expensive to fish for valid email addresses while giving the user
             // a better error if they goof their email.
             $target_email = id(new PhabricatorUserEmail())->loadOneWhere('address = %s', $email);
             $target_user = null;
             if ($target_email) {
                 $target_user = id(new PhabricatorUser())->loadOneWhere('phid = %s', $target_email->getUserPHID());
             }
             if (!$target_user) {
                 $errors[] = pht('There is no account associated with that email address.');
                 $e_email = pht('Invalid');
             }
             // If this address is unverified, only send a reset link to it if
             // the account has no verified addresses. This prevents an opportunistic
             // attacker from compromising an account if a user adds an email
             // address but mistypes it and doesn't notice.
             // (For a newly created account, all the addresses may be unverified,
             // which is why we'll send to an unverified address in that case.)
             if ($target_email && !$target_email->getIsVerified()) {
                 $verified_addresses = id(new PhabricatorUserEmail())->loadAllWhere('userPHID = %s AND isVerified = 1', $target_email->getUserPHID());
                 if ($verified_addresses) {
                     $errors[] = pht('That email address is not verified. You can only send ' . 'password reset links to a verified address.');
                     $e_email = pht('Unverified');
                 }
             }
             if (!$errors) {
                 $engine = new PhabricatorAuthSessionEngine();
                 $uri = $engine->getOneTimeLoginURI($target_user, null, PhabricatorAuthSessionEngine::ONETIME_RESET);
                 if ($is_serious) {
                     $body = pht("You can use this link to reset your Phabricator password:"******"\n\n  %s\n", $uri);
                 } else {
                     $body = pht("Condolences on forgetting your password. You can use this " . "link to reset it:\n\n" . "  %s\n\n" . "After you set a new password, consider writing it down on a " . "sticky note and attaching it to your monitor so you don't " . "forget again! Choosing a very short, easy-to-remember password " . "like \"cat\" or \"1234\" might also help.\n\n" . "Best Wishes,\nPhabricator\n", $uri);
                 }
                 $mail = id(new PhabricatorMetaMTAMail())->setSubject(pht('[Phabricator] Password Reset'))->setForceDelivery(true)->addRawTos(array($target_email->getAddress()))->setBody($body)->saveAndSend();
                 return $this->newDialog()->setTitle(pht('Check Your Email'))->setShortTitle(pht('Email Sent'))->appendParagraph(pht('An email has been sent with a link you can use to login.'))->addCancelButton('/', pht('Done'));
             }
         }
     }
     $error_view = null;
     if ($errors) {
         $error_view = new PHUIInfoView();
         $error_view->setErrors($errors);
     }
     $email_auth = new PHUIFormLayoutView();
     $email_auth->appendChild($error_view);
     $email_auth->setUser($request->getUser())->setFullWidth(true)->appendChild(id(new AphrontFormTextControl())->setLabel(pht('Email'))->setName('email')->setValue($request->getStr('email'))->setError($e_email))->appendChild(id(new AphrontFormRecaptchaControl())->setLabel(pht('Captcha'))->setError($e_captcha));
     $crumbs = $this->buildApplicationCrumbs();
     $crumbs->addTextCrumb(pht('Reset Password'));
     $dialog = new AphrontDialogView();
     $dialog->setUser($request->getUser());
     $dialog->setTitle(pht('Forgot Password / Email Login'));
     $dialog->appendChild($email_auth);
     $dialog->addSubmitButton(pht('Send Email'));
     $dialog->setSubmitURI('/login/email/');
     return $this->buildApplicationPage(array($crumbs, $dialog), array('title' => pht('Forgot Password')));
 }
Пример #4
0
    public function sendUsernameChangeEmail(PhabricatorUser $admin, $old_username)
    {
        $admin_username = $admin->getUserName();
        $admin_realname = $admin->getRealName();
        $new_username = $this->getUserName();
        $password_instructions = null;
        if (PhabricatorPasswordAuthProvider::getPasswordProvider()) {
            $engine = new PhabricatorAuthSessionEngine();
            $uri = $engine->getOneTimeLoginURI($this, null, PhabricatorAuthSessionEngine::ONETIME_USERNAME);
            $password_instructions = <<<EOTXT
If you use a password to login, you'll need to reset it before you can login
again. You can reset your password by following this link:

  {$uri}

And, of course, you'll need to use your new username to login from now on. If
you use OAuth to login, nothing should change.

EOTXT;
        }
        $body = <<<EOBODY
{$admin_username} ({$admin_realname}) has changed your Phabricator username.

  Old Username: {$old_username}
  New Username: {$new_username}

{$password_instructions}
EOBODY;
        $mail = id(new PhabricatorMetaMTAMail())->addTos(array($this->getPHID()))->setForceDelivery(true)->setSubject('[Phabricator] Username Changed')->setBody($body)->saveAndSend();
    }
Пример #5
0
 public function sendUsernameChangeEmail(PhabricatorUser $admin, $old_username)
 {
     $admin_username = $admin->getUserName();
     $admin_realname = $admin->getRealName();
     $new_username = $this->getUserName();
     $password_instructions = null;
     if (PhabricatorPasswordAuthProvider::getPasswordProvider()) {
         $engine = new PhabricatorAuthSessionEngine();
         $uri = $engine->getOneTimeLoginURI($this, null, PhabricatorAuthSessionEngine::ONETIME_USERNAME);
         $password_instructions = sprintf("%s\n\n  %s\n\n%s\n", pht("If you use a password to login, you'll need to reset it " . "before you can login again. You can reset your password by " . "following this link:"), $uri, pht("And, of course, you'll need to use your new username to login " . "from now on. If you use OAuth to login, nothing should change."));
     }
     $body = sprintf("%s\n\n  %s\n  %s\n\n%s", pht('%s (%s) has changed your Phabricator username.', $admin_username, $admin_realname), pht('Old Username: %s', $old_username), pht('New Username: %s', $new_username), $password_instructions);
     $mail = id(new PhabricatorMetaMTAMail())->addTos(array($this->getPHID()))->setForceDelivery(true)->setSubject(pht('[Phabricator] Username Changed'))->setBody($body)->saveAndSend();
 }
 public function handleRequest(AphrontRequest $request)
 {
     $viewer = $this->getViewer();
     $id = $request->getURIData('id');
     $link_type = $request->getURIData('type');
     $key = $request->getURIData('key');
     $email_id = $request->getURIData('emailID');
     if ($request->getUser()->isLoggedIn()) {
         return $this->renderError(pht('You are already logged in.'));
     }
     $target_user = id(new PhabricatorPeopleQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withIDs(array($id))->executeOne();
     if (!$target_user) {
         return new Aphront404Response();
     }
     // NOTE: As a convenience to users, these one-time login URIs may also
     // be associated with an email address which will be verified when the
     // URI is used.
     // This improves the new user experience for users receiving "Welcome"
     // emails on installs that require verification: if we did not verify the
     // email, they'd immediately get roadblocked with a "Verify Your Email"
     // error and have to go back to their email account, wait for a
     // "Verification" email, and then click that link to actually get access to
     // their account. This is hugely unwieldy, and if the link was only sent
     // to the user's email in the first place we can safely verify it as a
     // side effect of login.
     // The email hashed into the URI so users can't verify some email they
     // do not own by doing this:
     //
     //  - Add some address you do not own;
     //  - request a password reset;
     //  - change the URI in the email to the address you don't own;
     //  - login via the email link; and
     //  - get a "verified" address you don't control.
     $target_email = null;
     if ($email_id) {
         $target_email = id(new PhabricatorUserEmail())->loadOneWhere('userPHID = %s AND id = %d', $target_user->getPHID(), $email_id);
         if (!$target_email) {
             return new Aphront404Response();
         }
     }
     $engine = new PhabricatorAuthSessionEngine();
     $token = $engine->loadOneTimeLoginKey($target_user, $target_email, $key);
     if (!$token) {
         return $this->newDialog()->setTitle(pht('Unable to Login'))->setShortTitle(pht('Login Failure'))->appendParagraph(pht('The login link you clicked is invalid, out of date, or has ' . 'already been used.'))->appendParagraph(pht('Make sure you are copy-and-pasting the entire link into ' . 'your browser. Login links are only valid for 24 hours, and ' . 'can only be used once.'))->appendParagraph(pht('You can try again, or request a new link via email.'))->addCancelButton('/login/email/', pht('Send Another Email'));
     }
     if ($request->isFormPost()) {
         // If we have an email bound into this URI, verify email so that clicking
         // the link in the "Welcome" email is good enough, without requiring users
         // to go through a second round of email verification.
         $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
         // Nuke the token and all other outstanding password reset tokens.
         // There is no particular security benefit to destroying them all, but
         // it should reduce HackerOne reports of nebulous harm.
         PhabricatorAuthTemporaryToken::revokeTokens($target_user, array($target_user->getPHID()), array(PhabricatorAuthSessionEngine::ONETIME_TEMPORARY_TOKEN_TYPE, PhabricatorAuthSessionEngine::PASSWORD_TEMPORARY_TOKEN_TYPE));
         if ($target_email) {
             id(new PhabricatorUserEditor())->setActor($target_user)->verifyEmail($target_user, $target_email);
         }
         unset($unguarded);
         $next = '/';
         if (!PhabricatorPasswordAuthProvider::getPasswordProvider()) {
             $next = '/settings/panel/external/';
         } else {
             // We're going to let the user reset their password without knowing
             // the old one. Generate a one-time token for that.
             $key = Filesystem::readRandomCharacters(16);
             $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
             id(new PhabricatorAuthTemporaryToken())->setObjectPHID($target_user->getPHID())->setTokenType(PhabricatorAuthSessionEngine::PASSWORD_TEMPORARY_TOKEN_TYPE)->setTokenExpires(time() + phutil_units('1 hour in seconds'))->setTokenCode(PhabricatorHash::digest($key))->save();
             unset($unguarded);
             $next = (string) id(new PhutilURI('/settings/panel/password/'))->setQueryParams(array('key' => $key));
             $request->setTemporaryCookie(PhabricatorCookies::COOKIE_HISEC, 'yes');
         }
         PhabricatorCookies::setNextURICookie($request, $next, $force = true);
         return $this->loginUser($target_user);
     }
     // NOTE: We need to CSRF here so attackers can't generate an email link,
     // then log a user in to an account they control via sneaky invisible
     // form submissions.
     switch ($link_type) {
         case PhabricatorAuthSessionEngine::ONETIME_WELCOME:
             $title = pht('Welcome to Phabricator');
             break;
         case PhabricatorAuthSessionEngine::ONETIME_RECOVER:
             $title = pht('Account Recovery');
             break;
         case PhabricatorAuthSessionEngine::ONETIME_USERNAME:
         case PhabricatorAuthSessionEngine::ONETIME_RESET:
         default:
             $title = pht('Login to Phabricator');
             break;
     }
     $body = array();
     $body[] = pht('Use the button below to log in as: %s', phutil_tag('strong', array(), $target_user->getUsername()));
     if ($target_email && !$target_email->getIsVerified()) {
         $body[] = pht('Logging in will verify %s as an email address you own.', phutil_tag('strong', array(), $target_email->getAddress()));
     }
     $body[] = pht('After logging in you should set a password for your account, or ' . 'link your account to an external account that you can use to ' . 'authenticate in the future.');
     $dialog = $this->newDialog()->setTitle($title)->addSubmitButton(pht('Login (%s)', $target_user->getUsername()))->addCancelButton('/');
     foreach ($body as $paragraph) {
         $dialog->appendParagraph($paragraph);
     }
     return id(new AphrontDialogResponse())->setDialog($dialog);
 }