[BUGFIX] Check default salting method first
[Packages/TYPO3.CMS.git] / typo3 / sysext / saltedpasswords / Classes / Utility / ExtensionManagerConfigurationUtility.php
1 <?php
2 namespace TYPO3\CMS\Saltedpasswords\Utility;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) Steffen Ritter (info@rs-websystems.de)
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 * A copy is found in the text file GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29 use TYPO3\CMS\Core\Messaging\FlashMessage;
30
31 /**
32 * class providing configuration checks for saltedpasswords.
33 *
34 * @author Steffen Ritter <info@rs-websystems.de>
35 * @since 2009-09-04
36 */
37 class ExtensionManagerConfigurationUtility {
38
39 /**
40 * @var integer
41 */
42 protected $errorType = FlashMessage::OK;
43
44 /**
45 * @var string
46 */
47 protected $header;
48
49 /**
50 * @var string
51 */
52 protected $preText;
53
54 /**
55 * @var array
56 */
57 protected $problems = array();
58
59 /**
60 * @var array
61 */
62 protected $extConf = array();
63
64 /**
65 * Set the error level if no higher level
66 * is set already
67 *
68 * @param string $level One out of error, ok, warning, info
69 * @return void
70 */
71 private function setErrorLevel($level) {
72 switch ($level) {
73 case 'error':
74 $this->errorType = FlashMessage::ERROR;
75 $this->header = 'Errors found in your configuration';
76 $this->preText = 'SaltedPasswords will not work until these problems have been resolved:<br />';
77 break;
78 case 'warning':
79 if ($this->errorType < FlashMessage::ERROR) {
80 $this->errorType = FlashMessage::WARNING;
81 $this->header = 'Warnings about your configuration';
82 $this->preText = 'SaltedPasswords might behave different than expected:<br />';
83 }
84 break;
85 case 'info':
86 if ($this->errorType < FlashMessage::WARNING) {
87 $this->errorType = FlashMessage::INFO;
88 $this->header = 'Additional information';
89 $this->preText = '<br />';
90 }
91 break;
92 case 'ok':
93 // TODO: Remove INFO condition as it has lower importance
94 if ($this->errorType < FlashMessage::WARNING && $this->errorType != FlashMessage::INFO) {
95 $this->errorType = FlashMessage::OK;
96 $this->header = 'No errors were found';
97 $this->preText = 'SaltedPasswords has been configured correctly and works as expected.<br />';
98 }
99 break;
100 }
101 }
102
103 /**
104 * Renders the flash messages if problems have been found.
105 *
106 * @return string The flash message as HTML.
107 */
108 private function renderFlashMessage() {
109 $message = '';
110 // If there are problems, render them into an unordered list
111 if (count($this->problems) > 0) {
112 $message = '<ul>
113 <li>###PROBLEMS###</li>
114 </ul>';
115 $message = str_replace('###PROBLEMS###', implode('<br />&nbsp;</li><li>', $this->problems), $message);
116 if ($this->errorType > FlashMessage::OK) {
117 $message .= '<br />
118 Note, that a wrong configuration might have impact on the security of
119 your TYPO3 installation and the usability of the backend.';
120 }
121 }
122 if (empty($message)) {
123 $this->setErrorLevel('ok');
124 }
125 $message = $this->preText . $message;
126 $flashMessage = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Messaging\\FlashMessage', $message, $this->header, $this->errorType);
127 return $flashMessage->render();
128 }
129
130 /**
131 * Initializes this object.
132 *
133 * @return void
134 */
135 private function init() {
136 $requestSetup = $this->processPostData((array) $_REQUEST['data']);
137 $extConf = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['saltedpasswords']);
138 $this->extConf['BE'] = array_merge((array) $extConf['BE.'], (array) $requestSetup['BE.']);
139 $this->extConf['FE'] = array_merge((array) $extConf['FE.'], (array) $requestSetup['FE.']);
140 $GLOBALS['LANG']->includeLLFile('EXT:saltedpasswords/locallang.xlf');
141 }
142
143 /**
144 * Checks the backend configuration and shows a message if necessary.
145 *
146 * @param array $params Field information to be rendered
147 * @param \TYPO3\CMS\Core\TypoScript\ConfigurationForm $pObj The calling parent object.
148 * @return string Messages as HTML if something needs to be reported
149 */
150 public function checkConfigurationBackend(array $params, $pObj) {
151 $this->init();
152 $extConf = $this->extConf['BE'];
153 // The backend is called over SSL
154 $SSL = $GLOBALS['TYPO3_CONF_VARS']['BE']['lockSSL'] > 0 && $GLOBALS['TYPO3_CONF_VARS']['BE']['loginSecurityLevel'] != 'superchallenged';
155 $rsaAuthLoaded = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('rsaauth');
156 // SSL configured?
157 if ($SSL) {
158 $this->setErrorLevel('ok');
159 $problems[] = 'The backend is configured to use SaltedPasswords over SSL.';
160 } elseif ($rsaAuthLoaded) {
161 if (trim($GLOBALS['TYPO3_CONF_VARS']['BE']['loginSecurityLevel']) === 'rsa') {
162 if ($this->isRsaAuthBackendAvailable()) {
163 $this->setErrorLevel('ok');
164 $problems[] = 'The backend is configured to use SaltedPasswords with RSA authentication.';
165 } else {
166 // This means that login would fail because rsaauth is not working properly
167 $this->setErrorLevel('error');
168 $problems[] = '<strong>Using the extension "rsaauth" is not possible, as no encryption backend ' .
169 'is available. Please install and configure the PHP extension "openssl". ' .
170 'See <a href="http://php.net/manual/en/openssl.installation.php" target="_blank">PHP.net</a></strong>.';
171 }
172 } else {
173 // This means that rsaauth is enabled but not used
174 $this->setErrorLevel('warning');
175 $problems[] = 'The "rsaauth" extension is installed, but TYPO3 is not configured to use it during login.
176 Use the Install Tool to set the Login Security Level for the backend to "rsa"
177 ($TYPO3_CONF_VARS[\'BE\'][\'loginSecurityLevel\'])';
178 }
179 } else {
180 // This means that we don't use any encryption method
181 $this->setErrorLevel('warning');
182 $problems[] = 'SaltedPasswords is used without any transfer encryption, this means your passwords are sent in plain text.
183 Please install rsaauth to secure your passwords submits.<br />
184 <ul>
185 <li>Install the "rsaauth" extension and use the Install Tool to set the
186 Login Security Level for the backend to "rsa"
187 ($TYPO3_CONF_VARS[\'BE\'][\'loginSecurityLevel\'])</li>
188
189 <li>If you have the option to use SSL, you can also configure your
190 backend for SSL usage:<br />
191 Use the Install Tool to set the Security-Level for the backend
192 to "normal" ($TYPO3_CONF_VARS[\'BE\'][\'loginSecurityLevel\']) and
193 the SSL-locking option to a value greater than "0"
194 (see description - $TYPO3_CONF_VARS[\'BE\'][\'lockSSL\'])</li>
195 </ul>
196 <br />
197 It is also possible to use "lockSSL" and "rsa" Login Security Level at the same
198 time.';
199 }
200 // Only saltedpasswords as authsservice
201 if ($extConf['onlyAuthService']) {
202 // Warn user that the combination with "forceSalted" may lock him out from Backend
203 if ($extConf['forceSalted']) {
204 $this->setErrorLevel('warning');
205 $problems[] = 'SaltedPasswords has been configured to be the only authentication service for
206 the backend. Additionally, usage of salted passwords is enforced (forceSalted).
207 The result is that there is no chance to login with users not having a salted
208 password hash.<br />
209 <strong><i>WARNING:</i></strong> This may lock you out of the backend!';
210 } else {
211 // Inform the user that things like openid won't work anymore
212 $this->setErrorLevel('info');
213 $problems[] = 'SaltedPasswords has been configured to be the only authentication service for
214 the backend. This means that other services like "ipauth", "openid", etc. will
215 be ignored (except "rsauth", which is implicitely used).';
216 }
217 }
218 // forceSalted is set
219 if ($extConf['forceSalted'] && !$extConf['onlyAuthService']) {
220 $this->setErrorLevel('info');
221 $problems[] = 'SaltedPasswords has been configured to enforce salted passwords (forceSalted).
222 <br />
223 This means that only passwords in the format of this extension will succeed for
224 login.<br />
225 <strong><i>IMPORTANT:</i></strong> This has the effect that passwords that are set from
226 the Install Tool will not work!';
227 }
228 // updatePasswd wont work with "forceSalted"
229 if ($extConf['updatePasswd'] && $extConf['forceSalted']) {
230 $this->setErrorLevel('error');
231 $problems[] = 'SaltedPasswords is configured wrong and will not work as expected:<br />
232 It is not possible to set "updatePasswd" and "forceSalted" at the same time.
233 Please disable either one of them.';
234 }
235 // Check if the configured hash-method is available on system
236 $instance = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getSaltingInstance(NULL, 'BE');
237 if ($instance === NULL || !$instance->isAvailable()) {
238 $this->setErrorLevel('error');
239 $problems[] = 'The selected method for hashing your salted passwords is not available on this
240 system! Please check your configuration.';
241 }
242 $this->problems = $problems;
243 return $this->renderFlashMessage();
244 }
245
246 /**
247 * Checks if rsaauth is able to obtain a backend
248 *
249 * @return boolean
250 */
251 protected function isRsaAuthBackendAvailable() {
252 /**
253 * Try to instantiate an RSAauth backend. If this does not work, it means that OpenSSL is not usable
254 *
255 * @var $rsaauthBackendFactory \TYPO3\CMS\Rsaauth\Backend\BackendFactory
256 */
257 $rsaauthBackendFactory = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Rsaauth\\Backend\\BackendFactory');
258 $backend = $rsaauthBackendFactory->getBackend();
259 return $backend !== NULL;
260 }
261
262 /**
263 * Checks the frontend configuration and shows a message if necessary.
264 *
265 * @param array $params Field information to be rendered
266 * @param \TYPO3\CMS\Core\TypoScript\ConfigurationForm $pObj The calling parent object.
267 * @return string Messages as HTML if something needs to be reported
268 */
269 public function checkConfigurationFrontend(array $params, $pObj) {
270 $this->init();
271 $extConf = $this->extConf['FE'];
272 $problems = array();
273 if ($extConf['enabled']) {
274 // Inform the user if securityLevel in FE is challenged or blank --> extension won't work
275 if (!\TYPO3\CMS\Core\Utility\GeneralUtility::inList('normal,rsa', $GLOBALS['TYPO3_CONF_VARS']['FE']['loginSecurityLevel'])) {
276 $this->setErrorLevel('info');
277 $problems[] = '<strong>IMPORTANT:</strong><br />
278 Frontend requirements for SaltedPasswords are not met, therefore the
279 authentication will not work even if it was explicitly enabled for frontend
280 usage:<br />
281 <ul>
282 <li>Install the "rsaauth" extension and use the Install Tool to set the
283 Login Security Level for the frontend to "rsa"
284 ($TYPO3_CONF_VARS[\'FE\'][\'loginSecurityLevel\'])</li>
285
286 <li>Alternatively, use the Install Tool to set the Login Security Level
287 for the frontend to "normal"
288 ($TYPO3_CONF_VARS[\'FE\'][\'loginSecurityLevel\'])</li>
289 </ul>
290 <br />
291 Make sure that the Login Security Level is not set to "" or "challenged"!';
292 } elseif (trim($GLOBALS['TYPO3_CONF_VARS']['FE']['loginSecurityLevel']) === 'rsa') {
293 if ($this->isRsaAuthBackendAvailable()) {
294 $this->setErrorLevel('ok');
295 $problems[] = 'The frontend is configured to use SaltedPasswords with RSA authentication.';
296 } else {
297 // This means that login would fail because rsaauth is not working properly
298 $this->setErrorLevel('error');
299 $problems[] = '<strong>Using the extension "rsaauth" is not possible, as no encryption backend ' . 'is available. Please install and configure the PHP extension "openssl". ' . 'See <a href="http://php.net/manual/en/openssl.installation.php" target="_blank">PHP.net</a></strong>.';
300 }
301 }
302 // Only saltedpasswords as authsservice
303 if ($extConf['onlyAuthService']) {
304 // Warn user taht the combination with "forceSalted" may lock him out from frontend
305 if ($extConf['forceSalted']) {
306 $this->setErrorLevel('warning');
307 $problems[] = 'SaltedPasswords has been configured to enforce salted passwords (forceSalted).
308 <br />
309 This means that only passwords in the format of this extension will succeed for
310 login.<br />
311 <strong><i>IMPORTANT:</i></strong> Because of this, it is not possible to login with
312 users not having a salted password hash (e.g. existing frontend users).';
313 } else {
314 // Inform the user that things like openid won't work anymore
315 $this->setErrorLevel('info');
316 $problems[] = 'SaltedPasswords has been configured to be the only authentication service for
317 frontend logins. This means that other services like "ipauth", "openid", etc.
318 will be ignored.';
319 }
320 }
321 // forceSalted is set
322 if ($extConf['forceSalted'] && !$extConf['onlyAuthService']) {
323 $this->setErrorLevel('warning');
324 $problems[] = 'SaltedPasswords has been configured to enforce salted passwords (forceSalted).
325 <br />
326 This means that only passwords in the format of this extension will succeed for
327 login.<br />
328 <strong><i>IMPORTANT:</i></strong> This has the effect that passwords that were set
329 before SaltedPasswords was used will not work (in fact, they need to be
330 redefined).';
331 }
332 // updatePasswd wont work with "forceSalted"
333 if ($extConf['updatePasswd'] && $extConf['forceSalted']) {
334 $this->setErrorLevel('error');
335 $problems[] = 'SaltedPasswords is configured wrong and will not work as expected:<br />
336 It is not possible to set "updatePasswd" and "forceSalted" at the same time.
337 Please disable either one of them.';
338 }
339 } else {
340 // Not enabled warning
341 $this->setErrorLevel('info');
342 $problems[] = 'SaltedPasswords has been disabled for frontend users.';
343 }
344 $this->problems = $problems;
345 return $this->renderFlashMessage();
346 }
347
348 /**
349 * Renders a selector element that allows to select the hash method to be used.
350 *
351 * @param array $params Field information to be rendered
352 * @param \TYPO3\CMS\Core\TypoScript\ConfigurationForm $pObj The calling parent object.
353 * @param string $disposal The configuration disposal ('FE' or 'BE')
354 * @return string The HTML selector
355 */
356 protected function buildHashMethodSelector(array $params, $pObj, $disposal) {
357 $this->init();
358 $propertyName = $params['propertyName'];
359 $unknownVariablePleaseRenameMe = '\'' . substr(md5($propertyName), 0, 10) . '\'';
360 $p_field = '';
361 $registeredMethods = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getRegisteredSaltedHashingMethods();
362 foreach ($registeredMethods as $class => $reference) {
363 $classInstance = \TYPO3\CMS\Core\Utility\GeneralUtility::getUserObj($reference, 'tx_');
364 if ($classInstance instanceof \TYPO3\CMS\Saltedpasswords\Salt\SaltInterface && $classInstance->isAvailable()) {
365 $sel = $this->extConf[$disposal]['saltedPWHashingMethod'] == $class ? ' selected="selected" ' : '';
366 $label = 'ext.saltedpasswords.title.' . strtolower(end(explode('\\', $class)));
367 $p_field .= '<option value="' . htmlspecialchars($class) . '"' . $sel . '>' . $GLOBALS['LANG']->getLL($label) . '</option>';
368 }
369 }
370 $p_field = '<select id="' . $propertyName . '" name="' . $params['fieldName'] . '" onChange="uFormUrl(' . $unknownVariablePleaseRenameMe . ')">' . $p_field . '</select>';
371 return $p_field;
372 }
373
374 /**
375 * Renders a selector element that allows to select the hash method to be used (frontend disposal).
376 *
377 * @param array $params Field information to be rendered
378 * @param \TYPO3\CMS\Core\TypoScript\ConfigurationForm $pObj The calling parent object.
379 * @return string The HTML selector
380 */
381 public function buildHashMethodSelectorFE(array $params, $pObj) {
382 return $this->buildHashMethodSelector($params, $pObj, 'FE');
383 }
384
385 /**
386 * Renders a selector element that allows to select the hash method to be used (backend disposal)
387 *
388 * @param array $params Field information to be rendered
389 * @param \TYPO3\CMS\Core\TypoScript\ConfigurationForm $pObj The calling parent object.
390 * @return string The HTML selector
391 */
392 public function buildHashMethodSelectorBE(array $params, $pObj) {
393 return $this->buildHashMethodSelector($params, $pObj, 'BE');
394 }
395
396 /**
397 * Processes the information submitted by the user using a POST request and
398 * transforms it to a TypoScript node notation.
399 *
400 * @param array $postArray Incoming POST information
401 * @return array Processed and transformed POST information
402 */
403 private function processPostData(array $postArray = array()) {
404 foreach ($postArray as $key => $value) {
405 // TODO: Explain
406 $parts = explode('.', $key, 2);
407 if (count($parts) == 2) {
408 // TODO: Explain
409 $value = $this->processPostData(array($parts[1] => $value));
410 $postArray[$parts[0] . '.'] = array_merge((array) $postArray[($parts[0] . '.')], $value);
411 } else {
412 // TODO: Explain
413 $postArray[$parts[0]] = $value;
414 }
415 }
416 return $postArray;
417 }
418
419 }