Page MenuHomePhabricator

D18840.diff
No OneTemporary

D18840.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -2112,6 +2112,7 @@
'PhabricatorAuthSessionGarbageCollector' => 'applications/auth/garbagecollector/PhabricatorAuthSessionGarbageCollector.php',
'PhabricatorAuthSessionInfo' => 'applications/auth/data/PhabricatorAuthSessionInfo.php',
'PhabricatorAuthSessionQuery' => 'applications/auth/query/PhabricatorAuthSessionQuery.php',
+ 'PhabricatorAuthSetPasswordController' => 'applications/auth/controller/PhabricatorAuthSetPasswordController.php',
'PhabricatorAuthSetupCheck' => 'applications/config/check/PhabricatorAuthSetupCheck.php',
'PhabricatorAuthStartController' => 'applications/auth/controller/PhabricatorAuthStartController.php',
'PhabricatorAuthTOTPKeyTemporaryTokenType' => 'applications/auth/factor/PhabricatorAuthTOTPKeyTemporaryTokenType.php',
@@ -7377,6 +7378,7 @@
'PhabricatorAuthSessionGarbageCollector' => 'PhabricatorGarbageCollector',
'PhabricatorAuthSessionInfo' => 'Phobject',
'PhabricatorAuthSessionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
+ 'PhabricatorAuthSetPasswordController' => 'PhabricatorAuthController',
'PhabricatorAuthSetupCheck' => 'PhabricatorSetupCheck',
'PhabricatorAuthStartController' => 'PhabricatorAuthController',
'PhabricatorAuthTOTPKeyTemporaryTokenType' => 'PhabricatorAuthTemporaryTokenType',
diff --git a/src/applications/auth/application/PhabricatorAuthApplication.php b/src/applications/auth/application/PhabricatorAuthApplication.php
--- a/src/applications/auth/application/PhabricatorAuthApplication.php
+++ b/src/applications/auth/application/PhabricatorAuthApplication.php
@@ -84,6 +84,7 @@
=> 'PhabricatorAuthSSHKeyDeactivateController',
'view/(?P<id>\d+)/' => 'PhabricatorAuthSSHKeyViewController',
),
+ 'password/' => 'PhabricatorAuthSetPasswordController',
),
'/oauth/(?P<provider>\w+)/login/'
diff --git a/src/applications/auth/controller/PhabricatorAuthOneTimeLoginController.php b/src/applications/auth/controller/PhabricatorAuthOneTimeLoginController.php
--- a/src/applications/auth/controller/PhabricatorAuthOneTimeLoginController.php
+++ b/src/applications/auth/controller/PhabricatorAuthOneTimeLoginController.php
@@ -139,8 +139,7 @@
->save();
unset($unguarded);
- $username = $target_user->getUsername();
- $panel_uri = "/settings/user/{$username}/page/password/";
+ $panel_uri = '/auth/password/';
$next = (string)id(new PhutilURI($panel_uri))
->setQueryParams(
diff --git a/src/applications/auth/controller/PhabricatorAuthSetPasswordController.php b/src/applications/auth/controller/PhabricatorAuthSetPasswordController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/auth/controller/PhabricatorAuthSetPasswordController.php
@@ -0,0 +1,155 @@
+<?php
+
+final class PhabricatorAuthSetPasswordController
+ extends PhabricatorAuthController {
+
+ public function shouldAllowPartialSessions() {
+ return true;
+ }
+
+ public function shouldAllowLegallyNonCompliantUsers() {
+ return true;
+ }
+
+ public function handleRequest(AphrontRequest $request) {
+ $viewer = $this->getViewer();
+
+ if (!PhabricatorPasswordAuthProvider::getPasswordProvider()) {
+ return new Aphront404Response();
+ }
+
+ $token = id(new PhabricatorAuthSessionEngine())->requireHighSecuritySession(
+ $viewer,
+ $request,
+ '/');
+
+ $key = $request->getStr('key');
+ $password_type = PhabricatorAuthPasswordResetTemporaryTokenType::TOKENTYPE;
+ if (!$key) {
+ return new Aphront404Response();
+ }
+
+ $auth_token = id(new PhabricatorAuthTemporaryTokenQuery())
+ ->setViewer($viewer)
+ ->withTokenResources(array($viewer->getPHID()))
+ ->withTokenTypes(array($password_type))
+ ->withTokenCodes(array(PhabricatorHash::weakDigest($key)))
+ ->withExpired(false)
+ ->executeOne();
+ if (!$auth_token) {
+ return new Aphront404Response();
+ }
+
+ $min_len = PhabricatorEnv::getEnvConfig('account.minimum-password-length');
+ $min_len = (int)$min_len;
+
+ $e_password = true;
+ $e_confirm = true;
+ $errors = array();
+ if ($request->isFormPost()) {
+ $password = $request->getStr('password');
+ $confirm = $request->getStr('confirm');
+
+ $e_password = null;
+ $e_confirm = null;
+
+ if (!strlen($password)) {
+ $errors[] = pht('You must choose a password or skip this step.');
+ $e_password = pht('Required');
+ } else if (strlen($password) < $min_len) {
+ $errors[] = pht(
+ 'The selected password is too short. Passwords must be a minimum '.
+ 'of %s characters.',
+ new PhutilNumber($min_len));
+ $e_password = pht('Too Short');
+ } else if (!strlen($confirm)) {
+ $errors[] = pht('You must confirm the selecetd password.');
+ $e_confirm = pht('Required');
+ } else if ($password !== $confirm) {
+ $errors[] = pht('The password and confirmation do not match.');
+ $e_password = pht('Invalid');
+ $e_confirm = pht('Invalid');
+ } else if (PhabricatorCommonPasswords::isCommonPassword($password)) {
+ $e_password = pht('Very Weak');
+ $errors[] = pht(
+ 'The selected password is very weak: it is one of the most common '.
+ 'passwords in use. Choose a stronger password.');
+ }
+
+ if (!$errors) {
+ $envelope = new PhutilOpaqueEnvelope($password);
+
+ // This write is unguarded because the CSRF token has already
+ // been checked in the call to $request->isFormPost() and
+ // the CSRF token depends on the password hash, so when it
+ // is changed here the CSRF token check will fail.
+ $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
+
+ id(new PhabricatorUserEditor())
+ ->setActor($viewer)
+ ->changePassword($viewer, $envelope);
+
+ unset($unguarded);
+
+ // Destroy the token.
+ $auth_token->delete();
+
+ return id(new AphrontRedirectResponse())->setURI('/');
+ }
+ }
+
+ $len_caption = null;
+ if ($min_len) {
+ $len_caption = pht('Minimum password length: %d characters.', $min_len);
+ }
+
+ if ($viewer->hasPassword()) {
+ $title = pht('Reset Password');
+ $crumb = pht('Reset Password');
+ $submit = pht('Reset Password');
+ } else {
+ $title = pht('Set Password');
+ $crumb = pht('Set Password');
+ $submit = pht('Set Account Password');
+ }
+
+ $form = id(new AphrontFormView())
+ ->setViewer($viewer)
+ ->addHiddenInput('key', $key)
+ ->appendChild(
+ id(new AphrontFormPasswordControl())
+ ->setDisableAutocomplete(true)
+ ->setLabel(pht('New Password'))
+ ->setError($e_password)
+ ->setName('password'))
+ ->appendChild(
+ id(new AphrontFormPasswordControl())
+ ->setDisableAutocomplete(true)
+ ->setLabel(pht('Confirm Password'))
+ ->setCaption($len_caption)
+ ->setError($e_confirm)
+ ->setName('confirm'))
+ ->appendChild(
+ id(new AphrontFormSubmitControl())
+ ->addCancelButton('/', pht('Skip This Step'))
+ ->setValue($submit));
+
+ $form_box = id(new PHUIObjectBoxView())
+ ->setHeaderText($title)
+ ->setFormErrors($errors)
+ ->setBackground(PHUIObjectBoxView::WHITE_CONFIG)
+ ->setForm($form);
+
+ $main_view = id(new PHUITwoColumnView())
+ ->setFooter($form_box);
+
+ $crumbs = $this->buildApplicationCrumbs()
+ ->addTextCrumb($crumb)
+ ->setBorder(true);
+
+ return $this->newPage()
+ ->setTitle($title)
+ ->setCrumbs($crumbs)
+ ->appendChild($main_view);
+ }
+}
diff --git a/src/applications/people/storage/PhabricatorUser.php b/src/applications/people/storage/PhabricatorUser.php
--- a/src/applications/people/storage/PhabricatorUser.php
+++ b/src/applications/people/storage/PhabricatorUser.php
@@ -262,6 +262,10 @@
PhabricatorPeopleUserPHIDType::TYPECONST);
}
+ public function hasPassword() {
+ return (bool)strlen($this->passwordHash);
+ }
+
public function setPassword(PhutilOpaqueEnvelope $envelope) {
if (!$this->getPHID()) {
throw new Exception(
diff --git a/src/applications/settings/panel/PhabricatorPasswordSettingsPanel.php b/src/applications/settings/panel/PhabricatorPasswordSettingsPanel.php
--- a/src/applications/settings/panel/PhabricatorPasswordSettingsPanel.php
+++ b/src/applications/settings/panel/PhabricatorPasswordSettingsPanel.php
@@ -35,23 +35,10 @@
$min_len = PhabricatorEnv::getEnvConfig('account.minimum-password-length');
$min_len = (int)$min_len;
- // NOTE: To change your password, you need to prove you own the account,
- // either by providing the old password or by carrying a token to
- // the workflow from a password reset email.
-
- $key = $request->getStr('key');
- $password_type = PhabricatorAuthPasswordResetTemporaryTokenType::TOKENTYPE;
-
- $token = null;
- if ($key) {
- $token = id(new PhabricatorAuthTemporaryTokenQuery())
- ->setViewer($user)
- ->withTokenResources(array($user->getPHID()))
- ->withTokenTypes(array($password_type))
- ->withTokenCodes(array(PhabricatorHash::weakDigest($key)))
- ->withExpired(false)
- ->executeOne();
- }
+ // NOTE: Users can also change passwords through the separate "set/reset"
+ // interface which is reached by logging in with a one-time token after
+ // registration or password reset. If this flow changes, that flow may
+ // also need to change.
$e_old = true;
$e_new = true;
@@ -59,12 +46,10 @@
$errors = array();
if ($request->isFormPost()) {
- if (!$token) {
- $envelope = new PhutilOpaqueEnvelope($request->getStr('old_pw'));
- if (!$user->comparePassword($envelope)) {
- $errors[] = pht('The old password you entered is incorrect.');
- $e_old = pht('Invalid');
- }
+ $envelope = new PhutilOpaqueEnvelope($request->getStr('old_pw'));
+ if (!$user->comparePassword($envelope)) {
+ $errors[] = pht('The old password you entered is incorrect.');
+ $e_old = pht('Invalid');
}
$pass = $request->getStr('new_pw');
@@ -98,16 +83,7 @@
unset($unguarded);
- if ($token) {
- // Destroy the token.
- $token->delete();
-
- // If this is a password set/reset, kick the user to the home page
- // after we update their account.
- $next = '/';
- } else {
- $next = $this->getPanelURI('?saved=true');
- }
+ $next = $this->getPanelURI('?saved=true');
id(new PhabricatorAuthSessionEngine())->terminateLoginSessions(
$user,
@@ -125,19 +101,15 @@
} catch (PhabricatorPasswordHasherUnavailableException $ex) {
$can_upgrade = false;
- // Only show this stuff if we aren't on the reset workflow. We can
- // do resets regardless of the old hasher's availability.
- if (!$token) {
- $errors[] = pht(
- 'Your password is currently hashed using an algorithm which is '.
- 'no longer available on this install.');
- $errors[] = pht(
- 'Because the algorithm implementation is missing, your password '.
- 'can not be used or updated.');
- $errors[] = pht(
- 'To set a new password, request a password reset link from the '.
- 'login screen and then follow the instructions.');
- }
+ $errors[] = pht(
+ 'Your password is currently hashed using an algorithm which is '.
+ 'no longer available on this install.');
+ $errors[] = pht(
+ 'Because the algorithm implementation is missing, your password '.
+ 'can not be used or updated.');
+ $errors[] = pht(
+ 'To set a new password, request a password reset link from the '.
+ 'login screen and then follow the instructions.');
}
if ($can_upgrade) {
@@ -153,20 +125,13 @@
$len_caption = pht('Minimum password length: %d characters.', $min_len);
}
- $form = new AphrontFormView();
- $form
- ->setUser($user)
- ->addHiddenInput('key', $key);
-
- if (!$token) {
- $form->appendChild(
+ $form = id(new AphrontFormView())
+ ->setViewer($user)
+ ->appendChild(
id(new AphrontFormPasswordControl())
->setLabel(pht('Old Password'))
->setError($e_old)
- ->setName('old_pw'));
- }
-
- $form
+ ->setName('old_pw'))
->appendChild(
id(new AphrontFormPasswordControl())
->setDisableAutocomplete(true)

File Metadata

Mime Type
text/plain
Expires
Fri, Jan 24, 1:21 AM (21 h, 21 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7038471
Default Alt Text
D18840.diff (12 KB)

Event Timeline