Fixed bug #17383: Open forms cannot be saved after "Relogin" (Security Token errors...
authorsteffenk <steffenk@709f56b5-9817-0410-a4d7-c38de5d9e867>
Mon, 21 Feb 2011 19:09:46 +0000 (19:09 +0000)
committersteffenk <steffenk@709f56b5-9817-0410-a4d7-c38de5d9e867>
Mon, 21 Feb 2011 19:09:46 +0000 (19:09 +0000)
git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@10520 709f56b5-9817-0410-a4d7-c38de5d9e867

ChangeLog
t3lib/class.t3lib_befunc.php
t3lib/class.t3lib_pagerenderer.php
t3lib/class.t3lib_tceforms.php
t3lib/config_default.php
t3lib/formprotection/class.t3lib_formprotection_backendformprotection.php
typo3/classes/class.ajaxlogin.php
typo3/index.php
typo3/js/extjs/viewportConfiguration.js
typo3/js/loginrefresh.js

index 2535f25..474f390 100755 (executable)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,6 @@
 2011-02-21  Steffen Kamper  <steffen@typo3.org
 
+       * Fixed bug #17383: Open forms cannot be saved after "Relogin" (Security Token errors) (Thanks to Helmut Hummel)
        * Fixed bug #17684 Admin Panel renders invalid markup (Thanks to Markus Klein)
 
 2011-02-20  Steffen Kamper  <steffen@typo3.org
index 3bffa39..01c553b 100644 (file)
@@ -3333,7 +3333,7 @@ final class t3lib_BEfunc {
         */
        public static function getUrlToken($formName = 'securityToken', $tokenName = 'formToken') {
                $formprotection = t3lib_formprotection_Factory::get();
-               return '&' . $tokenName . '=' . $formprotection->generateToken($formName);
+               return '&' . $tokenName . '=' . $formprotection->generateToken($formName) . '-' . $formName;
        }
 
        /*******************************************
index 534c7ba..dd536a5 100644 (file)
@@ -986,7 +986,7 @@ class t3lib_PageRenderer implements t3lib_Singleton {
                        // does this only with multiple arguments
                $this->addExtOnReadyCode('
                        (function() {
-                               TYPO3.ExtDirectToken = "' . $token . '";
+                               TYPO3.ExtDirectToken = "' . $token . '-extDirect";
                                for (var api in Ext.app.ExtDirectAPI) {
                                        var provider = Ext.Direct.addProvider(Ext.app.ExtDirectAPI[api]);
                                        provider.on("beforecall", function(provider, transaction, meta) {
index 9af7a11..f883256 100644 (file)
@@ -4983,7 +4983,7 @@ class t3lib_TCEforms {
         */
        public static function getHiddenTokenField($formName = 'securityToken', $tokenName = 'formToken') {
                $formprotection = t3lib_formprotection_Factory::get();
-               return '<input type="hidden" name="' .$tokenName . '" value="' . $formprotection->generateToken($formName) . '" />';
+               return '<input type="hidden" name="' .$tokenName . '" value="' . $formprotection->generateToken($formName) . '-' . $formName . '" />';
        }
 
        /**
index 271cc59..258124e 100644 (file)
@@ -510,6 +510,7 @@ $TYPO3_CONF_VARS = array(
                        'BackendLogin::refreshLogin'            => 'typo3/classes/class.ajaxlogin.php:AjaxLogin->refreshLogin',
                        'BackendLogin::isTimedOut'                      => 'typo3/classes/class.ajaxlogin.php:AjaxLogin->isTimedOut',
                        'BackendLogin::getChallenge'            => 'typo3/classes/class.ajaxlogin.php:AjaxLogin->getChallenge',
+                       'BackendLogin::refreshTokens'           => 'typo3/classes/class.ajaxlogin.php:AjaxLogin->refreshTokens',
                        'DonateWindow::disable'                         => 'typo3/classes/class.donatewindow.php:DonateWindow->disable',
                        'DonateWindow::postpone'                        => 'typo3/classes/class.donatewindow.php:DonateWindow->postpone',
                        'ExtDirect::getAPI' => 't3lib/extjs/class.t3lib_extjs_extdirectapi.php:t3lib_extjs_ExtDirectApi->getAPI',
index 8af6d8d..4d167d8 100644 (file)
@@ -152,6 +152,20 @@ class t3lib_formprotection_BackendFormProtection extends t3lib_formprotection_Ab
        }
 
        /**
+        * Override the abstract class to be able to strip out
+        * the token id from the POST variable.
+        *
+        * @see t3lib/formprotection/t3lib_formprotection_Abstract::validateToken()
+        */
+       public function validateToken(
+               $token, $formName, $action = '', $formInstanceName = ''
+       ) {
+               list($tokenId, $_) = explode('-', (string)$token);
+
+               return parent::validateToken($tokenId, $formName, $action, $formInstanceName);
+       }
+
+       /**
         * Creates or displayes an error message telling the user that the submitted
         * form token is invalid.
         *
index ff3e1a9..d56dd8c 100644 (file)
@@ -43,14 +43,14 @@ class AjaxLogin {
         * @return      void
         */
        public function login(array $parameters, TYPO3AJAX $ajaxObj) {
-               if ($GLOBALS['BE_USER']->user['uid']) {
-                       $formprotection = t3lib_formprotection_Factory::get();
-                       $token = $formprotection->generateToken('extDirect');
-
-                       $json = array(
-                               'success' => TRUE,
-                               'token' => $token
-                       );
+               if ($this->isAuthorizedBackendSession()) {
+                       $json = array('success' => TRUE);
+                       $token = '';
+                       if ($this->hasLoginBeenProcessed()) {
+                               $formprotection = t3lib_formprotection_Factory::get();
+                               $json['accessToken'] = $formprotection->generateToken('refreshTokens');
+                               $formprotection->persistTokens();
+                       }
                } else {
                        $json = array('success' => FALSE);
                }
@@ -59,6 +59,30 @@ class AjaxLogin {
        }
 
        /**
+        * Checks if a user is logged in and the session is active.
+        *
+        * @return boolean
+        */
+       protected function isAuthorizedBackendSession() {
+               return (isset($GLOBALS['BE_USER']) && $GLOBALS['BE_USER'] instanceof t3lib_beUserAuth && isset($GLOBALS['BE_USER']->user['uid']));
+       }
+
+       /**
+        * Check whether the user was not already authorized
+        *
+        * @return boolean
+        */
+       protected function hasLoginBeenProcessed() {
+               $loginFormData = $GLOBALS['BE_USER']->getLoginFormData();
+
+               return ($loginFormData['status'] == 'login')
+                       && isset($loginFormData['uname'])
+                       && isset($loginFormData['uident'])
+                       && isset($loginFormData['chalvalue'])
+                       && ((string)$_COOKIE['be_typo_user'] !== (string)$GLOBALS['BE_USER']->id);
+       }
+
+       /**
         * Logs out the current BE user
         *
         * @param       array           $parameters: Parameters (not used)
@@ -140,6 +164,43 @@ class AjaxLogin {
                $parent->addContent('challenge', $_SESSION['login_challenge']);
                $parent->setContentFormat('json');
        }
+
+       /**
+        * Generates new tokens for the ones found in the DOM.
+        *
+        * @param       array           $parameters: Parameters (not used)
+        * @param       TYPO3AJAX       $parent: The calling parent AJAX object
+        */
+       public function refreshTokens(array $parameters, TYPO3AJAX $parent) {
+               $accessToken = (string)t3lib_div::_GP('accessToken');
+               $formprotection = t3lib_formprotection_Factory::get();
+
+               if ($formprotection->validateToken($accessToken, 'refreshTokens')) {
+                       $oldTokens = json_decode((string)t3lib_div::_GP('tokens'));
+                       $regeneratedTokens = new stdClass();
+
+                       foreach ($oldTokens as $oldToken) {
+                               $newToken = $this->generateNewToken($oldToken);
+                               $regeneratedTokens->$oldToken = $newToken;
+                       }
+               }
+               $parent->addContent('newTokens', $regeneratedTokens);
+               $parent->setContentFormat('json');
+
+               $formprotection->persistTokens();
+       }
+
+       /**
+        * Generate new token.
+        *
+        * @param string $oldToken
+        * @return string regenerated Token
+        */
+       protected function generateNewToken($oldToken) {
+               list ($tokenId, $formName) = explode('-', $oldToken);
+               return t3lib_formprotection_Factory::get()->generateToken($formName) . '-' . $formName;
+       }
+
 }
 
 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['typo3/classes/class.ajaxlogin.php'])) {
index f9d11d1..3b594cd 100644 (file)
@@ -398,7 +398,8 @@ class SC_index {
                                t3lib_utility_Http::redirect($this->redirectToURL);
                        } else {
                                $formprotection = t3lib_formprotection_Factory::get();
-                               $token = $formprotection->generateToken('extDirect');
+                               $accessToken = $formprotection->generateToken('refreshTokens');
+                               $formprotection->persistTokens();
                                $TBE_TEMPLATE->JScode.=$TBE_TEMPLATE->wrapScriptTags('
                                        if (parent.opener && (parent.opener.busy || parent.opener.TYPO3.loginRefresh)) {
                                                if (parent.opener.TYPO3.loginRefresh) {
@@ -406,7 +407,7 @@ class SC_index {
                                                } else {
                                                        parent.opener.busy.loginRefreshed();
                                                }
-                                               parent.opener.TYPO3.ExtDirectToken = "' . $token . '";
+                                               parent.opener.TYPO3.loginRefresh.refreshTokens("' . $accessToken . '");
                                                parent.close();
                                        }
                                ');
index ee256ba..13a0a28 100644 (file)
@@ -89,7 +89,8 @@ TYPO3.Viewport.configuration = {
                                                        id: 'typo3-navigationIframe',
                                                        border: false,
                                                        hidden: true,
-                                                       xtype: 'iframePanel'
+                                                       xtype: 'iframePanel',
+                                                       name: 'navigation'
                                                }
                                        ]
                                },
index 854fd0a..ef35ce5 100644 (file)
@@ -226,7 +226,7 @@ Ext.ux.TYPO3.loginRefresh = Ext.extend(Ext.util.Observable, {
                                control.updateText(String.format(TYPO3.LLL.core.refresh_login_countdown, rest));
                        }
                });
-               
+
                this.loginRefreshWindow.on('close', function(){
                        TYPO3.loginRefresh.startTimer();
                });
@@ -306,7 +306,7 @@ Ext.ux.TYPO3.loginRefresh = Ext.extend(Ext.util.Observable, {
                                                // User is logged in
                                                Ext.getCmp("loginformWindow").hide();
                                                TYPO3.loginRefresh.startTimer();
-                                               TYPO3.ExtDirectToken = result.token;
+                                               TYPO3.loginRefresh.refreshTokens(result.accessToken);
                                        } else {
                                                // TODO: add failure to notification system instead of alert
                                                Ext.Msg.alert(TYPO3.LLL.core.refresh_login_failed, TYPO3.LLL.core.refresh_login_failed_message);
@@ -337,6 +337,97 @@ Ext.ux.TYPO3.loginRefresh = Ext.extend(Ext.util.Observable, {
                } else {
                        this.submitForm();
                }
+       },
+
+       getOutdatedTokens: function() {
+               var tokens = [];
+               var searchTokenPlaces = [top, top.content.document];
+
+               if (top.nav instanceof TYPO3.iframePanel) {
+                       searchTokenPlaces.push(top.nav.getIframe());
+               }
+
+               Ext.each(searchTokenPlaces, function(searchPlace) {
+                       var links = searchPlace.Ext.query('a[href*=formToken]');
+                       Ext.each(links, function(linkTag) {
+                               tokens.push(Ext.urlDecode(linkTag.href).formToken);
+                       });
+
+                       var formFields = searchPlace.Ext.query("form input[name=formToken]");
+                       Ext.each(formFields, function(inputField) {
+                               tokens.push(inputField.value);
+                       });
+
+                       var linksOnclick = searchPlace.Ext.query('a[onclick*=formToken]');
+                       Ext.each(linksOnclick, function(linkTag) {
+                               tokens.push(linkTag.attributes.onclick.value.match(/&formToken=([^&]*)&/).pop());
+                       });
+
+                       if (Ext.isString(searchPlace.TYPO3.ExtDirectToken)) {
+                               tokens.push(searchPlace.TYPO3.ExtDirectToken);
+                       }
+
+               });
+
+               return tokens;
+       },
+
+       replaceOutdatedTokens: function(newTokens) {
+               var searchTokenPlaces = [top, top.content.document];
+
+               if (top.nav instanceof TYPO3.iframePanel) {
+                       searchTokenPlaces.push(top.nav.getIframe());
+               }
+
+               Ext.each(searchTokenPlaces, function(searchPlace) {
+                       var links = searchPlace.Ext.query('a[href*=formToken]');
+                       Ext.each(links, function(linkTag) {
+                               var url = Ext.urlDecode(linkTag.href);
+                               url.formToken = newTokens[url.formToken];
+                               linkTag.href = unescape(Ext.urlEncode(url));
+                       });
+
+                       var formFields = searchPlace.Ext.query("form input[name=formToken]");
+                       Ext.each(formFields, function(inputField) {
+                               inputField.value = newTokens[inputField.value];
+                       });
+
+                       var linksOnclick = searchPlace.Ext.query('a[onclick*=formToken]');
+                       Ext.each(linksOnclick, function(linkTag) {
+                               var token = linkTag.attributes.onclick.value.match(/&formToken=([^&]*)&/).pop();
+                               linkTag.attributes.onclick.value = linkTag.attributes.onclick.value.replace(new RegExp(token), newTokens[token]);
+                       });
+
+                       if (Ext.isString(searchPlace.TYPO3.ExtDirectToken)) {
+                               searchPlace.TYPO3.ExtDirectToken = newTokens[searchPlace.TYPO3.ExtDirectToken];
+                       }
+               });
+       },
+
+       refreshTokens: function(accessToken) {
+               Ext.Ajax.request({
+                       url: "ajax.php",
+                       params: {
+                               "ajaxID": "BackendLogin::refreshTokens",
+                               "accessToken": accessToken,
+                               "tokens": Ext.encode(this.getOutdatedTokens())
+                       },
+                       method: "POST",
+                       scope: this,
+                       success: function(response, opts) {
+                               var result = Ext.util.JSON.decode(response.responseText);
+                               TYPO3.loginRefresh.replaceOutdatedTokens(result.newTokens);
+                       },
+                       failure: function(response, opts) {
+                               TYPO3.Flashmessage.display(
+                                               TYPO3.Severity.error,
+                                               'Refresh tokens',
+                                               'Refreshing tokens after relogin faild. Please reload the backend.',
+                                               30
+                                       );
+                       }
+
+               });
        }
 });