42 if ($passwordTransmissionStrategy ===
'normal') {
43 $loginData[
'uident_text'] = $loginData[
'uident'];
59 if ((
string)$this->login[
'uident_text'] ===
'') {
61 $this->
writelog(255, 3, 3, 2,
'Login-attempt from ###IP### for username \'%s\' with an empty password!', [
64 $this->logger->warning(sprintf(
'Login-attempt from %s, for username \'%s\' with an empty password!', $this->authInfo[
'REMOTE_ADDR'], $this->login[
'uname']));
69 if (!is_array($user)) {
71 $this->
writelog(255, 3, 3, 2,
'Login-attempt from ###IP###, username \'%s\' not found!!', [$this->login[
'uname']]);
72 $this->logger->info(
'Login-attempt from username \'' . $this->login[
'uname'] .
'\' not found!
', [
73 'REMOTE_ADDR
' => $this->authInfo['REMOTE_ADDR
']
76 $this->logger->debug('User found
', [
77 $this->db_user['userid_column
'] => $user[$this->db_user['userid_column
']],
78 $this->db_user['username_column
'] => $user[$this->db_user['username_column
']]
97 public function authUser(array $user): int
99 // Early 100 "not responsible, check other services" if username or password is empty
100 if (!isset($this->login['uident_text
']) || (string)$this->login['uident_text
'] === ''
101 || !isset($this->login['uname
']) || (string)$this->login['uname
'] === '') {
105 if (empty($this->db_user['table
'])) {
106 throw new \RuntimeException('User database table not
set', 1533159150);
109 $submittedUsername = (string)$this->login['uname
'];
110 $submittedPassword = (string)$this->login['uident_text
'];
111 $passwordHashInDatabase = $user['password
'];
112 $queriedDomain = $this->authInfo['HTTP_HOST
'];
113 $configuredDomainLock = $user['lockToDomain
'];
114 $userDatabaseTable = $this->db_user['table
'];
116 $isSaltedPassword = false;
117 $isValidPassword = false;
118 $isReHashNeeded = false;
119 $isDomainLockMet = false;
121 $saltFactory = GeneralUtility::makeInstance(PasswordHashFactory::class);
123 // Get a hashed password instance for the hash stored in db of this user
124 $invalidPasswordHashException = null;
126 $hashInstance = $saltFactory->get($passwordHashInDatabase, TYPO3_MODE);
127 } catch (InvalidPasswordHashException $invalidPasswordHashException) {
128 // This can be refactored if the 'else' part below is gone in TYPO3 v10.0: Log and return 100 here
129 $hashInstance = null;
131 // An instance of the currently configured salted password mechanism
133 $defaultHashInstance = $saltFactory->getDefaultHashInstance(TYPO3_MODE);
137 $isSaltedPassword =
true;
138 $isValidPassword = $hashInstance->checkPassword($submittedPassword, $passwordHashInDatabase);
139 if ($isValidPassword) {
140 if ($hashInstance->isHashUpdateNeeded($passwordHashInDatabase)
141 || $defaultHashInstance != $hashInstance
145 $isReHashNeeded = true;
147 if (empty($configuredDomainLock)) {
149 $isDomainLockMet =
true;
150 } elseif (!strcasecmp($configuredDomainLock, $queriedDomain)) {
152 $isDomainLockMet =
true;
155 } elseif (substr($user[
'password'], 0, 2) ===
'M$') {
161 $hashInstance = $saltFactory->get(substr($passwordHashInDatabase, 1), TYPO3_MODE);
162 $isSaltedPassword =
true;
163 $isValidPassword = $hashInstance->checkPassword(md5($submittedPassword), substr($passwordHashInDatabase, 1));
164 if ($isValidPassword) {
166 $isReHashNeeded =
true;
167 if (empty($configuredDomainLock)) {
169 $isDomainLockMet =
true;
170 } elseif (!strcasecmp($configuredDomainLock, $queriedDomain)) {
172 $isDomainLockMet =
true;
175 }
catch (InvalidPasswordHashException $e) {
183 if ($invalidPasswordHashException !==
null) {
184 throw $invalidPasswordHashException;
188 if (!$isSaltedPassword) {
192 $message =
'Login-attempt from ###IP###, username \'%s\', no suitable hash method found!';
194 $this->
writelog(255, 3, 3, 1, $message, [$submittedUsername]);
199 if (!$isValidPassword) {
201 $message =
'Login-attempt from ###IP###, username \'%s\', password not accepted!';
203 $this->
writelog(255, 3, 3, 1, $message, [$submittedUsername]);
208 if (!$isDomainLockMet) {
210 $errorMessage =
'Login-attempt from ###IP###, username \'%s\', locked domain \'%s\' did not match \'%s\'!';
211 $this->
writeLogMessage($errorMessage, $user[$this->db_user[
'username_column']], $configuredDomainLock, $queriedDomain);
212 $this->
writelog(255, 3, 3, 1, $errorMessage, [$user[$this->db_user[
'username_column']], $configuredDomainLock, $queriedDomain]);
217 if ($isReHashNeeded) {
222 $defaultHashInstance->getHashedPassword($submittedPassword)
227 $this->
writeLogMessage(TYPO3_MODE .
' Authentication successful for username \'%s\'', $submittedUsername);
244 if ($this->mode ===
'getGroupsFE') {
246 if ($user[$this->db_user[
'usergroup_column']] ??
false) {
247 $groupList = $user[$this->db_user[
'usergroup_column']];
252 foreach (
$GLOBALS[
'TYPO3_CONF_VARS'][
'FE'][
'IPmaskMountGroups'] ?? [] as $IPel) {
253 if ($this->authInfo[
'REMOTE_ADDR'] && $IPel[0] && GeneralUtility::cmpIP($this->authInfo[
'REMOTE_ADDR'], $IPel[0])) {
254 $groups[] = (int)$IPel[1];
257 $groups = array_unique($groups);
258 if (!empty($groups)) {
259 $this->logger->debug(
'Get usergroups with id: ' . implode(
',', $groups));
260 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
261 ->getQueryBuilderForTable($this->db_groups[
'table']);
262 if (!empty($this->authInfo[
'showHiddenRecords'])) {
263 $queryBuilder->getRestrictions()->removeByType(HiddenRestriction::class);
266 $res = $queryBuilder->select(
'*')
267 ->from($this->db_groups[
'table'])
269 $queryBuilder->expr()->in(
271 $queryBuilder->createNamedParameter($groups, Connection::PARAM_INT_ARRAY)
273 $queryBuilder->expr()->orX(
274 $queryBuilder->expr()->eq(
276 $queryBuilder->createNamedParameter(
'', \PDO::PARAM_STR)
278 $queryBuilder->expr()->isNull(
'lockToDomain'),
279 $queryBuilder->expr()->eq(
281 $queryBuilder->createNamedParameter($this->authInfo[
'HTTP_HOST'], \PDO::PARAM_STR)
287 while ($row = $res->fetch()) {
288 $groupDataArr[$row[
'uid']] = $row;
291 $this->logger->debug(
'No usergroups found.');
294 return $groupDataArr;
310 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
'fe_groups');
311 if (!empty($this->authInfo[
'showHiddenRecords'])) {
312 $queryBuilder->getRestrictions()->removeByType(HiddenRestriction::class);
316 ->select(
'uid',
'subgroup')
317 ->from($this->db_groups[
'table'])
319 $queryBuilder->expr()->in(
321 $queryBuilder->createNamedParameter(
322 GeneralUtility::intExplode(
',', $grList,
true),
323 Connection::PARAM_INT_ARRAY
326 $queryBuilder->expr()->orX(
327 $queryBuilder->expr()->eq(
329 $queryBuilder->createNamedParameter(
'', \PDO::PARAM_STR)
331 $queryBuilder->expr()->isNull(
'lockToDomain'),
332 $queryBuilder->expr()->eq(
334 $queryBuilder->createNamedParameter($this->authInfo[
'HTTP_HOST'], \PDO::PARAM_STR)
343 while ($row = $res->fetch()) {
344 if (!in_array($row[
'uid'], $groups)) {
345 $groups[] = $row[
'uid'];
347 $groupRows[$row[
'uid']] = $row;
350 $include_staticArr = GeneralUtility::intExplode(
',', $grList);
352 foreach ($include_staticArr as $uid) {
354 $row = $groupRows[$uid];
356 if (is_array($row) && !GeneralUtility::inList($idList, $uid) && trim($row[
'subgroup'])) {
358 $theList = implode(
',', GeneralUtility::intExplode(
',', $row[
'subgroup']));
360 $this->
getSubGroups($theList, $idList .
',' . $uid, $groups);
374 $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($table);
377 [
'password' => $newPassword],
380 $this->logger->notice(
'Automatic password update for user record in ' . $table .
' with uid ' . $uid);
395 if (!empty($params)) {
396 $message = vsprintf($message, $params);
398 $message = str_replace(
'###IP###', (
string)GeneralUtility::getIndpEnv(
'REMOTE_ADDR'), $message);
399 if (TYPO3_MODE ===
'FE') {
400 $timeTracker = GeneralUtility::makeInstance(TimeTracker::class);
401 $timeTracker->setTSlogMessage($message);
403 $this->logger->notice($message);