shell bypass 403
<?php
/**
* @package Joomla.Plugin
* @subpackage System.Webauthn
*
* @copyright (C) 2020 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\System\Webauthn\PluginTraits;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Event\AbstractEvent;
use Joomla\CMS\Event\GenericEvent;
use Joomla\CMS\Event\Plugin\System\Webauthn\Ajax;
use Joomla\CMS\Event\Plugin\System\Webauthn\Ajax as PlgSystemWebauthnAjax;
use Joomla\CMS\Event\Plugin\System\Webauthn\AjaxChallenge as PlgSystemWebauthnAjaxChallenge;
use Joomla\CMS\Event\Plugin\System\Webauthn\AjaxCreate as PlgSystemWebauthnAjaxCreate;
use Joomla\CMS\Event\Plugin\System\Webauthn\AjaxDelete as PlgSystemWebauthnAjaxDelete;
use Joomla\CMS\Event\Plugin\System\Webauthn\AjaxInitCreate as PlgSystemWebauthnAjaxInitCreate;
use Joomla\CMS\Event\Plugin\System\Webauthn\AjaxLogin as PlgSystemWebauthnAjaxLogin;
use Joomla\CMS\Event\Plugin\System\Webauthn\AjaxSaveLabel as PlgSystemWebauthnAjaxSaveLabel;
use Joomla\CMS\Event\Result\ResultAwareInterface;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Log\Log;
use Joomla\CMS\Uri\Uri;
use Joomla\Event\Event;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Allows the plugin to handle AJAX requests in the backend of the site, where com_ajax is not
* available when we are not logged in.
*
* @since 4.0.0
*/
trait AjaxHandler
{
/**
* Processes the callbacks from the passwordless login views.
*
* Note: this method is called from Joomla's com_ajax or, in the case of backend logins,
* through the special onAfterInitialize handler we have created to work around com_ajax usage
* limitations in the backend.
*
* @param Event $event The event we are handling
*
* @return void
*
* @throws \Exception
* @since 4.0.0
*/
public function onAjaxWebauthn(Ajax $event): void
{
$input = $this->getApplication()->getInput();
// Get the return URL from the session
$returnURL = $this->getApplication()->getSession()->get('plg_system_webauthn.returnUrl', Uri::base());
$result = null;
try {
Log::add("Received AJAX callback.", Log::DEBUG, 'webauthn.system');
if (!($this->getApplication() instanceof CMSApplication)) {
Log::add("This is not a CMS application", Log::NOTICE, 'webauthn.system');
return;
}
$akaction = $input->getCmd('akaction');
if (!$this->getApplication()->checkToken('request')) {
throw new \RuntimeException(Text::_('JERROR_ALERTNOAUTHOR'));
}
// Empty action? No bueno.
if (empty($akaction)) {
throw new \RuntimeException(Text::_('PLG_SYSTEM_WEBAUTHN_ERR_AJAX_INVALIDACTION'));
}
// Call the plugin event onAjaxWebauthnSomething where Something is the akaction param.
/** @var AbstractEvent|ResultAwareInterface $triggerEvent */
$eventName = 'onAjaxWebauthn' . ucfirst($akaction);
switch ($eventName) {
case 'onAjaxWebauthn':
$eventClass = PlgSystemWebauthnAjax::class;
break;
case 'onAjaxWebauthnChallenge':
$eventClass = PlgSystemWebauthnAjaxChallenge::class;
break;
case 'onAjaxWebauthnCreate':
$eventClass = PlgSystemWebauthnAjaxCreate::class;
break;
case 'onAjaxWebauthnDelete':
$eventClass = PlgSystemWebauthnAjaxDelete::class;
break;
case 'onAjaxWebauthnInitcreate':
$eventClass = PlgSystemWebauthnAjaxInitCreate::class;
break;
case 'onAjaxWebauthnLogin':
$eventClass = PlgSystemWebauthnAjaxLogin::class;
break;
case 'onAjaxWebauthnSavelabel':
$eventClass = PlgSystemWebauthnAjaxSaveLabel::class;
break;
default:
$eventClass = GenericEvent::class;
break;
}
$triggerEvent = new $eventClass($eventName, []);
$result = $this->getApplication()->getDispatcher()->dispatch($eventName, $triggerEvent);
$results = ($result instanceof ResultAwareInterface) ? ($result['result'] ?? []) : [];
$result = array_reduce(
$results,
function ($carry, $result) {
return $carry ?? $result;
},
null
);
} catch (\Exception $e) {
Log::add("Callback failure, redirecting to $returnURL.", Log::DEBUG, 'webauthn.system');
$this->getApplication()->getSession()->set('plg_system_webauthn.returnUrl', null);
$this->getApplication()->enqueueMessage($e->getMessage(), 'error');
$this->getApplication()->redirect($returnURL);
return;
}
if (!\is_null($result)) {
switch ($input->getCmd('encoding', 'json')) {
case 'raw':
Log::add("Callback complete, returning raw response.", Log::DEBUG, 'webauthn.system');
echo $result;
break;
case 'redirect':
$modifiers = '';
if (isset($result['message'])) {
$type = $result['type'] ?? 'info';
$this->getApplication()->enqueueMessage($result['message'], $type);
$modifiers = " and setting a system message of type $type";
}
if (isset($result['url'])) {
Log::add("Callback complete, performing redirection to {$result['url']}{$modifiers}.", Log::DEBUG, 'webauthn.system');
$this->getApplication()->redirect($result['url']);
}
Log::add("Callback complete, performing redirection to {$result}{$modifiers}.", Log::DEBUG, 'webauthn.system');
$this->getApplication()->redirect($result);
return;
default:
Log::add("Callback complete, returning JSON.", Log::DEBUG, 'webauthn.system');
echo json_encode($result);
break;
}
$this->getApplication()->close(200);
}
Log::add("Null response from AJAX callback, redirecting to $returnURL", Log::DEBUG, 'webauthn.system');
$this->getApplication()->getSession()->set('plg_system_webauthn.returnUrl', null);
$this->getApplication()->redirect($returnURL);
}
}