From 8e8cde4c1180d4b4de85bd0e4cbdba4936a68a84 Mon Sep 17 00:00:00 2001 From: v-dumas Date: Fri, 7 Nov 2025 14:14:51 +0100 Subject: [PATCH 1/8] =?UTF-8?q?N=C2=B08534=20-=20Prevent=20Admin=20from=20?= =?UTF-8?q?suicide?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/userrights.class.inc.php | 8 ++- dictionaries/cs.dictionary.itop.ui.php | 1 + dictionaries/da.dictionary.itop.ui.php | 1 + dictionaries/de.dictionary.itop.ui.php | 1 + dictionaries/en.dictionary.itop.ui.php | 1 + dictionaries/en_gb.dictionary.itop.ui.php | 1 + dictionaries/es_cr.dictionary.itop.ui.php | 1 + dictionaries/fr.dictionary.itop.ui.php | 1 + dictionaries/hu.dictionary.itop.ui.php | 1 + dictionaries/it.dictionary.itop.ui.php | 1 + dictionaries/ja.dictionary.itop.ui.php | 1 + dictionaries/nl.dictionary.itop.ui.php | 1 + dictionaries/pl.dictionary.itop.ui.php | 1 + dictionaries/pt_br.dictionary.itop.ui.php | 1 + dictionaries/ru.dictionary.itop.ui.php | 1 + dictionaries/sk.dictionary.itop.ui.php | 1 + dictionaries/tr.dictionary.itop.ui.php | 1 + dictionaries/zh_cn.dictionary.itop.ui.php | 1 + .../src/BaseTestCase/ItopDataTestCase.php | 25 ++++++++++ .../unitary-tests/core/UserRightsTest.php | 49 +++++++++++++++++-- 20 files changed, 94 insertions(+), 5 deletions(-) diff --git a/core/userrights.class.inc.php b/core/userrights.class.inc.php index d29aa7742a..c686dbbe1d 100644 --- a/core/userrights.class.inc.php +++ b/core/userrights.class.inc.php @@ -404,14 +404,14 @@ public function DoCheckToWrite() } if (!in_array(ADMIN_PROFILE_NAME, $aProfiles)) { - // Check if the user is yet allowed to modify Users + // Prevent a User to lose the right to modify Users if (method_exists($oAddon, 'ResetCache')) { $aCurrentProfiles = Session::Get('profile_list'); // Set the current profiles into a session variable (not yet in the database) Session::Set('profile_list', $aProfiles); $oAddon->ResetCache(); - if (!$oAddon->IsActionAllowed($this, 'User', UR_ACTION_MODIFY, null)) { + if (!$oAddon->IsActionAllowed($this, get_class($this), UR_ACTION_MODIFY, null)) { $this->m_aCheckIssues[] = Dict::S('Class:User/Error:CurrentProfilesHaveInsufficientRights'); } $oAddon->ResetCache(); @@ -422,6 +422,10 @@ public function DoCheckToWrite() Session::Set('profile_list', $aCurrentProfiles); } } + // Prevent an administrator to remove their own admin profile + if (UserRights::IsAdministrator($this)) { + $this->m_aCheckIssues[] = Dict::S('Class:User/Error:AdminProfileCannotBeRemovedBySelf'); + } } } } diff --git a/dictionaries/cs.dictionary.itop.ui.php b/dictionaries/cs.dictionary.itop.ui.php index 1befaac79b..63386bf583 100755 --- a/dictionaries/cs.dictionary.itop.ui.php +++ b/dictionaries/cs.dictionary.itop.ui.php @@ -171,6 +171,7 @@ 'Class:User/Error:ProfileNotAllowed' => 'Profil "%1$s" nemůže být přidán, byl by mu odepřen přístup do backoffice', 'Class:User/Error:StatusChangeIsNotAllowed' => 'Změna není povolena pro vašeho vlastního uživatele', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'Přístupné organizace musí obsahovat organizaci uživatele.', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you~~', 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'Aktuální seznam profilů neposkytuje dostatečná přístupová práva (uživatele již nelze upravovat)', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'Profil Portal power user neposkytuje dostatečná přístupová práva (je třeba přidat jiný profil)', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'Uživatel musí být přiřazen minimálně do jedné organizace.', diff --git a/dictionaries/da.dictionary.itop.ui.php b/dictionaries/da.dictionary.itop.ui.php index 9c21bcb04e..36ab94bb68 100644 --- a/dictionaries/da.dictionary.itop.ui.php +++ b/dictionaries/da.dictionary.itop.ui.php @@ -171,6 +171,7 @@ 'Class:User/Error:ProfileNotAllowed' => 'Profile "%1$s" cannot be added it will deny the access to backoffice~~', 'Class:User/Error:StatusChangeIsNotAllowed' => 'Changing status is not allowed for your own User~~', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'Allowed organizations must contain User organization~~', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you~~', 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'The current list of profiles does not give sufficient access rights (Users are not modifiable anymore)~~', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'The Portal power user profile does not give sufficient access rights (another profile must be added)~~', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'At least one organization must be assigned to this user.~~', diff --git a/dictionaries/de.dictionary.itop.ui.php b/dictionaries/de.dictionary.itop.ui.php index 314bc16738..b9bb685f27 100644 --- a/dictionaries/de.dictionary.itop.ui.php +++ b/dictionaries/de.dictionary.itop.ui.php @@ -170,6 +170,7 @@ 'Class:User/Error:ProfileNotAllowed' => 'Profil "%1$s" kann nicht hinzugefügt werde, es verhindert den Zugriff auf das Backoffice.', 'Class:User/Error:StatusChangeIsNotAllowed' => 'Statusänderungen sind für den eigenen Benutzer nicht erlaubt.', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'Die Organisation des Benutzers muss in den erlaubten Organisationen enthalten sein.', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you~~', 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'Die aktuelle Liste an Profilen vergibt unzureichende Berechtigungen (Benutzer können nicht mehr geändert werden)', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'Das Profil des Portal-Power-Benutzers hat nicht ausreichend Zugriffsrechte (ein weiteres Profil muss hinzugefügt werden)', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'Mindestens eine Organisation muss diesem Benutzer zugewiesen sein.', diff --git a/dictionaries/en.dictionary.itop.ui.php b/dictionaries/en.dictionary.itop.ui.php index f42fa2322f..9e69538d85 100644 --- a/dictionaries/en.dictionary.itop.ui.php +++ b/dictionaries/en.dictionary.itop.ui.php @@ -185,6 +185,7 @@ 'Class:User/Error:ProfileNotAllowed' => 'Profile "%1$s" cannot be added it will deny the access to backoffice', 'Class:User/Error:StatusChangeIsNotAllowed' => 'Changing status is not allowed for your own User', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'Allowed organizations must contain User organization', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you', 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'The current list of profiles does not give sufficient access rights (Users are not modifiable anymore)', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'The Portal power user profile does not give sufficient access rights (another profile must be added)', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'At least one organization must be assigned to this user.', diff --git a/dictionaries/en_gb.dictionary.itop.ui.php b/dictionaries/en_gb.dictionary.itop.ui.php index 9b08ae3038..1a42f58d87 100644 --- a/dictionaries/en_gb.dictionary.itop.ui.php +++ b/dictionaries/en_gb.dictionary.itop.ui.php @@ -185,6 +185,7 @@ 'Class:User/Error:ProfileNotAllowed' => 'Profile "%1$s" cannot be added as it will deny access to the back office.', 'Class:User/Error:StatusChangeIsNotAllowed' => 'Changing status is not allowed for your own User', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'Allowed organisations must contain User organisation', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you~~', 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'The current list of profiles does not give sufficient access rights (Users are not modifiable any more)', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'The Portal power user profile does not give sufficient access rights (another profile must be added)', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'At least one organisation must be assigned to this user.', diff --git a/dictionaries/es_cr.dictionary.itop.ui.php b/dictionaries/es_cr.dictionary.itop.ui.php index 943ccb1ded..d9c9adc865 100644 --- a/dictionaries/es_cr.dictionary.itop.ui.php +++ b/dictionaries/es_cr.dictionary.itop.ui.php @@ -169,6 +169,7 @@ 'Class:User/Error:ProfileNotAllowed' => 'No se puede agregar el perfil "%1$s"; denegará el acceso al backoffice', 'Class:User/Error:StatusChangeIsNotAllowed' => 'Cambiar estatus no está permitido para su propio usuario', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'Las organizaciones permitidas deben contener una organización de usuario', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you~~', 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'La lista actual de perfiles no otorga suficientes permisos de acceso (los usuarios ya no son modificables)', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'El perfil de usuario avanzado del Portal no otorga suficientes derechos de acceso (se debe agregar otro perfil)', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'Al menos una organización debe ser asignada a este usuario.', diff --git a/dictionaries/fr.dictionary.itop.ui.php b/dictionaries/fr.dictionary.itop.ui.php index 7b0f147d0f..0500b80f46 100644 --- a/dictionaries/fr.dictionary.itop.ui.php +++ b/dictionaries/fr.dictionary.itop.ui.php @@ -176,6 +176,7 @@ 'Class:User/Error:ProfileNotAllowed' => 'Le profil "%1$s" ne peux pas être ajouté à son propre utilisateur, il interdit l\'accès à la console', 'Class:User/Error:StatusChangeIsNotAllowed' => 'Impossible de changer l\'état de son propre utilisateur', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'Les organisations permises doivent contenir l\'organisation de l\'utilisateur', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'Vous ne pouvez pas vous retirer le profile Administrateur. Demandez à un autre Administrateur de le faire pour vous', 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'Les profils existants ne permettent pas de modifier les utilisateurs', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'Le profil Portal power user ne donne pas suffisamment de droits à l\'utilisateur (un autre profil doit être ajouté)', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'L\'utilisateur doit avoir au moins une organisation.', diff --git a/dictionaries/hu.dictionary.itop.ui.php b/dictionaries/hu.dictionary.itop.ui.php index b532b0e7ed..c1bff2332a 100755 --- a/dictionaries/hu.dictionary.itop.ui.php +++ b/dictionaries/hu.dictionary.itop.ui.php @@ -171,6 +171,7 @@ 'Class:User/Error:ProfileNotAllowed' => 'A "%1$s" profil nem adható hozzá, le lesz tiltva', 'Class:User/Error:StatusChangeIsNotAllowed' => 'A saját felhasználó státuszának cseréje nem engedélyezett', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'Az engedélyezett szervezeteknek tartalmazniuk kell a felhasználói szervezetet', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you~~', 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'A profilok jelenlegi listája nem ad elegendő hozzáférési jogot (a felhasználók már nem módosíthatók)', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'The Portal power user profile does not give sufficient access rights (another profile must be added)~~', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'A felhasználóhoz legalább egy szervezeti egységet hozzá kell rendelni', diff --git a/dictionaries/it.dictionary.itop.ui.php b/dictionaries/it.dictionary.itop.ui.php index 8eef4acbe6..3d7fc9336b 100644 --- a/dictionaries/it.dictionary.itop.ui.php +++ b/dictionaries/it.dictionary.itop.ui.php @@ -171,6 +171,7 @@ 'Class:User/Error:ProfileNotAllowed' => 'Il profilo "%1$s" non può essere aggiunto poiché nega l\'accesso al back office.', 'Class:User/Error:StatusChangeIsNotAllowed' => 'La modifica dello stato non è consentita per il proprio utente.', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'Le organizzazioni consentite devono includere l\'organizzazione dell\'utente.', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you~~', 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'L\'elenco attuale dei profili non conferisce diritti di accesso sufficienti (gli utenti non sono più modificabili).', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'Il profilo utente con poteri del portale non concede diritti di accesso sufficienti (deve essere aggiunto un altro profilo)', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'È necessario assegnare almeno un\'organizzazione a questo utente.', diff --git a/dictionaries/ja.dictionary.itop.ui.php b/dictionaries/ja.dictionary.itop.ui.php index d18df50028..3da685193d 100644 --- a/dictionaries/ja.dictionary.itop.ui.php +++ b/dictionaries/ja.dictionary.itop.ui.php @@ -171,6 +171,7 @@ 'Class:User/Error:ProfileNotAllowed' => 'Profile "%1$s" cannot be added it will deny the access to backoffice~~', 'Class:User/Error:StatusChangeIsNotAllowed' => 'Changing status is not allowed for your own User~~', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'Allowed organizations must contain User organization~~', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you~~', 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'The current list of profiles does not give sufficient access rights (Users are not modifiable anymore)~~', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'The Portal power user profile does not give sufficient access rights (another profile must be added)~~', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'At least one organization must be assigned to this user.~~', diff --git a/dictionaries/nl.dictionary.itop.ui.php b/dictionaries/nl.dictionary.itop.ui.php index 28f84cbd0b..45536d900d 100644 --- a/dictionaries/nl.dictionary.itop.ui.php +++ b/dictionaries/nl.dictionary.itop.ui.php @@ -171,6 +171,7 @@ 'Class:User/Error:ProfileNotAllowed' => 'Profiel "%1$s" kan niet toegevoegd worden omdat het de toegang tot de backoffice zou ontzeggen.', 'Class:User/Error:StatusChangeIsNotAllowed' => 'Je kan de status voor je eigen gebruikersaccount niet wijzigen.', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'De toegestande organisaties moeten minstens de organisatie bevatten waartoe de gebruikersaccount behoort.', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you~~', 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'De huidige lijst van profielen heeft niet voldoende toegangsrechten (gebruikersaccount zijn niet meer wijzigbaar).', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'The Portal power user profile does not give sufficient access rights (another profile must be added)~~', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'Minstens één organisatie moet toegewezen zijn aan deze gebruiker', diff --git a/dictionaries/pl.dictionary.itop.ui.php b/dictionaries/pl.dictionary.itop.ui.php index a102e0a6ed..0c710890de 100644 --- a/dictionaries/pl.dictionary.itop.ui.php +++ b/dictionaries/pl.dictionary.itop.ui.php @@ -171,6 +171,7 @@ 'Class:User/Error:ProfileNotAllowed' => 'Nie można dodać profilu "%1$s" nie ma on dostępu do zaplecza', 'Class:User/Error:StatusChangeIsNotAllowed' => 'Zmiana statusu nie jest dozwolona dla własnego użytkownika', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'Dozwolone organizacje muszą zawierać organizację użytkownika', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you~~', 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'Aktualna lista profili nie daje wystarczających praw dostępu (Użytkowników nie można już modyfikować)', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'Profil użytkownika zaawansowanego Portalu nie zapewnia wystarczających praw dostępu (należy dodać kolejny profil)', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'Do użytkownika musi być przypisana co najmniej jedna organizacja.', diff --git a/dictionaries/pt_br.dictionary.itop.ui.php b/dictionaries/pt_br.dictionary.itop.ui.php index 8fc66488bc..5a8eb160ce 100644 --- a/dictionaries/pt_br.dictionary.itop.ui.php +++ b/dictionaries/pt_br.dictionary.itop.ui.php @@ -171,6 +171,7 @@ 'Class:User/Error:ProfileNotAllowed' => 'O perfil "%1$s" não pôde ser adicionado, ele negará o acesso ao backoffice', 'Class:User/Error:StatusChangeIsNotAllowed' => 'Alterar o status da conta não é permitido para o seu próprio usuário', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'As organizações permitidas devem conter apenas usuários pertencentes a organização', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you~~', 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'A lista atual de perfis não fornece permissões de acesso suficientes (os usuários não são mais modificáveis)', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'The Portal power user profile does not give sufficient access rights (another profile must be added)~~', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'Pelo menos uma organização deve ser atribuída a esse usuário', diff --git a/dictionaries/ru.dictionary.itop.ui.php b/dictionaries/ru.dictionary.itop.ui.php index 77560b23ca..a6bb82ee87 100644 --- a/dictionaries/ru.dictionary.itop.ui.php +++ b/dictionaries/ru.dictionary.itop.ui.php @@ -172,6 +172,7 @@ 'Class:User/Error:ProfileNotAllowed' => 'Profile "%1$s" cannot be added it will deny the access to backoffice~~', 'Class:User/Error:StatusChangeIsNotAllowed' => 'Changing status is not allowed for your own User~~', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'Allowed organizations must contain User organization~~', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you~~', 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'The current list of profiles does not give sufficient access rights (Users are not modifiable anymore)~~', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'The Portal power user profile does not give sufficient access rights (another profile must be added)~~', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'Этому пользователю должна быть назначена хотя бы одна организация.', diff --git a/dictionaries/sk.dictionary.itop.ui.php b/dictionaries/sk.dictionary.itop.ui.php index 79c9a287bd..5356ef76bd 100644 --- a/dictionaries/sk.dictionary.itop.ui.php +++ b/dictionaries/sk.dictionary.itop.ui.php @@ -175,6 +175,7 @@ 'Class:User/Error:ProfileNotAllowed' => 'Profile "%1$s" cannot be added it will deny the access to backoffice~~', 'Class:User/Error:StatusChangeIsNotAllowed' => 'Changing status is not allowed for your own User~~', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'Allowed organizations must contain User organization~~', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you~~', 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'The current list of profiles does not give sufficient access rights (Users are not modifiable anymore)~~', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'The Portal power user profile does not give sufficient access rights (another profile must be added)~~', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'At least one organization must be assigned to this user.~~', diff --git a/dictionaries/tr.dictionary.itop.ui.php b/dictionaries/tr.dictionary.itop.ui.php index f3b953065b..e42b6fef8f 100644 --- a/dictionaries/tr.dictionary.itop.ui.php +++ b/dictionaries/tr.dictionary.itop.ui.php @@ -171,6 +171,7 @@ 'Class:User/Error:ProfileNotAllowed' => 'Profile "%1$s" cannot be added it will deny the access to backoffice~~', 'Class:User/Error:StatusChangeIsNotAllowed' => 'Changing status is not allowed for your own User~~', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'Allowed organizations must contain User organization~~', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you~~', 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'The current list of profiles does not give sufficient access rights (Users are not modifiable anymore)~~', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'The Portal power user profile does not give sufficient access rights (another profile must be added)~~', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'At least one organization must be assigned to this user.~~', diff --git a/dictionaries/zh_cn.dictionary.itop.ui.php b/dictionaries/zh_cn.dictionary.itop.ui.php index e60fb82c6d..5975cfce0f 100644 --- a/dictionaries/zh_cn.dictionary.itop.ui.php +++ b/dictionaries/zh_cn.dictionary.itop.ui.php @@ -173,6 +173,7 @@ 'Class:User/Error:ProfileNotAllowed' => '无法添加角色 "%1$s" 因为这将导致禁止访问后台', 'Class:User/Error:StatusChangeIsNotAllowed' => '不允许更改您自己用户的状态', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => '允许访问组织必须包含用户组织', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you~~', 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => '当前指定的角色列表没有提供足够的访问权限 (用户将无法被修改)', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'The Portal power user profile does not give sufficient access rights (another profile must be added)~~', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => '必须为此用户指定一个组织.', diff --git a/tests/php-unit-tests/src/BaseTestCase/ItopDataTestCase.php b/tests/php-unit-tests/src/BaseTestCase/ItopDataTestCase.php index dd58070843..932c685eb4 100644 --- a/tests/php-unit-tests/src/BaseTestCase/ItopDataTestCase.php +++ b/tests/php-unit-tests/src/BaseTestCase/ItopDataTestCase.php @@ -650,6 +650,31 @@ protected function AddProfileToUser($oUser, $iProfileId) return $oUser; } + /** + * @param \DBObject $oUser + * @param int $iProfileId + * + * @return \DBObject + * @throws Exception + */ + protected function RemoveProfileFromUser($oUser, $iProfileId) + { + /** @var \ormLinkSet $oSet */ + $oSet = $oUser->Get('profile_list'); + foreach ($oSet as $oUserProfile) + { + if ($oUserProfile->Get('profileid') == $iProfileId) + { + $oSet->RemoveItem($oUserProfile->GetKey()); + break; + } + } + $oUser = $this->updateObject(User::class, $oUser->GetKey(), array( + 'profile_list' => $oSet, + )); + return $oUser; + } + /** * Create a Hypervisor in database * diff --git a/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php b/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php index cecdd4b7ff..50ad61cf8c 100644 --- a/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php +++ b/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php @@ -354,6 +354,7 @@ public function DeletingSelfUserProvider(): array return [ 'Administrator' => [1], 'Configuration manager' => [3], + 'SuperUser' => [117], ]; } @@ -385,6 +386,7 @@ public function RemovingOwnContactProvider(): array return [ 'Administrator' => [1], 'Configuration manager' => [3], + 'SuperUser' => [117], ]; } @@ -408,18 +410,19 @@ public function testUpgradingToAdmin() } /** + * @dataProvider RemovingOwnProfileProvider * @doesNotPerformAssertions * * @throws \CoreException * @throws \DictExceptionUnknownLanguage * @throws \OQLException */ - public function testDenyingUserModification() + public function testDenyingOwnUserModification(int $iProfileId) { - $oUser = $this->CreateUniqueUserAndLogin('test1', 1); + $oUser = $this->CreateUniqueUserAndLogin('test1', $iProfileId); $this->AddProfileToUser($oUser, 3); - // Keep only the profile 3 (remove profile 1) + // Keep only the profile 3 (Configuration manager) $oSet = new \ormLinkSet(\UserLocal::class, 'profile_list', \DBObjectSet::FromScratch(\URP_UserProfile::class)); $oSet->AddItem(MetaModel::NewObject('URP_UserProfile', ['profileid' => 3, 'reason' => 'UNIT Tests'])); $oUser->Set('profile_list', $oSet); @@ -430,6 +433,13 @@ public function testDenyingUserModification() } catch (CoreCannotSaveObjectException $e) { } } + public function RemovingOwnProfileProvider(): array + { + return [ + 'Administrator' => [1], + 'SuperUser' => [117], + ]; + } /** *@dataProvider NonAdminCanListOwnProfilesProvider @@ -539,6 +549,39 @@ public function testFindUser_UnknownLogin() ); } + public function testAdminCannotRemoveOwnAdminProfile() + { + $oUser = $this->CreateUniqueUserAndLogin('admin111', 1); // Administrator + // Keep only the SuperUser profile (remove Administrator profile) + $this->AddProfileToUser($oUser, 117); // SuperUser profile for the test + + $this->expectException(CoreCannotSaveObjectException::class); + $this->expectExceptionMessage('Class:User/Error:AdminProfileCannotBeRemovedBySelf'); + $this->RemoveProfileFromUser($oUser, 1); // Remove admin profile + } + + /** + * @dataProvider RemovingProfileProvider + */ + public function testUserCannotLoseUserEditionRights(int $iProfileId) + { + $oUser = $this->CreateUniqueUserAndLogin('configmgr111', $iProfileId); // SuperUser + // Keep only the configuration manager profile (remove SuperUser profile) + $this->AddProfileToUser($oUser, 3); + $this->expectException(CoreCannotSaveObjectException::class); + $this->expectExceptionMessage('Class:User/Error:CurrentProfilesHaveInsufficientRights'); + $this->RemoveProfileFromUser($oUser, $iProfileId); + } + + + public function RemovingProfileProvider(): array + { + return [ + 'Administrator' => [1], + 'SuperUser' => [117], + ]; + } + public function FindUserAndAssertItHasBeenFound($sLogin, $iExpectedKey) { $oUser = $this->InvokeNonPublicStaticMethod(UserRights::class, "FindUser", [$sLogin]); From 3ff4fab40a42bf617ec60268f7eae6e947d5a973 Mon Sep 17 00:00:00 2001 From: v-dumas Date: Fri, 7 Nov 2025 15:32:12 +0100 Subject: [PATCH 2/8] =?UTF-8?q?N=C2=B08534=20-=20Prevent=20Admin=20from=20?= =?UTF-8?q?suicide=20(2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../userrightsprofile.class.inc.php | 1 + dictionaries/en.dictionary.itop.ui.php | 4 ++-- dictionaries/fr.dictionary.itop.ui.php | 6 ++--- .../unitary-tests/core/UserRightsTest.php | 22 +++++++++---------- 4 files changed, 16 insertions(+), 17 deletions(-) diff --git a/addons/userrights/userrightsprofile.class.inc.php b/addons/userrights/userrightsprofile.class.inc.php index d2560bbe8d..5952ece3e5 100644 --- a/addons/userrights/userrightsprofile.class.inc.php +++ b/addons/userrights/userrightsprofile.class.inc.php @@ -536,6 +536,7 @@ public function ResetCache() // Cache $this->m_aObjectActionGrants = []; $this->m_aAdministrators = null; + $this->aUsersProfilesList = []; } public function LoadCache() diff --git a/dictionaries/en.dictionary.itop.ui.php b/dictionaries/en.dictionary.itop.ui.php index 9e69538d85..c46c31a44c 100644 --- a/dictionaries/en.dictionary.itop.ui.php +++ b/dictionaries/en.dictionary.itop.ui.php @@ -185,8 +185,8 @@ 'Class:User/Error:ProfileNotAllowed' => 'Profile "%1$s" cannot be added it will deny the access to backoffice', 'Class:User/Error:StatusChangeIsNotAllowed' => 'Changing status is not allowed for your own User', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'Allowed organizations must contain User organization', - 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you', - 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'The current list of profiles does not give sufficient access rights (Users are not modifiable anymore)', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove your own Administrator profile. Ask another Administrator to do it for you', + 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'You cannot remove your own rights to edit users', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'The Portal power user profile does not give sufficient access rights (another profile must be added)', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'At least one organization must be assigned to this user.', 'Class:User/Error:OrganizationNotAllowed' => 'Organization not allowed.', diff --git a/dictionaries/fr.dictionary.itop.ui.php b/dictionaries/fr.dictionary.itop.ui.php index 0500b80f46..cbb13790b7 100644 --- a/dictionaries/fr.dictionary.itop.ui.php +++ b/dictionaries/fr.dictionary.itop.ui.php @@ -168,7 +168,7 @@ 'Class:User/Attribute:allowed_org_list' => 'Organisations permises', 'Class:User/Attribute:allowed_org_list+' => 'L\'utilisateur a le droit de voir les données des organisations listées ici. Si aucune organisation n\'est spécifiée, alors aucune restriction ne s\'applique.', 'Class:User/Attribute:status' => 'Etat', - 'Class:User/Attribute:status+' => 'Est-ce que ce compte utilisateur est actif, ou non?', + 'Class:User/Attribute:status+' => 'Est-ce que ce compte utilisateur est actif, ou non ?', 'Class:User/Attribute:status/Value:enabled' => 'Actif', 'Class:User/Attribute:status/Value:disabled' => 'Désactivé', 'Class:User/Error:LoginMustBeUnique' => 'Le login doit être unique - "%1s" est déjà utilisé.', @@ -176,8 +176,8 @@ 'Class:User/Error:ProfileNotAllowed' => 'Le profil "%1$s" ne peux pas être ajouté à son propre utilisateur, il interdit l\'accès à la console', 'Class:User/Error:StatusChangeIsNotAllowed' => 'Impossible de changer l\'état de son propre utilisateur', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'Les organisations permises doivent contenir l\'organisation de l\'utilisateur', - 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'Vous ne pouvez pas vous retirer le profile Administrateur. Demandez à un autre Administrateur de le faire pour vous', - 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'Les profils existants ne permettent pas de modifier les utilisateurs', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'Vous ne pouvez pas supprimer votre propre profil Administrateur. Demandez à un autre Administrateur de le faire pour vous', + 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'Vous ne pouvez pas supprimer vos propres droits de modification des utilisateurs.', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'Le profil Portal power user ne donne pas suffisamment de droits à l\'utilisateur (un autre profil doit être ajouté)', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'L\'utilisateur doit avoir au moins une organisation.', 'Class:User/Error:OrganizationNotAllowed' => 'Organisation non autorisée.', diff --git a/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php b/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php index 50ad61cf8c..552dc39d57 100644 --- a/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php +++ b/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php @@ -279,28 +279,26 @@ public function ActionAllowedOnAttributeProvider(): array } /** - * @dataProvider ProfileDenyingConsoleProvider - * @doesNotPerformAssertions + * @dataProvider UserCannotLoseConsoleAccessProvider * * @throws \CoreException * @throws \DictExceptionUnknownLanguage * @throws \OQLException */ - public function testProfileDenyingConsole(int $iProfileId) + public function testUserCannotLoseConsoleAccess(int $iProfileId) { $oUser = $this->CreateUniqueUserAndLogin('test1', $iProfileId); - try { - $this->AddProfileToUser($oUser, 2); - $this->fail('Profile should not be added'); - } catch (CoreCannotSaveObjectException $e) { - } + $this->expectException(CoreCannotSaveObjectException::class); + $this->expectExceptionMessage('Profile "Portal user" cannot be added it will deny the access to backoffice'); + $this->AddProfileToUser($oUser, 2); } - public function ProfileDenyingConsoleProvider(): array + public function UserCannotLoseConsoleAccessProvider(): array { return [ 'Administrator' => [1], + 'SuperUser' => [117], ]; } @@ -556,7 +554,7 @@ public function testAdminCannotRemoveOwnAdminProfile() $this->AddProfileToUser($oUser, 117); // SuperUser profile for the test $this->expectException(CoreCannotSaveObjectException::class); - $this->expectExceptionMessage('Class:User/Error:AdminProfileCannotBeRemovedBySelf'); + $this->expectExceptionMessage('You cannot remove your own Administrator profile. Ask another Administrator to do it for you'); $this->RemoveProfileFromUser($oUser, 1); // Remove admin profile } @@ -566,10 +564,10 @@ public function testAdminCannotRemoveOwnAdminProfile() public function testUserCannotLoseUserEditionRights(int $iProfileId) { $oUser = $this->CreateUniqueUserAndLogin('configmgr111', $iProfileId); // SuperUser - // Keep only the configuration manager profile (remove SuperUser profile) $this->AddProfileToUser($oUser, 3); + $this->expectException(CoreCannotSaveObjectException::class); - $this->expectExceptionMessage('Class:User/Error:CurrentProfilesHaveInsufficientRights'); + $this->expectExceptionMessage('You cannot remove your own rights to edit users'); $this->RemoveProfileFromUser($oUser, $iProfileId); } From 60c7556afc6a43571d02ac36aefd20118838f9f8 Mon Sep 17 00:00:00 2001 From: v-dumas Date: Fri, 7 Nov 2025 15:42:33 +0100 Subject: [PATCH 3/8] =?UTF-8?q?N=C2=B08534=20-=20Prevent=20Admin=20from=20?= =?UTF-8?q?suicide=20(3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../unitary-tests/core/UserRightsTest.php | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php b/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php index 552dc39d57..8baa3ed97c 100644 --- a/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php +++ b/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php @@ -303,28 +303,26 @@ public function UserCannotLoseConsoleAccessProvider(): array } /** - * @dataProvider ProfileCannotModifySelfProvider - * @doesNotPerformAssertions + * @dataProvider UserCannotElevateTheirOwnRightsProvider * * @throws \CoreException * @throws \DictExceptionUnknownLanguage * @throws \OQLException */ - public function testProfileCannotModifySelf(int $iProfileId) + public function testUserCannotElevateTheirOwnRights(int $iCurrentProfileId, int $iElevatedProfileId) { - $oUser = $this->CreateUniqueUserAndLogin('test1', $iProfileId); + $oUser = $this->CreateUniqueUserAndLogin('test1', $iCurrentProfileId); - try { - $this->AddProfileToUser($oUser, 1); // trying to become an admin - $this->fail('User should not modify self'); - } catch (CoreException $e) { - } + $this->expectException(CoreCannotSaveObjectException::class); + $this->AddProfileToUser($oUser, $iElevatedProfileId); } - public function ProfileCannotModifySelfProvider(): array + public function UserCannotElevateTheirOwnRightsProvider(): array { return [ - 'Configuration manager' => [3], + 'Configuration manager to SuperUser' => ['current'=> 3, 'added' => 117], + 'Configuration manager to Administrator' => ['current'=> 3, 'added' => 1], + 'SuperUser to Administrator' => ['current'=> 117, 'added' => 1], ]; } From 6cdb5f6c68427fec92c19e43deccfb7fe05e44e8 Mon Sep 17 00:00:00 2001 From: v-dumas Date: Fri, 7 Nov 2025 16:06:50 +0100 Subject: [PATCH 4/8] =?UTF-8?q?N=C2=B08534=20-=20Prevent=20Admin=20from=20?= =?UTF-8?q?suicide=20(4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../unitary-tests/core/UserRightsTest.php | 120 +++++------------- 1 file changed, 30 insertions(+), 90 deletions(-) diff --git a/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php b/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php index 8baa3ed97c..a08dd33ad0 100644 --- a/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php +++ b/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php @@ -327,25 +327,21 @@ public function UserCannotElevateTheirOwnRightsProvider(): array } /** - * @dataProvider DeletingSelfUserProvider - * @doesNotPerformAssertions + * @dataProvider UserCannotDeleteOwnUserProvider * * @throws \CoreException * @throws \DictExceptionUnknownLanguage * @throws \OQLException */ - public function testDeletingSelfUser(int $iProfileId) + public function testUserCannotDeleteOwnUser(int $iProfileId) { $oUser = $this->CreateUniqueUserAndLogin('test1', $iProfileId); - try { - $oUser->DBDelete(); - $this->fail('Current User cannot be deleted'); - } catch (DeleteException $e) { - } + $this->expectException(DeleteException::class); + $oUser->DBDelete(); } - public function DeletingSelfUserProvider(): array + public function UserCannotDeleteOwnUserProvider(): array { return [ 'Administrator' => [1], @@ -355,8 +351,7 @@ public function DeletingSelfUserProvider(): array } /** - * @dataProvider RemovingOwnContactProvider - * @doesNotPerformAssertions + * @dataProvider UserCannotRemoveOwnContactProvider * * @param int $iProfileId * @@ -364,20 +359,16 @@ public function DeletingSelfUserProvider(): array * @throws \DictExceptionUnknownLanguage * @throws \OQLException */ - public function testRemovingOwnContact(int $iProfileId) + public function testUserCannotRemoveOwnContact(int $iProfileId) { $oUser = $this->CreateUniqueUserAndLogin('test1', $iProfileId); $oUser->Set('contactid', 0); - - try { - $oUser->DBWrite(); - $this->fail('Current User cannot remove his own contact'); - } catch (CoreCannotSaveObjectException $e) { - } + $this->expectException(CoreCannotSaveObjectException::class); + $oUser->DBWrite(); } - public function RemovingOwnContactProvider(): array + public function UserCannotRemoveOwnContactProvider(): array { return [ 'Administrator' => [1], @@ -386,50 +377,32 @@ public function RemovingOwnContactProvider(): array ]; } - /** - * @doesNotPerformAssertions - * - * @throws \CoreException - * @throws \DictExceptionUnknownLanguage - * @throws \OQLException - */ - public function testUpgradingToAdmin() + public function testAdminCannotRemoveOwnAdminProfile() { - $oUser = $this->CreateUniqueUserAndLogin('test1', 3); + $oUser = $this->CreateUniqueUserAndLogin('admin111', 1); // Administrator + // Keep only the SuperUser profile (remove Administrator profile) + $this->AddProfileToUser($oUser, 117); // SuperUser profile for the test - try { - $this->AddProfileToUser($oUser, 1); - $this->fail('Should not be able to upgrade to Administrator'); - } catch (CoreCannotSaveObjectException $e) { - } catch (CoreException $e) { - } + $this->expectException(CoreCannotSaveObjectException::class); + $this->expectExceptionMessage('You cannot remove your own Administrator profile. Ask another Administrator to do it for you'); + $this->RemoveProfileFromUser($oUser, 1); // Remove admin profile } /** - * @dataProvider RemovingOwnProfileProvider - * @doesNotPerformAssertions - * - * @throws \CoreException - * @throws \DictExceptionUnknownLanguage - * @throws \OQLException + * @dataProvider UserCannotLoseUserEditionRightsProvider */ - public function testDenyingOwnUserModification(int $iProfileId) + public function testUserCannotLoseUserEditionRights(int $iProfileId) { - $oUser = $this->CreateUniqueUserAndLogin('test1', $iProfileId); + $oUser = $this->CreateUniqueUserAndLogin('configmgr111', $iProfileId); // SuperUser $this->AddProfileToUser($oUser, 3); - // Keep only the profile 3 (Configuration manager) - $oSet = new \ormLinkSet(\UserLocal::class, 'profile_list', \DBObjectSet::FromScratch(\URP_UserProfile::class)); - $oSet->AddItem(MetaModel::NewObject('URP_UserProfile', ['profileid' => 3, 'reason' => 'UNIT Tests'])); - $oUser->Set('profile_list', $oSet); - - try { - $oUser->DBWrite(); - $this->fail('Should not be able to deny User modifications'); - } catch (CoreCannotSaveObjectException $e) { - } + $this->expectException(CoreCannotSaveObjectException::class); + $this->expectExceptionMessage('You cannot remove your own rights to edit users'); + $this->RemoveProfileFromUser($oUser, $iProfileId); } - public function RemovingOwnProfileProvider(): array + + + public function UserCannotLoseUserEditionRightsProvider(): array { return [ 'Administrator' => [1], @@ -477,18 +450,18 @@ public function testNonAdminCannotListAdminProfiles($bHideAdministrators, $iExpe $oSearch = new DBObjectSearch('URP_UserProfile'); $oSearch->AddCondition('userid', $oUserAdmin->GetKey()); $oSet = new DBObjectSet($oSearch); - $this->assertEquals($iExpectedCount, $oSet->Count()); + $this->assertEquals($iExpectedCount, $oSet->Count(), 'Visibility on Link between User and Administrator Profiles should be controlled by hide_administrators setting'); // Get the Profiles as well $oSearch = DBObjectSearch::FromOQL('SELECT URP_Profiles JOIN URP_UserProfile ON URP_UserProfile.profileid = URP_Profiles.id WHERE URP_UserProfile.userid='.$oUserAdmin->GetKey()); $oSet = new DBObjectSet($oSearch); - $this->assertEquals($iExpectedCount, $oSet->Count()); + $this->assertEquals($iExpectedCount, $oSet->Count(), 'Visibility on Administrator Profiles should be controlled by hide_administrators setting'); } public function NonAdminCannotListAdminProfilesProvider(): array { return [ - 'with Admins visible' => [false, 1], - 'with Admins hidden' => [true, 0], + 'with Admins visible' => ['hide_administrators' => false, 'visible_objects' => 1], + 'with Admins hidden' => ['hide_administrators' => true, 'visible_objects' => 0], ]; } @@ -545,39 +518,6 @@ public function testFindUser_UnknownLogin() ); } - public function testAdminCannotRemoveOwnAdminProfile() - { - $oUser = $this->CreateUniqueUserAndLogin('admin111', 1); // Administrator - // Keep only the SuperUser profile (remove Administrator profile) - $this->AddProfileToUser($oUser, 117); // SuperUser profile for the test - - $this->expectException(CoreCannotSaveObjectException::class); - $this->expectExceptionMessage('You cannot remove your own Administrator profile. Ask another Administrator to do it for you'); - $this->RemoveProfileFromUser($oUser, 1); // Remove admin profile - } - - /** - * @dataProvider RemovingProfileProvider - */ - public function testUserCannotLoseUserEditionRights(int $iProfileId) - { - $oUser = $this->CreateUniqueUserAndLogin('configmgr111', $iProfileId); // SuperUser - $this->AddProfileToUser($oUser, 3); - - $this->expectException(CoreCannotSaveObjectException::class); - $this->expectExceptionMessage('You cannot remove your own rights to edit users'); - $this->RemoveProfileFromUser($oUser, $iProfileId); - } - - - public function RemovingProfileProvider(): array - { - return [ - 'Administrator' => [1], - 'SuperUser' => [117], - ]; - } - public function FindUserAndAssertItHasBeenFound($sLogin, $iExpectedKey) { $oUser = $this->InvokeNonPublicStaticMethod(UserRights::class, "FindUser", [$sLogin]); From 62421606ade212ec0d1d5f2d6185beb96e232b46 Mon Sep 17 00:00:00 2001 From: v-dumas Date: Fri, 7 Nov 2025 17:11:48 +0100 Subject: [PATCH 5/8] =?UTF-8?q?N=C2=B08534=20-=20Prevent=20Admin=20from=20?= =?UTF-8?q?suicide=20(5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/userrights.class.inc.php | 25 ++++++++++ .../unitary-tests/core/UserRightsTest.php | 46 +++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/core/userrights.class.inc.php b/core/userrights.class.inc.php index c686dbbe1d..cfc8628cf6 100644 --- a/core/userrights.class.inc.php +++ b/core/userrights.class.inc.php @@ -428,6 +428,16 @@ public function DoCheckToWrite() } } } + elseif ($this->IsPrivilegedUser()) { + // Prevent Privileged User to be saved with profiles denying the access to the backoffice + $oSet->Rewind(); + while ($oUserProfile = $oSet->Fetch()) { + $sProfile = $oUserProfile->Get('profile'); + if (in_array($sProfile, $aForbiddenProfiles)) { + $this->m_aCheckIssues[] = Dict::Format('Class:User/Error:PrivilegedUserMustHaveAccessToBackOffice', $sProfile); + } + } + } } // Only administrators can manage administrators @@ -639,6 +649,21 @@ protected function IsCurrentUser(): bool } return UserRights::GetUserId() == $this->GetKey(); } + + private function IsPrivilegedUser(): bool + { + $aPrivilegedProfiles = ['Administrator' => '1', 'REST Services User' => '1024', 'SuperUser' => '117']; + + $oSet = $this->Get('profile_list'); + $oSet->Rewind(); + while ($oUserProfile = $oSet->Fetch()) { + $iProfile = $oUserProfile->Get('profileid'); + if (in_array($iProfile, $aPrivilegedProfiles)) { + return true; + } + } + return false; + } } /** diff --git a/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php b/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php index a08dd33ad0..a06072b679 100644 --- a/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php +++ b/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php @@ -35,6 +35,7 @@ use DBObjectSet; use DeleteException; use MetaModel; +use UserLocal; use UserRights; use utils; @@ -80,6 +81,21 @@ protected function CreateUniqueUserAndLogin(string $sLoginPrefix, int $iProfileI return $oUser; } + protected function GivenUserWithProfiles(string $sLogin, array $aProfileIds): DBObject + { + $oProfiles = new \ormLinkSet(\UserLocal::class, 'profile_list', \DBObjectSet::FromScratch(\URP_UserProfile::class)); + foreach ($aProfileIds as $iProfileId) { + $oProfiles->AddItem(MetaModel::NewObject('URP_UserProfile', ['profileid' => $iProfileId, 'reason' => 'UNIT Tests'])); + } + $oUser = MetaModel::NewObject('UserLocal', array( + 'login' => $sLogin, + 'password' => 'Password1!', + 'expiration' => UserLocal::EXPIRE_NEVER, + 'profile_list' => $oProfiles, + )); + return $oUser; + } + public function testIsLoggedIn() { $this->assertFalse(UserRights::IsLoggedIn()); @@ -410,6 +426,36 @@ public function UserCannotLoseUserEditionRightsProvider(): array ]; } + /** + * @dataProvider PrivilegedUsersMustHaveBackofficeAccessProvider + */ + public function testPrivilegedUsersMustHaveBackofficeAccess(int $iProfileId) + { + $oUser = $this->GivenUserWithProfiles('test1', [$iProfileId, 2]); + + $this->expectException(CoreCannotSaveObjectException::class); + //$this->expectExceptionMessage('It is not allowed to deny backoffice access to privileged Users'); + $this->expectExceptionMessage('Class:User/Error:PrivilegedUserMustHaveAccessToBackOffice'); + $oUser->DBInsert(); + + } + public function PrivilegedUsersMustHaveBackofficeAccessProvider(): array + { + return [ + 'killing another administrator' => [1], + 'killing superuser ' => [117], + 'killing Rest User' => [1024], + + ]; + } + public function testNonPrivilegedUsersCanBeDeniedFromBackoffice() + { + $oUser = $this->GivenUserWithProfiles('test1', [5, 2]); + // No exception expected + $oUser->DBInsert(); + $this->expectNotToPerformAssertions(); + } + /** *@dataProvider NonAdminCanListOwnProfilesProvider */ From 0ca3a760dfdc1de41cf4da87896b2dcc9ad363df Mon Sep 17 00:00:00 2001 From: v-dumas Date: Fri, 7 Nov 2025 18:05:18 +0100 Subject: [PATCH 6/8] =?UTF-8?q?N=C2=B08534=20-=20Prevent=20Admin=20from=20?= =?UTF-8?q?suicide=20(6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dictionaries/cs.dictionary.itop.ui.php | 3 ++- dictionaries/da.dictionary.itop.ui.php | 5 +++-- dictionaries/de.dictionary.itop.ui.php | 3 ++- dictionaries/en.dictionary.itop.ui.php | 5 +++-- dictionaries/en_gb.dictionary.itop.ui.php | 3 ++- dictionaries/es_cr.dictionary.itop.ui.php | 3 ++- dictionaries/fr.dictionary.itop.ui.php | 1 + dictionaries/hu.dictionary.itop.ui.php | 3 ++- dictionaries/it.dictionary.itop.ui.php | 3 ++- dictionaries/ja.dictionary.itop.ui.php | 5 +++-- dictionaries/nl.dictionary.itop.ui.php | 3 ++- dictionaries/pl.dictionary.itop.ui.php | 3 ++- dictionaries/pt_br.dictionary.itop.ui.php | 3 ++- dictionaries/ru.dictionary.itop.ui.php | 5 +++-- dictionaries/sk.dictionary.itop.ui.php | 5 +++-- dictionaries/tr.dictionary.itop.ui.php | 5 +++-- dictionaries/zh_cn.dictionary.itop.ui.php | 3 ++- tests/php-unit-tests/unitary-tests/core/UserRightsTest.php | 3 +-- 18 files changed, 40 insertions(+), 24 deletions(-) diff --git a/dictionaries/cs.dictionary.itop.ui.php b/dictionaries/cs.dictionary.itop.ui.php index 63386bf583..ba5d234df2 100755 --- a/dictionaries/cs.dictionary.itop.ui.php +++ b/dictionaries/cs.dictionary.itop.ui.php @@ -168,10 +168,11 @@ 'Class:User/Attribute:status/Value:disabled' => 'Neaktivní', 'Class:User/Error:LoginMustBeUnique' => 'Uživatelské jméno musí být jedinečné - "%1s" je již použito.', 'Class:User/Error:AtLeastOneProfileIsNeeded' => 'Uživateli musí být přidělen alespoň jeden profil.', + 'Class:User/Error:PrivilegedUserMustHaveAccessToBackOffice' => 'Profile "%1$s" cannot be given to privileged Users (Administrators, SuperUsers and REST Services Users)~~', 'Class:User/Error:ProfileNotAllowed' => 'Profil "%1$s" nemůže být přidán, byl by mu odepřen přístup do backoffice', 'Class:User/Error:StatusChangeIsNotAllowed' => 'Změna není povolena pro vašeho vlastního uživatele', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'Přístupné organizace musí obsahovat organizaci uživatele.', - 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you~~', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove your own Administrator profile. Ask another Administrator to do it for you~~', 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'Aktuální seznam profilů neposkytuje dostatečná přístupová práva (uživatele již nelze upravovat)', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'Profil Portal power user neposkytuje dostatečná přístupová práva (je třeba přidat jiný profil)', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'Uživatel musí být přiřazen minimálně do jedné organizace.', diff --git a/dictionaries/da.dictionary.itop.ui.php b/dictionaries/da.dictionary.itop.ui.php index 36ab94bb68..9821f83a68 100644 --- a/dictionaries/da.dictionary.itop.ui.php +++ b/dictionaries/da.dictionary.itop.ui.php @@ -168,11 +168,12 @@ 'Class:User/Attribute:status/Value:disabled' => 'Disabled~~', 'Class:User/Error:LoginMustBeUnique' => 'Login skal være entydig - "%1s" er allerede i brug.', 'Class:User/Error:AtLeastOneProfileIsNeeded' => 'Mindst en profil skal knyttes til denne bruger.', + 'Class:User/Error:PrivilegedUserMustHaveAccessToBackOffice' => 'Profile "%1$s" cannot be given to privileged Users (Administrators, SuperUsers and REST Services Users)~~', 'Class:User/Error:ProfileNotAllowed' => 'Profile "%1$s" cannot be added it will deny the access to backoffice~~', 'Class:User/Error:StatusChangeIsNotAllowed' => 'Changing status is not allowed for your own User~~', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'Allowed organizations must contain User organization~~', - 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you~~', - 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'The current list of profiles does not give sufficient access rights (Users are not modifiable anymore)~~', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove your own Administrator profile. Ask another Administrator to do it for you~~', + 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'You cannot remove your own rights to edit Users~~', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'The Portal power user profile does not give sufficient access rights (another profile must be added)~~', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'At least one organization must be assigned to this user.~~', 'Class:User/Error:OrganizationNotAllowed' => 'Organization not allowed.~~', diff --git a/dictionaries/de.dictionary.itop.ui.php b/dictionaries/de.dictionary.itop.ui.php index b9bb685f27..0418378292 100644 --- a/dictionaries/de.dictionary.itop.ui.php +++ b/dictionaries/de.dictionary.itop.ui.php @@ -167,10 +167,11 @@ 'Class:User/Attribute:status/Value:disabled' => 'Inaktiv', 'Class:User/Error:LoginMustBeUnique' => 'Login-Namen müssen unterschiedlich sein - "%1s" benutzt diesen Login-Name bereits.', 'Class:User/Error:AtLeastOneProfileIsNeeded' => 'Mindestens ein Profil muss diesem Benutzer zugewiesen sein.', + 'Class:User/Error:PrivilegedUserMustHaveAccessToBackOffice' => 'Profile "%1$s" cannot be given to privileged Users (Administrators, SuperUsers and REST Services Users)~~', 'Class:User/Error:ProfileNotAllowed' => 'Profil "%1$s" kann nicht hinzugefügt werde, es verhindert den Zugriff auf das Backoffice.', 'Class:User/Error:StatusChangeIsNotAllowed' => 'Statusänderungen sind für den eigenen Benutzer nicht erlaubt.', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'Die Organisation des Benutzers muss in den erlaubten Organisationen enthalten sein.', - 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you~~', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove your own Administrator profile. Ask another Administrator to do it for you~~', 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'Die aktuelle Liste an Profilen vergibt unzureichende Berechtigungen (Benutzer können nicht mehr geändert werden)', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'Das Profil des Portal-Power-Benutzers hat nicht ausreichend Zugriffsrechte (ein weiteres Profil muss hinzugefügt werden)', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'Mindestens eine Organisation muss diesem Benutzer zugewiesen sein.', diff --git a/dictionaries/en.dictionary.itop.ui.php b/dictionaries/en.dictionary.itop.ui.php index c46c31a44c..d143598e0f 100644 --- a/dictionaries/en.dictionary.itop.ui.php +++ b/dictionaries/en.dictionary.itop.ui.php @@ -177,15 +177,16 @@ 'Class:User/Attribute:allowed_org_list+' => 'The end user is allowed to see data belonging to the following organizations. If no organization is specified, there is no restriction.', 'Class:User/Attribute:status' => 'Status', 'Class:User/Attribute:status+' => 'Whether the user account is enabled or disabled.', - 'Class:User/Attribute:status/Value:enabled' => 'Enabled', + 'Class:User/Attribute:status/Value:enabled' => 'Enabled', 'Class:User/Attribute:status/Value:disabled' => 'Disabled', 'Class:User/Error:LoginMustBeUnique' => 'Login must be unique - "%1$s" is already being used.', 'Class:User/Error:AtLeastOneProfileIsNeeded' => 'At least one profile must be assigned to this user.', + 'Class:User/Error:PrivilegedUserMustHaveAccessToBackOffice' => 'Profile "%1$s" cannot be given to privileged Users (Administrators, SuperUsers and REST Services Users)', 'Class:User/Error:ProfileNotAllowed' => 'Profile "%1$s" cannot be added it will deny the access to backoffice', 'Class:User/Error:StatusChangeIsNotAllowed' => 'Changing status is not allowed for your own User', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'Allowed organizations must contain User organization', - 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove your own Administrator profile. Ask another Administrator to do it for you', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove your own Administrator profile. Ask another Administrator to do it for you~~', 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'You cannot remove your own rights to edit users', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'The Portal power user profile does not give sufficient access rights (another profile must be added)', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'At least one organization must be assigned to this user.', diff --git a/dictionaries/en_gb.dictionary.itop.ui.php b/dictionaries/en_gb.dictionary.itop.ui.php index 1a42f58d87..c54e33c0be 100644 --- a/dictionaries/en_gb.dictionary.itop.ui.php +++ b/dictionaries/en_gb.dictionary.itop.ui.php @@ -182,10 +182,11 @@ 'Class:User/Error:LoginMustBeUnique' => 'Login must be unique - "%1$s" is already being used.', 'Class:User/Error:AtLeastOneProfileIsNeeded' => 'At least one profile must be assigned to this user.', + 'Class:User/Error:PrivilegedUserMustHaveAccessToBackOffice' => 'Profile "%1$s" cannot be given to privileged Users (Administrators, SuperUsers and REST Services Users)~~', 'Class:User/Error:ProfileNotAllowed' => 'Profile "%1$s" cannot be added as it will deny access to the back office.', 'Class:User/Error:StatusChangeIsNotAllowed' => 'Changing status is not allowed for your own User', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'Allowed organisations must contain User organisation', - 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you~~', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove your own Administrator profile. Ask another Administrator to do it for you~~', 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'The current list of profiles does not give sufficient access rights (Users are not modifiable any more)', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'The Portal power user profile does not give sufficient access rights (another profile must be added)', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'At least one organisation must be assigned to this user.', diff --git a/dictionaries/es_cr.dictionary.itop.ui.php b/dictionaries/es_cr.dictionary.itop.ui.php index d9c9adc865..032df260f6 100644 --- a/dictionaries/es_cr.dictionary.itop.ui.php +++ b/dictionaries/es_cr.dictionary.itop.ui.php @@ -166,10 +166,11 @@ 'Class:User/Attribute:status/Value:disabled' => 'Deshabilitado', 'Class:User/Error:LoginMustBeUnique' => 'Usuario debe ser único - "%1s" ya se encuentra en uso.', 'Class:User/Error:AtLeastOneProfileIsNeeded' => 'Al menos un Perfil debe ser asignado a este usuario.', + 'Class:User/Error:PrivilegedUserMustHaveAccessToBackOffice' => 'Profile "%1$s" cannot be given to privileged Users (Administrators, SuperUsers and REST Services Users)~~', 'Class:User/Error:ProfileNotAllowed' => 'No se puede agregar el perfil "%1$s"; denegará el acceso al backoffice', 'Class:User/Error:StatusChangeIsNotAllowed' => 'Cambiar estatus no está permitido para su propio usuario', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'Las organizaciones permitidas deben contener una organización de usuario', - 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you~~', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove your own Administrator profile. Ask another Administrator to do it for you~~', 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'La lista actual de perfiles no otorga suficientes permisos de acceso (los usuarios ya no son modificables)', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'El perfil de usuario avanzado del Portal no otorga suficientes derechos de acceso (se debe agregar otro perfil)', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'Al menos una organización debe ser asignada a este usuario.', diff --git a/dictionaries/fr.dictionary.itop.ui.php b/dictionaries/fr.dictionary.itop.ui.php index cbb13790b7..c6d3782fb2 100644 --- a/dictionaries/fr.dictionary.itop.ui.php +++ b/dictionaries/fr.dictionary.itop.ui.php @@ -173,6 +173,7 @@ 'Class:User/Attribute:status/Value:disabled' => 'Désactivé', 'Class:User/Error:LoginMustBeUnique' => 'Le login doit être unique - "%1s" est déjà utilisé.', 'Class:User/Error:AtLeastOneProfileIsNeeded' => 'L\'utilisateur doit avoir au moins un profil.', + 'Class:User/Error:PrivilegedUserMustHaveAccessToBackOffice' => 'Le profil "%1$s" ne peut pas être donné aux Administrateurs, SuperUsers et REST Services Users', 'Class:User/Error:ProfileNotAllowed' => 'Le profil "%1$s" ne peux pas être ajouté à son propre utilisateur, il interdit l\'accès à la console', 'Class:User/Error:StatusChangeIsNotAllowed' => 'Impossible de changer l\'état de son propre utilisateur', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'Les organisations permises doivent contenir l\'organisation de l\'utilisateur', diff --git a/dictionaries/hu.dictionary.itop.ui.php b/dictionaries/hu.dictionary.itop.ui.php index c1bff2332a..0425e600f3 100755 --- a/dictionaries/hu.dictionary.itop.ui.php +++ b/dictionaries/hu.dictionary.itop.ui.php @@ -168,10 +168,11 @@ 'Class:User/Attribute:status/Value:disabled' => 'Letiltott', 'Class:User/Error:LoginMustBeUnique' => 'A felhasználónévnek egyedinek kell lennie - "%1s" már létezik.', 'Class:User/Error:AtLeastOneProfileIsNeeded' => 'Legalább egy profilt a felhasználóhoz kell rendelni.', + 'Class:User/Error:PrivilegedUserMustHaveAccessToBackOffice' => 'Profile "%1$s" cannot be given to privileged Users (Administrators, SuperUsers and REST Services Users)~~', 'Class:User/Error:ProfileNotAllowed' => 'A "%1$s" profil nem adható hozzá, le lesz tiltva', 'Class:User/Error:StatusChangeIsNotAllowed' => 'A saját felhasználó státuszának cseréje nem engedélyezett', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'Az engedélyezett szervezeteknek tartalmazniuk kell a felhasználói szervezetet', - 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you~~', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove your own Administrator profile. Ask another Administrator to do it for you~~', 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'A profilok jelenlegi listája nem ad elegendő hozzáférési jogot (a felhasználók már nem módosíthatók)', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'The Portal power user profile does not give sufficient access rights (another profile must be added)~~', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'A felhasználóhoz legalább egy szervezeti egységet hozzá kell rendelni', diff --git a/dictionaries/it.dictionary.itop.ui.php b/dictionaries/it.dictionary.itop.ui.php index 3d7fc9336b..075e089e85 100644 --- a/dictionaries/it.dictionary.itop.ui.php +++ b/dictionaries/it.dictionary.itop.ui.php @@ -168,10 +168,11 @@ 'Class:User/Attribute:status/Value:disabled' => 'Disabilitato', 'Class:User/Error:LoginMustBeUnique' => 'Il Login deve essere unico - "%1s" già in uso', 'Class:User/Error:AtLeastOneProfileIsNeeded' => 'È necessario almeno un profilo assegnato all\'utente.', + 'Class:User/Error:PrivilegedUserMustHaveAccessToBackOffice' => 'Profile "%1$s" cannot be given to privileged Users (Administrators, SuperUsers and REST Services Users)~~', 'Class:User/Error:ProfileNotAllowed' => 'Il profilo "%1$s" non può essere aggiunto poiché nega l\'accesso al back office.', 'Class:User/Error:StatusChangeIsNotAllowed' => 'La modifica dello stato non è consentita per il proprio utente.', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'Le organizzazioni consentite devono includere l\'organizzazione dell\'utente.', - 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you~~', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove your own Administrator profile. Ask another Administrator to do it for you~~', 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'L\'elenco attuale dei profili non conferisce diritti di accesso sufficienti (gli utenti non sono più modificabili).', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'Il profilo utente con poteri del portale non concede diritti di accesso sufficienti (deve essere aggiunto un altro profilo)', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'È necessario assegnare almeno un\'organizzazione a questo utente.', diff --git a/dictionaries/ja.dictionary.itop.ui.php b/dictionaries/ja.dictionary.itop.ui.php index 3da685193d..90ed99b526 100644 --- a/dictionaries/ja.dictionary.itop.ui.php +++ b/dictionaries/ja.dictionary.itop.ui.php @@ -168,11 +168,12 @@ 'Class:User/Attribute:status/Value:disabled' => 'Disabled~~', 'Class:User/Error:LoginMustBeUnique' => 'ログイン名は一意でないといけません。- "%1s" はすでに使われています。', 'Class:User/Error:AtLeastOneProfileIsNeeded' => '少なくとも1件のプロフィールがこのユーザに指定されなければなりません。', + 'Class:User/Error:PrivilegedUserMustHaveAccessToBackOffice' => 'Profile "%1$s" cannot be given to privileged Users (Administrators, SuperUsers and REST Services Users)~~', 'Class:User/Error:ProfileNotAllowed' => 'Profile "%1$s" cannot be added it will deny the access to backoffice~~', 'Class:User/Error:StatusChangeIsNotAllowed' => 'Changing status is not allowed for your own User~~', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'Allowed organizations must contain User organization~~', - 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you~~', - 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'The current list of profiles does not give sufficient access rights (Users are not modifiable anymore)~~', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove your own Administrator profile. Ask another Administrator to do it for you~~', + 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'You cannot remove your own rights to edit Users~~', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'The Portal power user profile does not give sufficient access rights (another profile must be added)~~', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'At least one organization must be assigned to this user.~~', 'Class:User/Error:OrganizationNotAllowed' => 'Organization not allowed.~~', diff --git a/dictionaries/nl.dictionary.itop.ui.php b/dictionaries/nl.dictionary.itop.ui.php index 45536d900d..14496f6a6b 100644 --- a/dictionaries/nl.dictionary.itop.ui.php +++ b/dictionaries/nl.dictionary.itop.ui.php @@ -168,10 +168,11 @@ 'Class:User/Attribute:status/Value:disabled' => 'Uitgeschakeld', 'Class:User/Error:LoginMustBeUnique' => 'Login moet uniek zijn - "%1s" is al in gebruik', 'Class:User/Error:AtLeastOneProfileIsNeeded' => 'Minstens één profiel moet toegewezen zijn aan deze gebruiker', + 'Class:User/Error:PrivilegedUserMustHaveAccessToBackOffice' => 'Profile "%1$s" cannot be given to privileged Users (Administrators, SuperUsers and REST Services Users)~~', 'Class:User/Error:ProfileNotAllowed' => 'Profiel "%1$s" kan niet toegevoegd worden omdat het de toegang tot de backoffice zou ontzeggen.', 'Class:User/Error:StatusChangeIsNotAllowed' => 'Je kan de status voor je eigen gebruikersaccount niet wijzigen.', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'De toegestande organisaties moeten minstens de organisatie bevatten waartoe de gebruikersaccount behoort.', - 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you~~', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove your own Administrator profile. Ask another Administrator to do it for you~~', 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'De huidige lijst van profielen heeft niet voldoende toegangsrechten (gebruikersaccount zijn niet meer wijzigbaar).', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'The Portal power user profile does not give sufficient access rights (another profile must be added)~~', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'Minstens één organisatie moet toegewezen zijn aan deze gebruiker', diff --git a/dictionaries/pl.dictionary.itop.ui.php b/dictionaries/pl.dictionary.itop.ui.php index 0c710890de..7d34909009 100644 --- a/dictionaries/pl.dictionary.itop.ui.php +++ b/dictionaries/pl.dictionary.itop.ui.php @@ -168,10 +168,11 @@ 'Class:User/Attribute:status/Value:disabled' => 'Wyłączone', 'Class:User/Error:LoginMustBeUnique' => 'Login musi być unikatowy - "%1s" jest już używany.', 'Class:User/Error:AtLeastOneProfileIsNeeded' => 'Do użytkownika musi być przypisany co najmniej jeden profil.', + 'Class:User/Error:PrivilegedUserMustHaveAccessToBackOffice' => 'Profile "%1$s" cannot be given to privileged Users (Administrators, SuperUsers and REST Services Users)~~', 'Class:User/Error:ProfileNotAllowed' => 'Nie można dodać profilu "%1$s" nie ma on dostępu do zaplecza', 'Class:User/Error:StatusChangeIsNotAllowed' => 'Zmiana statusu nie jest dozwolona dla własnego użytkownika', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'Dozwolone organizacje muszą zawierać organizację użytkownika', - 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you~~', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove your own Administrator profile. Ask another Administrator to do it for you~~', 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'Aktualna lista profili nie daje wystarczających praw dostępu (Użytkowników nie można już modyfikować)', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'Profil użytkownika zaawansowanego Portalu nie zapewnia wystarczających praw dostępu (należy dodać kolejny profil)', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'Do użytkownika musi być przypisana co najmniej jedna organizacja.', diff --git a/dictionaries/pt_br.dictionary.itop.ui.php b/dictionaries/pt_br.dictionary.itop.ui.php index 5a8eb160ce..5a7e30a965 100644 --- a/dictionaries/pt_br.dictionary.itop.ui.php +++ b/dictionaries/pt_br.dictionary.itop.ui.php @@ -168,10 +168,11 @@ 'Class:User/Attribute:status/Value:disabled' => 'Inativa', 'Class:User/Error:LoginMustBeUnique' => 'Login deve ser único - "%1s" já existe', 'Class:User/Error:AtLeastOneProfileIsNeeded' => 'Pelo menos um perfil deve ser atribuído a esse usuário', + 'Class:User/Error:PrivilegedUserMustHaveAccessToBackOffice' => 'Profile "%1$s" cannot be given to privileged Users (Administrators, SuperUsers and REST Services Users)~~', 'Class:User/Error:ProfileNotAllowed' => 'O perfil "%1$s" não pôde ser adicionado, ele negará o acesso ao backoffice', 'Class:User/Error:StatusChangeIsNotAllowed' => 'Alterar o status da conta não é permitido para o seu próprio usuário', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'As organizações permitidas devem conter apenas usuários pertencentes a organização', - 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you~~', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove your own Administrator profile. Ask another Administrator to do it for you~~', 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'A lista atual de perfis não fornece permissões de acesso suficientes (os usuários não são mais modificáveis)', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'The Portal power user profile does not give sufficient access rights (another profile must be added)~~', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'Pelo menos uma organização deve ser atribuída a esse usuário', diff --git a/dictionaries/ru.dictionary.itop.ui.php b/dictionaries/ru.dictionary.itop.ui.php index a6bb82ee87..4240845b02 100644 --- a/dictionaries/ru.dictionary.itop.ui.php +++ b/dictionaries/ru.dictionary.itop.ui.php @@ -169,11 +169,12 @@ 'Class:User/Attribute:status/Value:disabled' => 'Отключен', 'Class:User/Error:LoginMustBeUnique' => 'Логин должен быть уникальным - "%1s" уже используется.', 'Class:User/Error:AtLeastOneProfileIsNeeded' => 'Как минимум один профиль должен быть назначен данному пользователю.', + 'Class:User/Error:PrivilegedUserMustHaveAccessToBackOffice' => 'Profile "%1$s" cannot be given to privileged Users (Administrators, SuperUsers and REST Services Users)~~', 'Class:User/Error:ProfileNotAllowed' => 'Profile "%1$s" cannot be added it will deny the access to backoffice~~', 'Class:User/Error:StatusChangeIsNotAllowed' => 'Changing status is not allowed for your own User~~', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'Allowed organizations must contain User organization~~', - 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you~~', - 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'The current list of profiles does not give sufficient access rights (Users are not modifiable anymore)~~', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove your own Administrator profile. Ask another Administrator to do it for you~~', + 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'You cannot remove your own rights to edit Users~~', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'The Portal power user profile does not give sufficient access rights (another profile must be added)~~', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'Этому пользователю должна быть назначена хотя бы одна организация.', 'Class:User/Error:OrganizationNotAllowed' => 'Организация не разрешена.', diff --git a/dictionaries/sk.dictionary.itop.ui.php b/dictionaries/sk.dictionary.itop.ui.php index 5356ef76bd..50d911df6f 100644 --- a/dictionaries/sk.dictionary.itop.ui.php +++ b/dictionaries/sk.dictionary.itop.ui.php @@ -172,11 +172,12 @@ 'Class:User/Attribute:status/Value:disabled' => 'Disabled~~', 'Class:User/Error:LoginMustBeUnique' => 'Prihlasovacie meno musí byť jedinečné - "%1s" sa už používa.', 'Class:User/Error:AtLeastOneProfileIsNeeded' => 'Aspoň jeden profil musí byť priradený k profilu.', + 'Class:User/Error:PrivilegedUserMustHaveAccessToBackOffice' => 'Profile "%1$s" cannot be given to privileged Users (Administrators, SuperUsers and REST Services Users)~~', 'Class:User/Error:ProfileNotAllowed' => 'Profile "%1$s" cannot be added it will deny the access to backoffice~~', 'Class:User/Error:StatusChangeIsNotAllowed' => 'Changing status is not allowed for your own User~~', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'Allowed organizations must contain User organization~~', - 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you~~', - 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'The current list of profiles does not give sufficient access rights (Users are not modifiable anymore)~~', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove your own Administrator profile. Ask another Administrator to do it for you~~', + 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'You cannot remove your own rights to edit Users~~', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'The Portal power user profile does not give sufficient access rights (another profile must be added)~~', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'At least one organization must be assigned to this user.~~', 'Class:User/Error:OrganizationNotAllowed' => 'Organization not allowed.~~', diff --git a/dictionaries/tr.dictionary.itop.ui.php b/dictionaries/tr.dictionary.itop.ui.php index e42b6fef8f..b690896ae8 100644 --- a/dictionaries/tr.dictionary.itop.ui.php +++ b/dictionaries/tr.dictionary.itop.ui.php @@ -168,11 +168,12 @@ 'Class:User/Attribute:status/Value:disabled' => 'Disabled~~', 'Class:User/Error:LoginMustBeUnique' => 'Kullanıcı adı tekil olmalı - "%1s" mevcut bir kullanıcıya ait.', 'Class:User/Error:AtLeastOneProfileIsNeeded' => 'En az bir profil kullanıcıya atanmalı', + 'Class:User/Error:PrivilegedUserMustHaveAccessToBackOffice' => 'Profile "%1$s" cannot be given to privileged Users (Administrators, SuperUsers and REST Services Users)~~', 'Class:User/Error:ProfileNotAllowed' => 'Profile "%1$s" cannot be added it will deny the access to backoffice~~', 'Class:User/Error:StatusChangeIsNotAllowed' => 'Changing status is not allowed for your own User~~', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'Allowed organizations must contain User organization~~', - 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you~~', - 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'The current list of profiles does not give sufficient access rights (Users are not modifiable anymore)~~', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove your own Administrator profile. Ask another Administrator to do it for you~~', + 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'You cannot remove your own rights to edit Users~~', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'The Portal power user profile does not give sufficient access rights (another profile must be added)~~', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'At least one organization must be assigned to this user.~~', 'Class:User/Error:OrganizationNotAllowed' => 'Organization not allowed.~~', diff --git a/dictionaries/zh_cn.dictionary.itop.ui.php b/dictionaries/zh_cn.dictionary.itop.ui.php index 5975cfce0f..6c0e707262 100644 --- a/dictionaries/zh_cn.dictionary.itop.ui.php +++ b/dictionaries/zh_cn.dictionary.itop.ui.php @@ -170,10 +170,11 @@ 'Class:User/Attribute:status/Value:disabled' => '停用', 'Class:User/Error:LoginMustBeUnique' => '登录名必须唯一 - "%1s" 已经被使用.', 'Class:User/Error:AtLeastOneProfileIsNeeded' => '必须指定至少一个角色给此用户.', + 'Class:User/Error:PrivilegedUserMustHaveAccessToBackOffice' => 'Profile "%1$s" cannot be given to privileged Users (Administrators, SuperUsers and REST Services Users)~~', 'Class:User/Error:ProfileNotAllowed' => '无法添加角色 "%1$s" 因为这将导致禁止访问后台', 'Class:User/Error:StatusChangeIsNotAllowed' => '不允许更改您自己用户的状态', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => '允许访问组织必须包含用户组织', - 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove the Administrator profile from your own user. Ask another Administrator to do it for you~~', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove your own Administrator profile. Ask another Administrator to do it for you~~', 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => '当前指定的角色列表没有提供足够的访问权限 (用户将无法被修改)', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'The Portal power user profile does not give sufficient access rights (another profile must be added)~~', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => '必须为此用户指定一个组织.', diff --git a/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php b/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php index a06072b679..f51f493daf 100644 --- a/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php +++ b/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php @@ -434,8 +434,7 @@ public function testPrivilegedUsersMustHaveBackofficeAccess(int $iProfileId) $oUser = $this->GivenUserWithProfiles('test1', [$iProfileId, 2]); $this->expectException(CoreCannotSaveObjectException::class); - //$this->expectExceptionMessage('It is not allowed to deny backoffice access to privileged Users'); - $this->expectExceptionMessage('Class:User/Error:PrivilegedUserMustHaveAccessToBackOffice'); + $this->expectExceptionMessage('Profile "Portal user" cannot be given to privileged Users (Administrators, SuperUsers and REST Services Users)'); $oUser->DBInsert(); } From 7c83bd7635668fb7c931e8dd796bcec224ef57bb Mon Sep 17 00:00:00 2001 From: v-dumas Date: Fri, 7 Nov 2025 18:17:36 +0100 Subject: [PATCH 7/8] =?UTF-8?q?N=C2=B08534=20-=20Prevent=20Admin=20from=20?= =?UTF-8?q?suicide=20(7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dictionaries/en.dictionary.itop.ui.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dictionaries/en.dictionary.itop.ui.php b/dictionaries/en.dictionary.itop.ui.php index d143598e0f..2f6b66450f 100644 --- a/dictionaries/en.dictionary.itop.ui.php +++ b/dictionaries/en.dictionary.itop.ui.php @@ -186,8 +186,8 @@ 'Class:User/Error:ProfileNotAllowed' => 'Profile "%1$s" cannot be added it will deny the access to backoffice', 'Class:User/Error:StatusChangeIsNotAllowed' => 'Changing status is not allowed for your own User', 'Class:User/Error:AllowedOrgsMustContainUserOrg' => 'Allowed organizations must contain User organization', - 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove your own Administrator profile. Ask another Administrator to do it for you~~', - 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'You cannot remove your own rights to edit users', + 'Class:User/Error:AdminProfileCannotBeRemovedBySelf' => 'You cannot remove your own Administrator profile. Ask another Administrator to do it for you', + 'Class:User/Error:CurrentProfilesHaveInsufficientRights' => 'You cannot remove your own rights to edit Users', 'Class:User/Error:PortalPowerUserHasInsufficientRights' => 'The Portal power user profile does not give sufficient access rights (another profile must be added)', 'Class:User/Error:AtLeastOneOrganizationIsNeeded' => 'At least one organization must be assigned to this user.', 'Class:User/Error:OrganizationNotAllowed' => 'Organization not allowed.', From 68881c9e80dd05b23d5b4b7aede57e51b416e5bc Mon Sep 17 00:00:00 2001 From: v-dumas Date: Thu, 13 Nov 2025 16:44:15 +0100 Subject: [PATCH 8/8] =?UTF-8?q?N=C2=B08534=20-=20Fix=20tested=20messages?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/php-unit-tests/unitary-tests/core/UserRightsTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php b/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php index f51f493daf..696577e865 100644 --- a/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php +++ b/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php @@ -413,7 +413,7 @@ public function testUserCannotLoseUserEditionRights(int $iProfileId) $this->AddProfileToUser($oUser, 3); $this->expectException(CoreCannotSaveObjectException::class); - $this->expectExceptionMessage('You cannot remove your own rights to edit users'); + $this->expectExceptionMessage('You cannot remove your own rights to edit Users'); $this->RemoveProfileFromUser($oUser, $iProfileId); }