[BUGFIX] Deprecated functions used in on fresh 6.0 final
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Security / Channel / RequestHashService.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Security\Channel;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2010-2012 Extbase Team (http://forge.typo3.org/projects/typo3v4-mvc)
8 * Extbase is a backport of TYPO3 Flow. All credits go to the TYPO3 Flow team.
9 * All rights reserved
10 *
11 * This script is part of the TYPO3 project. The TYPO3 project is
12 * free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * The GNU General Public License can be found at
18 * http://www.gnu.org/copyleft/gpl.html.
19 * A copy is found in the textfile GPL.txt and important notices to the license
20 * from the author is found in LICENSE.txt distributed with these scripts.
21 *
22 *
23 * This script is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * This copyright notice MUST APPEAR in all copies of the script!
29 ***************************************************************/
30 /**
31 * This is a Service which can generate a request hash and check whether the currently given arguments
32 * fit to the request hash.
33 *
34 * It is used when forms are generated and submitted:
35 * After a form has been generated, the method "generateRequestHash" is called with the names of all form fields.
36 * It cleans up the array of form fields and creates another representation of it, which is then serialized and hashed.
37 *
38 * Both serialized form field list and the added hash form the request hash, which will be sent over the wire (as an argument __hmac).
39 *
40 * On the validation side, the validation happens in two steps:
41 * 1) Check if the request hash is consistent (the hash value fits to the serialized string)
42 * 2) Check that _all_ GET/POST parameters submitted occur inside the form field list of the request hash.
43 *
44 * Note: It is crucially important that a private key is computed into the hash value! This is done inside the HashService.
45 *
46 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later
47 */
48 class RequestHashService implements \TYPO3\CMS\Core\SingletonInterface {
49
50 /**
51 * @var \TYPO3\CMS\Extbase\Security\Cryptography\HashService
52 */
53 protected $hashService;
54
55 /**
56 * @param \TYPO3\CMS\Extbase\Security\Cryptography\HashService $hashService
57 * @return void
58 */
59 public function injectHashService(\TYPO3\CMS\Extbase\Security\Cryptography\HashService $hashService) {
60 $this->hashService = $hashService;
61 }
62
63 /**
64 * Generate a request hash for a list of form fields
65 *
66 * @param array $formFieldNames Array of form fields
67 * @param string $fieldNamePrefix
68 * @throws \TYPO3\CMS\Extbase\Security\Exception\InvalidArgumentForRequestHashGenerationException
69 * @return string request hash
70 * @todo might need to become public API lateron, as we need to call it from Fluid
71 */
72 public function generateRequestHash($formFieldNames, $fieldNamePrefix = '') {
73 $formFieldArray = array();
74 foreach ($formFieldNames as $formField) {
75 $formFieldParts = explode('[', $formField);
76 $currentPosition = &$formFieldArray;
77 for ($i = 0; $i < count($formFieldParts); $i++) {
78 $formFieldPart = $formFieldParts[$i];
79 if (substr($formFieldPart, -1) == ']') {
80 $formFieldPart = substr($formFieldPart, 0, -1);
81 }
82 // Strip off closing ] if needed
83 if (!is_array($currentPosition)) {
84 throw new \TYPO3\CMS\Extbase\Security\Exception\InvalidArgumentForRequestHashGenerationException('The form field name "' . $formField . '" collides with a previous form field name which declared the field as string. (String overridden by Array)', 1255072196);
85 }
86 if ($i == count($formFieldParts) - 1) {
87 if (isset($currentPosition[$formFieldPart]) && is_array($currentPosition[$formFieldPart])) {
88 throw new \TYPO3\CMS\Extbase\Security\Exception\InvalidArgumentForRequestHashGenerationException('The form field name "' . $formField . '" collides with a previous form field name which declared the field as array. (Array overridden by String)', 1255072587);
89 }
90 // Last iteration - add a string
91 if ($formFieldPart === '') {
92 $currentPosition[] = 1;
93 } else {
94 $currentPosition[$formFieldPart] = 1;
95 }
96 } else {
97 if ($formFieldPart === '') {
98 throw new \TYPO3\CMS\Extbase\Security\Exception\InvalidArgumentForRequestHashGenerationException('The form field name "' . $formField . '" is invalid. Reason: "[]" used not as last argument.', 1255072832);
99 }
100 if (!isset($currentPosition[$formFieldPart])) {
101 $currentPosition[$formFieldPart] = array();
102 }
103 $currentPosition = &$currentPosition[$formFieldPart];
104 }
105 }
106 }
107 if ($fieldNamePrefix !== '') {
108 $formFieldArray = isset($formFieldArray[$fieldNamePrefix]) ? $formFieldArray[$fieldNamePrefix] : array();
109 }
110 return $this->serializeAndHashFormFieldArray($formFieldArray);
111 }
112
113 /**
114 * Serialize and hash the form field array
115 *
116 * @param array $formFieldArray form field array to be serialized and hashed
117 * @return string Hash
118 */
119 protected function serializeAndHashFormFieldArray($formFieldArray) {
120 $serializedFormFieldArray = serialize($formFieldArray);
121 return $serializedFormFieldArray . $this->hashService->generateHmac($serializedFormFieldArray);
122 }
123
124 /**
125 * Verify the request. Checks if there is an __hmac argument, and if yes, tries to validate and verify it.
126 *
127 * In the end, $request->setHmacVerified is set depending on the value.
128 *
129 * @param \TYPO3\CMS\Extbase\Mvc\Web\Request $request The request to verify
130 * @throws \TYPO3\CMS\Extbase\Security\Exception\SyntacticallyWrongRequestHashException
131 * @return void
132 */
133 public function verifyRequest(\TYPO3\CMS\Extbase\Mvc\Web\Request $request) {
134 if (!$request->getInternalArgument('__hmac')) {
135 $request->setHmacVerified(FALSE);
136 return;
137 }
138 $hmac = $request->getInternalArgument('__hmac');
139 if (strlen($hmac) < 40) {
140 throw new \TYPO3\CMS\Extbase\Security\Exception\SyntacticallyWrongRequestHashException('Request hash too short. This is a probably manipulation attempt!', 1255089361);
141 }
142 $serializedFieldNames = substr($hmac, 0, -40);
143 // TODO: Constant for hash length needs to be introduced
144 $hash = substr($hmac, -40);
145 if ($this->hashService->validateHmac($serializedFieldNames, $hash)) {
146 $requestArguments = $request->getArguments();
147 // Unset framework arguments
148 unset($requestArguments['__referrer']);
149 unset($requestArguments['__hmac']);
150 if ($this->checkFieldNameInclusion($requestArguments, unserialize($serializedFieldNames))) {
151 $request->setHmacVerified(TRUE);
152 } else {
153 $request->setHmacVerified(FALSE);
154 }
155 } else {
156 $request->setHmacVerified(FALSE);
157 }
158 }
159
160 /**
161 * Check if every element in $requestArguments is in $allowedFields as well.
162 *
163 * @param array $requestArguments
164 * @param array $allowedFields
165 * @return boolean TRUE if ALL fields inside requestArguments are in $allowedFields, FALSE otherwise.
166 */
167 protected function checkFieldNameInclusion(array $requestArguments, array $allowedFields) {
168 foreach ($requestArguments as $argumentName => $argumentValue) {
169 if (!isset($allowedFields[$argumentName])) {
170 return FALSE;
171 }
172 if (is_array($requestArguments[$argumentName]) && is_array($allowedFields[$argumentName])) {
173 if (!$this->checkFieldNameInclusion($requestArguments[$argumentName], $allowedFields[$argumentName])) {
174 return FALSE;
175 }
176 } elseif (!is_array($requestArguments[$argumentName]) && !is_array($allowedFields[$argumentName])) {
177 } elseif (!is_array($requestArguments[$argumentName]) && $requestArguments[$argumentName] === '' && is_array($allowedFields[$argumentName])) {
178 } else {
179 // different types - error
180 return FALSE;
181 }
182 }
183 return TRUE;
184 }
185 }
186
187 ?>