summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Pott2014-07-15 09:21:15 (GMT)
committerAlex Pott2014-07-15 09:21:15 (GMT)
commitf4751717cc554452c1e78596d97f587c059c8ae6 (patch)
treedbda2321fe7b9f4f2a1a6e79462469827f2daeec
parent291b99816d08d5dbfad415e2fc9abf9f14d5c027 (diff)
Issue #1998198 by pwolanin, splatio, Albert Volkman, tim.plunkett, andypost, disasm, Les Lim, tkuldeep17: Convert user_pass_reset to a new-style Form object.
-rw-r--r--core/modules/user/src/Controller/UserController.php109
-rw-r--r--core/modules/user/src/Form/UserForm.php24
-rw-r--r--core/modules/user/src/Form/UserPasswordResetForm.php119
-rw-r--r--core/modules/user/src/Tests/UserPasswordResetTest.php7
-rw-r--r--core/modules/user/user.pages.inc89
-rw-r--r--core/modules/user/user.routing.yml5
6 files changed, 237 insertions, 116 deletions
diff --git a/core/modules/user/src/Controller/UserController.php b/core/modules/user/src/Controller/UserController.php
index c27e3c9..5cab518 100644
--- a/core/modules/user/src/Controller/UserController.php
+++ b/core/modules/user/src/Controller/UserController.php
@@ -11,6 +11,10 @@ use Drupal\Component\Utility\Xss;
use Drupal\Core\Controller\ControllerBase;
use Drupal\user\UserInterface;
use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
+use Drupal\Core\Datetime\Date;
+use Drupal\user\UserStorageInterface;
/**
* Controller routines for user routes.
@@ -18,6 +22,111 @@ use Symfony\Component\HttpFoundation\Request;
class UserController extends ControllerBase {
/**
+ * The date formatting service.
+ *
+ * @var \Drupal\Core\Datetime\Date
+ */
+ protected $date;
+
+ /**
+ * The user storage.
+ *
+ * @var \Drupal\user\UserStorageInterface
+ */
+ protected $userStorage;
+
+ /**
+ * Constructs a UserController object.
+ *
+ * @param \Drupal\Core\Datetime\Date $date
+ * The date formatting service.
+ * @param \Drupal\user\UserStorageInterface $user_storage
+ * The user storage.
+ */
+ public function __construct(Date $date, UserStorageInterface $user_storage) {
+ $this->date = $date;
+ $this->userStorage = $user_storage;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function create(ContainerInterface $container) {
+ return new static(
+ $container->get('date'),
+ $container->get('entity.manager')->getStorage('user')
+ );
+ }
+
+ /**
+ * Returns the user password reset page.
+ *
+ * @param int $uid
+ * UID of user requesting reset.
+ * @param int $timestamp
+ * The current timestamp.
+ * @param string $hash
+ * Login link hash.
+ *
+ * @return array|\Symfony\Component\HttpFoundation\RedirectResponse
+ * The form structure or a redirect response.
+ *
+ * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
+ * If the login link is for a blocked user or invalid user ID.
+ */
+ public function resetPass($uid, $timestamp, $hash) {
+ $account = $this->currentUser();
+ $config = $this->config('user.settings');
+ // When processing the one-time login link, we have to make sure that a user
+ // isn't already logged in.
+ if ($account->isAuthenticated()) {
+ // The current user is already logged in.
+ if ($account->id() == $uid) {
+ drupal_set_message($this->t('You are logged in as %user. <a href="!user_edit">Change your password.</a>', array('%user' => $account->getUsername(), '!user_edit' => $this->url('user.edit', array('user' => $account->id())))));
+ }
+ // A different user is already logged in on the computer.
+ else {
+ if ($reset_link_user = $this->userStorage->load($uid)) {
+ drupal_set_message($this->t('Another user (%other_user) is already logged into the site on this computer, but you tried to use a one-time link for user %resetting_user. Please <a href="!logout">logout</a> and try using the link again.',
+ array('%other_user' => $account->getUsername(), '%resetting_user' => $reset_link_user->getUsername(), '!logout' => $this->url('user.logout'))));
+ }
+ else {
+ // Invalid one-time link specifies an unknown user.
+ drupal_set_message($this->t('The one-time login link you clicked is invalid.'));
+ }
+ }
+ return $this->redirect('<front>');
+ }
+ else {
+ // The current user is not logged in, so check the parameters.
+ // Time out, in seconds, until login URL expires.
+ $timeout = $config->get('password_reset_timeout');
+ $current = REQUEST_TIME;
+ /* @var \Drupal\user\UserInterface $user */
+ $user = $this->userStorage->load($uid);
+ // Verify that the user exists and is active.
+ if ($user && $user->isActive()) {
+ // No time out for first time login.
+ if ($user->getLastLoginTime() && $current - $timestamp > $timeout) {
+ drupal_set_message($this->t('You have tried to use a one-time login link that has expired. Please request a new one using the form below.'));
+ return $this->redirect('user.pass');
+ }
+ elseif ($user->isAuthenticated() && ($timestamp >= $user->getLastLoginTime()) && ($timestamp <= $current) && ($hash === user_pass_rehash($user->getPassword(), $timestamp, $user->getLastLoginTime()))) {
+ $expiration_date = $user->getLastLoginTime() ? $this->date->format($timestamp + $timeout) : NULL;
+ return $this->formBuilder()->getForm('Drupal\user\Form\UserPasswordResetForm', $user, $expiration_date, $timestamp, $hash);
+ }
+ else {
+ drupal_set_message($this->t('You have tried to use a one-time login link that has either been used or is no longer valid. Please request a new one using the form below.'));
+ return $this->redirect('user.pass');
+ }
+ }
+ }
+ // Blocked or invalid user ID, so deny access. The parameters will be in the
+ // watchdog's URL for the administrator to check.
+ throw new AccessDeniedHttpException();
+ }
+
+ /**
* Returns the user page.
*
* Displays user profile if user is logged in, or login form for anonymous
diff --git a/core/modules/user/src/Form/UserForm.php b/core/modules/user/src/Form/UserForm.php
deleted file mode 100644
index 919cb1e..0000000
--- a/core/modules/user/src/Form/UserForm.php
+++ /dev/null
@@ -1,24 +0,0 @@
-<?php
-/**
- * @file
- * Contains \Drupal\user\Form\UserForm.
- */
-
-namespace Drupal\user\Form;
-
-/**
- * Temporary form controller for user module.
- */
-class UserForm {
-
- /**
- * Wraps user_pass_reset().
- *
- * @todo Remove user_pass_reset().
- */
- public function resetPass($uid, $timestamp, $hash, $operation) {
- module_load_include('pages.inc', 'user');
- return \Drupal::formBuilder()->getForm('user_pass_reset', $uid, $timestamp, $hash, $operation);
- }
-
-}
diff --git a/core/modules/user/src/Form/UserPasswordResetForm.php b/core/modules/user/src/Form/UserPasswordResetForm.php
new file mode 100644
index 0000000..ba7c121
--- /dev/null
+++ b/core/modules/user/src/Form/UserPasswordResetForm.php
@@ -0,0 +1,119 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\user\Form\UserPasswordResetForm.
+ */
+
+namespace Drupal\user\Form;
+
+use Drupal\Core\Session\AccountInterface;
+use Drupal\Component\Utility\Crypt;
+use Drupal\Core\Form\FormBase;
+use Psr\Log\LoggerInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Form controller for the user password forms.
+ */
+class UserPasswordResetForm extends FormBase {
+
+ /**
+ * A logger instance.
+ *
+ * @var \Psr\Log\LoggerInterface
+ */
+ protected $logger;
+
+ /**
+ * Constructs a new UserPasswordResetForm.
+ *
+ * @param \Psr\Log\LoggerInterface $logger
+ * A logger instance.
+ */
+ public function __construct(LoggerInterface $logger) {
+ $this->logger = $logger;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function create(ContainerInterface $container) {
+ return new static(
+ $container->get('logger.factory')->get('user')
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getFormID() {
+ return 'user_pass_reset';
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param array $form
+ * An associative array containing the structure of the form.
+ * @param array $form_state
+ * An associative array containing the current state of the form.
+ * @param \Drupal\Core\Session\AccountInterface $user
+ * User requesting reset.
+ * @param string $expiration_date
+ * Formatted expiration date for the login link, or NULL if the link does
+ * not expire.
+ * @param int $timestamp
+ * The current timestamp.
+ * @param string $hash
+ * Login link hash.
+ */
+ public function buildForm(array $form, array &$form_state, AccountInterface $user = NULL, $expiration_date = NULL, $timestamp = NULL, $hash = NULL) {
+ if ($expiration_date) {
+ $form['message'] = array('#markup' => $this->t('<p>This is a one-time login for %user_name and will expire on %expiration_date.</p><p>Click on this button to log in to the site and change your password.</p>', array('%user_name' => $user->getUsername(), '%expiration_date' => $expiration_date)));
+ }
+ else {
+ // No expiration for first time login.
+ $form['message'] = array('#markup' => $this->t('<p>This is a one-time login for %user_name.</p><p>Click on this button to log in to the site and change your password.</p>', array('%user_name' => $user->getUsername())));
+ }
+
+ $form['#title'] = 'Reset Password';
+ $form['user'] = array(
+ '#type' => 'value',
+ '#value' => $user,
+ );
+ $form['timestamp'] = array(
+ '#type' => 'value',
+ '#value' => $timestamp,
+ );
+ $form['help'] = array('#markup' => '<p>' . $this->t('This login can be used only once.') . '</p>');
+ $form['actions'] = array('#type' => 'actions');
+ $form['actions']['submit'] = array(
+ '#type' => 'submit',
+ '#value' => $this->t('Log in'),
+ );
+ return $form;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function submitForm(array &$form, array &$form_state) {
+ /** @var $user \Drupal\user\UserInterface */
+ $user = $form_state['values']['user'];
+ user_login_finalize($user);
+ $this->logger->notice('User %name used one-time login link at time %timestamp.', array('%name' => $user->getUsername(), '%timestamp' => $form_state['values']['timestamp']));
+ drupal_set_message($this->t('You have just used your one-time login link. It is no longer necessary to use this link to log in. Please change your password.'));
+ // Let the user's password be changed without the current password check.
+ $token = Crypt::randomBytesBase64(55);
+ $_SESSION['pass_reset_' . $user->id()] = $token;
+ $form_state['redirect_route']['route_name'] = 'user.edit';
+ $form_state['redirect_route']['route_parameters'] = array('user' => $user->id());
+ $form_state['redirect_route']['options'] = array(
+ 'query' => array('pass-reset-token' => $token),
+ 'absolute' => TRUE,
+ );
+ }
+
+}
+
diff --git a/core/modules/user/src/Tests/UserPasswordResetTest.php b/core/modules/user/src/Tests/UserPasswordResetTest.php
index 41adecc..1045e2c 100644
--- a/core/modules/user/src/Tests/UserPasswordResetTest.php
+++ b/core/modules/user/src/Tests/UserPasswordResetTest.php
@@ -106,6 +106,13 @@ class UserPasswordResetTest extends WebTestBase {
$_uid = $this->account->id();
$this->drupalGet("user/reset/$_uid/$bogus_timestamp/" . user_pass_rehash($this->account->getPassword(), $bogus_timestamp, $this->account->getLastLoginTime()));
$this->assertText(t('You have tried to use a one-time login link that has expired. Please request a new one using the form below.'), 'Expired password reset request rejected.');
+
+ // Create a user, block the account, and verify that a login link is denied.
+ $timestamp = REQUEST_TIME - 1;
+ $blocked_account = $this->drupalCreateUser()->block();
+ $blocked_account->save();
+ $this->drupalGet("user/reset/" . $blocked_account->id() . "/$timestamp/" . user_pass_rehash($blocked_account->getPassword(), $timestamp, $blocked_account->getLastLoginTime()));
+ $this->assertResponse(403);
}
/**
diff --git a/core/modules/user/user.pages.inc b/core/modules/user/user.pages.inc
index 4b6a0ae..4a09d7b 100644
--- a/core/modules/user/user.pages.inc
+++ b/core/modules/user/user.pages.inc
@@ -6,97 +6,8 @@
*/
use Drupal\Core\Render\Element;
-use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
-use Symfony\Component\HttpKernel\HttpKernelInterface;
-use Drupal\Component\Utility\Crypt;
-
-/**
- * Menu callback; process one time login link and redirects to the user page on success.
- *
- * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
- * Use \Drupal\user\Form\UserForm::resetPass().
- */
-function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $action = NULL) {
- global $user;
-
- // When processing the one-time login link, we have to make sure that a user
- // isn't already logged in.
- if ($user->isAuthenticated()) {
- // The existing user is already logged in.
- if ($user->id() == $uid) {
- drupal_set_message(t('You are logged in as %user. <a href="!user_edit">Change your password.</a>', array('%user' => $user->getUsername(), '!user_edit' => url("user/" . $user->id() . "/edit"))));
- }
- // A different user is already logged in on the computer.
- else {
- $reset_link_account = user_load($uid);
- if (!empty($reset_link_account)) {
- drupal_set_message(t('Another user (%other_user) is already logged into the site on this computer, but you tried to use a one-time link for user %resetting_user. Please <a href="!logout">logout</a> and try using the link again.',
- array('%other_user' => $user->getUsername(), '%resetting_user' => $reset_link_account->getUsername(), '!logout' => url('user/logout'))));
- } else {
- // Invalid one-time link specifies an unknown user.
- drupal_set_message(t('The one-time login link you clicked is invalid.'));
- }
- }
- return new RedirectResponse(url('<front>', array('absolute' => TRUE)));
- }
- else {
- // Time out, in seconds, until login URL expires.
- $timeout = \Drupal::config('user.settings')->get('password_reset_timeout');
- $current = REQUEST_TIME;
- $account = user_load($uid);
- // Verify that the user exists and is active.
- if ($timestamp <= $current && $account && $account->isActive()) {
- // No time out for first time login.
- if ($account->getLastLoginTime() && $current - $timestamp > $timeout) {
- drupal_set_message(t('You have tried to use a one-time login link that has expired. Please request a new one using the form below.'));
- return new RedirectResponse(url('user/password', array('absolute' => TRUE)));
- }
- elseif ($account->isAuthenticated() && $timestamp >= $account->getLastLoginTime() && $timestamp <= $current && $hashed_pass == user_pass_rehash($account->getPassword(), $timestamp, $account->getLastLoginTime())) {
- // First stage is a confirmation form, then login
- if ($action == 'login') {
- // Set the new user.
- // user_login_finalize() also updates the login timestamp of the
- // user, which invalidates further use of the one-time login link.
- user_login_finalize($account);
- \Drupal::logger('user')->notice('User %name used one-time login link at time %timestamp.', array('%name' => $account->getUsername(), '%timestamp' => $timestamp));
- drupal_set_message(t('You have just used your one-time login link. It is no longer necessary to use this link to log in. Please change your password.'));
- // Let the user's password be changed without the current password check.
- $token = Crypt::randomBytesBase64(55);
- $_SESSION['pass_reset_' . $user->id()] = $token;
- return new RedirectResponse(url('user/' . $user->id() . '/edit', array(
- 'query' => array('pass-reset-token' => $token),
- 'absolute' => TRUE,
- )));
- }
- else {
- if (!$account->getLastLoginTime()) {
- // No expiration for first time login.
- $form['message'] = array('#markup' => t('<p>This is a one-time login for %user_name.</p><p>Click on this button to log in to the site and change your password.</p>', array('%user_name' => $account->getUsername())));
- }
- else {
- $form['message'] = array('#markup' => t('<p>This is a one-time login for %user_name and will expire on %expiration_date.</p><p>Click on this button to log in to the site and change your password.</p>', array('%user_name' => $account->getUsername(), '%expiration_date' => format_date($timestamp + $timeout))));
- }
- $form['help'] = array('#markup' => '<p>' . t('This login can be used only once.') . '</p>');
- $form['actions'] = array('#type' => 'actions');
- $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Log in'));
- $form['#action'] = url("user/reset/$uid/$timestamp/$hashed_pass/login");
- return $form;
- }
- }
- else {
- drupal_set_message(t('You have tried to use a one-time login link that has either been used or is no longer valid. Please request a new one using the form below.'));
- return new RedirectResponse(url('user/password', array('absolute' => TRUE)));
- }
- }
- else {
- // Deny access, no more clues.
- // Everything will be in the watchdog's URL for the administrator to check.
- throw new AccessDeniedHttpException();
- }
- }
-}
/**
* Prepares variables for user templates.
diff --git a/core/modules/user/user.routing.yml b/core/modules/user/user.routing.yml
index 0a7b842..087ffec 100644
--- a/core/modules/user/user.routing.yml
+++ b/core/modules/user/user.routing.yml
@@ -182,11 +182,10 @@ user.cancel_confirm:
_entity_access: 'user.delete'
user.reset:
- path: '/user/reset/{uid}/{timestamp}/{hash}/{operation}'
+ path: '/user/reset/{uid}/{timestamp}/{hash}'
defaults:
- _content: '\Drupal\user\Form\UserForm::resetPass'
+ _content: '\Drupal\user\Controller\UserController::resetPass'
_title: 'Reset password'
- operation: NULL
requirements:
_access: 'TRUE'
options: