class.tx_ter_helper.php 11.1 KB
Newer Older
1
<?php
2
/*
3
4
5
6
7
8
9
10
11
12
13
 * This file is part of the TYPO3 CMS project.
 *
 * It is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License, either version 2
 * of the License, or any later version.
 *
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
 *
 * The TYPO3 project - inspiring people to share!
 */
14

15
16
17
18
19
/**
 * Helper functions used in the TER API
 *
 * @author    Robert Lemke <robert@typo3.org>
 */
Thomas Löffler's avatar
Thomas Löffler committed
20
use TYPO3\CMS\Core\Database\ConnectionPool;
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
use TYPO3\CMS\Core\Utility\GeneralUtility;

// Error codes:
define('TX_TER_ERROR_GENERAL_EXTREPDIRDOESNTEXIST', '100');
define('TX_TER_ERROR_GENERAL_NOUSERORPASSWORD', '101');
define('TX_TER_ERROR_GENERAL_USERNOTFOUND', '102');
define('TX_TER_ERROR_GENERAL_WRONGPASSWORD', '103');
define('TX_TER_ERROR_GENERAL_DATABASEERROR', '104');
define('TX_TER_ERROR_GENERAL_EXTENSIONCONTAINSNOFILES', '105');

define('TX_TER_ERROR_UPLOADEXTENSION_EXTENSIONDOESNTEXIST', '202');
define('TX_TER_ERROR_UPLOADEXTENSION_EXTENSIONCONTAINSNOFILES', '203');
define('TX_TER_ERROR_UPLOADEXTENSION_WRITEERRORWHILEWRITINGFILES', '204');
define('TX_TER_ERROR_UPLOADEXTENSION_EXTENSIONTOOBIG', '205');
define('TX_TER_ERROR_UPLOADEXTENSION_EXISTINGEXTENSIONRECORDNOTFOUND', '206');
define('TX_TER_ERROR_UPLOADEXTENSION_FILEMD5DOESNOTMATCH', '207');
define('TX_TER_ERROR_UPLOADEXTENSION_ACCESSDENIED', '208');
define('TX_TER_ERROR_UPLOADEXTENSION_TYPO3DEPENDENCYINCORRECT', '209');
define('TX_TER_ERROR_UPLOADEXTENSION_TYPO3DEPENDENCYCHECKFAILED', '210');
define('TX_TER_ERROR_UPLOADEXTENSION_EXTENSIONVERSIONEXISTS', '211');
41
define('TX_TER_ERROR_UPLOADEXTENSION_NOUPLOADCOMMENT', '212');
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94

define('TX_TER_ERROR_REGISTEREXTENSIONKEY_DBERRORWHILEINSERTINGKEY', '300');

define('TX_TER_ERROR_DELETEEXTENSIONKEY_ACCESSDENIED', '500');
define('TX_TER_ERROR_DELETEEXTENSIONKEY_KEYDOESNOTEXIST', '501');
define('TX_TER_ERROR_DELETEEXTENSIONKEY_CANTDELETEBECAUSEVERSIONSEXIST', '502');

define('TX_TER_ERROR_MODIFYEXTENSIONKEY_ACCESSDENIED', '600');
define('TX_TER_ERROR_MODIFYEXTENSIONKEY_SETTINGTOTHISOWNERISNOTPOSSIBLE', '601');
define('TX_TER_ERROR_MODIFYEXTENSIONKEY_KEYDOESNOTEXIST', '602');

define('TX_TER_ERROR_SETREVIEWSTATE_NOUSERGROUPDEFINED', '700');
define('TX_TER_ERROR_SETREVIEWSTATE_ACCESSDENIED', '701');
define('TX_TER_ERROR_SETREVIEWSTATE_EXTENSIONVERSIONDOESNOTEXIST', '702');

define('TX_TER_ERROR_INCREASEEXTENSIONDOWNLOADCOUNTER_NOUSERGROUPDEFINED', '800');
define('TX_TER_ERROR_INCREASEEXTENSIONDOWNLOADCOUNTER_ACCESSDENIED', '801');
define('TX_TER_ERROR_INCREASEEXTENSIONDOWNLOADCOUNTER_EXTENSIONVERSIONDOESNOTEXIST', '802');
define('TX_TER_ERROR_INCREASEEXTENSIONDOWNLOADCOUNTER_INCREMENTORNOTPOSITIVEINTEGER', '803');
define('TX_TER_ERROR_INCREASEEXTENSIONDOWNLOADCOUNTER_EXTENSIONKEYDOESNOTEXIST', '804');

define('TX_TER_ERROR_DELETEEXTENSION_ACCESS_DENIED', '900');
define('TX_TER_ERROR_DELETEEXTENSION_EXTENSIONDOESNTEXIST', '901');

// Result codes:
define('TX_TER_RESULT_GENERAL_OK', '10000');
define('TX_TER_RESULT_ERRORS_OCCURRED', '10001');

define('TX_TER_RESULT_EXTENSIONKEYALREADYEXISTS', '10500');
define('TX_TER_RESULT_EXTENSIONKEYDOESNOTEXIST', '10501');
define('TX_TER_RESULT_EXTENSIONKEYNOTVALID', '10502');
define('TX_TER_RESULT_EXTENSIONKEYSUCCESSFULLYREGISTERED', '10503');
define('TX_TER_RESULT_EXTENSIONSUCCESSFULLYUPLOADED', '10504');
define('TX_TER_RESULT_EXTENSIONSUCCESSFULLYDELETED', '10505');

/**
 * TYPO3 Extension Repository, helper functions
 *
 * @author    Robert Lemke <robert@typo3.org>
 */
class tx_ter_helper
{
    protected $pluginObj;

    /**
     * Constructor
     *
     * @param    object $pluginObj : Reference to parent object
     * @access    public
     */
    public function __construct($pluginObj)
    {
        $this->pluginObj = $pluginObj;
Thomas Löffler's avatar
Thomas Löffler committed
95
96
        $this->pluginObj->conf['adminFrontendUsergroupUid'] = 26;
        $this->pluginObj->conf['securityTeamFrontendUsergroupUid'] = 22;
97
98
99
100
101
102
103
104
105
    }

    /**
     * This verifies the given fe_users username/password.
     * Either the fe_user row is returned or an exception is thrown.
     *
     * @param    object $accountData : Account data information with username, password and upload password
     * @return    mixed        If success, returns array of fe_users, otherwise error string.
     * @access    public
106
     * @throws \T3o\Ter\Exception\UnauthorizedException
107
     */
Thomas Löffler's avatar
Thomas Löffler committed
108
    public function getValidUser(object $accountData): ?array
109
    {
Thomas Löffler's avatar
Thomas Löffler committed
110
        if ($accountData->username === '' || $accountData->password === '') {
111
            throw new \T3o\Ter\Exception\UnauthorizedException('No user or no password submitted.', TX_TER_ERROR_GENERAL_NOUSERORPASSWORD);
112
113
        }

Thomas Löffler's avatar
Fix CGL    
Thomas Löffler committed
114
        $user = $this->getUserByUsername($accountData->username);
Thomas Löffler's avatar
Thomas Löffler committed
115
116
117

        if ($user) {
            if (!$this->userIsAlreadyLoggedIn($accountData) && !$this->ldapValidationSucceeded($accountData)) {
118
                throw new \T3o\Ter\Exception\UnauthorizedException('Wrong password.', TX_TER_ERROR_GENERAL_WRONGPASSWORD);
119
            }
Thomas Löffler's avatar
Thomas Löffler committed
120
            $user['admin'] = $this->userIsAdmin($user['usergroup']) || $this->userIsSecurityTeamMember($user['usergroup']);
121
        } else {
122
            throw new \T3o\Ter\Exception\UnauthorizedException('The specified user does not exist. You need to login first on extensions.typo3.org.', TX_TER_ERROR_GENERAL_USERNOTFOUND);
123
124
        }

Thomas Löffler's avatar
Thomas Löffler committed
125
126
        return $user;
    }
127

Thomas Löffler's avatar
Thomas Löffler committed
128
129
130
131
132
133
134
135
136
137
138
139
140
141
    private function getUserByUsername(string $username = ''): ?array
    {
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('fe_users');

        $userRecord = $queryBuilder
            ->select('*')
            ->from('fe_users')
            ->where(
                $queryBuilder->expr()->eq('username', $queryBuilder->createNamedParameter($username))
            )
            ->execute()
            ->fetch();

        return $userRecord ?: null;
142
143
    }

144
145
146
147
148
149
    /**
     * @param string $userGroupList
     * @return bool
     */
    private function userIsAdmin(string $userGroupList): bool
    {
Thomas Löffler's avatar
Thomas Löffler committed
150
        return $this->pluginObj->conf['adminFrontendUsergroupUid'] > 0 && GeneralUtility::inList($userGroupList, (int)$this->pluginObj->conf['adminFrontendUsergroupUid']);
151
152
153
154
155
156
157
158
    }

    /**
     * @param string $userGroupList
     * @return bool
     */
    private function userIsSecurityTeamMember(string $userGroupList): bool
    {
Thomas Löffler's avatar
Thomas Löffler committed
159
        return $this->pluginObj->conf['securityTeamFrontendUsergroupUid'] > 0 && GeneralUtility::inList($userGroupList, (int)$this->pluginObj->conf['securityTeamFrontendUsergroupUid']);
160
161
    }

162
163
164
165
166
167
168
    /**
     * We check whether a user is logged in by TYPO3
     * because of a sent session cookie
     *
     * @param $accountData
     * @return bool
     */
Thomas Löffler's avatar
Thomas Löffler committed
169
    private function userIsAlreadyLoggedIn(object $accountData): bool
170
171
    {
        /** @var \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController $tsfe */
Thomas Löffler's avatar
Thomas Löffler committed
172
        $tsfe = $GLOBALS['TSFE'];
173

Thomas Löffler's avatar
Thomas Löffler committed
174
        return !empty($tsfe->fe_user->user['username']) && $accountData->username === $tsfe->fe_user->user['username'];
175
176
    }

177
178
179
180
181
182
    /**
     * Check if LDAP authenticates the credentials
     *
     * @param stdClass $accountData
     * @return bool
     */
Thomas Löffler's avatar
Thomas Löffler committed
183
    private function ldapValidationSucceeded(\stdClass $accountData): bool
184
185
186
187
188
189
190
191
192
193
194
195
196
197
    {
        if (!\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('ig_ldap_sso_auth')) {
            return false;
        }

        /** @var \Causal\IgLdapSsoAuth\Domain\Repository\ConfigurationRepository $configurationRepository */
        $configurationRepository = GeneralUtility::makeInstance(\Causal\IgLdapSsoAuth\Domain\Repository\ConfigurationRepository::class);
        $configurationRecords = $configurationRepository->findAll();

        \Causal\IgLdapSsoAuth\Library\Configuration::initialize('fe', $configurationRecords[0]);

        return (bool)\Causal\IgLdapSsoAuth\Library\Authentication::ldapAuthenticate($accountData->username, $accountData->password);
    }

198
199
200
201
202
    /**
     * Checks for correct account data without throwing an exception.
     * It just returns TRUE / FALSE
     *
     * @param  object $accountData
203
     * @return bool
204
     */
Thomas Löffler's avatar
Thomas Löffler committed
205
    public function checkValidUser(string $accountData): bool
206
    {
Thomas Löffler's avatar
Thomas Löffler committed
207
        if ($accountData->username === '' || $accountData->password === '') {
208
209
            $success = false;
        } else {
Thomas Löffler's avatar
Thomas Löffler committed
210
211
            $user = $this->getUserByUsername($accountData->username);
            $success = $user && $this->ldapValidationSucceeded($accountData);
212
213
214
215
216
217
218
219
220
221
222
        }

        return $success;
    }

    /**
     * Checks if the given extension key is unique and not registered yet.
     * Takes underscores into account, so the key "ter_ter" can't be registered
     * if "te_rt_er" or "terter" already exist.
     *
     * @param    string $extensionKey : The extension key to check
223
     * @return    bool        Returns TRUE if the extension key is unique and not used yet, otherwise FALSE
224
225
226
     * @access    public
     * @author  Elmar Hinz
     */
Thomas Löffler's avatar
Thomas Löffler committed
227
    public function extensionKeyIsAvailable(string $extensionKey): bool
228
229
    {
        $cleanedExtensionKey = str_replace('_', '', $extensionKey);
Thomas Löffler's avatar
Thomas Löffler committed
230

231
232
233
234
235
236
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_ter_extensionkeys');
        $result = $queryBuilder->select('extensionkey')
            ->from('tx_ter_extensionkeys')
            ->add('where', 'REPLACE(extensionkey, "_", "") = ' . $queryBuilder->createNamedParameter($cleanedExtensionKey))
            ->execute()
            ->rowCount();
237

238
        return $result === 0;
239
240
241
242
243
244
245
246
247
    }

    /**
     * Based on $extKey this returns the extension-key record.
     *
     * @param    string $extKey : Extension key
     * @return    mixed        The extension key row or FALSE
     * @access    public
     */
Thomas Löffler's avatar
Thomas Löffler committed
248
    public function getExtensionKeyRecord(string $extKey): ?array
249
    {
Thomas Löffler's avatar
Thomas Löffler committed
250
251
252
253
254
255
256
257
258
259
260
261
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_ter_extensionkeys');

        $extensionKeyRecord = $queryBuilder
            ->select('*')
            ->from('tx_ter_extensionkeys')
            ->where(
                $queryBuilder->expr()->eq('extensionkey', $queryBuilder->createNamedParameter($extKey))
            )
            ->execute()
            ->fetch();

        return $extensionKeyRecord ?: null;
262
263
264
265
266
267
268
269
270
    }

    /***
     * Load an instance of the BE_USER to use with TCEFORM
     *
     * @param string $username Username
     * @param boolean $isAdmin Set admin rights
     * @return void
     */
Thomas Löffler's avatar
Thomas Löffler committed
271
    public function loadBackendUser(string $username, bool $isAdmin = false): void
272
273
274
275
276
277
278
    {
        if (!empty($GLOBALS['BE_USER'])) {
            return;
        }

        $GLOBALS['BE_USER'] = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::class);
        $GLOBALS['BE_USER']->user = [
279
            'uid' => 0,
280
281
282
283
284
285
286
287
            'username' => $username,
            'admin' => (int)$isAdmin,
        ];
    }

    /**
     * Load an instance of the LANG object
     *
Thomas Löffler's avatar
Thomas Löffler committed
288
     * @param string $lang Used language ident
289
     */
Thomas Löffler's avatar
Thomas Löffler committed
290
    public function loadLang(string $lang = 'default'): void
291
292
293
294
295
    {
        if (!empty($GLOBALS['LANG'])) {
            return;
        }

Thomas Löffler's avatar
Thomas Löffler committed
296
        $GLOBALS['LANG'] = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Localization\LanguageService::class);
297
298
        $GLOBALS['LANG']->init($lang);
    }
299
}