[TASK] Change PHP namespace of EXT:openid to FoT3
[Packages/TYPO3.CMS.git] / typo3 / sysext / openid / Classes / OpenidService.php
1 <?php
2 namespace FoT3\Openid;
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\Database\DatabaseConnection;
18 use TYPO3\CMS\Core\Service\AbstractService;
19 use TYPO3\CMS\Core\TimeTracker\TimeTracker;
20 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
21 use TYPO3\CMS\Core\Utility\GeneralUtility;
22 use TYPO3\CMS\Core\Authentication\AbstractUserAuthentication;
23 use TYPO3\CMS\Core\Utility\HttpUtility;
24
25 require_once ExtensionManagementUtility::extPath('openid') . 'lib/php-openid/Auth/OpenID/Interface.php';
26
27 /**
28 * Service "OpenID Authentication" for the "openid" extension.
29 */
30 class OpenidService extends AbstractService
31 {
32 /**
33 * The extension key
34 *
35 * @var string
36 */
37 public $extKey = 'openid';
38
39 /**
40 * Login data as passed to initAuth()
41 *
42 * @var array
43 */
44 protected $loginData = array();
45
46 /**
47 * Additional authentication information provided by AbstractUserAuthentication.
48 * We use it to decide what database table contains user records.
49 *
50 * @var array
51 */
52 protected $authenticationInformation = array();
53
54 /**
55 * OpenID response object. It is initialized when OpenID provider returns
56 * with success/failure response to us.
57 *
58 * @var \Auth_OpenID_ConsumerResponse
59 */
60 protected $openIDResponse = null;
61
62 /**
63 * A reference to the calling object
64 *
65 * @var AbstractUserAuthentication
66 */
67 protected $parentObject;
68
69 /**
70 * @var DatabaseConnection
71 */
72 protected $databaseConnection;
73
74 /**
75 * If set to TRUE, than libraries are already included.
76 *
77 * @var bool
78 */
79 protected static $openIDLibrariesIncluded = false;
80
81 /**
82 * Constructs the OpenID authentication service.
83 */
84 public function __construct()
85 {
86 // Auth_Yadis_Yadis::getHTTPFetcher() will use a cURL fetcher if the functionality
87 // is available in PHP, however the TYPO3 setting is not considered here:
88 if (!defined('Auth_Yadis_CURL_OVERRIDE')) {
89 if (!$GLOBALS['TYPO3_CONF_VARS']['SYS']['curlUse']) {
90 define('Auth_Yadis_CURL_OVERRIDE', true);
91 }
92 }
93
94 $this->injectDatabaseConnection();
95 }
96
97 /**
98 * @param DatabaseConnection $databaseConnection
99 */
100 protected function injectDatabaseConnection(DatabaseConnection $databaseConnection = null)
101 {
102 $this->databaseConnection = $databaseConnection ?: $GLOBALS['TYPO3_DB'];
103 }
104
105 /**
106 * Checks if service is available,. In case of this service we check that
107 * prerequisites for "PHP OpenID" libraries are fulfilled:
108 * - GMP or BCMATH PHP extensions are installed and functional
109 * - set_include_path() PHP function is available
110 *
111 * @return bool TRUE if service is available
112 */
113 public function init()
114 {
115 $available = false;
116 if (extension_loaded('gmp')) {
117 $available = is_callable('gmp_init');
118 } elseif (extension_loaded('bcmath')) {
119 $available = is_callable('bcadd');
120 } else {
121 $this->writeLog('Neither bcmath, nor gmp PHP extension found. OpenID authentication will not be available.');
122 }
123 // We also need set_include_path() PHP function
124 if (!is_callable('set_include_path')) {
125 $available = false;
126 $this->writeLog('set_include_path() PHP function is not available. OpenID authentication is disabled.');
127 }
128 return $available ? parent::init() : false;
129 }
130
131 /**
132 * Initializes authentication for this service.
133 *
134 * @param string $subType: Subtype for authentication (either "getUserFE" or "getUserBE")
135 * @param array $loginData: Login data submitted by user and preprocessed by AbstractUserAuthentication
136 * @param array $authenticationInformation: Additional TYPO3 information for authentication services (unused here)
137 * @param AbstractUserAuthentication $parentObject Calling object
138 * @return void
139 */
140 public function initAuth($subType, array $loginData, array $authenticationInformation, AbstractUserAuthentication &$parentObject)
141 {
142 // Store login and authentication data
143 $this->loginData = $loginData;
144 $this->authenticationInformation = $authenticationInformation;
145 // If we are here after authentication by the OpenID server, get its response.
146 if (GeneralUtility::_GP('tx_openid_mode') === 'finish' && $this->openIDResponse === null) {
147 $this->includePHPOpenIDLibrary();
148 $openIDConsumer = $this->getOpenIDConsumer();
149 $this->openIDResponse = $openIDConsumer->complete($this->getReturnURL(GeneralUtility::_GP('tx_openid_claimed')));
150 }
151 $this->parentObject = $parentObject;
152 }
153
154 /**
155 * Process the submitted OpenID URL if valid.
156 *
157 * @param array $loginData Credentials that are submitted and potentially modified by other services
158 * @param string $passwordTransmissionStrategy Keyword of how the password has been hashed or encrypted before submission
159 * @return bool
160 */
161 public function processLoginData(array &$loginData, $passwordTransmissionStrategy)
162 {
163 $isProcessed = false;
164 // Pre-process the login only if no password has been submitted
165 if (empty($loginData['uident_text'])) {
166 try {
167 $openIdUrl = GeneralUtility::_POST('openid_url');
168 if (!empty($openIdUrl)) {
169 $loginData['uident_openid'] = $this->normalizeOpenID($openIdUrl);
170 $isProcessed = true;
171 } elseif (!empty($loginData['uname'])) {
172 // It might be the case that during frontend login the OpenID URL is submitted in the username field
173 // Since we are a low priority service, and no password has been submitted it is OK to just assume
174 // we might have gotten an OpenID URL
175 $loginData['uident_openid'] = $this->normalizeOpenID($loginData['uname']);
176 $isProcessed = true;
177 }
178 } catch (Exception $e) {
179 $this->writeLog($e->getMessage());
180 }
181 }
182 return $isProcessed;
183 }
184
185 /**
186 * This function returns the user record back to the AbstractUserAuthentication.
187 * It does not mean that user is authenticated, it means only that user is found. This
188 * function makes sure that user cannot be authenticated by any other service
189 * if user tries to use OpenID to authenticate.
190 *
191 * @return mixed User record (content of fe_users/be_users as appropriate for the current mode)
192 */
193 public function getUser()
194 {
195 if ($this->loginData['status'] !== 'login') {
196 return null;
197 }
198 $userRecord = null;
199 if ($this->openIDResponse instanceof \Auth_OpenID_ConsumerResponse) {
200 $GLOBALS['BACK_PATH'] = $this->getBackPath();
201 // We are running inside the OpenID return script
202 // Note: we cannot use $this->openIDResponse->getDisplayIdentifier()
203 // because it may return a different identifier. For example,
204 // LiveJournal server converts all underscore characters in the
205 // original identfier to dashes.
206 if ($this->openIDResponse->status === Auth_OpenID_SUCCESS) {
207 $openIDIdentifier = $this->getFinalOpenIDIdentifier();
208 if ($openIDIdentifier) {
209 $userRecord = $this->getUserRecord($openIDIdentifier);
210 if (!empty($userRecord) && is_array($userRecord)) {
211 // The above function will return user record from the OpenID. It means that
212 // user actually tried to authenticate using his OpenID. In this case
213 // we must change the password in the record to a long random string so
214 // that this user cannot be authenticated with other service.
215 $userRecord[$this->authenticationInformation['db_user']['userident_column']] = GeneralUtility::getRandomHexString(42);
216 $this->writeLog('User \'%s\' logged in with OpenID \'%s\'', $userRecord[$this->parentObject->formfield_uname], $openIDIdentifier);
217 } else {
218 $this->writeLog('Failed to login user using OpenID \'%s\'', $openIDIdentifier);
219 }
220 }
221 }
222 } elseif (!empty($this->loginData['uident_openid'])) {
223 $this->sendOpenIDRequest($this->loginData['uident_openid']);
224 }
225 return $userRecord;
226 }
227
228 /**
229 * Authenticates user using OpenID.
230 *
231 * @param array $userRecord User record
232 * @return int Code that shows if user is really authenticated.
233 */
234 public function authUser(array $userRecord)
235 {
236 $result = 100;
237 // 100 means "we do not know, continue"
238 if ($userRecord['tx_openid_openid'] !== '') {
239 // Check if user is identified by the OpenID
240 if ($this->openIDResponse instanceof \Auth_OpenID_ConsumerResponse) {
241 // If we have a response, it means OpenID server tried to authenticate
242 // the user. Now we just look what is the status and provide
243 // corresponding response to the caller
244 if ($this->openIDResponse->status === Auth_OpenID_SUCCESS) {
245 // Success (code 200)
246 $result = 200;
247 } else {
248 $this->writeLog('OpenID authentication failed with code \'%s\'.', $this->openIDResponse->status);
249 }
250 }
251 }
252 return $result;
253 }
254
255 /**
256 * Includes necessary files for the PHP OpenID library
257 *
258 * @return void
259 */
260 protected function includePHPOpenIDLibrary()
261 {
262 if (self::$openIDLibrariesIncluded) {
263 return;
264 }
265 // Prevent further calls
266 self::$openIDLibrariesIncluded = true;
267 // PHP OpenID libraries requires adjustments of path settings
268 $oldIncludePath = get_include_path();
269 $phpOpenIDLibPath = ExtensionManagementUtility::extPath('openid') . 'lib/php-openid';
270 @set_include_path(($phpOpenIDLibPath . PATH_SEPARATOR . $phpOpenIDLibPath . PATH_SEPARATOR . 'Auth' . PATH_SEPARATOR . $oldIncludePath));
271 // Make sure that random generator is properly set up. Constant could be
272 // defined by the previous inclusion of the file
273 if (!defined('Auth_OpenID_RAND_SOURCE')) {
274 if (TYPO3_OS === 'WIN') {
275 // No random generator on Windows!
276 define('Auth_OpenID_RAND_SOURCE', null);
277 } elseif (!is_readable('/dev/urandom')) {
278 if (is_readable('/dev/random')) {
279 define('Auth_OpenID_RAND_SOURCE', '/dev/random');
280 } else {
281 define('Auth_OpenID_RAND_SOURCE', null);
282 }
283 }
284 }
285 // Include files
286 require_once $phpOpenIDLibPath . '/Auth/OpenID/Consumer.php';
287 // Restore path
288 @set_include_path($oldIncludePath);
289 if (!is_array($_SESSION)) {
290 // Yadis requires session but session is not initialized when
291 // processing Backend authentication
292 @session_start();
293 $this->writeLog('Session is initialized');
294 }
295 }
296
297 /**
298 * Gets user record for the user with the OpenID provided by the user
299 *
300 * @param string $openIDIdentifier OpenID identifier to search for
301 * @return array Database fields from the table that corresponds to the current login mode (FE/BE)
302 */
303 protected function getUserRecord($openIDIdentifier)
304 {
305 $record = null;
306 try {
307 $openIDIdentifier = $this->normalizeOpenID($openIDIdentifier);
308 // $openIDIdentifier always has a trailing slash
309 // but tx_openid_openid field possibly not so check for both alternatives in database
310 $record = $this->databaseConnection->exec_SELECTgetSingleRow(
311 '*',
312 $this->authenticationInformation['db_user']['table'],
313 'tx_openid_openid IN ('
314 . $this->databaseConnection->fullQuoteStr($openIDIdentifier, $this->authenticationInformation['db_user']['table'])
315 . ',' . $this->databaseConnection->fullQuoteStr(rtrim($openIDIdentifier, '/'),
316 $this->authenticationInformation['db_user']['table']) . ')'
317 . $this->authenticationInformation['db_user']['check_pid_clause']
318 . $this->authenticationInformation['db_user']['enable_clause']
319 );
320 if ($record) {
321 // Make sure to work only with normalized OpenID during the whole process
322 $record['tx_openid_openid'] = $this->normalizeOpenID($record['tx_openid_openid']);
323 }
324 } catch (Exception $e) {
325 // This should never happen and generally means hack attempt.
326 // We just log it and do not return any records.
327 $this->writeLog($e->getMessage());
328 }
329
330 // Hook to modify the user record, e.g. to register a new user
331 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['openid']['getUserRecord']) && is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['openid']['getUserRecord'])) {
332 $_params = array(
333 'record' => &$record,
334 'response' => $this->openIDResponse,
335 'authInfo' => $this->authenticationInformation
336 );
337 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['openid']['getUserRecord'] as $funcName) {
338 GeneralUtility::callUserFunction($funcName, $_params, $this);
339 }
340 }
341
342 return $record;
343 }
344
345 /**
346 * Creates OpenID Consumer object with a TYPO3-specific store. This function
347 * is almost identical to the example from the PHP OpenID library.
348 *
349 * @return \Auth_OpenID_Consumer Consumer instance
350 */
351 protected function getOpenIDConsumer()
352 {
353 /* @var $openIDStore OpenidStore */
354 $openIDStore = GeneralUtility::makeInstance(OpenidStore::class);
355 $openIDStore->cleanup();
356 return new \Auth_OpenID_Consumer($openIDStore);
357 }
358
359 /**
360 * Sends request to the OpenID server to authenticate the user with the
361 * given ID. This function is almost identical to the example from the PHP
362 * OpenID library. Due to the OpenID specification we cannot do a slient login.
363 * Sometimes we have to redirect to the OpenID provider web site so that
364 * user can enter his password there. In this case we will redirect and provide
365 * a return adress to the special script inside this directory, which will
366 * handle the result appropriately.
367 *
368 * This function does not return on success. If it returns, it means something
369 * went totally wrong with OpenID.
370 *
371 * @param string $openIDIdentifier The OpenID identifier for discovery and auth request
372 * @return void
373 */
374 protected function sendOpenIDRequest($openIDIdentifier)
375 {
376 $this->includePHPOpenIDLibrary();
377 // Initialize OpenID client system, get the consumer
378 $openIDConsumer = $this->getOpenIDConsumer();
379 // Begin the OpenID authentication process
380 $authenticationRequest = $openIDConsumer->begin($openIDIdentifier);
381 if (!$authenticationRequest) {
382 // Not a valid OpenID. Since it can be some other ID, we just return
383 // and let other service handle it.
384 $this->writeLog('Could not create authentication request for OpenID identifier \'%s\'', $openIDIdentifier);
385 return;
386 }
387
388 // Hook to modify the auth request object, e.g. to request additional attributes
389 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['openid']['authRequest']) && is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['openid']['authRequest'])) {
390 $_params = array(
391 'authRequest' => $authenticationRequest,
392 'authInfo' => $this->authenticationInformation
393 );
394 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['openid']['authRequest'] as $funcName) {
395 GeneralUtility::callUserFunction($funcName, $_params, $this);
396 }
397 }
398
399 // Redirect the user to the OpenID server for authentication.
400 // Store the token for this authentication so we can verify the
401 // response.
402 // For OpenID version 1, we *should* send a redirect. For OpenID version 2,
403 // we should use a Javascript form to send a POST request to the server.
404 $returnURL = $this->getReturnURL($openIDIdentifier);
405 $trustedRoot = GeneralUtility::getIndpEnv('TYPO3_SITE_URL');
406 if ($authenticationRequest->shouldSendRedirect()) {
407 $redirectURL = $authenticationRequest->redirectURL($trustedRoot, $returnURL);
408 // If the redirect URL can't be built, return. We can only return.
409 if (\Auth_OpenID::isFailure($redirectURL)) {
410 $this->writeLog('Authentication request could not create redirect URL for OpenID identifier \'%s\'', $openIDIdentifier);
411 return;
412 }
413 // Send redirect. We use 303 code because it allows to redirect POST
414 // requests without resending the form. This is exactly what we need here.
415 // See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.4
416 @ob_end_clean();
417 HttpUtility::redirect($redirectURL, HttpUtility::HTTP_STATUS_303);
418 } else {
419 $formHtml = $authenticationRequest->htmlMarkup($trustedRoot, $returnURL, false, array('id' => 'openid_message'));
420 // Display an error if the form markup couldn't be generated;
421 // otherwise, render the HTML.
422 if (\Auth_OpenID::isFailure($formHtml)) {
423 // Form markup cannot be generated
424 $this->writeLog('Could not create form markup for OpenID identifier \'%s\'', $openIDIdentifier);
425 return;
426 } else {
427 @ob_end_clean();
428 echo $formHtml;
429 }
430 }
431 // If we reached this point, we must not return!
432 die;
433 }
434
435 /**
436 * Creates return URL for the OpenID server. When a user is authenticated by
437 * the OpenID server, the user will be sent to this URL to complete
438 * authentication process with the current site. We send it to our script.
439 *
440 * @param string $claimedIdentifier The OpenID identifier for discovery and auth request
441 * @return string Return URL
442 */
443 protected function getReturnURL($claimedIdentifier)
444 {
445 if ($this->authenticationInformation['loginType'] === 'FE') {
446 // We will use eID to send user back, create session data and
447 // return to the calling page.
448 // Notice: 'pid' and 'logintype' parameter names cannot be changed!
449 // They are essential for FE user authentication.
450 $returnURL = 'index.php?eID=tx_openid&' . 'pid=' . $this->authenticationInformation['db_user']['checkPidList'] . '&logintype=login';
451 } else {
452 // In the Backend we will use dedicated script to create session.
453 // It is much easier for the Backend to manage users.
454 // Notice: 'login_status' parameter name cannot be changed!
455 // It is essential for BE user authentication.
456 $returnURL = GeneralUtility::getIndpEnv('TYPO3_SITE_URL') . TYPO3_mainDir . 'index.php?login_status=login';
457 }
458 if (GeneralUtility::_GP('tx_openid_mode') === 'finish') {
459 $requestURL = GeneralUtility::_GP('tx_openid_location');
460 } else {
461 $requestURL = GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL');
462 }
463 $returnURL .= '&tx_openid_location=' . rawurlencode($requestURL) . '&tx_openid_location_signature=' . $this->getSignature($requestURL) . '&tx_openid_mode=finish&tx_openid_claimed=' . rawurlencode($claimedIdentifier) . '&tx_openid_signature=' . $this->getSignature($claimedIdentifier);
464 return GeneralUtility::locationHeaderUrl($returnURL);
465 }
466
467 /**
468 * Signs a GET parameter.
469 *
470 * @param string $parameter
471 * @return string
472 */
473 protected function getSignature($parameter)
474 {
475 return GeneralUtility::hmac($parameter, $this->extKey);
476 }
477
478 /**
479 * Implement normalization according to OpenID 2.0 specification
480 * See http://openid.net/specs/openid-authentication-2_0.html#normalization
481 *
482 * @param string $openIDIdentifier OpenID identifier to normalize
483 * @return string Normalized OpenID identifier
484 * @throws Exception
485 */
486 protected function normalizeOpenID($openIDIdentifier)
487 {
488 if (empty($openIDIdentifier)) {
489 throw new Exception('Empty OpenID Identifier given.', 1381922460);
490 }
491 // Strip everything with and behind the fragment delimiter character "#"
492 if (strpos($openIDIdentifier, '#') !== false) {
493 $openIDIdentifier = preg_replace('/#.*$/', '', $openIDIdentifier);
494 }
495 // A URI with a missing scheme is normalized to a http URI
496 if (!preg_match('#^https?://#', $openIDIdentifier)) {
497 $escapedIdentifier = $this->databaseConnection->quoteStr($openIDIdentifier, $this->authenticationInformation['db_user']['table']);
498 $condition = 'tx_openid_openid IN ('
499 . '\'http://' . $escapedIdentifier . '\','
500 . '\'http://' . $escapedIdentifier . '/\','
501 . '\'https://' . $escapedIdentifier . '\','
502 . '\'https://' . $escapedIdentifier . '/\''
503 . ')';
504 $row = $this->databaseConnection->exec_SELECTgetSingleRow(
505 'tx_openid_openid',
506 $this->authenticationInformation['db_user']['table'],
507 $condition
508 );
509 if (is_array($row)) {
510 $openIDIdentifier = $row['tx_openid_openid'];
511 } else {
512 // This only happens when the OpenID provider will select the final OpenID identity
513 // In this case we require a valid URL as we cannot guess the scheme
514 // So we throw an Exception and do not start the OpenID handshake at all
515 throw new Exception('Trying to authenticate with OpenID but identifier is neither found in a user record nor it is a valid URL.', 1381922465);
516 }
517 }
518 // An empty path component is normalized to a slash
519 // (e.g. "http://domain.org" -> "http://domain.org/")
520 if (preg_match('#^https?://[^/]+$#', $openIDIdentifier)) {
521 $openIDIdentifier .= '/';
522 }
523 return $openIDIdentifier;
524 }
525
526 /**
527 * Calculates the path to the TYPO3 directory from the current directory
528 *
529 * @return string
530 */
531 protected function getBackPath()
532 {
533 $extPath = ExtensionManagementUtility::siteRelPath('openid');
534 $segmentCount = count(explode('/', $extPath));
535 $path = str_pad('', $segmentCount * 3, '../') . TYPO3_mainDir;
536 return $path;
537 }
538
539 /**
540 * Obtains a real identifier for the user
541 *
542 * @return string
543 */
544 protected function getFinalOpenIDIdentifier()
545 {
546 $result = $this->getSignedParameter('openid_claimed_id');
547 if (!$result) {
548 $result = $this->getSignedParameter('openid_identity');
549 }
550 if (!$result) {
551 $result = $this->getSignedClaimedOpenIDIdentifier();
552 }
553 return $result;
554 }
555
556 /**
557 * Gets the signed OpenID that was sent back to this service.
558 *
559 * @return string The signed OpenID, if signature did not match this is empty
560 */
561 protected function getSignedClaimedOpenIDIdentifier()
562 {
563 $result = GeneralUtility::_GP('tx_openid_claimed');
564 $signature = $this->getSignature($result);
565 if ($signature !== GeneralUtility::_GP('tx_openid_signature')) {
566 $result = '';
567 }
568 return $result;
569 }
570
571 /**
572 * Obtains a value of the parameter if it is signed. If not signed, then
573 * empty string is returned.
574 *
575 * @param string $parameterName Must start with 'openid_'
576 * @return string
577 */
578 protected function getSignedParameter($parameterName)
579 {
580 $signedParametersList = GeneralUtility::_GP('openid_signed');
581 if (GeneralUtility::inList($signedParametersList, substr($parameterName, 7))) {
582 $result = GeneralUtility::_GP($parameterName);
583 } else {
584 $result = '';
585 }
586 return $result;
587 }
588
589 /**
590 * Writes log message. Destination log depends on the current system mode.
591 * For FE the function writes to the admin panel log. For BE messages are
592 * sent to the system log. If developer log is enabled, messages are also
593 * sent there.
594 *
595 * This function accepts variable number of arguments and can format
596 * parameters. The syntax is the same as for sprintf()
597 *
598 * @param string $message Message to output
599 * @return void
600 * @see GeneralUtility::sysLog()
601 * @see \TYPO3\CMS\Core\TimeTracker\TimeTracker::setTSlogMessage()
602 */
603 protected function writeLog($message)
604 {
605 if (func_num_args() > 1) {
606 $params = func_get_args();
607 array_shift($params);
608 $message = vsprintf($message, $params);
609 }
610 if (TYPO3_MODE === 'BE') {
611 GeneralUtility::sysLog($message, $this->extKey, GeneralUtility::SYSLOG_SEVERITY_NOTICE);
612 } else {
613 /** @var TimeTracker $tt */
614 $tt = $GLOBALS['TT'];
615 $tt->setTSlogMessage($message);
616 }
617 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['enable_DLOG']) {
618 GeneralUtility::devLog($message, $this->extKey, GeneralUtility::SYSLOG_SEVERITY_NOTICE);
619 }
620 }
621 }