mirror of
https://github.com/Combodo/iTop.git
synced 2026-06-27 02:06:36 +02:00
Compare commits
3 Commits
feature/96
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7fca6424ab | ||
|
|
f09a73c45a | ||
|
|
5a174dd8fa |
@@ -582,16 +582,26 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
|||||||
*/
|
*/
|
||||||
public function ListProfiles($oUser)
|
public function ListProfiles($oUser)
|
||||||
{
|
{
|
||||||
$aRet = [];
|
if (count($oUser->ListChanges()) === 0) { // backward compatibility
|
||||||
$oSearch = new DBObjectSearch('URP_UserProfile');
|
$aRet = [];
|
||||||
$oSearch->AllowAllData();
|
$oSearch = new DBObjectSearch('URP_UserProfile');
|
||||||
$oSearch->NoContextParameters();
|
$oSearch->AllowAllData();
|
||||||
$oSearch->Addcondition('userid', $oUser->GetKey(), '=');
|
$oSearch->NoContextParameters();
|
||||||
$oProfiles = new DBObjectSet($oSearch);
|
$oSearch->Addcondition('userid', $oUser->GetKey(), '=');
|
||||||
while ($oUserProfile = $oProfiles->Fetch()) {
|
$oProfiles = new DBObjectSet($oSearch);
|
||||||
$aRet[$oUserProfile->Get('profileid')] = $oUserProfile->Get('profileid_friendlyname');
|
while ($oUserProfile = $oProfiles->Fetch()) {
|
||||||
|
$aRet[$oUserProfile->Get('profileid')] = $oUserProfile->Get('profileid_friendlyname');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $aRet;
|
||||||
|
} else {
|
||||||
|
$aRet = [];
|
||||||
|
$oProfilesSet = $oUser->Get('profile_list');
|
||||||
|
foreach ($oProfilesSet as $oUserProfile) {
|
||||||
|
$aRet[$oUserProfile->Get('profileid')] = $oUserProfile->Get('profileid_friendlyname');
|
||||||
|
}
|
||||||
|
return $aRet;
|
||||||
}
|
}
|
||||||
return $aRet;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function GetSelectFilter($oUser, $sClass, $aSettings = [])
|
public function GetSelectFilter($oUser, $sClass, $aSettings = [])
|
||||||
@@ -705,26 +715,23 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
|||||||
protected function GetUserActionGrant($oUser, $sClass, $iActionCode)
|
protected function GetUserActionGrant($oUser, $sClass, $iActionCode)
|
||||||
{
|
{
|
||||||
$this->LoadCache();
|
$this->LoadCache();
|
||||||
|
if (count($oUser->ListChanges()) === 0) {
|
||||||
// load and cache permissions for the current user on the given class
|
// load and cache permissions for the current user on the given class
|
||||||
//
|
if (isset($this->m_aObjectActionGrants[$oUser->GetKey()][$sClass][$iActionCode])) {
|
||||||
$iUser = $oUser->GetKey();
|
$aTest = $this->m_aObjectActionGrants[$oUser->GetKey()][$sClass][$iActionCode];
|
||||||
if (isset($this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode])) {
|
if (is_array($aTest)) {
|
||||||
$aTest = $this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode];
|
return $aTest;
|
||||||
if (is_array($aTest)) {
|
}
|
||||||
return $aTest;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$sAction = self::$m_aActionCodes[$iActionCode];
|
$sAction = self::$m_aActionCodes[$iActionCode];
|
||||||
|
|
||||||
$bStatus = null;
|
$bStatus = null;
|
||||||
// Cache user's profiles
|
|
||||||
if (false === array_key_exists($iUser, $this->aUsersProfilesList)) {
|
$aProfileList = $this->GetProfileList($oUser);
|
||||||
$this->aUsersProfilesList[$iUser] = UserRights::ListProfiles($oUser);
|
|
||||||
}
|
|
||||||
// Call the API of UserRights because it caches the list for us
|
// Call the API of UserRights because it caches the list for us
|
||||||
foreach ($this->aUsersProfilesList[$iUser] as $iProfile => $oProfile) {
|
foreach ($aProfileList as $iProfile => $oProfile) {
|
||||||
$bGrant = $this->GetProfileActionGrant($iProfile, $sClass, $sAction);
|
$bGrant = $this->GetProfileActionGrant($iProfile, $sClass, $sAction);
|
||||||
if (!is_null($bGrant)) {
|
if (!is_null($bGrant)) {
|
||||||
if ($bGrant) {
|
if ($bGrant) {
|
||||||
@@ -742,7 +749,9 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
|||||||
$aRes = [
|
$aRes = [
|
||||||
'permission' => $iPermission,
|
'permission' => $iPermission,
|
||||||
];
|
];
|
||||||
$this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode] = $aRes;
|
if (count($oUser->ListChanges()) === 0) {
|
||||||
|
$this->m_aObjectActionGrants[$oUser->GetKey()][$sClass][$iActionCode] = $aRes;
|
||||||
|
}
|
||||||
return $aRes;
|
return $aRes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -824,18 +833,14 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
|||||||
{
|
{
|
||||||
$this->LoadCache();
|
$this->LoadCache();
|
||||||
// Note: this code is VERY close to the code of IsActionAllowed()
|
// Note: this code is VERY close to the code of IsActionAllowed()
|
||||||
$iUser = $oUser->GetKey();
|
|
||||||
|
|
||||||
// Cache user's profiles
|
$aProfileList = $this->GetProfileList($oUser);
|
||||||
if (false === array_key_exists($iUser, $this->aUsersProfilesList)) {
|
|
||||||
$this->aUsersProfilesList[$iUser] = UserRights::ListProfiles($oUser);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: The object set is ignored because it was interesting to optimize for huge data sets
|
// Note: The object set is ignored because it was interesting to optimize for huge data sets
|
||||||
// and acceptable to consider only the root class of the object set
|
// and acceptable to consider only the root class of the object set
|
||||||
$bStatus = null;
|
$bStatus = null;
|
||||||
// Call the API of UserRights because it caches the list for us
|
// Call the API of UserRights because it caches the list for us
|
||||||
foreach ($this->aUsersProfilesList[$iUser] as $iProfile => $oProfile) {
|
foreach ($aProfileList as $iProfile => $oProfile) {
|
||||||
$bGrant = $this->GetClassStimulusGrant($iProfile, $sClass, $sStimulusCode);
|
$bGrant = $this->GetClassStimulusGrant($iProfile, $sClass, $sStimulusCode);
|
||||||
if (!is_null($bGrant)) {
|
if (!is_null($bGrant)) {
|
||||||
if ($bGrant) {
|
if ($bGrant) {
|
||||||
@@ -893,6 +898,25 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
|||||||
}
|
}
|
||||||
return $bHasSharing;
|
return $bHasSharing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \User $oUser
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function GetProfileList(User $oUser): array
|
||||||
|
{
|
||||||
|
if (count($oUser->ListChanges()) === 0) { // if user is already in db and not changed
|
||||||
|
$iUser = $oUser->GetKey();
|
||||||
|
if (false === array_key_exists($iUser, $this->aUsersProfilesList)) {
|
||||||
|
$aProfiles = UserRights::ListProfiles($oUser);
|
||||||
|
$this->aUsersProfilesList[$iUser] = $aProfiles;
|
||||||
|
}
|
||||||
|
return $this->aUsersProfilesList[$iUser];
|
||||||
|
}
|
||||||
|
return UserRights::ListProfiles($oUser);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UserRights::SelectModule('UserRightsProfile');
|
UserRights::SelectModule('UserRightsProfile');
|
||||||
|
|||||||
@@ -1530,6 +1530,37 @@ class UserRights
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param User $oUser
|
||||||
|
* @param array $aExcludedProfilesId Administrator by default, but can also be other proofiles depending on needs (e.g. power portal user or REST profile)
|
||||||
|
* @return bool
|
||||||
|
* @throws ArchivedObjectException
|
||||||
|
* @throws CoreException
|
||||||
|
* @throws CoreUnexpectedValue
|
||||||
|
* @throws MySQLException
|
||||||
|
*/
|
||||||
|
public static function IsUserReadOnly(User $oUser, array $aExcludedProfilesId = [1]): bool
|
||||||
|
{
|
||||||
|
$oUserProfiles = $oUser->Get('profile_list');
|
||||||
|
$oUserRights = UserRights::GetModuleInstance();
|
||||||
|
while ($oUserProfile = $oUserProfiles->Fetch()) {
|
||||||
|
$iProfileId = $oUserProfile->Get('profileid');
|
||||||
|
if (in_array($iProfileId, $aExcludedProfilesId)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
foreach (MetaModel::GetClasses('bizmodel,grant_by_profile') as $sClass) {
|
||||||
|
foreach (['w', 'bw', 'd', 'bd'] as $sWriteActionCode) {
|
||||||
|
$bIsGranted = $oUserRights->GetProfileActionGrant($iProfileId, $sClass, $sWriteActionCode);
|
||||||
|
if ($bIsGranted === true) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $sClass
|
* @param string $sClass
|
||||||
* @param int $iActionCode see UR_ACTION_* constants
|
* @param int $iActionCode see UR_ACTION_* constants
|
||||||
|
|||||||
@@ -85,6 +85,13 @@
|
|||||||
<class id="Attachment"/>
|
<class id="Attachment"/>
|
||||||
</classes>
|
</classes>
|
||||||
</group>
|
</group>
|
||||||
|
<group id="Ticket" _delta="define">
|
||||||
|
<classes>
|
||||||
|
<class id="Ticket"/>
|
||||||
|
<class id="WorkOrder"/>
|
||||||
|
<class id="Attachment"/>
|
||||||
|
</classes>
|
||||||
|
</group>
|
||||||
<group id="Portal" _delta="define">
|
<group id="Portal" _delta="define">
|
||||||
<classes>
|
<classes>
|
||||||
<class id="lnkFunctionalCIToTicket"/>
|
<class id="lnkFunctionalCIToTicket"/>
|
||||||
@@ -205,6 +212,60 @@
|
|||||||
</group>
|
</group>
|
||||||
</groups>
|
</groups>
|
||||||
<profiles>
|
<profiles>
|
||||||
|
<profile id="5500" _delta="define">
|
||||||
|
<name>Configuration ReadOnly</name>
|
||||||
|
<description>This read-only profile allows to see CIs objects.</description>
|
||||||
|
<groups>
|
||||||
|
<group id="Configuration">
|
||||||
|
<actions>
|
||||||
|
<action id="action:read">allow</action>
|
||||||
|
<action id="action:bulk read">allow</action>
|
||||||
|
</actions>
|
||||||
|
</group>
|
||||||
|
<group id="General">
|
||||||
|
<actions>
|
||||||
|
<action id="action:read">allow</action>
|
||||||
|
<action id="action:bulk read">allow</action>
|
||||||
|
</actions>
|
||||||
|
</group>
|
||||||
|
</groups>
|
||||||
|
</profile>
|
||||||
|
<profile id="5501" _delta="define">
|
||||||
|
<name>Ticket ReadOnly</name>
|
||||||
|
<description>This read-only profile allows to see Ticket objects.</description>
|
||||||
|
<groups>
|
||||||
|
<group id="Ticket">
|
||||||
|
<actions>
|
||||||
|
<action id="action:read">allow</action>
|
||||||
|
<action id="action:bulk read">allow</action>
|
||||||
|
</actions>
|
||||||
|
</group>
|
||||||
|
<group id="General">
|
||||||
|
<actions>
|
||||||
|
<action id="action:read">allow</action>
|
||||||
|
<action id="action:bulk read">allow</action>
|
||||||
|
</actions>
|
||||||
|
</group>
|
||||||
|
</groups>
|
||||||
|
</profile>
|
||||||
|
<profile id="5502" _delta="define">
|
||||||
|
<name>Service Catalog ReadOnly</name>
|
||||||
|
<description>This read-only profile allows to see Service Catalog objects.</description>
|
||||||
|
<groups>
|
||||||
|
<group id="Service">
|
||||||
|
<actions>
|
||||||
|
<action id="action:read">allow</action>
|
||||||
|
<action id="action:bulk read">allow</action>
|
||||||
|
</actions>
|
||||||
|
</group>
|
||||||
|
<group id="General">
|
||||||
|
<actions>
|
||||||
|
<action id="action:read">allow</action>
|
||||||
|
<action id="action:bulk read">allow</action>
|
||||||
|
</actions>
|
||||||
|
</group>
|
||||||
|
</groups>
|
||||||
|
</profile>
|
||||||
<profile id="117" _delta="define">
|
<profile id="117" _delta="define">
|
||||||
<name>SuperUser</name>
|
<name>SuperUser</name>
|
||||||
<description>This profile allows all actions which are not Administrator restricted.</description>
|
<description>This profile allows all actions which are not Administrator restricted.</description>
|
||||||
|
|||||||
@@ -4,80 +4,64 @@
|
|||||||
<contactid>9</contactid>
|
<contactid>9</contactid>
|
||||||
<email>jules.vernes@it.com</email>
|
<email>jules.vernes@it.com</email>
|
||||||
<org_id_friendlyname>IT Department</org_id_friendlyname>
|
<org_id_friendlyname>IT Department</org_id_friendlyname>
|
||||||
<login>Agent</login>
|
<login>SupportAgent</login>
|
||||||
<language>EN US</language>
|
<language>EN US</language>
|
||||||
<status>disabled</status>
|
<status>disabled</status>
|
||||||
<profile_list>
|
<password><![CDATA[SupportAgent]]></password>
|
||||||
<Set>
|
|
||||||
<URP_UserProfile id="5">
|
|
||||||
<profileid>5</profileid>
|
|
||||||
<profile>Support Agent</profile>
|
|
||||||
<reason></reason>
|
|
||||||
</URP_UserProfile>
|
|
||||||
</Set>
|
|
||||||
</profile_list>
|
|
||||||
<allowed_org_list>
|
|
||||||
<Set>
|
|
||||||
</Set>
|
|
||||||
</allowed_org_list>
|
|
||||||
<password><![CDATA[R6rQ;p]JT*FA$aaP^4]]></password>
|
|
||||||
<expiration>force_expire</expiration>
|
<expiration>force_expire</expiration>
|
||||||
<password_renewed_date>2026-06-04</password_renewed_date>
|
<password_renewed_date>2026-06-04</password_renewed_date>
|
||||||
</UserLocal>
|
</UserLocal>
|
||||||
|
<URP_UserProfile id="5">
|
||||||
|
<userid>4</userid>
|
||||||
|
<userlogin>SupportAgent</userlogin>
|
||||||
|
<profileid>SELECT URP_Profiles WHERE id='5'</profileid>
|
||||||
|
<profile>Support Agent</profile>
|
||||||
|
<reason></reason>
|
||||||
|
</URP_UserProfile>
|
||||||
<UserLocal alias="UserLocal" id="5">
|
<UserLocal alias="UserLocal" id="5">
|
||||||
<contactid>26</contactid>
|
<contactid>26</contactid>
|
||||||
<contactid_friendlyname>Jean Ferrat</contactid_friendlyname>
|
<contactid_friendlyname>Jean Ferrat</contactid_friendlyname>
|
||||||
<org_id_friendlyname>IT Department</org_id_friendlyname>
|
<org_id_friendlyname>IT Department</org_id_friendlyname>
|
||||||
<login>config</login>
|
<login>ConfigManager</login>
|
||||||
<language>EN US</language>
|
<language>EN US</language>
|
||||||
<status>disabled</status>
|
<status>disabled</status>
|
||||||
<profile_list>
|
<password><![CDATA[$W[ConfigManager]]></password>
|
||||||
<Set>
|
|
||||||
<URP_UserProfile id="6">
|
|
||||||
<profileid>3</profileid>
|
|
||||||
<profile>Configuration Manager</profile>
|
|
||||||
<reason></reason>
|
|
||||||
</URP_UserProfile>
|
|
||||||
</Set>
|
|
||||||
</profile_list>
|
|
||||||
<allowed_org_list>
|
|
||||||
<Set>
|
|
||||||
</Set>
|
|
||||||
</allowed_org_list>
|
|
||||||
<password><![CDATA[$W[:"7+Gf"Y\sd8#E~]]></password>
|
|
||||||
<expiration>force_expire</expiration>
|
<expiration>force_expire</expiration>
|
||||||
<password_renewed_date>2026-06-04</password_renewed_date>
|
<password_renewed_date>2026-06-04</password_renewed_date>
|
||||||
</UserLocal>
|
</UserLocal>
|
||||||
|
<URP_UserProfile id="6">
|
||||||
|
<userid>5</userid>
|
||||||
|
<userlogin>ConfigManager</userlogin>
|
||||||
|
<profileid>SELECT URP_Profiles WHERE id='3'</profileid>
|
||||||
|
<profile>Configuration Manager</profile>
|
||||||
|
<reason></reason>
|
||||||
|
</URP_UserProfile>
|
||||||
<UserLocal alias="UserLocal" id="2">
|
<UserLocal alias="UserLocal" id="2">
|
||||||
<contactid>15</contactid>
|
<contactid>15</contactid>
|
||||||
<email>agatha.christie@demo.com</email>
|
<email>agatha.christie@demo.com</email>
|
||||||
<org_id_friendlyname>Sales Department</org_id_friendlyname>
|
<org_id_friendlyname>Sales Department</org_id_friendlyname>
|
||||||
<login>Portal</login>
|
<login>PortalUser</login>
|
||||||
<language>EN US</language>
|
<language>EN US</language>
|
||||||
<status>disabled</status>
|
<status>disabled</status>
|
||||||
<profile_list>
|
<password><![CDATA[PortalUser]]></password>
|
||||||
<Set>
|
|
||||||
<URP_UserProfile id="2">
|
|
||||||
<profileid>2</profileid>
|
|
||||||
<profile>Portal user</profile>
|
|
||||||
<reason></reason>
|
|
||||||
</URP_UserProfile>
|
|
||||||
</Set>
|
|
||||||
</profile_list>
|
|
||||||
<allowed_org_list>
|
|
||||||
<Set>
|
|
||||||
<URP_UserOrg id="2">
|
|
||||||
<allowed_org_id>6</allowed_org_id>
|
|
||||||
<allowed_org_name>Sales Department</allowed_org_name>
|
|
||||||
<reason></reason>
|
|
||||||
<allowed_org_id_obsolescence_flag>no</allowed_org_id_obsolescence_flag>
|
|
||||||
</URP_UserOrg>
|
|
||||||
</Set>
|
|
||||||
</allowed_org_list>
|
|
||||||
<password><![CDATA[-Why]KDdMJvkuB8#e]]></password>
|
|
||||||
<expiration>force_expire</expiration>
|
<expiration>force_expire</expiration>
|
||||||
<password_renewed_date>2026-04-17</password_renewed_date>
|
<password_renewed_date>2026-04-17</password_renewed_date>
|
||||||
</UserLocal>
|
</UserLocal>
|
||||||
|
<URP_UserProfile id="2">
|
||||||
|
<userid>2</userid>
|
||||||
|
<userlogin>PortalUser</userlogin>
|
||||||
|
<profileid>SELECT URP_Profiles WHERE id='2'</profileid>
|
||||||
|
<profile>Portal user</profile>
|
||||||
|
<reason></reason>
|
||||||
|
</URP_UserProfile>
|
||||||
|
<URP_UserOrg id="2">
|
||||||
|
<userid>2</userid>
|
||||||
|
<userlogin>PortalUser</userlogin>
|
||||||
|
<allowed_org_id>6</allowed_org_id>
|
||||||
|
<allowed_org_name>Sales Department</allowed_org_name>
|
||||||
|
<reason></reason>
|
||||||
|
<allowed_org_id_obsolescence_flag>no</allowed_org_id_obsolescence_flag>
|
||||||
|
</URP_UserOrg>
|
||||||
<UserLocal alias="UserLocal" id="3">
|
<UserLocal alias="UserLocal" id="3">
|
||||||
<contactid>6</contactid>
|
<contactid>6</contactid>
|
||||||
<email>claude.monet@demo.com</email>
|
<email>claude.monet@demo.com</email>
|
||||||
@@ -85,32 +69,48 @@
|
|||||||
<login>SalesManager</login>
|
<login>SalesManager</login>
|
||||||
<language>EN US</language>
|
<language>EN US</language>
|
||||||
<status>disabled</status>
|
<status>disabled</status>
|
||||||
<profile_list>
|
<password><![CDATA[SalesManager]]></password>
|
||||||
<Set>
|
|
||||||
<URP_UserProfile id="4">
|
|
||||||
<profileid>12</profileid>
|
|
||||||
<profile>Portal power user</profile>
|
|
||||||
<reason></reason>
|
|
||||||
</URP_UserProfile>
|
|
||||||
<URP_UserProfile id="3">
|
|
||||||
<profileid>2</profileid>
|
|
||||||
<profile>Portal user</profile>
|
|
||||||
<reason></reason>
|
|
||||||
</URP_UserProfile>
|
|
||||||
</Set>
|
|
||||||
</profile_list>
|
|
||||||
<allowed_org_list>
|
|
||||||
<Set>
|
|
||||||
<URP_UserOrg id="1">
|
|
||||||
<allowed_org_id>6</allowed_org_id>
|
|
||||||
<allowed_org_name>Sales Department</allowed_org_name>
|
|
||||||
<reason></reason>
|
|
||||||
<allowed_org_id_obsolescence_flag>no</allowed_org_id_obsolescence_flag>
|
|
||||||
</URP_UserOrg>
|
|
||||||
</Set>
|
|
||||||
</allowed_org_list>
|
|
||||||
<password><![CDATA[D%r7hoZ})5*hvq5`{Q]]></password>
|
|
||||||
<expiration>force_expire</expiration>
|
<expiration>force_expire</expiration>
|
||||||
<password_renewed_date>2026-06-04</password_renewed_date>
|
<password_renewed_date>2026-06-04</password_renewed_date>
|
||||||
</UserLocal>
|
</UserLocal>
|
||||||
|
<URP_UserProfile id="4">
|
||||||
|
<userid>3</userid>
|
||||||
|
<userlogin>SalesManager</userlogin>
|
||||||
|
<profileid>SELECT URP_Profiles WHERE id='12'</profileid>
|
||||||
|
<profile>Portal power user</profile>
|
||||||
|
<reason></reason>
|
||||||
|
</URP_UserProfile>
|
||||||
|
<URP_UserProfile id="3">
|
||||||
|
<userid>3</userid>
|
||||||
|
<userlogin>SalesManager</userlogin>
|
||||||
|
<profileid>SELECT URP_Profiles WHERE id='2'</profileid>
|
||||||
|
<profile>Portal user</profile>
|
||||||
|
<reason></reason>
|
||||||
|
</URP_UserProfile>
|
||||||
|
<URP_UserOrg id="1">
|
||||||
|
<userid>3</userid>
|
||||||
|
<userlogin>SalesManager</userlogin>
|
||||||
|
<allowed_org_id>6</allowed_org_id>
|
||||||
|
<allowed_org_name>Sales Department</allowed_org_name>
|
||||||
|
<reason></reason>
|
||||||
|
<allowed_org_id_obsolescence_flag>no</allowed_org_id_obsolescence_flag>
|
||||||
|
</URP_UserOrg>
|
||||||
|
<UserLocal alias="UserLocal" id="6">
|
||||||
|
<contactid>18</contactid>
|
||||||
|
<email>rene.descartes@demo.com</email>
|
||||||
|
<org_id_friendlyname>Demo</org_id_friendlyname>
|
||||||
|
<login>SuperUser</login>
|
||||||
|
<language>EN US</language>
|
||||||
|
<status>disabled</status>
|
||||||
|
<password><![CDATA[SuperUser]]></password>
|
||||||
|
<expiration>force_expire</expiration>
|
||||||
|
<password_renewed_date>2026-04-17</password_renewed_date>
|
||||||
|
</UserLocal>
|
||||||
|
<URP_UserProfile id="7">
|
||||||
|
<userid>6</userid>
|
||||||
|
<userlogin>SuperUser</userlogin>
|
||||||
|
<profileid>SELECT URP_Profiles WHERE id='117'</profileid>
|
||||||
|
<profile>Super User</profile>
|
||||||
|
<reason></reason>
|
||||||
|
</URP_UserProfile>
|
||||||
</Set>
|
</Set>
|
||||||
|
|||||||
@@ -87,8 +87,6 @@ abstract class ItopDataTestCase extends ItopTestCase
|
|||||||
*/
|
*/
|
||||||
public const DEFAULT_TEST_ENVIRONMENT = 'production';
|
public const DEFAULT_TEST_ENVIRONMENT = 'production';
|
||||||
public const USE_TRANSACTION = true;
|
public const USE_TRANSACTION = true;
|
||||||
public const CREATE_TEST_ORG = false;
|
|
||||||
|
|
||||||
protected static $aURP_Profiles = [
|
protected static $aURP_Profiles = [
|
||||||
'Administrator' => 1,
|
'Administrator' => 1,
|
||||||
'Portal user' => 2,
|
'Portal user' => 2,
|
||||||
@@ -102,9 +100,15 @@ abstract class ItopDataTestCase extends ItopTestCase
|
|||||||
'Service Manager' => 10,
|
'Service Manager' => 10,
|
||||||
'Document author' => 11,
|
'Document author' => 11,
|
||||||
'Portal power user' => 12,
|
'Portal power user' => 12,
|
||||||
|
'Business partner user' => 40,
|
||||||
'REST Services User' => 1024,
|
'REST Services User' => 1024,
|
||||||
|
'Configuration ReadOnly' => 5500,
|
||||||
|
'Ticket ReadOnly' => 5501,
|
||||||
|
'Service Catalog ReadOnly' => 5502,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public const CREATE_TEST_ORG = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called before the first test of this test class is run (in the current process).
|
* This method is called before the first test of this test class is run (in the current process).
|
||||||
*/
|
*/
|
||||||
@@ -1463,16 +1467,42 @@ abstract class ItopDataTestCase extends ItopTestCase
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description To avoid adding finalclasses parameters to GivenUserInDB
|
||||||
|
* @param string $sPassword
|
||||||
|
* @param array $aProfiles Profile names Example: ['Administrator']
|
||||||
|
* @param bool $bReturnLogin
|
||||||
|
*
|
||||||
|
* @return string|int The unique login
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
protected function GivenTokenUserInDB(array $aProfiles, bool $bReturnLogin = true): string|int
|
||||||
|
{
|
||||||
|
$sLogin = 'demo_test_'.uniqid(__CLASS__, true);
|
||||||
|
|
||||||
|
$aProfileList = array_map(function ($sProfileId) {
|
||||||
|
return 'profileid:'.self::$aURP_Profiles[$sProfileId];
|
||||||
|
}, $aProfiles);
|
||||||
|
|
||||||
|
$iUser = $this->GivenObjectInDB('UserToken', [
|
||||||
|
'login' => $sLogin,
|
||||||
|
'language' => 'EN US',
|
||||||
|
'profile_list' => $aProfileList,
|
||||||
|
]);
|
||||||
|
return $bReturnLogin ? $sLogin : $iUser;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $sPassword
|
* @param string $sPassword
|
||||||
* @param array $aProfiles Profile names Example: ['Administrator']
|
* @param array $aProfiles Profile names Example: ['Administrator']
|
||||||
* @param string|null $sLogin
|
* @param string|null $sLogin
|
||||||
* @param string|null $sUserId
|
* @param string|null $sUserId
|
||||||
|
* @param bool $bReturnLogin
|
||||||
*
|
*
|
||||||
* @return string The unique login
|
* @return string The unique login
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
protected function GivenUserInDB(string $sPassword, array $aProfiles, ?string $sLogin = null, ?string &$sUserId = null): string
|
protected function GivenUserInDB(string $sPassword, array $aProfiles, ?string $sLogin = null, ?string &$sUserId = null, bool $bReturnLogin = true): string
|
||||||
{
|
{
|
||||||
if (is_null($sLogin)) {
|
if (is_null($sLogin)) {
|
||||||
$sLogin = 'demo_test_'.uniqid(__CLASS__, true);
|
$sLogin = 'demo_test_'.uniqid(__CLASS__, true);
|
||||||
@@ -1489,7 +1519,7 @@ abstract class ItopDataTestCase extends ItopTestCase
|
|||||||
'profile_list' => $aProfileList,
|
'profile_list' => $aProfileList,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $sLogin;
|
return $bReturnLogin ? $sLogin : $sUserId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -29,11 +29,11 @@ namespace Combodo\iTop\Test\UnitTest\Core;
|
|||||||
|
|
||||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||||
use CoreCannotSaveObjectException;
|
use CoreCannotSaveObjectException;
|
||||||
use CoreException;
|
|
||||||
use DBObject;
|
use DBObject;
|
||||||
use DBObjectSearch;
|
use DBObjectSearch;
|
||||||
use DBObjectSet;
|
use DBObjectSet;
|
||||||
use DeleteException;
|
use DeleteException;
|
||||||
|
use Dict;
|
||||||
use MetaModel;
|
use MetaModel;
|
||||||
use UserLocal;
|
use UserLocal;
|
||||||
use UserRights;
|
use UserRights;
|
||||||
@@ -81,6 +81,65 @@ class UserRightsTest extends ItopDataTestCase
|
|||||||
return $oUser;
|
return $oUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testIsActionAllowedWithNonInstantiatedUserObject()
|
||||||
|
{
|
||||||
|
$oUser = $this->GivenUserWithProfiles('test1', [self::$aURP_Profiles['Configuration Manager']]); // not a readonly profile
|
||||||
|
$oAdminUser = $this->GivenUserWithProfiles('test2', [self::$aURP_Profiles['Administrator']]);
|
||||||
|
$oAdminUser->DBInsert();
|
||||||
|
$_SESSION = [];
|
||||||
|
UserRights::Login($oAdminUser->Get('login'));
|
||||||
|
|
||||||
|
self::assertTrue(UserRights::IsActionAllowed('Server', UR_ACTION_MODIFY, null, $oUser) === UR_ALLOWED_YES);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $aProfileIds
|
||||||
|
* @param array $aShouldBeAllowedToSeeClass
|
||||||
|
* @param array $aShouldBeAllowedToEditClass
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @throws \ArchivedObjectException
|
||||||
|
* @throws \CoreCannotSaveObjectException
|
||||||
|
* @throws \CoreException
|
||||||
|
* @throws \CoreUnexpectedValue
|
||||||
|
* @throws \CoreWarning
|
||||||
|
* @throws \DictExceptionUnknownLanguage
|
||||||
|
* @throws \MySQLException
|
||||||
|
* @throws \OQLException
|
||||||
|
* @dataProvider ReadOnlyProvider
|
||||||
|
*/
|
||||||
|
public function testReadOnlyUser(array $aProfileIds, array $aShouldBeAllowedToSeeClass, array $aShouldBeAllowedToEditClass): void
|
||||||
|
{
|
||||||
|
|
||||||
|
$oUser = $this->GivenUserWithProfiles('test1', $aProfileIds);
|
||||||
|
$oUser->DBInsert();
|
||||||
|
$_SESSION = [];
|
||||||
|
UserRights::Login($oUser->Get('login'));
|
||||||
|
|
||||||
|
$aClassesToTest = ['FunctionalCI', 'Ticket', 'ServiceFamily'];
|
||||||
|
|
||||||
|
foreach ($aClassesToTest as $sClass) {
|
||||||
|
$bShouldBeAllowedToSee = in_array($sClass, $aShouldBeAllowedToSeeClass);
|
||||||
|
$bIsAllowedReading = (bool)UserRights::IsActionAllowed($sClass, UR_ACTION_READ);
|
||||||
|
|
||||||
|
$this->assertSame(
|
||||||
|
$bShouldBeAllowedToSee,
|
||||||
|
$bIsAllowedReading,
|
||||||
|
"User with profiles ".implode(',', $aProfileIds)." should ".($bShouldBeAllowedToSee ? "" : "NOT ")."be allowed to see class $sClass"
|
||||||
|
);
|
||||||
|
|
||||||
|
$bShouldBeAllowedToEdit = in_array($sClass, $aShouldBeAllowedToEditClass);
|
||||||
|
|
||||||
|
$bIsAllowedEditing = (bool)UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY);
|
||||||
|
|
||||||
|
$this->assertSame(
|
||||||
|
$bIsAllowedEditing,
|
||||||
|
$bShouldBeAllowedToEdit,
|
||||||
|
"User with profiles ".implode(',', $aProfileIds)." should ".($bShouldBeAllowedToEdit ? "" : "NOT ")."be allowed to edit class $sClass"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected function GivenUserWithProfiles(string $sLogin, array $aProfileIds): DBObject
|
protected function GivenUserWithProfiles(string $sLogin, array $aProfileIds): DBObject
|
||||||
{
|
{
|
||||||
$oProfiles = new \ormLinkSet(\UserLocal::class, 'profile_list', \DBObjectSet::FromScratch(\URP_UserProfile::class));
|
$oProfiles = new \ormLinkSet(\UserLocal::class, 'profile_list', \DBObjectSet::FromScratch(\URP_UserProfile::class));
|
||||||
@@ -433,7 +492,7 @@ class UserRightsTest extends ItopDataTestCase
|
|||||||
$oUser = $this->GivenUserWithProfiles('test1', [$iProfileId, 2]);
|
$oUser = $this->GivenUserWithProfiles('test1', [$iProfileId, 2]);
|
||||||
|
|
||||||
$this->expectException(CoreCannotSaveObjectException::class);
|
$this->expectException(CoreCannotSaveObjectException::class);
|
||||||
$this->expectExceptionMessage('Profile "Portal user" cannot be given to privileged Users (Administrators, SuperUsers and REST Services Users)');
|
$this->expectExceptionMessage(Dict::Format('Class:User/Error:PrivilegedUserMustHaveAccessToBackOffice', PORTAL_PROFILE_NAME));
|
||||||
$oUser->DBInsert();
|
$oUser->DBInsert();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -572,4 +631,82 @@ class UserRightsTest extends ItopDataTestCase
|
|||||||
$oUser = $this->InvokeNonPublicStaticMethod(UserRights::class, "FindUser", [$sLogin]);
|
$oUser = $this->InvokeNonPublicStaticMethod(UserRights::class, "FindUser", [$sLogin]);
|
||||||
static::assertNull($oUser, 'FindUser should return null when the login is unknown');
|
static::assertNull($oUser, 'FindUser should return null when the login is unknown');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function ReadOnlyProvider(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'CI' => [
|
||||||
|
'ProfilesId' => [
|
||||||
|
5500,
|
||||||
|
],
|
||||||
|
'ShouldBeAllowedToSeeClasses' => [
|
||||||
|
'FunctionalCI',
|
||||||
|
],
|
||||||
|
'ShouldBeAllowedToEditClasses' => [],
|
||||||
|
],
|
||||||
|
'Tickets' => [
|
||||||
|
'ProfilesId' => [
|
||||||
|
5501,
|
||||||
|
],
|
||||||
|
'ShouldBeAllowedToSeeClasses' => [
|
||||||
|
'Ticket',
|
||||||
|
],
|
||||||
|
'ShouldBeAllowedToEditClasses' => [],
|
||||||
|
],
|
||||||
|
'Catalog' => [
|
||||||
|
'ProfilesId' => [
|
||||||
|
5502,
|
||||||
|
],
|
||||||
|
'ShouldBeAllowedToSeeClasses' => [
|
||||||
|
'ServiceFamily',
|
||||||
|
],
|
||||||
|
'ShouldBeAllowedToEditClasses' => [],
|
||||||
|
],
|
||||||
|
'CI and Tickets' => [
|
||||||
|
'ProfilesId' => [
|
||||||
|
5500, 5501,
|
||||||
|
],
|
||||||
|
'ShouldBeAllowedToSeeClasses' => [
|
||||||
|
'FunctionalCI', 'Ticket',
|
||||||
|
],
|
||||||
|
'ShouldBeAllowedToEditClasses' => [],
|
||||||
|
],
|
||||||
|
'CI and Catalog' => [
|
||||||
|
'ProfilesId' => [
|
||||||
|
5500, 5502,
|
||||||
|
],
|
||||||
|
'ShouldBeAllowedToSeeClasses' => [
|
||||||
|
'FunctionalCI', 'ServiceFamily',
|
||||||
|
],
|
||||||
|
'ShouldBeAllowedToEditClasses' => [],
|
||||||
|
],
|
||||||
|
'Tickets and Catalog' => [
|
||||||
|
'ProfilesId' => [
|
||||||
|
5501, 5502,
|
||||||
|
],
|
||||||
|
'ShouldBeAllowedToSeeClasses' => [
|
||||||
|
'Ticket', 'ServiceFamily',
|
||||||
|
],
|
||||||
|
'ShouldBeAllowedToEditClasses' => [],
|
||||||
|
],
|
||||||
|
'Tickets and Catalog + profile Ccnfiguration Manager' => [
|
||||||
|
'ProfilesId' => [
|
||||||
|
5501, 5502, 3,
|
||||||
|
],
|
||||||
|
'ShouldBeAllowedToSeeClasses' => [
|
||||||
|
'FunctionalCI', 'Ticket', 'ServiceFamily',
|
||||||
|
],
|
||||||
|
'ShouldBeAllowedToEditClasses' => ['FunctionalCI'],
|
||||||
|
],
|
||||||
|
'CI, Tickets and Catalog' => [
|
||||||
|
'ProfilesId' => [
|
||||||
|
5500, 5501, 5502,
|
||||||
|
],
|
||||||
|
'ShouldBeAllowedToSeeClasses' => [
|
||||||
|
'FunctionalCI', 'Ticket', 'ServiceFamily',
|
||||||
|
],
|
||||||
|
'ShouldBeAllowedToEditClasses' => [],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user