Skip to content

Commit

Permalink
Automatically reload updated rights
Browse files Browse the repository at this point in the history
  • Loading branch information
ccailly authored Feb 1, 2024
1 parent 9014f0b commit ef93b74
Show file tree
Hide file tree
Showing 10 changed files with 388 additions and 34 deletions.
49 changes: 49 additions & 0 deletions install/migrations/update_10.0.x_to_10.1.0/profiles.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

/**
* ---------------------------------------------------------------------
*
* GLPI - Gestionnaire Libre de Parc Informatique
*
* http://glpi-project.org
*
* @copyright 2015-2024 Teclib' and contributors.
* @copyright 2003-2014 by the INDEPNET Development Team.
* @licence https://www.gnu.org/licenses/gpl-3.0.html
*
* ---------------------------------------------------------------------
*
* LICENSE
*
* This file is part of GLPI.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* ---------------------------------------------------------------------
*/

/**
* @var \Migration $migration
*/

$migration->addField(
'glpi_profiles',
'last_rights_update',
'timestamp',
[
'null' => false,
'value' => null
]
);
$migration->addKey('glpi_profiles', 'last_rights_update');
4 changes: 3 additions & 1 deletion install/mysql/glpi-empty.sql
Original file line number Diff line number Diff line change
Expand Up @@ -5807,6 +5807,7 @@ CREATE TABLE `glpi_profiles` (
`managed_domainrecordtypes` text,
`date_creation` timestamp NULL DEFAULT NULL,
`2fa_enforced` tinyint NOT NULL DEFAULT '0',
`last_rights_update` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `name` (`name`),
KEY `interface` (`interface`),
Expand All @@ -5815,7 +5816,8 @@ CREATE TABLE `glpi_profiles` (
KEY `date_creation` (`date_creation`),
KEY `tickettemplates_id` (`tickettemplates_id`),
KEY `changetemplates_id` (`changetemplates_id`),
KEY `problemtemplates_id` (`problemtemplates_id`)
KEY `problemtemplates_id` (`problemtemplates_id`),
KEY `last_rights_update` (`last_rights_update`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;


Expand Down
35 changes: 35 additions & 0 deletions src/Migration.php
Original file line number Diff line number Diff line change
Expand Up @@ -1265,6 +1265,8 @@ public function addRight($name, $rights = ALLSTANDARDRIGHT, $requiredrights = ['
],
sprintf('%1$s add right for %2$s', $this->version, $name)
);

$this->updateProfileLastRightsUpdate($profile['id']);
}

$this->displayWarning(
Expand Down Expand Up @@ -1329,6 +1331,8 @@ public function addRightByInterface($name, $right, $interface = 'central')
],
sprintf('%1$s update right for %2$s', $this->version, $name)
);

$this->updateProfileLastRightsUpdate($profile['id']);
}

$this->displayWarning(
Expand Down Expand Up @@ -1398,6 +1402,8 @@ public function updateRight($name, $rights, $requiredrights = ['config' => READ
],
sprintf('%1$s update right for %2$s', $this->version, $name)
);

$this->updateProfileLastRightsUpdate($profile['id']);
}

$this->displayWarning(
Expand All @@ -1409,6 +1415,35 @@ public function updateRight($name, $rights, $requiredrights = ['config' => READ
);
}

/**
* Update last rights update for given profile.
*
* @param int $profile_id
* @return void
*/
private function updateProfileLastRightsUpdate(int $profile_id): void
{
/** @var \DBmysql $DB */
global $DB;

// Check if the 'last_rights_update' field exists before trying to update it.
// This field may not exist yet as it is added by a migration, and other migrations
// that add a right could be executed before the migration that adds this field.
if (!$DB->fieldExists('glpi_profiles', 'last_rights_update')) {
return;
}

$DB->updateOrDie(
'glpi_profiles',
[
'last_rights_update' => Session::getCurrentTime()
],
[
'id' => $profile_id,
]
);
}

public function setOutputHandler($output_handler)
{

Expand Down
31 changes: 17 additions & 14 deletions src/Profile.php
Original file line number Diff line number Diff line change
Expand Up @@ -422,20 +422,23 @@ public function prepareInputForUpdate($input)


// Check if profile edit right was removed
$can_edit_profile = $this->fields['profile'] & UPDATE == UPDATE;
$updated_value = $input['_profile'][UPDATE . "_0"] ?? null;
$update_profiles_right_was_removed = $updated_value !== null && !(bool) $updated_value;
if (
$can_edit_profile
&& $update_profiles_right_was_removed
&& $this->isLastSuperAdminProfile()
) {
Session::addMessageAfterRedirect(
__("Can't remove update right on this profile as it is the only remaining profile with this right."),
false,
ERROR
);
unset($input['_profile']);
// `$this->fields['profile']` will not be present if the `profile` right is not present in DB for the current profile
if (array_key_exists('profile', $this->fields)) {
$can_edit_profile = $this->fields['profile'] & UPDATE == UPDATE;
$updated_value = $input['_profile'][UPDATE . "_0"] ?? null;
$update_profiles_right_was_removed = $updated_value !== null && !(bool) $updated_value;
if (
$can_edit_profile
&& $update_profiles_right_was_removed
&& $this->isLastSuperAdminProfile()
) {
Session::addMessageAfterRedirect(
__("Can't remove update right on this profile as it is the only remaining profile with this right."),
false,
ERROR
);
unset($input['_profile']);
}
}

if (isset($input['interface']) && $input['interface'] == 'helpdesk' && $this->isLastSuperAdminProfile()) {
Expand Down
26 changes: 8 additions & 18 deletions src/ProfileRight.php
Original file line number Diff line number Diff line change
Expand Up @@ -302,39 +302,29 @@ public static function updateProfileRights($profiles_id, array $rights = [])
public function post_addItem($history = true)
{
// Refresh session rights to avoid log out and login when rights change
$this->forceCurrentSessionRights($this->fields['profiles_id'], $this->fields['name'], $this->fields['rights']);
$this->updateProfileLastRightsUpdate($this->fields['profiles_id']);
}

public function post_updateItem($history = true)
{
// Refresh session rights to avoid log out and login when rights change
$this->forceCurrentSessionRights($this->fields['profiles_id'], $this->fields['name'], $this->fields['rights']);
$this->updateProfileLastRightsUpdate($this->fields['profiles_id']);
}

/**
* Force rights for given rightname on current session.
* Update last rights update for given profile.
*
* @param int $profile_id
* @param string $rightname
* @param int $rights
* @return void
*/
private function forceCurrentSessionRights(int $profile_id, string $rightname, int $rights): void
private function updateProfileLastRightsUpdate(int $profile_id): void
{
if (
isset($_SESSION['glpiactiveprofile']['id'])
&& $_SESSION['glpiactiveprofile']['id'] == $profile_id
&& (
!isset($_SESSION['glpiactiveprofile'][$rightname])
|| $_SESSION['glpiactiveprofile'][$rightname] != $rights
)
) {
$_SESSION['glpiactiveprofile'][$rightname] = $rights;
unset($_SESSION['glpimenu']);
}
Profile::getById($profile_id)->update([
'id' => $profile_id,
'last_rights_update' => Session::getCurrentTime()
]);
}


/**
* @since 085
*
Expand Down
40 changes: 39 additions & 1 deletion src/Session.php
Original file line number Diff line number Diff line change
Expand Up @@ -995,16 +995,24 @@ public static function checkValidSessionId()
} else {
$user_table = User::getTable();
$pu_table = Profile_User::getTable();
$profile_table = Profile::getTable();
$result = $DB->request(
[
'COUNT' => 'count',
'SELECT' => [$profile_table . '.last_rights_update'],
'FROM' => $user_table,
'LEFT JOIN' => [
$pu_table => [
'FKEY' => [
Profile_User::getTable() => 'users_id',
$user_table => 'id'
]
],
$profile_table => [
'FKEY' => [
$pu_table => 'profiles_id',
$profile_table => 'id'
]
]
],
'WHERE' => [
Expand All @@ -1013,10 +1021,20 @@ public static function checkValidSessionId()
$user_table . '.is_deleted' => 0,
$pu_table . '.profiles_id' => $profile_id,
] + getEntitiesRestrictCriteria($pu_table, 'entities_id', $entity_id, true),
'GROUPBY' => [$profile_table . '.id'],
]
);
if ($result->current()['count'] === 0) {

$row = $result->current();

if ($row['count'] === 0) {
$valid_user = false;
} elseif (
$row['last_rights_update'] !== null
&& $row['last_rights_update'] > $_SESSION['glpiactiveprofile']['last_rights_update'] ?? 0
) {
Session::reloadCurrentProfile();
$_SESSION['glpiactiveprofile']['last_rights_update'] = $row['last_rights_update'];
}
}

Expand Down Expand Up @@ -2170,4 +2188,24 @@ public static function canWriteSessionFiles(): bool
return $session_handler !== false
&& (strtolower($session_handler) !== 'files' || is_writable(GLPI_SESSION_DIR));
}

/**
* Reload the current profile from the database
* Update the session variable accordingly
*
* @return void
*/
public static function reloadCurrentProfile(): void
{
$current_profile_id = $_SESSION['glpiactiveprofile']['id'];

$profile = new Profile();
if ($profile->getFromDB($current_profile_id)) {
$profile->cleanProfile();
$_SESSION['glpiactiveprofile'] = array_merge(
$_SESSION['glpiactiveprofile'],
$profile->fields
);
}
}
}
90 changes: 90 additions & 0 deletions tests/functional/ProfileRight.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php

/**
* ---------------------------------------------------------------------
*
* GLPI - Gestionnaire Libre de Parc Informatique
*
* http://glpi-project.org
*
* @copyright 2015-2024 Teclib' and contributors.
* @copyright 2003-2014 by the INDEPNET Development Team.
* @licence https://www.gnu.org/licenses/gpl-3.0.html
*
* ---------------------------------------------------------------------
*
* LICENSE
*
* This file is part of GLPI.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* ---------------------------------------------------------------------
*/

namespace tests\units;

use DbTestCase;

class ProfileRight extends DbTestCase
{
public function testUpdateProfileLastRightsUpdate()
{
global $DB;

// Create a profile
$profile = getItemByTypeName('Profile', 'Super-Admin');

// Check that the last_rights_update field is not null
$this->variable($profile->fields['last_rights_update'])->isNotNull();

// Update the last_rights_update field to null
$this->updateItem('Profile', $profile->getID(), [
'last_rights_update' => null
]);
$profile->getFromDB($profile->getID());

// Check that the last_rights_update field is null
$this->variable($profile->fields['last_rights_update'])->isNull();

// Create a profile right
$profileRight = $this->createItem('ProfileRight', [
'profiles_id' => $profile->getID(),
'name' => 'testUpdateProfileLastRightsUpdate',
'rights' => READ
]);
$profile->getFromDB($profile->getID());

// Check that the last_rights_update field is not null
$this->variable($profile->fields['last_rights_update'])->isNotNull();

// Update the last_rights_update field to null
$this->updateItem('Profile', $profile->getID(), [
'last_rights_update' => null
]);
$profile->getFromDB($profile->getID());

// Check that the last_rights_update field is null
$this->variable($profile->fields['last_rights_update'])->isNull();

// Update the profile right
$this->updateItem('ProfileRight', $profileRight->getID(), [
'rights' => READ | UPDATE
]);
$profile->getFromDB($profile->getID());

// Check that the last_rights_update field is not null
$this->variable($profile->fields['last_rights_update'])->isNotNull();
}
}
4 changes: 4 additions & 0 deletions tests/functional/Search.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

use CommonDBTM;
use CommonITILActor;
use DateTime;
use DBConnection;
use DbTestCase;
use Document;
Expand Down Expand Up @@ -1615,6 +1616,9 @@ public function testTickets()
'Ticket' => (\Ticket::READMY + \Ticket::READNEWTICKET)
]);

// reload current profile to take into account the new rights
$this->login('tech', 'tech');

// do search and check presence of the created problem
$data = \Search::prepareDatasForSearch('Ticket', ['reset' => 'reset']);
\Search::constructSQL($data);
Expand Down
Loading

0 comments on commit ef93b74

Please sign in to comment.