name : nonewadmins.php
<?php
/**
 * @package   admintools
 * @copyright Copyright (c)2010-2023 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\User\User;
use Joomla\CMS\User\UserHelper;

defined('_JEXEC') || die;

class AtsystemFeatureNonewadmins extends AtsystemFeatureAbstract
{
	use AtsystemUtilTempdisable;

	protected $loadOrder = 210;

	/**
	 * Is this feature enabled?
	 *
	 * @return bool
	 */
	public function isEnabled()
	{
		$fromBackend  = $this->cparams->getValue('nonewadmins', 1) == 1;
		$fromFrontend = $this->cparams->getValue('nonewfrontendadmins', 1) == 1;

		$enabled = $fromBackend && $this->container->platform->isBackend();
		$enabled |= $fromFrontend && $this->container->platform->isFrontend();

		return $enabled;
	}

	/**
	 * Disables creating new admins or updating new ones
	 */
	public function onAfterInitialise()
	{
		$input  = $this->input;
		$option = $input->getCmd('option', '');
		$task   = $input->getCmd('task', '');

		if ($option != 'com_users' && $option != 'com_admin')
		{
			return;
		}

		$jform = $this->input->get('jform', [], 'array');

		$filteredTasks = [
			'save',
			'apply',
			'user.apply',
			'user.save',
			'user.save2new',
			'profile.apply',
			'profile.save',
		];

		if (!in_array($task, $filteredTasks))
		{
			return;
		}

		// Not editing, just core devs using the same task throughout the component, dammit
		if (empty($jform))
		{
			return;
		}

		$groups = [];

		if (isset($jform['groups']))
		{
			$groups = $jform['groups'];
		}

		$user = $this->container->platform->getUser((int) $jform['id']);

		// Sometimes $user->groups is null... let's be 100% sure that we loaded all the groups of the user
		if (empty($user->groups))
		{
			$user->groups = UserHelper::getUserGroups($user->id);
		}

		$makingNewAdmin = $this->hasAdminGroup($groups);
		$isAdmin        = $this->hasAdminGroup($user->groups);
		$isFrontend     = $this->container->platform->isFrontend();

		if (!$isAdmin && !$makingNewAdmin)
		{
			return;
		}

		// Allow editing my own user record if I am already an admin
		if ($isAdmin && ($this->container->platform->getUser()->id == $jform['id']))
		{
			return;
		}

		/**
		 * In the frontend we only stop requests which are trying to make a new admin. This lets execution fall through
		 * to onUserBeforeSave where we can check for Joomla! 3.9+ user consent changes.
		 */
		$newUser = array_merge($jform);

		if (array_key_exists('params', $newUser))
		{
			$newUser['params'] = json_encode($newUser['params']);
		}

		if ($isFrontend && !$makingNewAdmin && $this->allowEdit($user))
		{
			return;
		}

		// Get the correct reason (was the user being created in front- or back-end)?
		$reason = $this->container->platform->isBackend() ? 'nonewadmins' : 'nonewfrontendadmins';

		// Log and autoban security exception
		$extraInfo = "Submitted JForm Variables :\n";
		$extraInfo .= print_r($jform, true);
		$extraInfo .= "\n";

		// Display the error only if the user should be really blocked (ie we're not in the Whitelist)
		if ($this->exceptionsHandler->logAndAutoban($reason, $extraInfo))
		{
			// Throw an exception to prevent Joomla! processing this form
			$jlang = Factory::getLanguage();
			$jlang->load('joomla', JPATH_ROOT, 'en-GB', true);
			$jlang->load('joomla', JPATH_ROOT, $jlang->getDefault(), true);
			$jlang->load('joomla', JPATH_ROOT, null, true);

			throw new Exception(Text::_('JGLOBAL_AUTH_ACCESS_DENIED'), '403');
		}
	}

	/**
	 * Hooks into the Joomla! models before a user is saved. This catches the case where a 3PD extension tries to create
	 * a new user instead of going through com_users.
	 *
	 * @param   User|array  $oldUser  The existing user record
	 * @param   bool        $isNew    Is this a new user?
	 * @param   array       $data     The data to be saved
	 *
	 * @throws  Exception  When we catch a security exception
	 */
	public function onUserBeforeSave($oldUser, $isNew, $data)
	{
		// Are we temporarily disabled?
		if (self::getTempDisableFlag())
		{
			return;
		}

		// Only applies to admin users.
		$isAdmin = $this->hasAdminGroup($data['groups']);

		if (!$isAdmin)
		{
			return;
		}

		$user = $this->container->platform->getUser($data['id']);

		// We are allowed to edit the profile of a user without active consent
		if (!$isNew && $this->allowEdit($user))
		{
			return;
		}

		// We can always edit out own profile
		if ($this->container->platform->getUser()->id == $data['id'])
		{
			return;
		}

		// Get the correct reason (was the user being created in front- or back-end)?
		$reason = $this->container->platform->isBackend() ? 'nonewadmins' : 'nonewfrontendadmins';

		// Log and autoban security exception
		$extraInfo = "User Data Variables :\n";
		$extraInfo .= print_r($data, true);
		$extraInfo .= "\n";

		// Display the error only if the user should be really blocked (ie we're not in the Whitelist)
		if ($this->exceptionsHandler->logAndAutoban($reason, $extraInfo))
		{
			// Throw an exception to prevent Joomla! processing this form
			$jlang = Factory::getLanguage();
			$jlang->load('joomla', JPATH_ROOT, 'en-GB', true);
			$jlang->load('joomla', JPATH_ROOT, $jlang->getDefault(), true);
			$jlang->load('joomla', JPATH_ROOT, null, true);

			throw new Exception(Text::_('JGLOBAL_AUTH_ACCESS_DENIED'), '403');
		}
	}

	/**
	 * Is this a user who has not yet consented to the privacy policy?
	 *
	 * @param   User|User  $user
	 *
	 * @return  bool    Am I allowed to edit this user?
	 */
	private function allowEdit($user)
	{
		if (!$this->isJoomlaPrivacyEnabled())
		{
			return false;
		}

		return !$this->hasUserConsented($user);
	}
}

© 2025 Cubjrnet7