|
20 | 20 |
|
21 | 21 | namespace Combodo\iTop\Portal\Helper; |
22 | 22 |
|
| 23 | +use CoreException; |
23 | 24 | use LogChannels; |
24 | 25 | use UserRights; |
25 | 26 | use IssueLog; |
@@ -174,6 +175,123 @@ public function IsActionAllowed($sAction, $sObjectClass, $sObjectId = null) |
174 | 175 | return true; |
175 | 176 | } |
176 | 177 |
|
| 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 | + |
177 | 295 | /** |
178 | 296 | * @param string $sStimulusCode |
179 | 297 | * @param string $sObjectClass |
|
0 commit comments