diff --git a/typo3/sysext/extbase/Classes/Mvc/Request.php b/typo3/sysext/extbase/Classes/Mvc/Request.php index ebddbfedfea5ac65166901834deeef1c1a553019..1b06e3b8e6ec983ad0195493a0187418ffee51d9 100644 --- a/typo3/sysext/extbase/Classes/Mvc/Request.php +++ b/typo3/sysext/extbase/Classes/Mvc/Request.php @@ -390,27 +390,8 @@ class Request implements RequestInterface $this->internalArguments[$argumentName] = $value; return; } - switch ($argumentName) { - case '@extension': - $this->setControllerExtensionName($value); - break; - case '@subpackage': - $this->setControllerSubpackageKey($value); - break; - case '@controller': - $this->setControllerName($value); - break; - case '@action': - $this->setControllerActionName($value); - break; - case '@format': - $this->setFormat($value); - break; - case '@vendor': - $this->setControllerVendorName($value); - break; - default: - $this->arguments[$argumentName] = $value; + if ($argumentName[0] !== '@') { + $this->arguments[$argumentName] = $value; } } diff --git a/typo3/sysext/extbase/Classes/Mvc/Web/ReferringRequest.php b/typo3/sysext/extbase/Classes/Mvc/Web/ReferringRequest.php new file mode 100644 index 0000000000000000000000000000000000000000..085b67dce4ffb49706b968735fc7fa45f1aa687c --- /dev/null +++ b/typo3/sysext/extbase/Classes/Mvc/Web/ReferringRequest.php @@ -0,0 +1,56 @@ +<?php +namespace TYPO3\CMS\Extbase\Mvc\Web; + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +/** + * Represents a referring web request. + * + * @api + */ +class ReferringRequest extends Request +{ + /** + * Sets the value of the specified argument + * + * @param string $argumentName Name of the argument to set + * @param mixed $value The new value + */ + public function setArgument($argumentName, $value) + { + parent::setArgument($argumentName, $value); + + switch ($argumentName) { + case '@extension': + $this->setControllerExtensionName($value); + break; + case '@subpackage': + $this->setControllerSubpackageKey($value); + break; + case '@controller': + $this->setControllerName($value); + break; + case '@action': + $this->setControllerActionName($value); + break; + case '@format': + $this->setFormat($value); + break; + case '@vendor': + $this->setControllerVendorName($value); + break; + } + } + +} diff --git a/typo3/sysext/extbase/Classes/Mvc/Web/Request.php b/typo3/sysext/extbase/Classes/Mvc/Web/Request.php index bafa350eb20cfe65db54626436409ccd391efa5c..0481910c015f3d1834608760385aac06a517e1bb 100644 --- a/typo3/sysext/extbase/Classes/Mvc/Web/Request.php +++ b/typo3/sysext/extbase/Classes/Mvc/Web/Request.php @@ -183,20 +183,18 @@ class Request extends \TYPO3\CMS\Extbase\Mvc\Request /** * Get a freshly built request object pointing to the Referrer. * - * @return Request the referring request, or NULL if no referrer found + * @return ReferringRequest the referring request, or null if no referrer found */ public function getReferringRequest() { - if (isset($this->internalArguments['__referrer']) && is_array($this->internalArguments['__referrer'])) { - $referrerArray = $this->internalArguments['__referrer']; - $referringRequest = new \TYPO3\CMS\Extbase\Mvc\Web\Request(); + if (isset($this->internalArguments['__referrer']['@request'])) { + $referrerArray = unserialize($this->hashService->validateAndStripHmac($this->internalArguments['__referrer']['@request'])); $arguments = array(); - if (isset($referrerArray['arguments'])) { - $serializedArgumentsWithHmac = $referrerArray['arguments']; - $serializedArguments = $this->hashService->validateAndStripHmac($serializedArgumentsWithHmac); - $arguments = unserialize(base64_decode($serializedArguments)); - unset($referrerArray['arguments']); + if (isset($this->internalArguments['__referrer']['arguments'])) { + // This case is kept for compatibility in 7.6 and 6.2, but will be removed in 8 + $arguments = unserialize(base64_decode($this->hashService->validateAndStripHmac($this->internalArguments['__referrer']['arguments']))); } + $referringRequest = new ReferringRequest(); $referringRequest->setArguments(\TYPO3\CMS\Extbase\Utility\ArrayUtility::arrayMergeRecursiveOverrule($arguments, $referrerArray)); return $referringRequest; } diff --git a/typo3/sysext/fluid/Classes/ViewHelpers/FormViewHelper.php b/typo3/sysext/fluid/Classes/ViewHelpers/FormViewHelper.php index a0ad3e41aa80ead4128d7c95cfbf46af1820ae09..ea757f52708ed4e9f0c437446890fec29b37725b 100644 --- a/typo3/sysext/fluid/Classes/ViewHelpers/FormViewHelper.php +++ b/typo3/sysext/fluid/Classes/ViewHelpers/FormViewHelper.php @@ -71,6 +71,11 @@ class FormViewHelper extends \TYPO3\CMS\Fluid\ViewHelpers\Form\AbstractFormViewH */ protected $formActionUriArguments; + /** + * @var bool + */ + private $securedReferrerFieldRendered = false; + /** * @param \TYPO3\CMS\Extbase\Security\Cryptography\HashService $hashService */ @@ -159,6 +164,7 @@ class FormViewHelper extends \TYPO3\CMS\Fluid\ViewHelpers\Form\AbstractFormViewH $content .= $this->renderHiddenIdentityField($this->arguments['object'], $this->getFormObjectName()); $content .= $this->renderAdditionalIdentityFields(); $content .= $this->renderHiddenReferrerFields(); + $content .= $this->renderHiddenSecuredReferrerField(); // Render the trusted list of all properties after everything else has been rendered $content .= $this->renderTrustedPropertiesField(); @@ -232,7 +238,38 @@ class FormViewHelper extends \TYPO3\CMS\Fluid\ViewHelpers\Form\AbstractFormViewH $result .= '<input type="hidden" name="' . $this->prefixFieldName('__referrer[@controller]') . '" value="' . $controllerName . '" />' . LF; $result .= '<input type="hidden" name="' . $this->prefixFieldName('__referrer[@action]') . '" value="' . $actionName . '" />' . LF; $result .= '<input type="hidden" name="' . $this->prefixFieldName('__referrer[arguments]') . '" value="' . htmlspecialchars($this->hashService->appendHmac(base64_encode(serialize($request->getArguments())))) . '" />' . LF; + $result .= $this->renderHiddenSecuredReferrerField(); + + return $result; + } + /** + * Renders hidden form field for secured referrer information about the current controller and action. + * + * This method is called twice, to deal with subclasses of this class in a most compatible way + * + * @return string Hidden field with secured referrer information + */ + protected function renderHiddenSecuredReferrerField() + { + if ($this->securedReferrerFieldRendered) { + return ''; + } + $request = $this->renderingContext->getControllerContext()->getRequest(); + $extensionName = $request->getControllerExtensionName(); + $vendorName = $request->getControllerVendorName(); + $controllerName = $request->getControllerName(); + $actionName = $request->getControllerActionName(); + $actionRequest = [ + '@extension' => $extensionName, + '@controller' => $controllerName, + '@action' => $actionName, + ]; + if ($vendorName !== null) { + $actionRequest['@vendor'] = $vendorName; + } + $result = '<input type="hidden" name="' . $this->prefixFieldName('__referrer[@request]') . '" value="' . htmlspecialchars($this->hashService->appendHmac(serialize($actionRequest))) . '" />' . LF; + $this->securedReferrerFieldRendered = true; return $result; } diff --git a/typo3/sysext/fluid/Tests/Unit/ViewHelpers/FormViewHelperTest.php b/typo3/sysext/fluid/Tests/Unit/ViewHelpers/FormViewHelperTest.php index cd7d0019c357fb673616b38a4847595e09e3b71a..d6ac7c26835e88357ee857f022a3f55e916b3f05 100644 --- a/typo3/sysext/fluid/Tests/Unit/ViewHelpers/FormViewHelperTest.php +++ b/typo3/sysext/fluid/Tests/Unit/ViewHelpers/FormViewHelperTest.php @@ -88,7 +88,7 @@ class FormViewHelperTest extends ViewHelperBaseTestcase public function renderAddsObjectToViewHelperVariableContainer() { $formObject = new \stdClass(); - $viewHelper = $this->getAccessibleMock(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class, array('renderChildren', 'renderHiddenIdentityField', 'renderAdditionalIdentityFields', 'renderHiddenReferrerFields', 'renderRequestHashField', 'addFormObjectNameToViewHelperVariableContainer', 'addFieldNamePrefixToViewHelperVariableContainer', 'removeFormObjectNameFromViewHelperVariableContainer', 'removeFieldNamePrefixFromViewHelperVariableContainer', 'addFormFieldNamesToViewHelperVariableContainer', 'removeFormFieldNamesFromViewHelperVariableContainer', 'renderTrustedPropertiesField'), array(), '', false); + $viewHelper = $this->getAccessibleMock(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class, array('renderChildren', 'renderHiddenIdentityField', 'renderAdditionalIdentityFields', 'renderHiddenReferrerFields', 'renderHiddenSecuredReferrerField', 'renderRequestHashField', 'addFormObjectNameToViewHelperVariableContainer', 'addFieldNamePrefixToViewHelperVariableContainer', 'removeFormObjectNameFromViewHelperVariableContainer', 'removeFieldNamePrefixFromViewHelperVariableContainer', 'addFormFieldNamesToViewHelperVariableContainer', 'removeFormFieldNamesFromViewHelperVariableContainer', 'renderTrustedPropertiesField'), array(), '', false); $this->injectDependenciesIntoViewHelper($viewHelper); $viewHelper->setArguments(array('object' => $formObject)); $this->viewHelperVariableContainer->expects($this->at(0))->method('add')->with(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class, 'formObject', $formObject); @@ -104,7 +104,7 @@ class FormViewHelperTest extends ViewHelperBaseTestcase public function renderAddsObjectNameToTemplateVariableContainer() { $objectName = 'someObjectName'; - $viewHelper = $this->getAccessibleMock(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class, array('renderChildren', 'renderHiddenIdentityField', 'renderHiddenReferrerFields', 'renderRequestHashField', 'addFormObjectToViewHelperVariableContainer', 'addFieldNamePrefixToViewHelperVariableContainer', 'removeFormObjectFromViewHelperVariableContainer', 'removeFieldNamePrefixFromViewHelperVariableContainer', 'addFormFieldNamesToViewHelperVariableContainer', 'removeFormFieldNamesFromViewHelperVariableContainer', 'renderTrustedPropertiesField'), array(), '', false); + $viewHelper = $this->getAccessibleMock(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class, array('renderChildren', 'renderHiddenIdentityField', 'renderHiddenReferrerFields', 'renderHiddenSecuredReferrerField', 'renderRequestHashField', 'addFormObjectToViewHelperVariableContainer', 'addFieldNamePrefixToViewHelperVariableContainer', 'removeFormObjectFromViewHelperVariableContainer', 'removeFieldNamePrefixFromViewHelperVariableContainer', 'addFormFieldNamesToViewHelperVariableContainer', 'removeFormFieldNamesFromViewHelperVariableContainer', 'renderTrustedPropertiesField'), array(), '', false); $this->injectDependenciesIntoViewHelper($viewHelper); $viewHelper->setArguments(array('name' => $objectName)); $this->viewHelperVariableContainer->expects($this->once())->method('add')->with(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class, 'formObjectName', $objectName); @@ -167,7 +167,7 @@ class FormViewHelperTest extends ViewHelperBaseTestcase */ public function renderWrapsHiddenFieldsWithDivForXhtmlCompatibilityWithRewrittenPropertyMapper() { - $viewHelper = $this->getAccessibleMock($this->buildAccessibleProxy(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class), array('renderChildren', 'renderHiddenIdentityField', 'renderAdditionalIdentityFields', 'renderHiddenReferrerFields', 'renderTrustedPropertiesField'), array(), '', false); + $viewHelper = $this->getAccessibleMock($this->buildAccessibleProxy(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class), array('renderChildren', 'renderHiddenIdentityField', 'renderAdditionalIdentityFields', 'renderHiddenReferrerFields', 'renderHiddenSecuredReferrerField', 'renderTrustedPropertiesField'), array(), '', false); $this->mvcPropertyMapperConfigurationService->_set('hashService', new \TYPO3\CMS\Extbase\Security\Cryptography\HashService()); $viewHelper->_set('mvcPropertyMapperConfigurationService', $this->mvcPropertyMapperConfigurationService); parent::injectDependenciesIntoViewHelper($viewHelper); @@ -185,7 +185,7 @@ class FormViewHelperTest extends ViewHelperBaseTestcase */ public function renderWrapsHiddenFieldsWithDivAndAnAdditionalClassForXhtmlCompatibilityWithRewrittenPropertyMapper() { - $viewHelper = $this->getMock($this->buildAccessibleProxy(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class), array('renderChildren', 'renderHiddenIdentityField', 'renderAdditionalIdentityFields', 'renderHiddenReferrerFields', 'renderTrustedPropertiesField'), array(), '', false); + $viewHelper = $this->getMock($this->buildAccessibleProxy(\TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper::class), array('renderChildren', 'renderHiddenIdentityField', 'renderAdditionalIdentityFields', 'renderHiddenReferrerFields', 'renderHiddenSecuredReferrerField', 'renderTrustedPropertiesField'), array(), '', false); $this->mvcPropertyMapperConfigurationService->_set('hashService', new \TYPO3\CMS\Extbase\Security\Cryptography\HashService()); $viewHelper->_set('mvcPropertyMapperConfigurationService', $this->mvcPropertyMapperConfigurationService); parent::injectDependenciesIntoViewHelper($viewHelper); @@ -228,7 +228,11 @@ class FormViewHelperTest extends ViewHelperBaseTestcase $this->request->expects($this->atLeastOnce())->method('getControllerName')->will($this->returnValue('controllerName')); $this->request->expects($this->atLeastOnce())->method('getControllerActionName')->will($this->returnValue('controllerActionName')); $hiddenFields = $viewHelper->_call('renderHiddenReferrerFields'); - $expectedResult = chr(10) . '<input type="hidden" name="__referrer[@extension]" value="extensionName" />' . chr(10) . '<input type="hidden" name="__referrer[@controller]" value="controllerName" />' . chr(10) . '<input type="hidden" name="__referrer[@action]" value="controllerActionName" />' . chr(10) . '<input type="hidden" name="__referrer[arguments]" value="" />' . chr(10); + $expectedResult = chr(10) . '<input type="hidden" name="__referrer[@extension]" value="extensionName" />' + . chr(10) . '<input type="hidden" name="__referrer[@controller]" value="controllerName" />' + . chr(10) . '<input type="hidden" name="__referrer[@action]" value="controllerActionName" />' + . chr(10) . '<input type="hidden" name="__referrer[arguments]" value="" />' + . chr(10) . '<input type="hidden" name="__referrer[@request]" value="" />' . chr(10); $this->assertEquals($expectedResult, $hiddenFields); }