TYPO3 CMS  TYPO3_7-6
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 
23 {
29  public $prefixId = 'tx_saltedpasswords_sv1';
30 
36  public $scriptRelPath = 'sv1/class.tx_saltedpasswords_sv1.php';
37 
43  public $extKey = 'saltedpasswords';
44 
50  protected $extConf;
51 
58  protected $objInstanceSaltedPW = null;
59 
68  protected $authenticationFailed = false;
69 
77  public function init()
78  {
79  $available = false;
80  $mode = TYPO3_MODE;
81  if ($this->info['requestedServiceSubType'] === 'authUserBE') {
82  $mode = 'BE';
83  } elseif ($this->info['requestedServiceSubType'] === 'authUserFE') {
84  $mode = 'FE';
85  }
86  if (\TYPO3\CMS\Saltedpasswords\Utility\SaltedPasswordsUtility::isUsageEnabled($mode)) {
87  $available = true;
89  }
90  return $available ? parent::init() : false;
91  }
92 
101  public function compareUident(array $user, array $loginData, $passwordCompareStrategy = '')
102  {
103  $validPasswd = false;
104  $password = $loginData['uident_text'];
105  // Determine method used for given salted hashed password
106  $this->objInstanceSaltedPW = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getSaltingInstance($user['password']);
107  // Existing record is in format of Salted Hash password
108  if (is_object($this->objInstanceSaltedPW)) {
109  $validPasswd = $this->objInstanceSaltedPW->checkPassword($password, $user['password']);
110  // Record is in format of Salted Hash password but authentication failed
111  // skip further authentication methods
112  if (!$validPasswd) {
113  $this->authenticationFailed = true;
114  }
116  $skip = false;
117  // Test for wrong salted hashing method (only if current method is not related to default method)
118  if ($validPasswd && get_class($this->objInstanceSaltedPW) !== $defaultHashingClassName && !is_subclass_of($this->objInstanceSaltedPW, $defaultHashingClassName)) {
119  // Instantiate default method class
120  $this->objInstanceSaltedPW = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getSaltingInstance(null);
121  $this->updatePassword((int)$user['uid'], ['password' => $this->objInstanceSaltedPW->getHashedPassword($password)]);
122  }
123  if ($validPasswd && !$skip && $this->objInstanceSaltedPW->isHashUpdateNeeded($user['password'])) {
124  $this->updatePassword((int)$user['uid'], ['password' => $this->objInstanceSaltedPW->getHashedPassword($password)]);
125  }
126  } elseif (!(int)$this->extConf['forceSalted']) {
127  // Stored password is in deprecated salted hashing method
128  $hashingMethod = substr($user['password'], 0, 2);
129  if ($hashingMethod === 'C$' || $hashingMethod === 'M$') {
130  // Instantiate default method class
131  $this->objInstanceSaltedPW = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getSaltingInstance(substr($user['password'], 1));
132  // md5
133  if ($hashingMethod === 'M$') {
134  $validPasswd = $this->objInstanceSaltedPW->checkPassword(md5($password), substr($user['password'], 1));
135  } else {
136  $validPasswd = $this->objInstanceSaltedPW->checkPassword($password, substr($user['password'], 1));
137  }
138  // Skip further authentication methods
139  if (!$validPasswd) {
140  $this->authenticationFailed = true;
141  }
142  } elseif (preg_match('/[0-9abcdef]{32,32}/', $user['password'])) {
143  $validPasswd = md5($password) === (string)$user['password'];
144  // Skip further authentication methods
145  if (!$validPasswd) {
146  $this->authenticationFailed = true;
147  }
148  } else {
149  $validPasswd = (string)$password !== '' && (string)$password === (string)$user['password'];
150  }
151  // Should we store the new format value in DB?
152  if ($validPasswd && (int)$this->extConf['updatePasswd']) {
153  // Instantiate default method class
154  $this->objInstanceSaltedPW = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getSaltingInstance(null);
155  $this->updatePassword((int)$user['uid'], ['password' => $this->objInstanceSaltedPW->getHashedPassword($password)]);
156  }
157  }
158  return $validPasswd;
159  }
160 
172  public function authUser(array $user)
173  {
174  $OK = 100;
175  // The salted password service can only work correctly, if a non empty username along with a non empty password is provided.
176  // Otherwise a different service is allowed to check for other login credentials
177  if ((string)$this->login['uident_text'] !== '' && (string)$this->login['uname'] !== '') {
178  $validPasswd = $this->compareUident($user, $this->login);
179  if (!$validPasswd) {
180  // Failed login attempt (wrong password)
181  $errorMessage = 'Login-attempt from %s (%s), username \'%s\', password not accepted!';
182  // No delegation to further services
183  if ((int)$this->extConf['onlyAuthService'] || $this->authenticationFailed) {
184  $this->writeLogMessage(TYPO3_MODE . ' Authentication failed - wrong password for username \'%s\'', $this->login['uname']);
185  $OK = 0;
186  } else {
187  $this->writeLogMessage($errorMessage, $this->authInfo['REMOTE_ADDR'], $this->authInfo['REMOTE_HOST'], $this->login['uname']);
188  }
189  $this->writelog(255, 3, 3, 1, $errorMessage, [
190  $this->authInfo['REMOTE_ADDR'],
191  $this->authInfo['REMOTE_HOST'],
192  $this->login['uname']
193  ]);
194  \TYPO3\CMS\Core\Utility\GeneralUtility::sysLog(sprintf($errorMessage, $this->authInfo['REMOTE_ADDR'], $this->authInfo['REMOTE_HOST'], $this->login['uname']), 'core', \TYPO3\CMS\Core\Utility\GeneralUtility::SYSLOG_SEVERITY_INFO);
195  } elseif ($validPasswd && $user['lockToDomain'] && strcasecmp($user['lockToDomain'], $this->authInfo['HTTP_HOST'])) {
196  // Lock domain didn't match, so error:
197  $errorMessage = 'Login-attempt from %s (%s), username \'%s\', locked domain \'%s\' did not match \'%s\'!';
198  $this->writeLogMessage($errorMessage, $this->authInfo['REMOTE_ADDR'], $this->authInfo['REMOTE_HOST'], $this->login['uname'], $user['lockToDomain'], $this->authInfo['HTTP_HOST']);
199  $this->writelog(255, 3, 3, 1, $errorMessage, [
200  $this->authInfo['REMOTE_ADDR'],
201  $this->authInfo['REMOTE_HOST'],
202  $user[$this->db_user['username_column']],
203  $user['lockToDomain'],
204  $this->authInfo['HTTP_HOST']
205  ]);
206  \TYPO3\CMS\Core\Utility\GeneralUtility::sysLog(sprintf($errorMessage, $this->authInfo['REMOTE_ADDR'], $this->authInfo['REMOTE_HOST'], $user[$this->db_user['username_column']], $user['lockToDomain'], $this->authInfo['HTTP_HOST']), 'core', \TYPO3\CMS\Core\Utility\GeneralUtility::SYSLOG_SEVERITY_INFO);
207  $OK = 0;
208  } elseif ($validPasswd) {
209  $this->writeLogMessage(TYPO3_MODE . ' Authentication successful for username \'%s\'', $this->login['uname']);
210  $OK = 200;
211  }
212  }
213  return $OK;
214  }
215 
223  protected function updatePassword($uid, $updateFields)
224  {
225  $GLOBALS['TYPO3_DB']->exec_UPDATEquery($this->pObj->user_table, sprintf('uid = %u', $uid), $updateFields);
226  \TYPO3\CMS\Core\Utility\GeneralUtility::devLog(sprintf('Automatic password update for user record in %s with uid %u', $this->pObj->user_table, $uid), $this->extKey, 1);
227  }
228 
242  public function writeLogMessage($message)
243  {
244  if (func_num_args() > 1) {
245  $params = func_get_args();
246  array_shift($params);
247  $message = vsprintf($message, $params);
248  }
249  if (TYPO3_MODE === 'BE') {
250  \TYPO3\CMS\Core\Utility\GeneralUtility::sysLog($message, $this->extKey, \TYPO3\CMS\Core\Utility\GeneralUtility::SYSLOG_SEVERITY_NOTICE);
251  } else {
252  $GLOBALS['TT']->setTSlogMessage($message);
253  }
254  if (TYPO3_DLOG) {
255  \TYPO3\CMS\Core\Utility\GeneralUtility::devLog($message, $this->extKey, \TYPO3\CMS\Core\Utility\GeneralUtility::SYSLOG_SEVERITY_NOTICE);
256  }
257  }
258 }
static devLog($msg, $extKey, $severity=0, $dataVar=false)
compareUident(array $user, array $loginData, $passwordCompareStrategy='')
writelog($type, $action, $error, $details_nr, $details, $data, $tablename='', $recuid='', $recpid='')
static getSaltingInstance($saltedHash='', $mode=TYPO3_MODE)
Definition: SaltFactory.php:82
$uid
Definition: server.php:38
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']