TYPO3 CMS  TYPO3_7-6
ExtensionManagerConfigurationUtility.php
Go to the documentation of this file.
1 <?php
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
20 
26 {
31 
35  protected $header;
36 
40  protected $preText;
41 
45  protected $problems = [];
46 
50  protected $extConf = [];
51 
59  protected function setErrorLevel($level)
60  {
61  $lang = $this->getLanguageService();
62  switch ($level) {
63  case 'error':
64  $this->errorType = FlashMessage::ERROR;
65  $this->header = $lang->getLL('ext.saltedpasswords.configuration.header.errorsFound');
66  $this->preText = $lang->getLL('ext.saltedpasswords.configuration.message.errorsFound') . '<br />';
67  break;
68  case 'warning':
69  if ($this->errorType < FlashMessage::ERROR) {
70  $this->errorType = FlashMessage::WARNING;
71  $this->header = $lang->getLL('ext.saltedpasswords.configuration.header.warningsFound');
72  $this->preText = $lang->getLL('ext.saltedpasswords.configuration.message.warningsFound') . '<br />';
73  }
74  break;
75  case 'info':
76  if ($this->errorType < FlashMessage::WARNING) {
77  $this->errorType = FlashMessage::INFO;
78  $this->header = $lang->getLL('ext.saltedpasswords.configuration.header.additionalInformation');
79  $this->preText = '<br />';
80  }
81  break;
82  case 'ok':
83  // @todo Remove INFO condition as it has lower importance
84  if ($this->errorType < FlashMessage::WARNING && $this->errorType != FlashMessage::INFO) {
85  $this->errorType = FlashMessage::OK;
86  $this->header = $lang->getLL('ext.saltedpasswords.configuration.header.noErrorsFound');
87  $this->preText = $lang->getLL('ext.saltedpasswords.configuration.message.noErrorsFound') . '<br />';
88  }
89  break;
90  default:
91  }
92  }
93 
99  protected function renderMessage()
100  {
101  $message = '';
102  // If there are problems, render them into an unordered list
103  if (!empty($this->problems)) {
104  $message = '<ul><li>###PROBLEMS###</li></ul>';
105  $message = str_replace('###PROBLEMS###', implode('<br />&nbsp;</li><li>', $this->problems), $message);
106  if ($this->errorType > FlashMessage::OK) {
107  $message .= '<br />' .
108  $this->getLanguageService()->getLL('ext.saltedpasswords.configuration.message.securityWarning');
109  }
110  }
111  if (empty($message)) {
112  $this->setErrorLevel('ok');
113  }
114  $message = $this->preText . $message;
115 
116  $class = 'default';
117  switch ($this->errorType) {
119  $class = 'notice';
120  break;
121  case FlashMessage::INFO:
122  $class = 'info';
123  break;
124  case FlashMessage::OK:
125  $class = 'success';
126  break;
128  $class = 'warning';
129  break;
130  case FlashMessage::ERROR:
131  $class = 'danger';
132  break;
133  default:
134  }
135  $html = '<div class="panel panel-' . $class . '">' .
136  '<div class="panel-heading">' . $this->header . '</div>' .
137  '<div class="panel-body">' . $message . '</div>' .
138  '</div>';
139  return [
140  'errorType' => $this->errorType,
141  'html' => $html
142  ];
143  }
144 
150  private function init()
151  {
152  $requestSetup = $this->processPostData((array) $_REQUEST['data']);
153  $extConf = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['saltedpasswords']);
154  $this->extConf['BE'] = array_merge((array)$extConf['BE.'], (array)$requestSetup['BE.']);
155  $this->extConf['FE'] = array_merge((array)$extConf['FE.'], (array)$requestSetup['FE.']);
156  $this->getLanguageService()->includeLLFile('EXT:saltedpasswords/Resources/Private/Language/locallang.xlf');
157  }
158 
168  public function checkConfigurationBackend(array $params, $pObj)
169  {
170  $this->init();
171  $extConf = $this->extConf['BE'];
172  // The backend is called over SSL
173  $isBackendCalledOverSsl = (int)$GLOBALS['TYPO3_CONF_VARS']['BE']['lockSSL'] > 0;
174  $rsaAuthLoaded = ExtensionManagementUtility::isLoaded('rsaauth');
175  // SSL configured?
176  $lang = $this->getLanguageService();
177  if ($isBackendCalledOverSsl) {
178  $this->setErrorLevel('ok');
179  $problems[] = $lang->getLL('ext.saltedpasswords.configuration.message.backendSsl');
180  } elseif ($rsaAuthLoaded) {
181  $loginSecurityLevel = trim($GLOBALS['TYPO3_CONF_VARS']['BE']['loginSecurityLevel']) ?: 'normal';
182  if ($loginSecurityLevel === 'rsa') {
183  if ($this->isRsaAuthBackendAvailable()) {
184  $this->setErrorLevel('ok');
185  $problems[] = $lang->getLL('ext.saltedpasswords.configuration.message.backendRsa');
186  } else {
187  // This means that login would fail because rsaauth is not working properly
188  $this->setErrorLevel('error');
189  $problems[] = '<strong>' .
190  $lang->getLL('ext.saltedpasswords.configuration.message.openSslMissing') .
191  '<a href="http://php.net/manual/en/openssl.installation.php" target="_blank">PHP.net</a></strong>.';
192  }
193  } else {
194  // This means that rsaauth is enabled but not used
195  $this->setErrorLevel('warning');
196  $problems[] = $lang->getLL('ext.saltedpasswords.configuration.message.backendSecurityLevelNotRsa');
197  }
198  } else {
199  // This means that we don't use any encryption method
200  $this->setErrorLevel('warning');
201  $problems[] = $lang->getLL('ext.saltedpasswords.configuration.message.rsaInstructionsIntro') . '<br />
202  <ul>
203  <li>' . $lang->getLL('ext.saltedpasswords.configuration.message.rsaInstructionsFirstItem') . '</li>
204 
205  <li>' . nl2br($lang->getLL('ext.saltedpasswords.configuration.message.rsaInstructionsSecondItem')) .
206  '</li>
207  </ul>
208  <br />
209  ' . $lang->getLL('ext.saltedpasswords.configuration.message.rsaInstructionsFootnote');
210  }
211  // Only saltedpasswords as authsservice
212  if ($extConf['onlyAuthService']) {
213  // Warn user that the combination with "forceSalted" may lock him
214  // out from Backend
215  if ($extConf['forceSalted']) {
216  $this->setErrorLevel('warning');
217  $problems[] = $lang->getLL('ext.saltedpasswords.configuration.message.warningForceSalted') . '<br />
218  <strong><i>' . $lang->getLL('ext.saltedpasswords.configuration.label.warning') . '</i></strong> ' .
219  $lang->getLL('ext.saltedpasswords.configuration.message.warningForceSaltedNoteForBackend');
220  } else {
221  // Inform the user that things like openid won't work anymore
222  $this->setErrorLevel('info');
223  $problems[] = $lang->getLL('ext.saltedpasswords.configuration.message.infoOnlyBackendAuthService');
224  }
225  }
226  // forceSalted is set
227  if ($extConf['forceSalted'] && !$extConf['onlyAuthService']) {
228  $this->setErrorLevel('info');
229  $problems[] = $lang->getLL('ext.saltedpasswords.configuration.message.infoForceSalted') .
230  ' <br /> ' . $lang->getLL('ext.saltedpasswords.configuration.message.infoForceSaltedNote');
231  }
232  // updatePasswd wont work with "forceSalted"
233  if ($extConf['updatePasswd'] && $extConf['forceSalted']) {
234  $this->setErrorLevel('error');
235  $problems[] = $lang->getLL('ext.saltedpasswords.configuration.message.errorForceSaltedAndUpdatePassword') .
236  '<br /> ' .
237  $lang->getLL('ext.saltedpasswords.configuration.message.errorForceSaltedAndUpdatePasswordReason');
238  }
239  // Check if the configured hash-method is available on system
241  if ($instance === null || !$instance->isAvailable()) {
242  $this->setErrorLevel('error');
243  $problems[] = $lang->getLL('ext.saltedpasswords.configuration.message.errorHashMethodNotAvailable');
244  }
245  $this->problems = $problems;
246  $result = $this->renderMessage();
247  if (!empty($params['propertyName'])) {
248  return $result['html'];
249  }
250  return $result;
251  }
252 
258  protected function isRsaAuthBackendAvailable()
259  {
260  // Try to instantiate an RSAauth backend. If this does not work,
261  // it means that OpenSSL is not usable
263  $rsaauthBackendFactory = GeneralUtility::makeInstance(\TYPO3\CMS\Rsaauth\Backend\BackendFactory::class);
264  $backend = $rsaauthBackendFactory->getBackend();
265  return $backend !== null;
266  }
267 
277  public function checkConfigurationFrontend(array $params, $pObj)
278  {
279  $this->init();
280  $extConf = $this->extConf['FE'];
281  $problems = [];
282  $lang = $this->getLanguageService();
283  if ($extConf['enabled']) {
284  $loginSecurityLevel = trim($GLOBALS['TYPO3_CONF_VARS']['FE']['loginSecurityLevel']) ?: 'normal';
285  if ($loginSecurityLevel !== 'normal' && $loginSecurityLevel !== 'rsa') {
286  $this->setErrorLevel('info');
287  $problems[] = '<strong>' . $lang->getLL('ext.saltedpasswords.configuration.label.important') .
288  '</strong><br /> ' .
289  $lang->getLL('ext.saltedpasswords.configuration.message.infoLoginSecurityLevelDifferent') .
290  '<br />
291  <ul>
292  <li>' .
293  $lang->getLL('ext.saltedpasswords.configuration.message.infoLoginSecurityLevelDifferentFirstItem') .
294  '</li>
295 
296  <li>' .
297  $lang->getLL('ext.saltedpasswords.configuration.message.infoLoginSecurityLevelDifferentSecondItem') .
298  '</li>
299  </ul>
300  <br />
301  ' . $lang->getLL('ext.saltedpasswords.configuration.message.infoLoginSecurityLevelDifferentNote');
302  } elseif ($loginSecurityLevel === 'rsa') {
303  if (ExtensionManagementUtility::isLoaded('rsaauth')) {
304  if ($this->isRsaAuthBackendAvailable()) {
305  $this->setErrorLevel('ok');
306  $problems[] = $lang->getLL('ext.saltedpasswords.configuration.message.okFeRsaauthLoaded');
307  } else {
308  // This means that login would fail because rsaauth is not working properly
309  $this->setErrorLevel('error');
310  $problems[] = '<strong>' . $lang->getLL('ext.saltedpasswords.configuration.message.openSslMissing') .
311  ' <a href="http://php.net/manual/en/openssl.installation.php" target="_blank">PHP.net</a></strong>.';
312  }
313  } else {
314  // Rsaauth is not installed but configured to be used
315  $this->setErrorLevel('warning');
316  $problems[] = $lang->getLL('ext.saltedpasswords.configuration.message.warningRsaauthNotInstalledButConfigured');
317  }
318  }
319  // Only saltedpasswords as authsservice
320  if ($extConf['onlyAuthService']) {
321  // Warn user that the combination with "forceSalted" may lock
322  // him out from frontend
323  if ($extConf['forceSalted']) {
324  $this->setErrorLevel('warning');
325  $problems[] = nl2br($lang->getLL('ext.saltedpasswords.configuration.message.infoForceSalted')) .
326  '<strong><i>' . $lang->getLL('ext.saltedpasswords.configuration.label.important') .
327  '</i></strong> ' . $lang->getLL('ext.saltedpasswords.configuration.message.warningForceSaltedNoteForFrontend');
328  } else {
329  // Inform the user that things like openid won't work anymore
330  $this->setErrorLevel('info');
331  $problems[] = $lang->getLL('ext.saltedpasswords.configuration.message.infoOnlyFrontendAuthService');
332  }
333  }
334  // forceSalted is set
335  if ($extConf['forceSalted'] && !$extConf['onlyAuthService']) {
336  $this->setErrorLevel('warning');
337  $problems[] = nl2br($lang->getLL('ext.saltedpasswords.configuration.message.infoForceSalted')) .
338  '<strong><i>' . $lang->getLL('ext.saltedpasswords.configuration.label.important') .
339  '</i></strong> ' . $lang->getLL('ext.saltedpasswords.configuration.message.warningForceSaltedNote2');
340  }
341  // updatePasswd wont work with "forceSalted"
342  if ($extConf['updatePasswd'] && $extConf['forceSalted']) {
343  $this->setErrorLevel('error');
344  $problems[] = nl2br($lang->getLL('ext.saltedpasswords.configuration.message.errorForceSaltedAndUpdatePassword'));
345  }
346  } else {
347  // Not enabled warning
348  $this->setErrorLevel('info');
349  $problems[] = $lang->getLL('ext.saltedpasswords.configuration.message.infoSaltedpasswordsFrontendDisabled');
350  }
351  $this->problems = $problems;
352  $result = $this->renderMessage();
353  if (!empty($params['propertyName'])) {
354  return $result['html'];
355  }
356  return $result;
357  }
358 
367  protected function buildHashMethodSelector(array $params, $pObj, $disposal)
368  {
369  $this->init();
370  $propertyName = $params['propertyName'];
371  $unknownVariablePleaseRenameMe = '\'' . substr(md5($propertyName), 0, 10) . '\'';
372  $pField = '';
374  foreach ($registeredMethods as $class => $reference) {
375  $classInstance = GeneralUtility::getUserObj($reference);
376  if ($classInstance instanceof \TYPO3\CMS\Saltedpasswords\Salt\SaltInterface && $classInstance->isAvailable()) {
377  $sel = $this->extConf[$disposal]['saltedPWHashingMethod'] == $class ? ' selected="selected" ' : '';
378  $label = 'ext.saltedpasswords.title.' . strtolower(end(explode('\\', $class)));
379  $pField .= '<option value="' . htmlspecialchars($class) . '"' . $sel . '>' . $GLOBALS['LANG']->getLL($label) . '</option>';
380  }
381  }
382  $pField = '<select id="' . $propertyName . '" name="' . $params['fieldName'] .
383  '" onChange="uFormUrl(' . $unknownVariablePleaseRenameMe . ')">' . $pField . '</select>';
384  return $pField;
385  }
386 
395  public function buildHashMethodSelectorFE(array $params, $pObj)
396  {
397  return $this->buildHashMethodSelector($params, $pObj, 'FE');
398  }
399 
408  public function buildHashMethodSelectorBE(array $params, $pObj)
409  {
410  return $this->buildHashMethodSelector($params, $pObj, 'BE');
411  }
412 
420  protected function processPostData(array $postArray = [])
421  {
422  foreach ($postArray as $key => $value) {
423  // @todo Explain
424  $parts = explode('.', $key, 2);
425  if (count($parts) == 2) {
426  // @todo Explain
427  $value = $this->processPostData([$parts[1] => $value]);
428  $postArray[$parts[0] . '.'] = array_merge((array)$postArray[$parts[0] . '.'], $value);
429  } else {
430  // @todo Explain
431  $postArray[$parts[0]] = $value;
432  }
433  }
434  return $postArray;
435  }
436 
440  protected function getLanguageService()
441  {
442  return $GLOBALS['LANG'];
443  }
444 }
static getSaltingInstance($saltedHash='', $mode=TYPO3_MODE)
Definition: SaltFactory.php:82
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']