Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14761438
D18840.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
12 KB
Referenced Files
None
Subscribers
None
D18840.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D18840: Separate "Set/Reset Password" from "Change Password"
Attached
Detach File
Event Timeline
Log In to Comment