Files
ms1inscription-v5/rapports/components/security/table_based_user_grants_manager.php
2026-05-13 09:43:32 -04:00

524 lines
18 KiB
PHP

<?php
include_once dirname(__FILE__) . '/' . '../../database_engine/engine.php';
include_once dirname(__FILE__) . '/' . '../../database_engine/commands.php';
include_once dirname(__FILE__) . '/' . '../../database_engine/select_command.php';
include_once dirname(__FILE__) . '/' . '../dataset/dataset.php';
include_once dirname(__FILE__) . '/' . '../dataset/query_dataset.php';
include_once dirname(__FILE__) . '/' . 'datasource_security_info.php';
include_once dirname(__FILE__) . '/' . 'user_grants_manager.php';
include_once dirname(__FILE__) . '/' . 'user_manager.php';
include_once dirname(__FILE__) . '/' . '../utils/hash_utils.php';
class TableBasedUserGrantsManager extends UserGrantsManager implements IUserManager
{
/** @var ConnectionFactory */
private $connectionFactory;
/** @var array */
private $connectionOptions;
/** @var string */
private $usersTable;
private $users_UserId;
private $users_UserName;
private $users_Password;
private $userPermsTable;
private $userPerms_UserId;
private $userPerms_PageName;
private $userPerms_Grant;
private $securityCache = array();
private $adminGrantCache = array();
private $allowGuest = array();
/**
* @param ConnectionFactory $connectionFactory
* @param array $connectionOptions
* @param array $usersTableInfo
* @param array $userPermsTableInfo
* @param array $tableCaptions
* @param StringHasher $passwordHasher
* @param bool $allowGuest
*/
public function __construct($connectionFactory, $connectionOptions,
$usersTableInfo, $userPermsTableInfo, $tableCaptions, $passwordHasher, $allowGuest = true)
{
$this->allowGuest = $allowGuest;
$this->connectionFactory = $connectionFactory;
$this->connectionOptions = $connectionOptions;
$this->usersTable = $usersTableInfo['TableName'];
$this->users_UserId = $usersTableInfo['UserId'];
$this->users_UserName = $usersTableInfo['UserName'];
$this->users_Password = $usersTableInfo['Password'];
$this->userPermsTable = $userPermsTableInfo['TableName'];
$this->userPerms_UserId = $userPermsTableInfo['UserId'];
$this->userPerms_PageName = $userPermsTableInfo['PageName'];
$this->userPerms_Grant = $userPermsTableInfo['Grant'];
$this->tableCaptions = $tableCaptions;
$this->passwordHasher = $passwordHasher;
$this->adminGrantCache = array();
}
private function RetrieveSecurityInfo($userName, $dataSourceName)
{
$queryBuilder = new SelectCommand($this->connectionFactory->CreateEngCommandImp());
$queryBuilder->AddField($this->usersTable, $this->users_UserId, FieldType::Number, 'users_user_id');
$queryBuilder->AddField($this->usersTable, $this->users_UserName, FieldType::String, 'users_user_name');
$queryBuilder->AddField($this->userPermsTable, $this->userPerms_UserId, FieldType::Number, 'userperms_user_id');
$queryBuilder->AddField($this->userPermsTable, $this->userPerms_PageName, FieldType::String, 'userperms_pagename');
$queryBuilder->AddField($this->userPermsTable, $this->userPerms_Grant, FieldType::String, 'userperms_grant');
$queryBuilder->SetSourceTableName($this->userPermsTable);
$queryBuilder->AddJoin(JoinKind::LeftOuter, $this->usersTable, 'userperms_user_id', $this->users_UserId);
if ($userName == 'guest')
{
$queryBuilder->AddFieldFilter('userperms_user_id', new FieldFilter('-1', '='));
}
else
{
$queryBuilder->AddCompositeFieldFilter('OR',
array(
'users_user_name',
'userperms_user_id'
),
array(
new FieldFilter($userName, 'ILIKE'),
new FieldFilter('0', '=')
));
}
$queryBuilder->AddCompositeFieldFilter('OR',
array(
'userperms_pagename',
'userperms_pagename'
),
array(
new FieldFilter($dataSourceName, 'ILIKE'),
new FieldFilter('', '=')
));
$dataset = new QueryDataset($this->connectionFactory, $this->connectionOptions, $queryBuilder->GetSQL(), array(), array(), array(), 'user_grants');
$dataset->AddField(new StringField('userperms_grant'), false);
$result = null;
$dataset->Open();
$selectGrant = false;
$updateGrant = false;
$insertGrant = false;
$deleteGrant = false;
$adminGrant = false;
while ($dataset->Next())
{
$grant = $dataset->GetFieldValueByName('userperms_grant');
$selectGrant = $selectGrant || StringUtils::SameText($grant, 'select');
$updateGrant = $updateGrant || StringUtils::SameText($grant, 'update');
$insertGrant = $insertGrant || StringUtils::SameText($grant, 'insert');
$deleteGrant = $deleteGrant || StringUtils::SameText($grant, 'delete');
$adminGrant = $adminGrant || StringUtils::SameText($grant, 'admin');
if ($adminGrant)
{
$result = new AdminDataSourceSecurityInfo();
break;
}
}
$dataset->Close();
return !is_null($result) ? $result : new DataSourceSecurityInfo($selectGrant, $updateGrant, $insertGrant, $deleteGrant);
}
/**
* @param $userName
* @param $dataSourceName
* @return IDataSourceSecurityInfo
*/
public function GetSecurityInfo($userName, $dataSourceName)
{
$result = null;
if (isset($this->securityCache[$userName]))
if (isset($this->securityCache[$userName][$dataSourceName]))
$result = $this->securityCache[$userName][$dataSourceName];
if (is_null($result))
{
$result = $this->RetrieveSecurityInfo($userName, $dataSourceName);
if (!isset($this->securityCache[$userName]))
$this->securityCache[$userName] = array();
if (!isset($this->securityCache[$userName][$dataSourceName]))
$this->securityCache[$userName][$dataSourceName] = $result;
}
return $result;
}
private function CreateUsersDataset()
{
$usersDataset = new TableDataset($this->connectionFactory, $this->connectionOptions, $this->usersTable);
$usersDataset->AddField(new IntegerField($this->users_UserId), true);
$usersDataset->AddField(new StringField($this->users_UserName), false);
$usersDataset->AddField(new StringField($this->users_Password), false);
return $usersDataset;
}
private function CreateUserGrantsDataset()
{
$result = new TableDataset($this->connectionFactory, $this->connectionOptions, $this->userPermsTable);
$result->AddField(new IntegerField($this->userPerms_UserId), true);
$result->AddField(new StringField($this->userPerms_PageName), true);
$result->AddField(new StringField($this->userPerms_Grant), true);
return $result;
}
/**
* {@inheritdoc}
*/
public function CanAddUser()
{
return true;
}
/**
* {@inheritdoc}
*/
public function AddUser($id, $userName, $password)
{
$usersDataset = $this->CreateUsersDataset();
$usersDataset->Insert();
$usersDataset->SetFieldValueByName($this->users_UserId, $id);
$usersDataset->SetFieldValueByName($this->users_UserName, $userName);
$usersDataset->SetFieldValueByName($this->users_Password,
$this->passwordHasher->GetHash($password));
$usersDataset->Post();
}
/**
* {@inheritdoc}
*/
public function CanChangeUserName()
{
return true;
}
/**
* {@inheritdoc}
*/
public function ChangeUserName($user_id, $userName)
{
$usersDataset = $this->CreateUsersDataset();
$usersDataset->SetSingleRecordState(array($user_id));
$usersDataset->Open();
if ($usersDataset->Next())
{
$usersDataset->Edit();
$usersDataset->SetFieldValueByName($this->users_UserName, $userName);
$usersDataset->Post();
}
$usersDataset->Close();
return $userName;
}
/**
* {@inheritdoc}
*/
public function CanChangeUserPassword()
{
return true;
}
/**
* {@inheritdoc}
*/
public function ChangeUserPassword($user_id, $password)
{
$usersDataset = $this->CreateUsersDataset();
$usersDataset->SetSingleRecordState(array($user_id));
$usersDataset->Open();
if ($usersDataset->Next())
{
$usersDataset->Edit();
$usersDataset->SetFieldValueByName($this->users_Password,
$this->passwordHasher->GetHash($password));
$usersDataset->Post();
}
$usersDataset->Close();
}
/**
* {@inheritdoc}
*/
public function CanRemoveUser()
{
return true;
}
/**
* {@inheritdoc}
*/
public function RemoveUser($userId)
{
$usersDataset = $this->CreateUsersDataset();
$usersDataset->SetSingleRecordState(array($userId));
$usersDataset->Open();
if ($usersDataset->Next())
{
$usersDataset->Delete();
}
else
{
throw new Exception('User with user id = ' . $userId . ' does not exists.');
}
$usersDataset->Close();
}
/**
* @param string $userName
* @return boolean
*/
public function RetrieveAdminGrant($userName)
{
$queryBuilder = new SelectCommand($this->connectionFactory->CreateEngCommandImp());
$queryBuilder->AddField($this->usersTable, $this->users_UserId, FieldType::Number, 'users_user_id');
$queryBuilder->AddField($this->usersTable, $this->users_UserName, FieldType::String, 'users_user_name');
$queryBuilder->AddField($this->userPermsTable, $this->userPerms_UserId, FieldType::Number, 'userperms_user_id');
$queryBuilder->AddField($this->userPermsTable, $this->userPerms_PageName, FieldType::String, 'userperms_pagename');
$queryBuilder->AddField($this->userPermsTable, $this->userPerms_Grant, FieldType::String, 'userperms_grant');
$queryBuilder->SetSourceTableName($this->userPermsTable);
$queryBuilder->AddJoin(JoinKind::Inner, $this->usersTable, 'userperms_user_id', $this->users_UserId);
$queryBuilder->AddFieldFilter('users_user_name', new FieldFilter($userName, 'ILIKE'));
$queryBuilder->AddFieldFilter('userperms_grant', new FieldFilter('ADMIN', 'ILIKE'));
$queryBuilder->AddCompositeFieldFilter('OR',
array('userperms_pagename', 'userperms_pagename'),
array(new FieldFilter('', 'ILIKE'), new IsNullFieldFilter()));
$dataset = new QueryDataset($this->connectionFactory, $this->connectionOptions, $queryBuilder->GetSQL(), array(), array(), array(), 'user_grants');
$dataset->AddField(new StringField('userperms_grant'), false);
$dataset->Open();
if ($dataset->Next())
{
$dataset->Close();
return true;
}
$dataset->Close();
return false;
}
public function HasAdminGrant($userName)
{
if (!isset($this->adminGrantCache[$userName]))
$this->adminGrantCache[$userName] = $this->RetrieveAdminGrant($userName);
return $this->adminGrantCache[$userName];
}
/**
* @param int $userId
* @param Captions $captions
* @return array
*/
public function GetUserGrants($userId, Captions $captions)
{
$queryBuilder = new SelectCommand($this->connectionFactory->CreateEngCommandImp());
$queryBuilder->AddField($this->usersTable, $this->users_UserId, FieldType::Number, 'users_user_id');
$queryBuilder->AddField($this->usersTable, $this->users_UserName, FieldType::String, 'users_user_name');
$queryBuilder->AddField($this->userPermsTable, $this->userPerms_UserId, FieldType::Number, 'userperms_user_id');
$queryBuilder->AddField($this->userPermsTable, $this->userPerms_PageName, FieldType::String, 'userperms_pagename');
$queryBuilder->AddField($this->userPermsTable, $this->userPerms_Grant, FieldType::String, 'userperms_grant');
$queryBuilder->SetSourceTableName($this->userPermsTable);
$queryBuilder->AddJoin(JoinKind::LeftOuter, $this->usersTable, 'userperms_user_id', $this->users_UserId);
$queryBuilder->AddFieldFilter('userperms_user_id', new FieldFilter($userId, '='));
$dataset = new QueryDataset($this->connectionFactory, $this->connectionOptions, $queryBuilder->GetSQL(), array(), array(), array(), 'user_grants');
$dataset->AddField(new StringField('userperms_grant'), false);
$dataset->AddField(new StringField('userperms_pagename'), false);
$dataset->Open();
$pages = array();
$pages[''] = array(
'name' => '',
'caption' => $captions->GetMessageString('Application'),
'selectGrant' => false,
'updateGrant' => false,
'insertGrant' => false,
'deleteGrant' => false,
'adminGrant' => false
);
foreach($this->tableCaptions as $name => $caption)
$pages[$name] = array(
'name' => $name,
'caption' => $captions->RenderText($caption),
'selectGrant' => false,
'updateGrant' => false,
'insertGrant' => false,
'deleteGrant' => false,
'adminGrant' => false
);
while ($dataset->Next())
{
$grant = $dataset->GetFieldValueByName('userperms_grant');
$pageName = $dataset->GetFieldValueByName('userperms_pagename');
if (isset($pages[$pageName]))
{
$pages[$pageName]['selectGrant'] = $pages[$pageName]['selectGrant'] || StringUtils::SameText($grant, 'select');
$pages[$pageName]['updateGrant'] = $pages[$pageName]['updateGrant'] || StringUtils::SameText($grant, 'update');
$pages[$pageName]['insertGrant'] = $pages[$pageName]['insertGrant'] || StringUtils::SameText($grant, 'insert');
$pages[$pageName]['deleteGrant'] = $pages[$pageName]['deleteGrant'] || StringUtils::SameText($grant, 'delete');
$pages[$pageName]['adminGrant'] = $pages[$pageName]['adminGrant'] || StringUtils::SameText($grant, 'admin');
}
}
$dataset->Close();
return array_values($pages);
}
/**
* @param int $userId
* @param Captions $captions
* @return string
*/
public function GetUserGrantsAsJson($userId, Captions $captions)
{
return SystemUtils::ToJSON(array('status' => 'OK', 'result' => $this->GetUserGrants($userId, $captions)));
}
public function GetAllUsersAsJson()
{
$usersDataset = $this->CreateUsersDataset();
$usersDataset->Open();
$users = array();
if ($this->allowGuest)
array_push($users, array(
'id' => -1,
'name' => 'guest',
'password' => '******',
'editable' => false
));
array_push($users, array(
'id' => 0,
'name' => 'PUBLIC (All users)',
'password' => '******',
'editable' => false
));
while ($usersDataset->Next())
{
$user = array(
'id' => $usersDataset->GetFieldValueByName($this->users_UserId),
'name' => $usersDataset->GetFieldValueByName($this->users_UserName),
'password' => '******',
'editable' => true
);
array_push($users, $user);
}
$usersDataset->Close();
return SystemUtils::ToJSON($users);
}
public function FillEmptyPagePermsArray(&$pagePerms)
{
foreach($this->tableCaptions as $name => $caption)
array_push(
$pagePerms,
array(
'pageName' => $name,
'pageCaption' => $caption,
'acl' => ''
));
}
public function AddUserGrant($user_id, $page_name, $grant)
{
if ($this->NormalizeGrant($grant) != null)
{
$userGrants = $this->CreateUserGrantsDataset();
$userGrants->Insert();
$userGrants->SetFieldValueByName($this->userPerms_UserId, $user_id);
$userGrants->SetFieldValueByName($this->userPerms_PageName, $page_name);
$userGrants->SetFieldValueByName($this->userPerms_Grant, $this->NormalizeGrant($grant));
$userGrants->Post();
}
else
throw new Exception("$grant is not valid grant name.");
}
public function RemoveUserGrant($user_id, $page_name, $grant)
{
if ($this->NormalizeGrant($grant) != null)
{
$userGrants = $this->CreateUserGrantsDataset();
$userGrants->AddFieldFilter($this->userPerms_PageName,
new FieldFilter($page_name, '='));
$userGrants->AddFieldFilter($this->userPerms_UserId,
new FieldFilter($user_id, '='));
$userGrants->Open();
while($userGrants->Next())
{
if (StringUtils::SameText($userGrants->GetFieldValueByName($this->userPerms_Grant), $grant))
{
$userGrants->Delete();
$userGrants->Close();
return true;
}
}
$userGrants->Close();
throw new Exception("User with id = $user_id has no $grant grant.");
}
else
throw new Exception("$grant is not valid grant name.");
}
private function NormalizeGrant($grant)
{
if (StringUtils::SameText($grant, 'SELECT'))
return 'SELECT';
if (StringUtils::SameText($grant, 'UPDATE'))
return 'UPDATE';
if (StringUtils::SameText($grant, 'INSERT'))
return 'INSERT';
if (StringUtils::SameText($grant, 'DELETE'))
return 'DELETE';
if (StringUtils::SameText($grant, 'ADMIN'))
return 'ADMIN';
return null;
}
}