‪TYPO3CMS  9.5
SaltedPasswordService.php
Go to the documentation of this file.
1 <?php
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
21 
29 {
35  public ‪$prefixId = 'tx_saltedpasswords_sv1';
36 
42  public ‪$extKey = 'saltedpasswords';
43 
49  protected ‪$extConf;
50 
57  protected ‪$objInstanceSaltedPW;
58 
67  protected ‪$authenticationFailed = false;
68 
72  public function ‪__construct()
73  {
74  trigger_error('SaltedPasswordService will be removed in TYPO3 v10.0.', E_USER_DEPRECATED);
75  }
76 
82  public function ‪init()
83  {
85  parent::init();
86  return true;
87  }
88 
97  public function ‪compareUident(array $user, array $loginData, $passwordCompareStrategy = '')
98  {
99  $validPasswd = false;
100  $password = $loginData['uident_text'];
101  // Determine method used for given salted hashed password
102  // This calls deprecated getSaltingInstance(). This is "ok" since this SaltedPasswordService in itself is deprecated.
103  $this->objInstanceSaltedPW = ‪PasswordHashFactory::getSaltingInstance($user['password']);
104  // Existing record is in format of Salted Hash password
105  if (is_object($this->objInstanceSaltedPW)) {
106  $validPasswd = $this->objInstanceSaltedPW->checkPassword($password, $user['password']);
107  // Record is in format of Salted Hash password but authentication failed
108  // skip further authentication methods
109  if (!$validPasswd) {
110  $this->authenticationFailed = true;
111  }
113  $skip = false;
114  // Test for wrong salted hashing method (only if current method is not related to default method)
115  if ($validPasswd && get_class($this->objInstanceSaltedPW) !== $defaultHashingClassName && !is_subclass_of($this->objInstanceSaltedPW, $defaultHashingClassName)) {
116  // Instantiate default method class
117  // This calls deprecated getSaltingInstance(). This is "ok" since this SaltedPasswordService in itself is deprecated.
118  $this->objInstanceSaltedPW = ‪PasswordHashFactory::getSaltingInstance(null);
119  $this->‪updatePassword((int)$user['uid'], ['password' => $this->objInstanceSaltedPW->getHashedPassword($password)]);
120  }
121  if ($validPasswd && !$skip && $this->objInstanceSaltedPW->isHashUpdateNeeded($user['password'])) {
122  $this->‪updatePassword((int)$user['uid'], ['password' => $this->objInstanceSaltedPW->getHashedPassword($password)]);
123  }
124  } else {
125  // Stored password is in deprecated salted hashing method
126  $hashingMethod = substr($user['password'], 0, 2);
127  if ($hashingMethod === 'M$') {
128  // Instantiate default method class
129  // This calls deprecated getSaltingInstance(). This is "ok" since this SaltedPasswordService in itself is deprecated.
130  $this->objInstanceSaltedPW = ‪PasswordHashFactory::getSaltingInstance(substr($user['password'], 1));
131  // md5 passwords that have been upgraded to salted passwords using old scheduler task
132  // @todo: The entire 'else' should be dropped in TYPO3 v10.0, admins had to upgrade users to salted passwords with v8 latest since the
133  // @todo: scheduler task has been dropped with v9, users should have had logged in in TYPO3 v9 era, this fallback is obsolete with TYPO3 v10.0.
134  $validPasswd = $this->objInstanceSaltedPW->checkPassword(md5($password), substr($user['password'], 1));
135 
136  // Skip further authentication methods
137  if (!$validPasswd) {
138  $this->authenticationFailed = true;
139  }
140  }
141  // Upgrade to a sane salt mechanism if password was correct
142  if ($validPasswd) {
143  // Instantiate default method class
144  // This calls deprecated getSaltingInstance(). This is "ok" since this SaltedPasswordService in itself is deprecated.
145  $this->objInstanceSaltedPW = ‪PasswordHashFactory::getSaltingInstance(null);
146  $this->‪updatePassword((int)$user['uid'], ['password' => $this->objInstanceSaltedPW->getHashedPassword($password)]);
147  }
148  }
149  return $validPasswd;
150  }
151 
163  public function ‪authUser(array $user)
164  {
165  $OK = 100;
166  // The salted password service can only work correctly, if a non empty username along with a non empty password is provided.
167  // Otherwise a different service is allowed to check for other login credentials
168  if ((string)$this->login['uident_text'] !== '' && (string)$this->login['uname'] !== '') {
169  $validPasswd = $this->‪compareUident($user, $this->login);
170  if (!$validPasswd) {
171  // Failed login attempt (wrong password)
172  $errorMessage = 'Login-attempt from ###IP###, username \'%s\', password not accepted!';
173  // No delegation to further services
174  if ($this->authenticationFailed) {
175  $this->‪writeLogMessage(TYPO3_MODE . ' Authentication failed - wrong password for username \'%s\'', $this->login['uname']);
176  $OK = 0;
177  } else {
178  $this->‪writeLogMessage($errorMessage, $this->login['uname']);
179  }
180  $this->‪writelog(255, 3, 3, 1, $errorMessage, [
181  $this->login['uname']
182  ]);
183  $this->logger->info(sprintf($errorMessage, $this->login['uname']));
184  } elseif ($validPasswd && $user['lockToDomain'] && strcasecmp($user['lockToDomain'], $this->authInfo['HTTP_HOST'])) {
185  // Lock domain didn't match, so error:
186  $errorMessage = 'Login-attempt from ###IP###, username \'%s\', locked domain \'%s\' did not match \'%s\'!';
187  $this->‪writeLogMessage($errorMessage, $user[$this->db_user['username_column']], $user['lockToDomain'], $this->authInfo['HTTP_HOST']);
188  $this->‪writelog(255, 3, 3, 1, $errorMessage, [
189  $user[$this->db_user['username_column']],
190  $user['lockToDomain'],
191  $this->authInfo['HTTP_HOST']
192  ]);
193  $this->logger->info(sprintf($errorMessage, $user[$this->db_user['username_column']], $user['lockToDomain'], $this->authInfo['HTTP_HOST']));
194  $OK = 0;
195  } elseif ($validPasswd) {
196  $this->‪writeLogMessage(TYPO3_MODE . ' Authentication successful for username \'%s\'', $this->login['uname']);
197  $OK = 200;
198  }
199  }
200  return $OK;
201  }
202 
209  protected function ‪updatePassword($uid, $updateFields)
210  {
211  $connection = GeneralUtility::makeInstance(ConnectionPool::class)
212  ->getConnectionForTable($this->pObj->user_table);
213 
214  $connection->update(
215  $this->pObj->user_table,
216  $updateFields,
217  ['uid' => (int)$uid]
218  );
219 
220  $this->logger->notice('Automatic password update for user record in ' . $this->pObj->user_table . ' with uid ' . $uid);
221  }
222 
235  public function ‪writeLogMessage($message, ...$params)
236  {
237  if (!empty($params)) {
238  $message = vsprintf($message, $params);
239  }
240  if (TYPO3_MODE === 'FE') {
242  $timeTracker = GeneralUtility::makeInstance(TimeTracker::class);
243  $timeTracker->setTSlogMessage($message);
244  }
245  $this->logger->notice($message);
246  }
247 }
‪TYPO3\CMS\Core\Crypto\PasswordHashing\SaltedPasswordService\compareUident
‪bool compareUident(array $user, array $loginData, $passwordCompareStrategy='')
Definition: SaltedPasswordService.php:92
‪TYPO3\CMS\Core\Crypto\PasswordHashing\SaltedPasswordService\$objInstanceSaltedPW
‪TYPO3 CMS Core Crypto PasswordHashing PasswordHashInterface $objInstanceSaltedPW
Definition: SaltedPasswordService.php:53
‪TYPO3\CMS\Core\Crypto\PasswordHashing
Definition: AbstractComposedSalt.php:3
‪TYPO3\CMS\Core\Crypto\PasswordHashing\SaltedPasswordService\$extConf
‪mixed $extConf
Definition: SaltedPasswordService.php:46
‪TYPO3\CMS\Core\Authentication\AbstractAuthenticationService\writelog
‪writelog($type, $action, $error, $details_nr, $details, $data, $tablename='', $recuid='', $recpid='')
Definition: AbstractAuthenticationService.php:118
‪TYPO3\CMS\Core\Authentication\AbstractAuthenticationService
Definition: AbstractAuthenticationService.php:27
‪TYPO3\CMS\Core\Crypto\PasswordHashing\SaltedPasswordService\__construct
‪__construct()
Definition: SaltedPasswordService.php:67
‪TYPO3\CMS\Core\Crypto\PasswordHashing\SaltedPasswordService\writeLogMessage
‪writeLogMessage($message,... $params)
Definition: SaltedPasswordService.php:230
‪TYPO3\CMS\Core\Crypto\PasswordHashing\SaltedPasswordService
Definition: SaltedPasswordService.php:29
‪TYPO3\CMS\Core\Crypto\PasswordHashing\SaltedPasswordService\$prefixId
‪string $prefixId
Definition: SaltedPasswordService.php:34
‪TYPO3\CMS\Core\Crypto\PasswordHashing\PasswordHashFactory\getSaltingInstance
‪static PasswordHashInterface null getSaltingInstance($saltedHash='', $mode=TYPO3_MODE)
Definition: PasswordHashFactory.php:178
‪TYPO3\CMS\Core\Crypto\PasswordHashing\SaltedPasswordService\updatePassword
‪updatePassword($uid, $updateFields)
Definition: SaltedPasswordService.php:204
‪TYPO3\CMS\Core\Crypto\PasswordHashing\SaltedPasswordService\$extKey
‪string $extKey
Definition: SaltedPasswordService.php:40
‪TYPO3\CMS\Core\Crypto\PasswordHashing\SaltedPasswordsUtility\returnExtConf
‪static array returnExtConf($mode=TYPO3_MODE)
Definition: SaltedPasswordsUtility.php:68
‪TYPO3\CMS\Core\Crypto\PasswordHashing\SaltedPasswordService\init
‪bool init()
Definition: SaltedPasswordService.php:77
‪TYPO3\CMS\Core\Crypto\PasswordHashing\SaltedPasswordService\$authenticationFailed
‪bool $authenticationFailed
Definition: SaltedPasswordService.php:62
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:44
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:45
‪TYPO3\CMS\Core\TimeTracker\TimeTracker
Definition: TimeTracker.php:27
‪TYPO3\CMS\Core\Crypto\PasswordHashing\SaltedPasswordService\authUser
‪int authUser(array $user)
Definition: SaltedPasswordService.php:158
‪TYPO3\CMS\Core\Crypto\PasswordHashing\SaltedPasswordsUtility\getDefaultSaltingHashingMethod
‪static string getDefaultSaltingHashingMethod($mode=TYPO3_MODE)
Definition: SaltedPasswordsUtility.php:104