From 517e75283eae1d8a083d17a5613ff1f251fe51ce Mon Sep 17 00:00:00 2001 From: Dave Long <dave@longwaveconsulting.com> Date: Wed, 8 May 2024 10:22:38 +0100 Subject: [PATCH] Issue #3444978 by catch, Berdir: UserAuth BC layer is not working for modules that use it to provide email based logins (cherry picked from commit 26208e91c01e13f15b7103d9e0071e03cd5d5b0c) --- core/modules/user/src/Form/UserLoginForm.php | 8 +- core/modules/user/src/UserAuth.php | 42 +++------- core/modules/user/src/UserAuthentication.php | 88 ++++++++++++++++++++ core/modules/user/user.services.yml | 2 +- 4 files changed, 104 insertions(+), 36 deletions(-) create mode 100644 core/modules/user/src/UserAuthentication.php diff --git a/core/modules/user/src/Form/UserLoginForm.php b/core/modules/user/src/Form/UserLoginForm.php index e3df158e0f51..8fe696d15a53 100644 --- a/core/modules/user/src/Form/UserLoginForm.php +++ b/core/modules/user/src/Form/UserLoginForm.php @@ -246,10 +246,10 @@ public function validateAuthentication(array &$form, FormStateInterface $form_st if ($this->userAuth instanceof UserAuthenticationInterface) { $form_state->set('uid', $this->userAuth->authenticateAccount($account, $password) ? $account->id() : FALSE); } - else { - $uid = $this->userAuth->authenticate($form_state->getValue('name'), $password); - $form_state->set('uid', $uid); - } + } + elseif (!$this->userAuth instanceof UserAuthenticationInterface) { + $uid = $this->userAuth->authenticate($form_state->getValue('name'), $password); + $form_state->set('uid', $uid); } } } diff --git a/core/modules/user/src/UserAuth.php b/core/modules/user/src/UserAuth.php index b4f0c0c356dc..71c7077da6b2 100644 --- a/core/modules/user/src/UserAuth.php +++ b/core/modules/user/src/UserAuth.php @@ -8,7 +8,7 @@ /** * Validates user authentication credentials. */ -class UserAuth implements UserAuthInterface, UserAuthenticationInterface { +class UserAuth implements UserAuthInterface { /** * The entity type manager. @@ -33,6 +33,7 @@ class UserAuth implements UserAuthInterface, UserAuthenticationInterface { * The password service. */ public function __construct(EntityTypeManagerInterface $entity_type_manager, PasswordInterface $password_checker) { + @trigger_error(__CLASS__ . ' is deprecated in drupal:10.3.0 and will be removed from drupal:12.0.0. Implement \Drupal\user\UserAuthenticationInterface instead. See https://www.drupal.org/node/3411040'); $this->entityTypeManager = $entity_type_manager; $this->passwordChecker = $password_checker; } @@ -48,41 +49,20 @@ public function authenticate($username, #[\SensitiveParameter] $password) { $account_search = $this->entityTypeManager->getStorage('user')->loadByProperties(['name' => $username]); if ($account = reset($account_search)) { - if ($this->authenticateAccount($account, $password)) { + if ($this->passwordChecker->check($password, $account->getPassword())) { + // Successful authentication. $uid = $account->id(); - } - } - } - return $uid; - } - - /** - * {@inheritdoc} - */ - public function lookupAccount($identifier): UserInterface|false { - if (!empty($identifier)) { - $account_search = $this->entityTypeManager->getStorage('user')->loadByProperties(['name' => $identifier]); - if ($account = reset($account_search)) { - return $account; + // Update user to new password scheme if needed. + if ($this->passwordChecker->needsRehash($account->getPassword())) { + $account->setPassword($password); + $account->save(); + } + } } } - return FALSE; - } - /** - * {@inheritdoc} - */ - public function authenticateAccount(UserInterface $account, #[\SensitiveParameter] string $password): bool { - if ($this->passwordChecker->check($password, $account->getPassword())) { - // Update user to new password scheme if needed. - if ($this->passwordChecker->needsRehash($account->getPassword())) { - $account->setPassword($password); - $account->save(); - } - return TRUE; - } - return FALSE; + return $uid; } } diff --git a/core/modules/user/src/UserAuthentication.php b/core/modules/user/src/UserAuthentication.php new file mode 100644 index 000000000000..a7168442a7d1 --- /dev/null +++ b/core/modules/user/src/UserAuthentication.php @@ -0,0 +1,88 @@ +<?php + +namespace Drupal\user; + +use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\Core\Password\PasswordInterface; + +/** + * Validates user authentication credentials. + */ +class UserAuthentication implements UserAuthInterface, UserAuthenticationInterface { + + /** + * The entity type manager. + * + * @var \Drupal\Core\Entity\EntityTypeManagerInterface + */ + protected $entityTypeManager; + + /** + * The password hashing service. + * + * @var \Drupal\Core\Password\PasswordInterface + */ + protected $passwordChecker; + + /** + * Constructs a UserAuth object. + * + * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager + * The entity type manager. + * @param \Drupal\Core\Password\PasswordInterface $password_checker + * The password service. + */ + public function __construct(EntityTypeManagerInterface $entity_type_manager, PasswordInterface $password_checker) { + $this->entityTypeManager = $entity_type_manager; + $this->passwordChecker = $password_checker; + } + + /** + * {@inheritdoc} + */ + public function authenticate($username, #[\SensitiveParameter] $password) { + @trigger_error(__METHOD__ . ' is deprecated in drupal:10.3.0 and will be removed from drupal:12.0.0. Implement \Drupal\user\UserAuthenticationInterface instead. See https://www.drupal.org/node/3411040'); + $uid = FALSE; + + if (!empty($username) && strlen($password) > 0) { + $account_search = $this->entityTypeManager->getStorage('user')->loadByProperties(['name' => $username]); + + if ($account = reset($account_search)) { + if ($this->authenticateAccount($account, $password)) { + $uid = $account->id(); + } + } + } + return $uid; + } + + /** + * {@inheritdoc} + */ + public function lookupAccount($identifier): UserInterface|false { + if (!empty($identifier)) { + $account_search = $this->entityTypeManager->getStorage('user')->loadByProperties(['name' => $identifier]); + + if ($account = reset($account_search)) { + return $account; + } + } + return FALSE; + } + + /** + * {@inheritdoc} + */ + public function authenticateAccount(UserInterface $account, #[\SensitiveParameter] string $password): bool { + if ($this->passwordChecker->check($password, $account->getPassword())) { + // Update user to new password scheme if needed. + if ($this->passwordChecker->needsRehash($account->getPassword())) { + $account->setPassword($password); + $account->save(); + } + return TRUE; + } + return FALSE; + } + +} diff --git a/core/modules/user/user.services.yml b/core/modules/user/user.services.yml index e2ec9cc3a067..ec34738d992e 100644 --- a/core/modules/user/user.services.yml +++ b/core/modules/user/user.services.yml @@ -43,7 +43,7 @@ services: tags: - { name: theme_negotiator, priority: -40 } user.auth: - class: Drupal\user\UserAuth + class: Drupal\user\UserAuthentication arguments: ['@entity_type.manager', '@password'] Drupal\user\UserAuthInterface: '@user.auth' user.permissions: -- GitLab