Skip to content

Commit 75c52ad

Browse files
committed
Returns object if the current user is allowed to do the $sAction on an $sObjectClass object (with $sObjectId id)
1 parent f03b008 commit 75c52ad

File tree

1 file changed

+118
-0
lines changed

1 file changed

+118
-0
lines changed

datamodels/2.x/itop-portal-base/portal/src/Helper/SecurityHelper.php

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
namespace Combodo\iTop\Portal\Helper;
2222

23+
use CoreException;
2324
use LogChannels;
2425
use UserRights;
2526
use IssueLog;
@@ -174,6 +175,123 @@ public function IsActionAllowed($sAction, $sObjectClass, $sObjectId = null)
174175
return true;
175176
}
176177

178+
179+
/**
180+
* Returns object if the current user is allowed to do the $sAction on an $sObjectClass object (with $sObjectId id)
181+
* Checks are:
182+
* - Has a scope query for the $sObjectClass /$sObjectId/ $sAction
183+
* - Is allowed by datamodel for $sObjectClass / $sAction
184+
*
185+
* @param string $sAction Must be in UR_ACTION_READ|UR_ACTION_MODIFY|UR_ACTION_CREATE
186+
* @param string $sObjectClass
187+
* @param string $sObjectId
188+
* @param bool $bMustBeFound
189+
*
190+
* @throws \CoreExceptionif no result found and $bMustBeFound=true
191+
* @throws \MissingQueryArgument
192+
* @throws \MySQLException
193+
* @throws \MySQLHasGoneAwayException
194+
* @throws \OQLException
195+
*/
196+
public function GetObjectForAction($sAction, $sObjectClass, $sObjectId, $bMustBeFound)
197+
{
198+
$sDebugTracePrefix = __CLASS__.' / '.__METHOD__.' : Returned object for action '.$sAction.' on '.$sObjectClass.'::'.$sObjectId;
199+
200+
// Forcing allowed writing on the object if necessary. This is used in some particular cases.
201+
$bObjectIsCurrentUser = ($sObjectClass === 'Person' && $sObjectId == UserRights::GetContactId());
202+
if(in_array($sAction , array(UR_ACTION_MODIFY, UR_ACTION_READ)) && $bObjectIsCurrentUser){
203+
return MetaModel::GetObject($sObjectClass, $sObjectId, true,true);
204+
}
205+
206+
// Checking the scopes layer
207+
// - Transforming scope action as there is only 2 values
208+
$sScopeAction = ($sAction === UR_ACTION_READ) ? UR_ACTION_READ : UR_ACTION_MODIFY;
209+
// - Retrieving the query. If user has no scope, it can't access that kind of objects
210+
$oScopeQuery = $this->oScopeValidator->GetScopeFilterForProfiles(UserRights::ListProfiles(), $sObjectClass, $sScopeAction);
211+
if ($oScopeQuery === null)
212+
{
213+
IssueLog::Debug($sDebugTracePrefix.' as there was no scope defined for action '.$sScopeAction.' and profiles '.implode('/', UserRights::ListProfiles()), LogChannels::PORTAL);
214+
if ($bMustBeFound)
215+
{
216+
$sNotFoundErrorMessage = "No result for the single row query";
217+
IssueLog::Info($sNotFoundErrorMessage, LogChannels::CMDB_SOURCE, [
218+
'class' => $sObjectClass,
219+
'key' => $sObjectId
220+
]);
221+
throw new CoreException($sNotFoundErrorMessage);
222+
}
223+
return null;
224+
}
225+
226+
// Checking if object status is in cache (to avoid unnecessary query)
227+
if (isset(static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass][$sObjectId])) {
228+
if (static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass][$sObjectId] === false)
229+
{
230+
IssueLog::Debug($sDebugTracePrefix.' as it was denied in the scope objects cache', LogChannels::PORTAL);
231+
if ($bMustBeFound)
232+
{
233+
$sNotFoundErrorMessage = "No result for the single row query";
234+
IssueLog::Info($sNotFoundErrorMessage, LogChannels::CMDB_SOURCE, [
235+
'class' => $sObjectClass,
236+
'key' => $sObjectId
237+
]);
238+
throw new CoreException($sNotFoundErrorMessage);
239+
}
240+
return null;
241+
} else {
242+
return MetaModel::GetObject($sObjectClass, $sObjectId, true,true);
243+
}
244+
}
245+
else
246+
{
247+
248+
// Modifying query to filter on the ID
249+
// - Adding expression
250+
$sObjectKeyAtt = MetaModel::DBGetKey($sObjectClass);
251+
$oFieldExp = new FieldExpression($sObjectKeyAtt, $oScopeQuery->GetClassAlias());
252+
$oBinExp = new BinaryExpression($oFieldExp, '=', new VariableExpression('object_id'));
253+
$oScopeQuery->AddConditionExpression($oBinExp);
254+
// - Setting value
255+
$aQueryParams = $oScopeQuery->GetInternalParams();
256+
$aQueryParams['object_id'] = $sObjectId;
257+
$oScopeQuery->SetInternalParams($aQueryParams);
258+
unset($aQueryParams);
259+
IssueLog::Error('requete:'.$oScopeQuery->ToOQL(true));
260+
// - Checking if query result is null (which means that the user has no right to view this specific object)
261+
$oSet = new DBObjectSet($oScopeQuery);
262+
$oObject = $oSet->Fetch();
263+
if ($oObject === null)
264+
{
265+
// Updating cache
266+
static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass][$sObjectId] = false;
267+
IssueLog::Debug($sDebugTracePrefix.' as there was no result for the following scope query : '.$oScopeQuery->ToOQL(true), LogChannels::PORTAL);
268+
} else {
269+
// Updating cache
270+
static::$aAllowedScopeObjectsCache[$sScopeAction][$sObjectClass][$sObjectId] = true;
271+
}
272+
}
273+
274+
// Checking reading security layer. The object could be listed, check if it is actually allowed to view it
275+
if (UserRights::IsActionAllowed($sObjectClass, $sAction) == UR_ALLOWED_NO) {
276+
// For security reasons, we don't want to give the user too many information on why he cannot access the object.
277+
//throw new SecurityException('User not allowed to view this object', array('class' => $sObjectClass, 'id' => $sObjectId));
278+
IssueLog::Debug($sDebugTracePrefix.' as the user is not allowed to access this object according to the datamodel security (cf. Console settings)', LogChannels::PORTAL);
279+
$oObject = null;
280+
}
281+
282+
if ($bMustBeFound && $oObject === null )
283+
{
284+
$sNotFoundErrorMessage = "No result for the single row query";
285+
IssueLog::Info($sNotFoundErrorMessage, LogChannels::CMDB_SOURCE, [
286+
'class' => $sObjectClass,
287+
'key' => $sObjectId
288+
]);
289+
throw new CoreException($sNotFoundErrorMessage);
290+
}
291+
292+
return $oObject;
293+
}
294+
177295
/**
178296
* @param string $sStimulusCode
179297
* @param string $sObjectClass

0 commit comments

Comments
 (0)