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/core/userrights.class.inc.php b/core/userrights.class.inc.php index d29aa7742a..cfc8628cf6 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,20 @@ 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'); + } + } + } + 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); + } } } } @@ -635,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/dictionaries/cs.dictionary.itop.ui.php b/dictionaries/cs.dictionary.itop.ui.php index 1befaac79b..ba5d234df2 100755 --- a/dictionaries/cs.dictionary.itop.ui.php +++ b/dictionaries/cs.dictionary.itop.ui.php @@ -168,9 +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 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 9c21bcb04e..9821f83a68 100644 --- a/dictionaries/da.dictionary.itop.ui.php +++ b/dictionaries/da.dictionary.itop.ui.php @@ -168,10 +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: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 314bc16738..0418378292 100644 --- a/dictionaries/de.dictionary.itop.ui.php +++ b/dictionaries/de.dictionary.itop.ui.php @@ -167,9 +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 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 f42fa2322f..2f6b66450f 100644 --- a/dictionaries/en.dictionary.itop.ui.php +++ b/dictionaries/en.dictionary.itop.ui.php @@ -177,15 +177,17 @@ '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: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/en_gb.dictionary.itop.ui.php b/dictionaries/en_gb.dictionary.itop.ui.php index 9b08ae3038..c54e33c0be 100644 --- a/dictionaries/en_gb.dictionary.itop.ui.php +++ b/dictionaries/en_gb.dictionary.itop.ui.php @@ -182,9 +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 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 943ccb1ded..032df260f6 100644 --- a/dictionaries/es_cr.dictionary.itop.ui.php +++ b/dictionaries/es_cr.dictionary.itop.ui.php @@ -166,9 +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 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 7b0f147d0f..c6d3782fb2 100644 --- a/dictionaries/fr.dictionary.itop.ui.php +++ b/dictionaries/fr.dictionary.itop.ui.php @@ -168,15 +168,17 @@ '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é.', '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', - '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/dictionaries/hu.dictionary.itop.ui.php b/dictionaries/hu.dictionary.itop.ui.php index b532b0e7ed..0425e600f3 100755 --- a/dictionaries/hu.dictionary.itop.ui.php +++ b/dictionaries/hu.dictionary.itop.ui.php @@ -168,9 +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 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 8eef4acbe6..075e089e85 100644 --- a/dictionaries/it.dictionary.itop.ui.php +++ b/dictionaries/it.dictionary.itop.ui.php @@ -168,9 +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 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 d18df50028..90ed99b526 100644 --- a/dictionaries/ja.dictionary.itop.ui.php +++ b/dictionaries/ja.dictionary.itop.ui.php @@ -168,10 +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: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 28f84cbd0b..14496f6a6b 100644 --- a/dictionaries/nl.dictionary.itop.ui.php +++ b/dictionaries/nl.dictionary.itop.ui.php @@ -168,9 +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 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 a102e0a6ed..7d34909009 100644 --- a/dictionaries/pl.dictionary.itop.ui.php +++ b/dictionaries/pl.dictionary.itop.ui.php @@ -168,9 +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 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 8fc66488bc..5a7e30a965 100644 --- a/dictionaries/pt_br.dictionary.itop.ui.php +++ b/dictionaries/pt_br.dictionary.itop.ui.php @@ -168,9 +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 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 77560b23ca..4240845b02 100644 --- a/dictionaries/ru.dictionary.itop.ui.php +++ b/dictionaries/ru.dictionary.itop.ui.php @@ -169,10 +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: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 79c9a287bd..50d911df6f 100644 --- a/dictionaries/sk.dictionary.itop.ui.php +++ b/dictionaries/sk.dictionary.itop.ui.php @@ -172,10 +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: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 f3b953065b..b690896ae8 100644 --- a/dictionaries/tr.dictionary.itop.ui.php +++ b/dictionaries/tr.dictionary.itop.ui.php @@ -168,10 +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: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 e60fb82c6d..6c0e707262 100644 --- a/dictionaries/zh_cn.dictionary.itop.ui.php +++ b/dictionaries/zh_cn.dictionary.itop.ui.php @@ -170,9 +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 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/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..696577e865 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()); @@ -279,87 +295,79 @@ 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], ]; } /** - * @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], ]; } /** - * @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], 'Configuration manager' => [3], + 'SuperUser' => [117], ]; } /** - * @dataProvider RemovingOwnContactProvider - * @doesNotPerformAssertions + * @dataProvider UserCannotRemoveOwnContactProvider * * @param int $iProfileId * @@ -367,68 +375,84 @@ 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], 'Configuration manager' => [3], + 'SuperUser' => [117], ]; } + 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 + } + /** - * @doesNotPerformAssertions - * - * @throws \CoreException - * @throws \DictExceptionUnknownLanguage - * @throws \OQLException + * @dataProvider UserCannotLoseUserEditionRightsProvider */ - public function testUpgradingToAdmin() + public function testUserCannotLoseUserEditionRights(int $iProfileId) { - $oUser = $this->CreateUniqueUserAndLogin('test1', 3); + $oUser = $this->CreateUniqueUserAndLogin('configmgr111', $iProfileId); // SuperUser + $this->AddProfileToUser($oUser, 3); - 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 rights to edit Users'); + $this->RemoveProfileFromUser($oUser, $iProfileId); + } + + + public function UserCannotLoseUserEditionRightsProvider(): array + { + return [ + 'Administrator' => [1], + 'SuperUser' => [117], + ]; } /** - * @doesNotPerformAssertions - * - * @throws \CoreException - * @throws \DictExceptionUnknownLanguage - * @throws \OQLException + * @dataProvider PrivilegedUsersMustHaveBackofficeAccessProvider */ - public function testDenyingUserModification() + public function testPrivilegedUsersMustHaveBackofficeAccess(int $iProfileId) { - $oUser = $this->CreateUniqueUserAndLogin('test1', 1); - $this->AddProfileToUser($oUser, 3); + $oUser = $this->GivenUserWithProfiles('test1', [$iProfileId, 2]); - // Keep only the profile 3 (remove profile 1) - $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); + $this->expectException(CoreCannotSaveObjectException::class); + $this->expectExceptionMessage('Profile "Portal user" cannot be given to privileged Users (Administrators, SuperUsers and REST Services Users)'); + $oUser->DBInsert(); - try { - $oUser->DBWrite(); - $this->fail('Should not be able to deny User modifications'); - } catch (CoreCannotSaveObjectException $e) { - } + } + 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(); } /** @@ -471,18 +495,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], ]; }