8b5600120ed506d3692d6176490bc145177a74f0
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Authentication / CommandLineUserAuthentication.php
1 <?php
2 namespace TYPO3\CMS\Core\Authentication;
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
17 use TYPO3\CMS\Core\Crypto\Random;
18 use TYPO3\CMS\Core\Database\ConnectionPool;
19 use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
20 use TYPO3\CMS\Core\Utility\GeneralUtility;
21 use TYPO3\CMS\Saltedpasswords\Salt\SaltFactory;
22
23 /**
24 * TYPO3 backend user authentication on a CLI level
25 * Auto-logs in, only allowed on CLI
26 */
27 class CommandLineUserAuthentication extends BackendUserAuthentication
28 {
29
30 /**
31 * The username of the CLI user (there is only one)
32 * @var string
33 */
34 protected $username = '_cli_';
35
36 /**
37 * Constructor, only allowed in CLI mode
38 *
39 * @throws \RuntimeException
40 */
41 public function __construct()
42 {
43 if (!(TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_CLI)) {
44 throw new \RuntimeException('Creating a CLI-based user object on non-CLI level is not allowed', 1483971165);
45 }
46 if (!$this->isUserAllowedToLogin()) {
47 throw new \RuntimeException('Login Error: TYPO3 is in maintenance mode at the moment. Only administrators are allowed access.', 1483971855);
48 }
49 $this->dontSetCookie = true;
50 parent::__construct();
51 }
52
53 /**
54 * Logs-in the _CLI_ user. It does not need to check for credentials.
55 *
56 * @throws \RuntimeException when the user could not log in or it is an admin
57 */
58 public function authenticate()
59 {
60 // check if a _CLI_ user exists, if not, create one
61 $this->setBeUserByName($this->username);
62 if (!$this->user['uid']) {
63 // create a new BE user in the database
64 if (!$this->checkIfCliUserExists()) {
65 $this->createCliUser();
66 } else {
67 throw new \RuntimeException('No backend user named "_cli_" could be authenticated, maybe this user is "hidden"?', 1484050401);
68 }
69 $this->setBeUserByName($this->username);
70 }
71 if (!$this->user['uid']) {
72 throw new \RuntimeException('No backend user named "_cli_" could be created.', 1476107195);
73 }
74 // The groups are fetched and ready for permission checking in this initialization.
75 $this->fetchGroupData();
76 $this->backendSetUC();
77 // activate this functionality for DataHandler
78 $this->uc['recursiveDelete'] = true;
79 }
80
81 /**
82 * Logs in the TYPO3 Backend user "_cli_"
83 *
84 * @param bool $proceedIfNoUserIsLoggedIn if this option is set, then there won't be a redirect to the login screen of the Backend - used for areas in the backend which do not need user rights like the login page.
85 */
86 public function backendCheckLogin($proceedIfNoUserIsLoggedIn = false)
87 {
88 $this->authenticate();
89 }
90
91 /**
92 * Determines whether a CLI backend user is allowed to access TYPO3.
93 * Only when adminOnly is off (=0), and only allowed for admins and CLI users (=2)
94 *
95 * @return bool Whether the CLI user is allowed to access TYPO3
96 */
97 protected function isUserAllowedToLogin()
98 {
99 return in_array((int)$GLOBALS['TYPO3_CONF_VARS']['BE']['adminOnly'], [0, 2], true);
100 }
101
102 /**
103 * Check if a user with username "_cli_" exists. Deleted users are left out
104 * but hidden and start / endtime restricted users are considered.
105 *
106 * @return bool true if the user exists
107 */
108 protected function checkIfCliUserExists()
109 {
110 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('be_users');
111 $queryBuilder->getRestrictions()
112 ->removeAll()
113 ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
114 $count = $queryBuilder
115 ->count('*')
116 ->from('be_users')
117 ->where($queryBuilder->expr()->eq('username', $queryBuilder->createNamedParameter('_cli_')))
118 ->execute()
119 ->fetchColumn(0);
120 return (bool)$count;
121 }
122
123 /**
124 * Create a record in the DB table be_users called "_cli_" with no other information
125 */
126 protected function createCliUser()
127 {
128 $userFields = [
129 'username' => $this->username,
130 'password' => $this->generateHashedPassword(),
131 'admin' => 1,
132 'tstamp' => $GLOBALS['EXEC_TIME'],
133 'crdate' => $GLOBALS['EXEC_TIME']
134 ];
135
136 $databaseConnection = GeneralUtility::makeInstance(ConnectionPool::class)
137 ->getConnectionForTable('be_users');
138 $databaseConnection->insert('be_users', $userFields);
139 }
140
141 /**
142 * This function returns a salted hashed key.
143 *
144 * @return string a random password
145 */
146 protected function generateHashedPassword()
147 {
148 $cryptoService = GeneralUtility::makeInstance(Random::class);
149 $password = $cryptoService->generateRandomBytes(20);
150 $saltFactory = SaltFactory::getSaltingInstance(null, 'BE');
151 return $saltFactory->getHashedPassword($password);
152 }
153 }