[BUGFIX] Switch-User feature uses wrong user id for logging 89/45489/4
authorOliver Hader <oliver@typo3.org>
Tue, 29 Dec 2015 14:07:12 +0000 (15:07 +0100)
committerFrank Naegler <frank.naegler@typo3.org>
Fri, 26 Feb 2016 15:10:35 +0000 (16:10 +0100)
Issue #17643 introduced logging for a simulated backend user
(switch-user) and thus logs by using the original admin user.

This is a regression in PageLayoutController::renderQuickEdit
since the used backend user id is different to the persisted
one. Besides that, all actions are performed with the permissions
of the simulated user - thus, logging with a different user seems
to wrong. The sys_log.log_data field (array) is used to transport
the information of the original (admin) user.

This change reverts the initial change of issue #17643 and adds
the initial intention of that issue as addition to the persisted
data in sys_log.log_data. All affected components are adjusted as
well to visualize that a user has been simulated (log view, record
history and lowlevel_cleaner syslog command).

Resolves: #71580
Releases: master, 7.6
Change-Id: If12df60563afd1f0746d43e62f824b20f139df8c
Reviewed-on: https://review.typo3.org/45489
Reviewed-by: Frank Naegler <frank.naegler@typo3.org>
Tested-by: Frank Naegler <frank.naegler@typo3.org>
typo3/sysext/backend/Classes/History/RecordHistory.php
typo3/sysext/belog/Resources/Private/Language/locallang.xlf
typo3/sysext/belog/Resources/Private/Partials/Content/LogEntries.html
typo3/sysext/core/Classes/Authentication/BackendUserAuthentication.php
typo3/sysext/core/Classes/Error/AbstractExceptionHandler.php
typo3/sysext/core/Classes/Error/ErrorHandler.php
typo3/sysext/lang/locallang_show_rechis.xlf
typo3/sysext/lowlevel/Classes/SyslogCommand.php

index 4cf7d1e..3e541a2 100644 (file)
@@ -454,9 +454,17 @@ class RecordHistory
             }
             $i++;
             // Get user names
-            $userName = $entry['user'] ? $beUserArray[$entry['user']]['username'] : $languageService->getLL('externalChange', true);
             // Build up single line
             $singleLine = array();
+            $userName = $entry['user'] ? $beUserArray[$entry['user']]['username'] : $languageService->getLL('externalChange');
+            // Executed by switch-user
+            if (!empty($entry['originalUser'])) {
+                $userName .= ' (' . $languageService->getLL('viaUser') . ' ' . $beUserArray[$entry['originalUser']]['username'] . ')';
+            }
+            $singleLine['backendUserName'] = htmlspecialchars($userName);
+            $singleLine['backendUserUid'] = $entry['user'];
+            // add user name
+
             // Diff link
             $image = '<span title="' . $languageService->getLL('sumUpChanges', true) . '">' . $this->iconFactory->getIcon('actions-document-history-open', Icon::SIZE_SMALL)->render() . '</span>';
             $singleLine[] = '<span>' . $this->linkPage($image, array('diff' => $sysLogUid)) . '</span>';
@@ -763,7 +771,7 @@ class RecordHistory
         $databaseConnection = $this->getDatabaseConnection();
         $uid = $this->resolveElement($table, $uid);
         // Selecting the $this->maxSteps most recent states:
-        $rows = $databaseConnection->exec_SELECTgetRows('sys_history.*, sys_log.userid', 'sys_history, sys_log', 'sys_history.sys_log_uid = sys_log.uid
+        $rows = $databaseConnection->exec_SELECTgetRows('sys_history.*, sys_log.userid, sys_log.log_data', 'sys_history, sys_log', 'sys_history.sys_log_uid = sys_log.uid
                                                AND sys_history.tablename = ' . $databaseConnection->fullQuoteStr($table, 'sys_history') . '
                                                AND sys_history.recuid = ' . (int)$uid, '', 'sys_log.uid DESC', $this->maxSteps);
         $changeLog = array();
@@ -775,11 +783,13 @@ class RecordHistory
                     continue;
                 }
                 $hisDat = unserialize($row['history_data']);
+                $logData = unserialize($row['log_data']);
                 if (is_array($hisDat['newRecord']) && is_array($hisDat['oldRecord'])) {
                     // Add information about the history to the changeLog
                     $hisDat['uid'] = $row['uid'];
                     $hisDat['tstamp'] = $row['tstamp'];
                     $hisDat['user'] = $row['userid'];
+                    $hisDat['originalUser'] = (empty($logData['originalUser']) ? null : $logData['originalUser']);
                     $hisDat['snapshot'] = $row['snapshot'];
                     $hisDat['fieldlist'] = $row['fieldlist'];
                     $hisDat['tablename'] = $row['tablename'];
@@ -795,7 +805,7 @@ class RecordHistory
         // SELECT INSERTS/DELETES
         if ($this->showInsertDelete) {
             // Select most recent inserts and deletes // WITHOUT snapshots
-            $rows = $databaseConnection->exec_SELECTgetRows('uid, userid, action, tstamp', 'sys_log', 'type = 1
+            $rows = $databaseConnection->exec_SELECTgetRows('uid, userid, action, tstamp, log_data', 'sys_log', 'type = 1
                                                AND (action=1 OR action=3)
                                                AND tablename = ' . $databaseConnection->fullQuoteStr($table, 'sys_log') . '
                                                AND recuid = ' . (int)$uid, '', 'uid DESC', $this->maxSteps);
@@ -808,6 +818,7 @@ class RecordHistory
                     continue;
                 }
                 $hisDat = array();
+                $logData = unserialize($row['log_data']);
                 switch ($row['action']) {
                     case 1:
                         // Insert
@@ -820,6 +831,7 @@ class RecordHistory
                 }
                 $hisDat['tstamp'] = $row['tstamp'];
                 $hisDat['user'] = $row['userid'];
+                $hisDat['originalUser'] = (empty($logData['originalUser']) ? null : $logData['originalUser']);
                 $hisDat['tablename'] = $table;
                 $hisDat['recuid'] = $uid;
                 $changeLog[$row['uid']] = $hisDat;
index 991fcc5..9cc1464 100644 (file)
@@ -12,6 +12,9 @@
                        <trans-unit id="any">
                                <source>[Any]</source>
                        </trans-unit>
+                       <trans-unit id="viaUser">
+                               <source>via</source>
+                       </trans-unit>
                        <trans-unit id="live">
                                <source>LIVE</source>
                        </trans-unit>
index 5a4be25..cfd33ba 100755 (executable)
                                                                <f:if condition="{belog:username(uid:logItem.backendUserUid)}">
                                                                        <f:then><belog:username uid="{logItem.backendUserUid}" /></f:then>
                                                                        <f:else>[{logItem.backendUserUid}]</f:else>
-                                                               </f:if><br>
+                                                               </f:if>
+                                                               <f:if condition="{logItem.logData.originalUser}">
+                                                                       ({f:translate(key:'viaUser')} <f:if condition="{belog:username(uid:logItem.backendUserUid)}"><f:then><belog:username uid="{logItem.backendUserUid}" /></f:then><f:else>[{logItem.backendUserUid}]</f:else></f:if>)
+                                                               </f:if>
+                                                               <br>
                                                                <span class="text-muted">
                                                                        <f:if condition="{belog:workspaceTitle(uid:logItem.workspaceUid)}">
                                                                                <f:then><belog:workspaceTitle uid="{logItem.workspaceUid}" /></f:then>
index 77f194b..5ef7657 100644 (file)
@@ -2177,13 +2177,15 @@ class BackendUserAuthentication extends \TYPO3\CMS\Core\Authentication\AbstractU
      */
     public function writelog($type, $action, $error, $details_nr, $details, $data, $tablename = '', $recuid = '', $recpid = '', $event_pid = -1, $NEWid = '', $userId = 0)
     {
-        if (!$userId) {
-            // Use the original user's ID in case of a user switch
-            if (!empty($this->user['ses_backuserid'])) {
-                $userId = $this->user['ses_backuserid'];
-            } elseif (!empty($this->user['uid'])) {
-                $userId = $this->user['uid'];
+        if (!$userId && !empty($this->user['uid'])) {
+            $userId = $this->user['uid'];
+        }
+
+        if (!empty($this->user['ses_backuserid'])) {
+            if (empty($data)) {
+                $data = array();
             }
+            $data['originalUser'] = $this->user['ses_backuserid'];
         }
 
         $fields_values = array(
index 1e02d2c..b7148e0 100644 (file)
@@ -107,6 +107,7 @@ abstract class AbstractExceptionHandler implements ExceptionHandlerInterface, \T
         }
         $userId = 0;
         $workspace = 0;
+        $data = array();
         $backendUser = $this->getBackendUser();
         if (is_object($backendUser)) {
             if (isset($backendUser->user['uid'])) {
@@ -115,6 +116,9 @@ abstract class AbstractExceptionHandler implements ExceptionHandlerInterface, \T
             if (isset($backendUser->workspace)) {
                 $workspace = $backendUser->workspace;
             }
+            if (!empty($backendUser->user['ses_backuserid'])) {
+                $data['originalUser'] = $backendUser->user['ses_backuserid'];
+            }
         }
         $fields_values = array(
             'userid' => $userId,
@@ -123,6 +127,7 @@ abstract class AbstractExceptionHandler implements ExceptionHandlerInterface, \T
             'error' => 2,
             'details_nr' => 0,
             'details' => str_replace('%', '%%', $logMessage),
+            'log_data' => (empty($data) ? '' : serialize($data)),
             'IP' => (string)GeneralUtility::getIndpEnv('REMOTE_ADDR'),
             'tstamp' => $GLOBALS['EXEC_TIME'],
             'workspace' => $workspace
index 0c49916..0bd8d9a 100644 (file)
@@ -185,6 +185,7 @@ class ErrorHandler implements ErrorHandlerInterface
         if (is_object($databaseConnection) && $databaseConnection->isConnected()) {
             $userId = 0;
             $workspace = 0;
+            $data = array();
             $backendUser = $this->getBackendUser();
             if (is_object($backendUser)) {
                 if (isset($backendUser->user['uid'])) {
@@ -193,6 +194,9 @@ class ErrorHandler implements ErrorHandlerInterface
                 if (isset($backendUser->workspace)) {
                     $workspace = $backendUser->workspace;
                 }
+                if (!empty($backendUser->user['ses_backuserid'])) {
+                    $data['originalUser'] = $backendUser->user['ses_backuserid'];
+                }
             }
             $fields_values = array(
                 'userid' => $userId,
@@ -201,6 +205,7 @@ class ErrorHandler implements ErrorHandlerInterface
                 'error' => $severity,
                 'details_nr' => 0,
                 'details' => str_replace('%', '%%', $logMessage),
+                'log_data' => (empty($data) ? '' : serialize($data)),
                 'IP' => (string)GeneralUtility::getIndpEnv('REMOTE_ADDR'),
                 'tstamp' => $GLOBALS['EXEC_TIME'],
                 'workspace' => $workspace
index 92a95c6..d9e67c6 100644 (file)
@@ -45,6 +45,9 @@
                        <trans-unit id="externalChange">
                                <source>Intermediate external change!</source>
                        </trans-unit>
+                       <trans-unit id="viaUser">
+                               <source>via</source>
+                       </trans-unit>
                        <trans-unit id="sumUpChanges">
                                <source>Rollback (Preview)</source>
                        </trans-unit>
index bf79fa9..f07871a 100644 (file)
@@ -52,7 +52,11 @@ Showing last 25 hour entries from the syslog. More features pending. This is the
         $rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('*', 'sys_log', 'tstamp>' . ($GLOBALS['EXEC_TIME'] - 25 * 3600));
         foreach ($rows as $r) {
             $l = unserialize($r['log_data']);
-            $explained = '#' . $r['uid'] . ' ' . \TYPO3\CMS\Backend\Utility\BackendUtility::datetime($r['tstamp']) . ' USER[' . $r['userid'] . ']: ' . sprintf($r['details'], $l[0], $l[1], $l[2], $l[3], $l[4], $l[5]);
+            $userInformation = $r['userid'];
+            if (!empty($l['originalUser'])) {
+                $userInformation .= ' via ' . $l['originalUser'];
+            }
+            $explained = '#' . $r['uid'] . ' ' . \TYPO3\CMS\Backend\Utility\BackendUtility::datetime($r['tstamp']) . ' USER[' . $userInformation . ']: ' . sprintf($r['details'], $l[0], $l[1], $l[2], $l[3], $l[4], $l[5]);
             $resultArray['listing'][$r['uid']] = $explained;
             $resultArray['allDetails'][$r['uid']] = array($explained, \TYPO3\CMS\Core\Utility\GeneralUtility::arrayToLogString($r, 'uid,userid,action,recuid,tablename,recpid,error,tstamp,type,details_nr,IP,event_pid,NEWid,workspace'));
         }