[FEATURE] Create BE-user in installation wizard with a salted password
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Classes / Controller / Action / Tool / ImportantActions.php
1 <?php
2 namespace TYPO3\CMS\Install\Controller\Action\Tool;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2013 Christian Kuhn <lolli@schwarzbu.ch>
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 *
19 * This script is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * This copyright notice MUST APPEAR in all copies of the script!
25 ***************************************************************/
26
27 use TYPO3\CMS\Install\Controller\Action;
28 use TYPO3\CMS\Core\Utility\GeneralUtility;
29
30 /**
31 * Handle important actions
32 */
33 class ImportantActions extends Action\AbstractAction implements Action\ActionInterface {
34
35 /**
36 * Handle this action
37 *
38 * @return string content
39 */
40 public function handle() {
41 $this->initializeHandle();
42
43 if (isset($this->postValues['set']['changeEncryptionKey'])) {
44 $this->setNewEncryptionKeyAndLogOut();
45 }
46
47 $actionMessages = array();
48 if (isset($this->postValues['set']['changeInstallToolPassword'])) {
49 $actionMessages[] = $this->changeInstallToolPassword();
50 }
51 if (isset($this->postValues['set']['changeSiteName'])) {
52 $actionMessages[] = $this->changeSiteName();
53 }
54 if (isset($this->postValues['set']['createAdministrator'])) {
55 $actionMessages[] = $this->createAdministrator();
56 }
57 if (isset($this->postValues['set']['clearAllCache'])) {
58 $actionMessages[] = $this->clearAllCache();
59 }
60
61 // Database analyzer handling
62 if (isset($this->postValues['set']['databaseAnalyzerExecute'])
63 || isset($this->postValues['set']['databaseAnalyzerAnalyze'])
64 ) {
65 $this->loadExtLocalconfDatabaseAndExtTables();
66 }
67 if (isset($this->postValues['set']['databaseAnalyzerExecute'])) {
68 $actionMessages = array_merge($actionMessages, $this->databaseAnalyzerExecute());
69 }
70 if (isset($this->postValues['set']['databaseAnalyzerAnalyze'])) {
71 $actionMessages[] = $this->databaseAnalyzerAnalyze();
72 }
73
74 $this->view->assign('actionMessages', $actionMessages);
75
76 $operatingSystem = TYPO3_OS === 'WIN' ? 'Windows' : 'Unix';
77 $cgiDetected = (PHP_SAPI == 'fpm-fcgi' || PHP_SAPI == 'cgi' || PHP_SAPI == 'isapi' || PHP_SAPI == 'cgi-fcgi')
78 ? TRUE
79 : FALSE;
80
81 $this->view
82 ->assign('operatingSystem', $operatingSystem)
83 ->assign('cgiDetected', $cgiDetected)
84 ->assign('databaseName', $GLOBALS['TYPO3_CONF_VARS']['DB']['database'])
85 ->assign('databaseUsername', $GLOBALS['TYPO3_CONF_VARS']['DB']['username'])
86 ->assign('databaseHost', $GLOBALS['TYPO3_CONF_VARS']['DB']['host'])
87 ->assign('databasePort', $GLOBALS['TYPO3_CONF_VARS']['DB']['port'])
88 ->assign('databaseSocket', $GLOBALS['TYPO3_CONF_VARS']['DB']['socket'])
89 ->assign('databaseNumberOfTables', count($this->getDatabase()->admin_get_tables()))
90 ->assign('extensionCompatibilityTesterProtocolFile', GeneralUtility::getIndpEnv('TYPO3_SITE_URL') . 'typo3temp/ExtensionCompatibilityTester.txt');
91
92 return $this->view->render();
93 }
94
95 /**
96 * Set new password if requested
97 *
98 * @return \TYPO3\CMS\Install\Status\StatusInterface
99 */
100 protected function changeInstallToolPassword() {
101 $values = $this->postValues['values'];
102 if ($values['newInstallToolPassword'] !== $values['newInstallToolPasswordCheck']) {
103 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
104 $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\ErrorStatus');
105 $message->setTitle('Install tool password not changed');
106 $message->setMessage('Given passwords do not match.');
107 } elseif (strlen($values['newInstallToolPassword']) < 8) {
108 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
109 $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\ErrorStatus');
110 $message->setTitle('Install tool password not changed');
111 $message->setMessage('Given passwords must be a least eight characters long.');
112 } else {
113 /** @var \TYPO3\CMS\Core\Configuration\ConfigurationManager $configurationManager */
114 $configurationManager = $this->objectManager->get('TYPO3\\CMS\\Core\\Configuration\\ConfigurationManager');
115 $configurationManager->setLocalConfigurationValueByPath('BE/installToolPassword', md5($values['newInstallToolPassword']));
116 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
117 $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\OkStatus');
118 $message->setTitle('Install tool password changed');
119 }
120 return $message;
121 }
122
123 /**
124 * Set new site name
125 *
126 * @return \TYPO3\CMS\Install\Status\StatusInterface
127 */
128 protected function changeSiteName() {
129 $values = $this->postValues['values'];
130 if (isset($values['newSiteName']) && strlen($values['newSiteName']) > 0) {
131 /** @var \TYPO3\CMS\Core\Configuration\ConfigurationManager $configurationManager */
132 $configurationManager = $this->objectManager->get('TYPO3\\CMS\\Core\\Configuration\\ConfigurationManager');
133 $configurationManager->setLocalConfigurationValueByPath('SYS/sitename', $values['newSiteName']);
134 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
135 $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\OkStatus');
136 $message->setTitle('Site name changed');
137 $this->view->assign('siteName', $values['newSiteName']);
138 } else {
139 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
140 $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\ErrorStatus');
141 $message->setTitle('Site name not changed');
142 $message->setMessage('Site name must be at least one character long.');
143 }
144 return $message;
145 }
146
147 /**
148 * Clear all caches
149 *
150 * @return \TYPO3\CMS\Install\Status\StatusInterface
151 */
152 protected function clearAllCache() {
153 /** @var \TYPO3\CMS\Install\Service\ClearCacheService $clearCacheService */
154 $clearCacheService = $this->objectManager->get('TYPO3\\CMS\\Install\\Service\\ClearCacheService');
155 $clearCacheService->clearAll();
156 $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\OkStatus');
157 $message->setTitle('Successfully cleared all caches');
158 return $message;
159 }
160
161 /**
162 * Set new encryption key
163 *
164 * @return void
165 */
166 protected function setNewEncryptionKeyAndLogOut() {
167 $newKey = \TYPO3\CMS\Core\Utility\GeneralUtility::getRandomHexString(96);
168 /** @var \TYPO3\CMS\Core\Configuration\ConfigurationManager $configurationManager */
169 $configurationManager = $this->objectManager->get('TYPO3\\CMS\\Core\\Configuration\\ConfigurationManager');
170 $configurationManager->setLocalConfigurationValueByPath('SYS/encryptionKey', $newKey);
171 /** @var $formProtection \TYPO3\CMS\Core\FormProtection\InstallToolFormProtection */
172 $formProtection = \TYPO3\CMS\Core\FormProtection\FormProtectionFactory::get(
173 'TYPO3\\CMS\\Core\\FormProtection\\InstallToolFormProtection'
174 );
175 $formProtection->clean();
176 /** @var \TYPO3\CMS\Install\Service\SessionService $session */
177 $session = $this->objectManager->get('TYPO3\\CMS\\Install\\Service\\SessionService');
178 $session->destroySession();
179 \TYPO3\CMS\Core\Utility\HttpUtility::redirect('Install.php?install[context]=' . $this->getContext());
180 }
181
182 /**
183 * Create administrator user
184 *
185 * @return \TYPO3\CMS\Install\Status\StatusInterface
186 */
187 protected function createAdministrator() {
188 $values = $this->postValues['values'];
189 $username = preg_replace('/[^\\da-z._]/i', '', trim($values['newUserUsername']));
190 $password = $values['newUserPassword'];
191 $passwordCheck = $values['newUserPasswordCheck'];
192
193 if (strlen($username) < 1) {
194 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
195 $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\ErrorStatus');
196 $message->setTitle('Administrator user not created');
197 $message->setMessage('No valid username given.');
198 } elseif ($password !== $passwordCheck) {
199 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
200 $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\ErrorStatus');
201 $message->setTitle('Administrator user not created');
202 $message->setMessage('Passwords do not match.');
203 } elseif (strlen($password) < 8) {
204 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
205 $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\ErrorStatus');
206 $message->setTitle('Administrator user not created');
207 $message->setMessage('Password must be at least eight characters long.');
208 } else {
209 $database = $this->getDatabase();
210 $userExists = $database->exec_SELECTcountRows(
211 'uid',
212 'be_users',
213 'username=' . $database->fullQuoteStr($username, 'be_users')
214 );
215 if ($userExists) {
216 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
217 $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\ErrorStatus');
218 $message->setTitle('Administrator user not created');
219 $message->setMessage('A user with username ' . $username . ' exists already.');
220 } else {
221 $hashedPassword = $this->getHashedPassword($password);
222 $adminUserFields = array(
223 'username' => $username,
224 'password' => $hashedPassword,
225 'admin' => 1,
226 'tstamp' => $GLOBALS['EXEC_TIME'],
227 'crdate' => $GLOBALS['EXEC_TIME']
228 );
229 $database->exec_INSERTquery('be_users', $adminUserFields);
230 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
231 $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\OkStatus');
232 $message->setTitle('Administrator created');
233 }
234 }
235
236 return $message;
237 }
238
239 /**
240 * Execute database migration
241 *
242 * @return array<\TYPO3\CMS\Install\Status\StatusInterface>
243 */
244 protected function databaseAnalyzerExecute() {
245 $messages = array();
246
247 // Early return in case no updade was selected
248 if (empty($this->postValues['values'])) {
249 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
250 $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\WarningStatus');
251 $message->setTitle('No database changes selected');
252 $messages[] = $message;
253 return $message;
254 }
255
256 /** @var \TYPO3\CMS\Install\Service\SqlSchemaMigrationService $schemaMigrationService */
257 $schemaMigrationService = $this->objectManager->get('TYPO3\\CMS\\Install\\Service\\SqlSchemaMigrationService');
258 /** @var \TYPO3\CMS\Install\Service\SqlExpectedSchemaService $expectedSchemaService */
259 $expectedSchemaService = $this->objectManager->get('TYPO3\\CMS\\Install\\Service\\SqlExpectedSchemaService');
260 $expectedSchema = $expectedSchemaService->getExpectedDatabaseSchema();
261 $currentSchema = $schemaMigrationService->getFieldDefinitions_database();
262
263 $statementHashesToPerform = $this->postValues['values'];
264
265 $results = array();
266
267 // Difference from expected to current
268 $addCreateChange = $schemaMigrationService->getDatabaseExtra($expectedSchema, $currentSchema);
269 $addCreateChange = $schemaMigrationService->getUpdateSuggestions($addCreateChange);
270 $results[] = $schemaMigrationService->performUpdateQueries($addCreateChange['add'], $statementHashesToPerform);
271 $results[] = $schemaMigrationService->performUpdateQueries($addCreateChange['change'], $statementHashesToPerform);
272 $results[] = $schemaMigrationService->performUpdateQueries($addCreateChange['create_table'], $statementHashesToPerform);
273
274 // Difference from current to expected
275 $dropRename = $schemaMigrationService->getDatabaseExtra($currentSchema, $expectedSchema);
276 $dropRename = $schemaMigrationService->getUpdateSuggestions($dropRename, 'remove');
277 $results[] = $schemaMigrationService->performUpdateQueries($dropRename['change'], $statementHashesToPerform);
278 $results[] = $schemaMigrationService->performUpdateQueries($dropRename['drop'], $statementHashesToPerform);
279 $results[] = $schemaMigrationService->performUpdateQueries($dropRename['change_table'], $statementHashesToPerform);
280 $results[] = $schemaMigrationService->performUpdateQueries($dropRename['drop_table'], $statementHashesToPerform);
281
282 // Create error flash messages if any
283 foreach ($results as $resultSet) {
284 if (is_array($resultSet)) {
285 foreach ($resultSet as $errorMessage) {
286 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
287 $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\ErrorStatus');
288 $message->setTitle('Database update failed');
289 $message->setMessage('Error: ' . $errorMessage);
290 $messages[] = $message;
291 }
292 }
293 }
294
295 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
296 $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\OkStatus');
297 $message->setTitle('Executed database updates');
298 $messages[] = $message;
299
300 return $messages;
301 }
302
303 /**
304 * "Compare" action of analyzer
305 *
306 * @TODO: The SchemaMigration API is a mess and should be refactored
307 * @TODO: Refactoring this should aim to make EM and dbal independent from ext:install by moving SchemaMigration to ext:core
308 * @return \TYPO3\CMS\Install\Status\StatusInterface
309 */
310 protected function databaseAnalyzerAnalyze() {
311 /** @var \TYPO3\CMS\Install\Service\SqlSchemaMigrationService $schemaMigrationService */
312 $schemaMigrationService = $this->objectManager->get('TYPO3\\CMS\\Install\\Service\\SqlSchemaMigrationService');
313 /** @var \TYPO3\CMS\Install\Service\SqlExpectedSchemaService $expectedSchemaService */
314 $expectedSchemaService = $this->objectManager->get('TYPO3\\CMS\\Install\\Service\\SqlExpectedSchemaService');
315 $expectedSchema = $expectedSchemaService->getExpectedDatabaseSchema();
316
317 $currentSchema = $schemaMigrationService->getFieldDefinitions_database();
318
319 $databaseAnalyzerSuggestion = array();
320
321 // Difference from expected to current
322 $addCreateChange = $schemaMigrationService->getDatabaseExtra($expectedSchema, $currentSchema);
323 $addCreateChange = $schemaMigrationService->getUpdateSuggestions($addCreateChange);
324 if (isset($addCreateChange['create_table'])) {
325 $databaseAnalyzerSuggestion['addTable'] = array();
326 foreach ($addCreateChange['create_table'] as $hash => $statement) {
327 $databaseAnalyzerSuggestion['addTable'][$hash] = array(
328 'hash' => $hash,
329 'statement' => $statement,
330 );
331 }
332 }
333 if (isset($addCreateChange['add'])) {
334 $databaseAnalyzerSuggestion['addField'] = array();
335 foreach ($addCreateChange['add'] as $hash => $statement) {
336 $databaseAnalyzerSuggestion['addField'][$hash] = array(
337 'hash' => $hash,
338 'statement' => $statement,
339 );
340 }
341 }
342 if (isset($addCreateChange['change'])) {
343 $databaseAnalyzerSuggestion['change'] = array();
344 foreach ($addCreateChange['change'] as $hash => $statement) {
345 $databaseAnalyzerSuggestion['change'][$hash] = array(
346 'hash' => $hash,
347 'statement' => $statement,
348 );
349 if (isset($addCreateChange['change_currentValue'][$hash])) {
350 $databaseAnalyzerSuggestion['change'][$hash]['current'] = $addCreateChange['change_currentValue'][$hash];
351 }
352 }
353 }
354
355 // Difference from current to expected
356 $dropRename = $schemaMigrationService->getDatabaseExtra($currentSchema, $expectedSchema);
357 $dropRename = $schemaMigrationService->getUpdateSuggestions($dropRename, 'remove');
358 if (isset($dropRename['change_table'])) {
359 $databaseAnalyzerSuggestion['renameTableToUnused'] = array();
360 foreach ($dropRename['change_table'] as $hash => $statement) {
361 $databaseAnalyzerSuggestion['renameTableToUnused'][$hash] = array(
362 'hash' => $hash,
363 'statement' => $statement,
364 );
365 if (!empty($dropRename['tables_count'][$hash])) {
366 $databaseAnalyzerSuggestion['renameTableToUnused'][$hash]['count'] = $dropRename['tables_count'][$hash];
367 }
368 }
369 }
370 if (isset($dropRename['change'])) {
371 $databaseAnalyzerSuggestion['renameTableFieldToUnused'] = array();
372 foreach ($dropRename['change'] as $hash => $statement) {
373 $databaseAnalyzerSuggestion['renameTableFieldToUnused'][$hash] = array(
374 'hash' => $hash,
375 'statement' => $statement,
376 );
377 }
378 }
379 if (isset($dropRename['drop'])) {
380 $databaseAnalyzerSuggestion['deleteField'] = array();
381 foreach ($dropRename['drop'] as $hash => $statement) {
382 $databaseAnalyzerSuggestion['deleteField'][$hash] = array(
383 'hash' => $hash,
384 'statement' => $statement,
385 );
386 }
387 }
388 if (isset($dropRename['drop_table'])) {
389 $databaseAnalyzerSuggestion['deleteTable'] = array();
390 foreach ($dropRename['drop_table'] as $hash => $statement) {
391 $databaseAnalyzerSuggestion['deleteTable'][$hash] = array(
392 'hash' => $hash,
393 'statement' => $statement,
394 );
395 if (!empty($dropRename['tables_count'][$hash])) {
396 $databaseAnalyzerSuggestion['deleteTable'][$hash]['count'] = $dropRename['tables_count'][$hash];
397 }
398 }
399 }
400
401 $this->view->assign('databaseAnalyzerSuggestion', $databaseAnalyzerSuggestion);
402
403 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
404 $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\OkStatus');
405 $message->setTitle('Analyzed current database');
406 return $message;
407 }
408 }
409 ?>