uawdijnntqw1x1x1
IP : 216.73.217.142
Hostname : localhost.localdomain
Kernel : Linux localhost.localdomain 4.15.0-213-generic #224-Ubuntu SMP Mon Jun 19 13:30:12 UTC 2023 x86_64
Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
OS : Linux
PATH:
/
var
/
www
/
consult-e-syn
/
public_html
/
c1c92
/
..
/
plugins
/
system
/
loginguard_
/
loginguard.php
/
/
<?php /** * @package AkeebaLoginGuard * @copyright Copyright (c)2016-2020 Nicholas K. Dionysopoulos / Akeeba Ltd * @license GNU General Public License version 3, or later */ use Akeeba\LoginGuard\Site\Helper\Tfa; use FOF30\Container\Container; use Joomla\CMS\Application\CliApplication; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\CMS\Router\Route; use Joomla\CMS\Uri\Uri; use Joomla\CMS\User\User; // Prevent direct access defined('_JEXEC') or die; /** * Akeeba LoginGuard System Plugin * * Implements the captive Two Step Verification page */ class PlgSystemLoginguard extends CMSPlugin { /** * Are we enabled, all requirements met etc? * * @var bool */ public $enabled = true; /** * The component's container * * @var Container * @since 2.0.0 */ private $container = null; /** * User groups for which Two Step Verification is never applied * * @var array * @since 3.0.1 */ private $neverTSVUserGroups = []; /** * User groups for which Two Step Verification is mandatory * * @var array * @since 3.0.1 */ private $forceTSVUserGroups = []; /** * Constructor * * @param object &$subject The object to observe * @param array $config An optional associative array of configuration settings. * Recognized key values include 'name', 'group', 'params', 'language' * (this list is not meant to be comprehensive). */ public function __construct($subject, array $config = array()) { parent::__construct($subject, $config); // Load FOF if (!defined('FOF30_INCLUDED') && !@include_once(JPATH_LIBRARIES . '/fof30/include.php')) { $this->enabled = false; return; } // Make sure Akeeba LoginGuard is installed try { if ( !file_exists(JPATH_ADMINISTRATOR . '/components/com_loginguard') || !ComponentHelper::isInstalled('com_loginguard') || !ComponentHelper::isEnabled('com_loginguard') ) { throw new RuntimeException('Akeeba LoginGuard is not installed'); } $this->container = Container::getInstance('com_loginguard'); } catch (Exception $e) { $this->enabled = false; } // PHP version check $this->enabled = version_compare(PHP_VERSION, '7.1.0', 'ge'); // Parse settings $this->neverTSVUserGroups = $this->container->params->get('neverTSVUserGroups', []); if (!is_array($this->neverTSVUserGroups)) { $this->neverTSVUserGroups = []; } $this->forceTSVUserGroups = $this->container->params->get('forceTSVUserGroups', []); if (!is_array($this->forceTSVUserGroups)) { $this->forceTSVUserGroups = []; } } /** * MAGIC TRICK. If you have enabled Joomla's Privacy Consent you'd end up with an infinite redirection loop. That's * because Joomla! did a partial copy of my original research code on captive Joomla! logins. They did no implement * configurable exceptions since they do not know or care about third party extensions -- even when it's the same * extensions they copied code from. * * Since fixing Joomla's code is not an option we'll have to work around it based on our knowledge of real world * Joomla usage and how the beast truly works under the hood. It really helps that yours truly was the guy who * refactored the plugin system to use proper events for Joomla! 4 AND the person who invented the captive login * code pattern for Joomla :) * * In this episode of Crazy Stuff Nicholas Has To Do To Get Basic Functionality Working we will explore how to use * PHP Reflection to detect the offending Joomla! Privacy Consent system plugin and snuff it out before it can issue * its redirections. I invented captive login, I know how to work around it. * * @since 3.0.3 * @throws Exception */ public function onAfterInitialise() { $app = Factory::getApplication(); $option = $app->input->getCmd('option', null); /** * If we're going to need to perform a redirection and Joomla's privacy consent is also enabled we will snuff it * so it doesn't cause an infinite redirection loop. The correct solution would be Joomla! allowing users to * specify exceptions to the captive login but having its developers think of that requires them to use the CMS * in the real world which, as we know, is not the case. No problem. I've made a career working around the * Joomla! core, haven't I? */ if ( ($this->willNeedRedirect() || ($option == 'com_loginguard')) && version_compare(JVERSION, '3.8.999', 'gt')) { $this->snuffJoomlaPrivacyConsent(); } } /** * Gets triggered right after Joomla has finished with the SEF routing and before it has the chance to dispatch the * application (load any components). * * @return void * * @throws Exception */ public function onAfterRoute() { if (!$this->willNeedRedirect()) { return; } // Get the session objects try { $session = Factory::getSession(); } catch (Exception $e) { // Can't get access to the session? Must be under CLI which is not supported. return; } // Make sure we are logged in try { $app = Factory::getApplication(); // Joomla! 3: make sure the user identity is loaded. This MUST NOT be called in Joomla! 4, though. if (version_compare(JVERSION, '3.99999.99999', 'lt')) { $app->loadIdentity(); } $user = $app->getIdentity(); } catch (\Exception $e) { // This would happen if we are in CLI or under an old Joomla! version. Either case is not supported. return; } // We only kick in when the user has actually set up TFA or must definitely enable TFA. $needsTFA = $this->needsTFA($user); $disabledTSV = $this->disabledTSV($user); $mandatoryTSV = $this->mandatoryTSV($user); if ($needsTFA && !$disabledTSV) { // Save the current URL, but only if we haven't saved a URL or if the saved URL is NOT internal to the site. $return_url = $session->get('return_url', '', 'com_loginguard'); if (empty($return_url) || !Uri::isInternal($return_url)) { $session->set('return_url', Uri::getInstance()->toString(array('scheme', 'user', 'pass', 'host', 'port', 'path', 'query', 'fragment')), 'com_loginguard'); } // Redirect $url = Route::_('index.php?option=com_loginguard&view=captive', false); $app->redirect($url, 307); return; } // If we're here someone just logged in but does not have TFA set up. Just flag him as logged in and continue. $session->set('tfa_checked', 1, 'com_loginguard'); // If we don't have TFA set up yet AND the user plugin had set up a redirection we will honour it $redirectionUrl = $session->get('postloginredirect', null, 'com_loginguard'); // If the user is in a group that requires TFA we will redirect them to the setup page if (!$needsTFA && $mandatoryTSV) { // First unset the flag to make sure the redirection will apply until they conform to the mandatory TFA $session->set('tfa_checked', 0, 'com_loginguard'); // Now set a flag which forces rechecking TSV for this user $session->set('recheck_mandatory_tsv', 1, 'com_loginguard'); // Then redirect them to the setup page $this->redirectToTSVSetup(); } if (!$needsTFA && $redirectionUrl && !$disabledTSV) { $session->set('postloginredirect', null, 'com_loginguard'); Factory::getApplication()->redirect($redirectionUrl); } } /** * Hooks on the Joomla! login event. Detects silent logins and disables the Two Step Verification captive page in * this case. * * @param array $options Passed by Joomla. user: a User object; responseType: string, authentication response * type. */ public function onUserAfterLogin($options) { // Always reset the browser ID to avoid session poisoning attacks $session = Factory::getSession(); $session->set('browserId', null, 'com_loginguard'); $session->set('browserIdCodeLoaded', false, 'com_loginguard'); // Should I show 2SV even on silent logins? Default: 1 (yes, show) $switch = $this->params->get('2svonsilent', 1); if ($switch == 1) { return; } // Make sure I have a valid user /** @var User $user */ $user = $options['user']; if (!is_object($user) || !($user instanceof User)) { return; } // Make sure this is a silent login if (!$this->isSilentLogin($user, $options['responseType'])) { return; } // Set the flag indicating that 2SV is already checked. $session->set('tfa_checked', 1, 'com_loginguard'); } /** * Does the current user need to complete TFA authentication before being allowed to access the site? * * @param User $user The user object * * @return bool */ private function needsTFA(User $user) { /** @var \Akeeba\LoginGuard\Site\Model\Tfa $tfaModel */ $tfaModel = $this->container->factory->model('Tfa')->tmpInstance(); // Get the user's TFA records $records = $tfaModel->user_id($user->id)->get(true); // No TFA methods? Then we obviously don't need to display a captive login page. if ($records->count() < 1) { return false; } // Let's get a list of all currently active TFA methods $tfaMethods = Tfa::getTfaMethods(); // If not TFA method is active we can't really display a captive login page. if (empty($tfaMethods)) { return false; } // Get a list of just the method names $methodNames = []; foreach ($tfaMethods as $tfaMethod) { $methodNames[] = $tfaMethod['name']; } // Filter the records based on currently active TFA methods foreach ($records as $record) { if (in_array($record->method, $methodNames)) { // We found an active method. Show the captive page. return true; } } // No viable TFA method found. We won't show the captive page. return false; } /** * Checks if we are running under a CLI script or inside an administrator session * * @return array * * @throws Exception */ protected function isCliAdmin() { $isAdmin = false; try { if (is_null(Factory::$application)) { $isCLI = true; } else { $app = Factory::getApplication(); $isCLI = $app instanceof \Exception || $app instanceof CliApplication; } } catch (\Exception $e) { $isCLI = true; } if (!$isCLI && Factory::$application) { $isAdmin = Factory::getApplication()->isClient('administrator'); } return [$isCLI, $isAdmin]; } /** * Does the user belong in a group indicating TSV should be disabled for them? * * @param JUser|User $user * * @return bool */ private function disabledTSV($user) { // If the user belongs to a "never check for TSV" user group they are exempt from TSV $userGroups = $user->getAuthorisedGroups(); $belongsToTSVUserGroups = array_intersect($this->neverTSVUserGroups, $userGroups); return !empty($belongsToTSVUserGroups); } /** * Does the user belong in a group indicating TSV is required for them? * * @param JUser|User $user * * @return bool */ private function mandatoryTSV($user) { // If the user belongs to a "never check for TSV" user group they are exempt from TSV $userGroups = $user->getAuthorisedGroups(); $belongsToTSVUserGroups = array_intersect($this->forceTSVUserGroups, $userGroups); return !empty($belongsToTSVUserGroups); } /** * Redirect the user to the Two Step Verification method setup page. * * @return void * * @since 3.0.1 */ private function redirectToTSVSetup() { try { $app = Factory::getApplication(); } catch (\Exception $e) { // This would happen if we are in CLI or under an old Joomla! version. Either case is not supported. return; } // If we are in a LoginGuard page do not redirect $option = strtolower($app->input->getCmd('option')); if ($option == 'com_loginguard') { return; } // Otherwise redirect to the LoginGuard TSV setup page after enqueueing a message $url = 'index.php?option=com_loginguard&view=Methods'; $app->redirect($url, 307); } /** * Check whether we'll need to do a redirection to the captive page. * * @return bool * * @since 3.0.4 * * @throws Exception */ private function willNeedRedirect() { // If the requirements are not met do not proceed if (!$this->enabled) { return false; } // Get the session objects try { $session = Factory::getSession(); } catch (Exception $e) { // Can't get access to the session? Must be under CLI which is not supported. return false; } /** * We only kick in if the session flag is not set AND the user is not flagged for monitoring of their TSV status * * In case a user belongs to a group which requires TSV to be always enabled and they logged in without having * TSV enabled we have the recheck flag. This prevents the user from enabling and immediately disabling TSV, * circumventing the requirement for TSV. */ $tfaChecked = $session->get('tfa_checked', 0, 'com_loginguard'); $tfaRecheck = $session->get('recheck_mandatory_tsv', 0, 'com_loginguard'); if ($tfaChecked && !$tfaRecheck) { return false; } // Make sure we are logged in try { $app = Factory::getApplication(); // Joomla! 3: make sure the user identity is loaded. This MUST NOT be called in Joomla! 4, though. if (version_compare(JVERSION, '3.99999.99999', 'lt')) { $app->loadIdentity(); } $user = $app->getIdentity(); } catch (\Exception $e) { // This would happen if we are in CLI or under an old Joomla! version. Either case is not supported. return false; } // The plugin only needs to kick in when you have logged in if ($user->get('guest')) { return false; } /** * Special handling when the requireReset flag is set on the user account. * * Joomla checks the requireReset flag on the user account in the application's doExecute method. If it is set * it will call CMSApplication::checkUserRequireReset() which issues a redirection for the user to reset their * password. * * One easy option here is to say "if the user must reset their password don't show the 2SV captive page" * Unfortunately, that would be a bad idea because of the naive and insecure manner Joomla goes about the forced * password reset. Instead of going through the actual password reset (“Forgot your password?”) page it instead * redirects the user the user profile editor page! This allows the logged in user to view and change everything * in the user profile, including disabling and changing the 2SV options. Considering that forced password reset * is meant to be primarily used when we suspect that the user's account has been compromised this creates a * grave security risk. The attacker in possession of the username and password can trick a Super User into * forcing a password reset, thereby allowing them to bypass Two Step Verification and take over the user * account. * * Instead, we unset the requireReset user flag for the duration of the page load when this method here is * called. This prevents Joomla from redirecting. As a result you need to go through Two Step Verification as * per usual. Once you do that the tfa_checked flag is set in the session and this method never reaches this * point of execution where we unset the requireReset flag. Therefore Joomla now sees the requireReset flag and * shows you the user profile edit page. Now it's safe to do so since you have already proven your identity by * means of Two Step Verification i.e. there's no doubt we should let you make any kind of user account change. * * @see \Joomla\CMS\Application\SiteApplication::doExecute() * @see \Joomla\CMS\Application\CMSApplication::checkUserRequireReset() */ if ($user->get('requireReset', 0)) { $user->set('requireReset', 0); } [$isCLI, $isAdmin] = $this->isCliAdmin(); // TFA is not applicable under CLI if ($isCLI) { return false; } // If we are in the administrator section we only kick in when the user has backend access privileges if ($isAdmin && !$user->authorise('core.login.admin')) { return false; } $needsTFA = $this->needsTFA($user); if ($tfaChecked && $tfaRecheck && $needsTFA) { return false; } // We only kick in if the option and task are not the ones of the captive page $option = strtolower($app->input->getCmd('option')); $task = strtolower($app->input->getCmd('task')); $view = strtolower($app->input->getCmd('view')); if ($option == 'com_loginguard') { // In case someone gets any funny ideas... $app->input->set('tmpl', 'index'); $app->input->set('format', 'html'); $app->input->set('layout', null); if (empty($view) && (strpos($task, '.') !== false)) { [$view, $task] = explode('.', $task, 2); } // The captive login page is always allowed if ($view === 'captive') { return false; } // These views are only allowed if you do not have 2SV enabled *or* if you have already logged in. if (!$needsTFA && in_array($view, array('ajax', 'method', 'methods'))) { return false; } } // Allow the frontend user to log out (in case they forgot their TFA code or something) if (!$isAdmin && ($option == 'com_users') && ($task == 'user.logout')) { return false; } // Allow the backend user to log out (in case they forgot their TFA code or something) if ($isAdmin && ($option == 'com_login') && ($task == 'logout')) { return false; } /** * Allow com_ajax. This is required for cookie acceptance in the following scenario. Your session has expired, * therefore you need to re-apply TFA. Moreover, your cookie acceptance cookie has also expired and you need to * accept the site's cookies again. */ if ($option == 'com_ajax') { return false; } return true; } /** * Kills the Joomla Privacy Consent plugin when we are showing the Two Step Verification. * * JPC uses captive login code copied from our DataCompliance component. However, they removed the exceptions we * have for other captive logins. As a result the JPC captive login interfered with LoginGuard's captive login, * causing an infinite redirection. * * Due to complete lack of support for exceptions, this method here does something evil. It hunts down the observer * (plugin hook) installed by the JPC plugin and removes it from the loaded plugins. This prevents the redirection * of the captive login. THIS IS NOT THE BEST WAY TO DO THINGS. You should NOT ever, EVER!!!! copy this code. I am * someone who has spent 15+ years dealing with Joomla's core code and I know what I'm doing, why I'm doing it and, * most importantly, how it can possibly break. don't go about merrily copying this code if you do not understand * how Joomla event dispatching works. You'll break shit and I'm not to blame. Thank you! * * @since 3.0.4 * @throws ReflectionException */ private function snuffJoomlaPrivacyConsent() { /** * The privacy suite is not ported to Joomla! 4 yet. */ if (version_compare(JVERSION, '3.9999.9999', 'ge')) { return; } // The broken Joomla! consent plugin is not activated if (!class_exists('PlgSystemPrivacyconsent')) { return; } // Get the events dispatcher and find which observer is the offending plugin $dispatcher = JEventDispatcher::getInstance(); $refDispatcher = new ReflectionObject($dispatcher); $refObservers = $refDispatcher->getProperty('_observers'); $refObservers->setAccessible(true); $observers = $refObservers->getValue($dispatcher); $jConsentObserverId = 0; foreach ($observers as $id => $o) { if (!is_object($o)) { continue; } if ($o instanceof \PlgSystemPrivacyconsent) { $jConsentObserverId = $id; break; } } // Nope. Cannot find the offending plugin. if ($jConsentObserverId == 0) { return; } // Now we need to remove the offending plugin from the onAfterRoute event. $refMethods = $refDispatcher->getProperty('_methods'); $refMethods->setAccessible(true); $methods = $refMethods->getValue($dispatcher); $methods['onafterroute'] = array_filter($methods['onafterroute'], function($id) use ($jConsentObserverId) { return $id != $jConsentObserverId; }); $refMethods->setValue($dispatcher, $methods); } /** * Suppress Two Step Verification when Joomla performs a silent login (cookie, social login / single sign-on, GMail, * LDAP). In these cases the login risk has been managed externally. * * For your reference, the Joomla authentication response types are as follows: * * - Joomla: username and password login. We recommend using 2SV with it. * - Cookie: "Remember Me" cookie with a secure, single use token and other safeguards for the user session. * - GMail: login with GMail credentials (probably no longer works) * - LDAP: Joomla's LDAP plugin * - SocialLogin: Akeeba Social Login (login with Facebook etc) * * @param User $user * @param string $responseType * * @return bool * * @since 3.1.0 */ private function isSilentLogin(User $user, $responseType) { // Fail early if the user is not properly logged in. if (!is_object($user) || $user->guest) { return false; } // Get the custom Joomla login responses we will consider "silent" $rawCustomResponses = $this->params->get('silentresponses', ''); $customResponses = explode(',', $rawCustomResponses); $customResponses = array_map('trim', $customResponses); $customResponses = array_filter($customResponses, function ($x) { return !empty($x); }); $silentResponses = array_unique($customResponses); // If all else fails, use our default list (Joomla's Remember Me cookie and Akeeba SocialLogin) if (empty($silentResponses)) { $silentResponses = array('cookie', 'sociallogin'); } // Is it a silent login after all? if (is_string($responseType) && !empty($responseType) && in_array(strtolower($responseType), $silentResponses)) { return true; } return false; } }
/var/www/consult-e-syn/public_html/c1c92/../plugins/system/loginguard_/loginguard.php