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