包含:登录失败锁定、90天密码有效期、30分钟会话超时、 强制改密、登录审计日志、屏幕水印、企业背景图、 备案信息固定底部、favicon、JS空集合保护、 会话过期体验优化(403 JSON)、display_errors 关闭、 固定 key 根治 Integrity check failed 等全部改动 注意:config.inc.php/.htaccess/.user.ini 含敏感信息, 通过 .gitignore 排除,勿推送到公开仓库。
240 lines
6.0 KiB
PHP
240 lines
6.0 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
namespace MRBS\Auth;
|
|
|
|
use Joomla\CMS\Factory;
|
|
use MRBS\Joomla\JFactory;
|
|
use MRBS\User;
|
|
|
|
require_once MRBS_ROOT . '/auth/cms/joomla.inc';
|
|
|
|
|
|
class AuthJoomla extends Auth
|
|
{
|
|
public function __construct()
|
|
{
|
|
$this->checkSessionMatchesType();
|
|
}
|
|
|
|
|
|
public function validateUser(
|
|
#[\SensitiveParameter]
|
|
?string $user,
|
|
#[\SensitiveParameter]
|
|
?string $pass)
|
|
{
|
|
if (version_compare(JVERSION, '5.0', '<'))
|
|
{
|
|
$mainframe = JFactory::getApplication('site');
|
|
}
|
|
else
|
|
{
|
|
$mainframe = Factory::getApplication('site');
|
|
}
|
|
|
|
return $mainframe->login(array('username' => $user, 'password' => $pass)) ? $user : false;
|
|
}
|
|
|
|
|
|
protected function getUserFresh(?string $username=null) : ?User
|
|
{
|
|
if ($username === '')
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (version_compare(JVERSION, '5.0', '<'))
|
|
{
|
|
$joomla_user = JFactory::getUser($username);
|
|
}
|
|
else
|
|
{
|
|
$joomla_user = Factory::getUser($username);
|
|
}
|
|
|
|
if ($joomla_user === false)
|
|
{
|
|
return new User($username);
|
|
}
|
|
|
|
if ($joomla_user->guest)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
$user = new User($joomla_user->username);
|
|
$user->display_name = $joomla_user->name;
|
|
$user->email = $joomla_user->email;
|
|
$user->level = self::getUserLevel($joomla_user);
|
|
|
|
return $user;
|
|
}
|
|
|
|
|
|
// TODO: sort out where getCurrentUser belongs. We have it in both
|
|
// TODO: Auth and Session for Joomla!
|
|
public function getCurrentUser() : ?User
|
|
{
|
|
return $this->getUserFresh();
|
|
}
|
|
|
|
|
|
// Return an array of MRBS users, indexed by 'username' and 'display_name'
|
|
public function getUsernames() : array
|
|
{
|
|
$result = array();
|
|
|
|
// We only want MRBS users, not all the Joomla users
|
|
$groups = self::getMRBSGroups();
|
|
|
|
// Get the user ids associated with those groups
|
|
$user_ids = array();
|
|
|
|
foreach($groups as $group)
|
|
{
|
|
// Include child groups by doing it recursively
|
|
if (version_compare(JVERSION, '5.0', '<'))
|
|
{
|
|
$user_ids = array_merge($user_ids, \JAccess::getUsersByGroup($group, $recursive = true));
|
|
}
|
|
else
|
|
{
|
|
$user_ids = array_merge($user_ids, \Joomla\CMS\Access\Access::getUsersByGroup($group, $recursive = true));
|
|
}
|
|
}
|
|
|
|
$user_ids = array_unique($user_ids);
|
|
|
|
// No doubt it would be faster to do this with a single SQL query, but then we wouldn't
|
|
// be using the Joomla API abstraction.
|
|
foreach ($user_ids as $user_id)
|
|
{
|
|
if (version_compare(JVERSION, '5.0', '<'))
|
|
{
|
|
$user = JFactory::getUser((int)$user_id);
|
|
}
|
|
else
|
|
{
|
|
$user = Factory::getUser((int)$user_id);
|
|
}
|
|
// Check to see that the user has a username. The result of getUser() on a user_id that doesn't exist is,
|
|
// strangely, a user object with all properties set to null. In theory (?) all the user_ids returned by
|
|
// getUsersByGroup() should exist, but there has been a case where this is not so. See
|
|
// https://github.com/meeting-room-booking-system/mrbs-code/issues/3682 .
|
|
if (isset($user->username))
|
|
{
|
|
$result[] = array(
|
|
'username' => $user->username,
|
|
'display_name' => $user->name
|
|
);
|
|
}
|
|
else
|
|
{
|
|
trigger_error("The Joomla user with id $user_id appears in Joomla groups but not in Joomla users.", E_USER_WARNING);
|
|
}
|
|
}
|
|
|
|
// Need to sort the users
|
|
self::sortUsers($result);
|
|
|
|
return $result;
|
|
}
|
|
|
|
|
|
// Get an array of Joomla groups that have MRBS user or admin rights
|
|
private static function getMRBSGroups() : array
|
|
{
|
|
global $auth;
|
|
|
|
$result = array();
|
|
|
|
// Get all the Joomla access levels that have MRBS user or admin rights
|
|
$mrbs_access_levels = array_merge($auth['joomla']['admin_access_levels'],
|
|
$auth['joomla']['user_access_levels']);
|
|
|
|
$mrbs_access_levels = array_unique($mrbs_access_levels);
|
|
|
|
// There doesn't seem to be a Joomla API to do this, so we'll have to do
|
|
// it with direct access to the database.
|
|
|
|
// Get a db connection.
|
|
if (version_compare(JVERSION, '5.0', '<'))
|
|
{
|
|
$db = JFactory::getDbo();
|
|
}
|
|
else
|
|
{
|
|
$db = Factory::getDbo();
|
|
}
|
|
|
|
|
|
// Create a new query object.
|
|
$query = $db->getQuery(true);
|
|
|
|
// Execute the query
|
|
$query->select($db->quoteName(array('rules')));
|
|
$query->from($db->quoteName('#__viewlevels'));
|
|
$query->where($db->quoteName('id') . ' IN ('. implode(',', $mrbs_access_levels) . ')');
|
|
$db->setQuery($query);
|
|
$column = $db->loadColumn();
|
|
|
|
// Process the results into an array
|
|
foreach ($column as $rules)
|
|
{
|
|
$result = array_merge($result, (json_decode($rules)));
|
|
}
|
|
|
|
// Remove duplicates
|
|
$result = array_unique($result);
|
|
|
|
return $result;
|
|
}
|
|
|
|
|
|
private static function getUserLevel(object $joomla_user) : int
|
|
{
|
|
global $auth;
|
|
|
|
$required_class = (version_compare(JVERSION, '5.0', '<')) ? 'MRBS\Joomla\JUser' : 'Joomla\CMS\User\User';
|
|
$actual_class = get_class($joomla_user);
|
|
if ($actual_class !== $required_class)
|
|
{
|
|
$message = 'Argument #1 ($joomla_user) must be of type ' . "$required_class, $actual_class given";
|
|
throw new \TypeError($message);
|
|
}
|
|
|
|
// User not logged in, user level '0'
|
|
if ($joomla_user->guest)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Otherwise get the user's access levels
|
|
$authorised_levels = $joomla_user->getAuthorisedViewLevels();
|
|
|
|
// Check if they have admin access
|
|
if (isset($auth['joomla']['admin_access_levels']))
|
|
{
|
|
$admin_levels = (array)$auth['joomla']['admin_access_levels'];
|
|
if (count(array_intersect($authorised_levels, $admin_levels)) > 0)
|
|
{
|
|
return 2;
|
|
}
|
|
}
|
|
|
|
// Check if they have user access
|
|
if (isset($auth['joomla']['user_access_levels']))
|
|
{
|
|
$user_levels = (array)$auth['joomla']['user_access_levels'];
|
|
if (count(array_intersect($authorised_levels, $user_levels)) > 0)
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// Everybody else is access level '0'
|
|
return 0;
|
|
}
|
|
|
|
}
|