Bladeren bron

REST/JSON services. Take the user rights into account. Something was already done for core/create and core/delete, but the symptoms were not clear. The other verbs (update, apply_stimulus, get and get_related) had no protection at all.

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@3704 a333f486-631f-4898-b8df-5754b55c2be0
romainq 9 jaren geleden
bovenliggende
commit
a78e3fdf22
1 gewijzigde bestanden met toevoegingen van 137 en 50 verwijderingen
  1. 137 50
      core/restservices.class.inc.php

+ 137 - 50
core/restservices.class.inc.php

@@ -314,11 +314,23 @@ class CoreServices implements iRestServiceProvider
 			$aFields = RestUtils::GetMandatoryParam($aParams, 'fields');
 			$aShowFields = RestUtils::GetFieldList($sClass, $aParams, 'output_fields');
 			$bExtendedOutput = (RestUtils::GetOptionalParam($aParams, 'output_fields', '*') == '*+');
-	
-			$oObject = RestUtils::MakeObjectFromFields($sClass, $aFields);
-			$oObject->DBInsert();
-	
-			$oResult->AddObject(0, 'created', $oObject, $aShowFields, $bExtendedOutput);
+
+			if (UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY) != UR_ALLOWED_YES)
+			{
+				$oResult->code = RestResult::UNAUTHORIZED;
+				$oResult->message = "The current user does not have enough permissions for creating data of class $sClass";
+			}
+			elseif (UserRights::IsActionAllowed($sClass, UR_ACTION_BULK_MODIFY) != UR_ALLOWED_YES)
+			{
+				$oResult->code = RestResult::UNAUTHORIZED;
+				$oResult->message = "The current user does not have enough permissions for massively creating data of class $sClass";
+			}
+			else
+			{
+				$oObject = RestUtils::MakeObjectFromFields($sClass, $aFields);
+				$oObject->DBInsert();
+				$oResult->AddObject(0, 'created', $oObject, $aShowFields, $bExtendedOutput);
+			}
 			break;
 	
 		case 'core/update':
@@ -329,11 +341,25 @@ class CoreServices implements iRestServiceProvider
 			$aShowFields = RestUtils::GetFieldList($sClass, $aParams, 'output_fields');
 			$bExtendedOutput = (RestUtils::GetOptionalParam($aParams, 'output_fields', '*') == '*+');
 	
-			$oObject = RestUtils::FindObjectFromKey($sClass, $key);
-			RestUtils::UpdateObjectFromFields($oObject, $aFields);
-			$oObject->DBUpdate();
-	
-			$oResult->AddObject(0, 'updated', $oObject, $aShowFields, $bExtendedOutput);
+			// Note: the target class cannot be based on the result of FindObjectFromKey, because in case the user does not have read access, that function already fails with msg 'Nothing found'
+			$sTargetClass = RestUtils::GetObjectSetFromKey($sClass, $key)->GetFilter()->GetClass();
+			if (UserRights::IsActionAllowed($sTargetClass, UR_ACTION_MODIFY) != UR_ALLOWED_YES)
+			{
+				$oResult->code = RestResult::UNAUTHORIZED;
+				$oResult->message = "The current user does not have enough permissions for modifying data of class $sTargetClass";
+			}
+			elseif (UserRights::IsActionAllowed($sTargetClass, UR_ACTION_MODIFY) != UR_ALLOWED_YES)
+			{
+				$oResult->code = RestResult::UNAUTHORIZED;
+				$oResult->message = "The current user does not have enough permissions for massively modifying data of class $sTargetClass";
+			}
+			else
+			{
+				$oObject = RestUtils::FindObjectFromKey($sClass, $key);
+				RestUtils::UpdateObjectFromFields($oObject, $aFields);
+				$oObject->DBUpdate();
+				$oResult->AddObject(0, 'updated', $oObject, $aShowFields, $bExtendedOutput);
+			}
 			break;
 	
 		case 'core/apply_stimulus':
@@ -345,48 +371,63 @@ class CoreServices implements iRestServiceProvider
 			$bExtendedOutput = (RestUtils::GetOptionalParam($aParams, 'output_fields', '*') == '*+');
 			$sStimulus = RestUtils::GetMandatoryParam($aParams, 'stimulus');
 	
-			$oObject = RestUtils::FindObjectFromKey($sClass, $key);
-			RestUtils::UpdateObjectFromFields($oObject, $aFields);
-		
-			$aTransitions = $oObject->EnumTransitions();
-			$aStimuli = MetaModel::EnumStimuli(get_class($oObject));
-			if (!isset($aTransitions[$sStimulus]))
+			// Note: the target class cannot be based on the result of FindObjectFromKey, because in case the user does not have read access, that function already fails with msg 'Nothing found'
+			$sTargetClass = RestUtils::GetObjectSetFromKey($sClass, $key)->GetFilter()->GetClass();
+			if (UserRights::IsActionAllowed($sTargetClass, UR_ACTION_MODIFY) != UR_ALLOWED_YES)
 			{
-				// Invalid stimulus
-				$oResult->code = RestResult::INTERNAL_ERROR;
-				$oResult->message = "Invalid stimulus: '$sStimulus' on the object ".$oObject->GetName()." in state '".$oObject->GetState()."'";
+				$oResult->code = RestResult::UNAUTHORIZED;
+				$oResult->message = "The current user does not have enough permissions for modifying data of class $sTargetClass";
+			}
+			elseif (UserRights::IsActionAllowed($sTargetClass, UR_ACTION_BULK_MODIFY) != UR_ALLOWED_YES)
+			{
+				$oResult->code = RestResult::UNAUTHORIZED;
+				$oResult->message = "The current user does not have enough permissions for massively modifying data of class $sTargetClass";
 			}
 			else
 			{
-				$aTransition = $aTransitions[$sStimulus];
-				$sTargetState = $aTransition['target_state'];
-				$aStates = MetaModel::EnumStates($sClass);
-				$aTargetStateDef = $aStates[$sTargetState];
-				$aExpectedAttributes = $aTargetStateDef['attribute_list'];
-				
-				$aMissingMandatory = array();
-				foreach($aExpectedAttributes as $sAttCode => $iExpectCode)
+				$oObject = RestUtils::FindObjectFromKey($sClass, $key);
+				RestUtils::UpdateObjectFromFields($oObject, $aFields);
+			
+				$aTransitions = $oObject->EnumTransitions();
+				$aStimuli = MetaModel::EnumStimuli(get_class($oObject));
+				if (!isset($aTransitions[$sStimulus]))
 				{
-					if ( ($iExpectCode & OPT_ATT_MANDATORY) && ($oObject->Get($sAttCode) == ''))
+					// Invalid stimulus
+					$oResult->code = RestResult::INTERNAL_ERROR;
+					$oResult->message = "Invalid stimulus: '$sStimulus' on the object ".$oObject->GetName()." in state '".$oObject->GetState()."'";
+				}
+				else
+				{
+					$aTransition = $aTransitions[$sStimulus];
+					$sTargetState = $aTransition['target_state'];
+					$aStates = MetaModel::EnumStates($sClass);
+					$aTargetStateDef = $aStates[$sTargetState];
+					$aExpectedAttributes = $aTargetStateDef['attribute_list'];
+					
+					$aMissingMandatory = array();
+					foreach($aExpectedAttributes as $sAttCode => $iExpectCode)
+					{
+						if ( ($iExpectCode & OPT_ATT_MANDATORY) && ($oObject->Get($sAttCode) == ''))
+						{
+							$aMissingMandatory[] = $sAttCode;
+						}
+					}				
+					if (count($aMissingMandatory) == 0)
 					{
-						$aMissingMandatory[] = $sAttCode;
+						// If all the mandatory fields are already present, just apply the transition silently...
+						if ($oObject->ApplyStimulus($sStimulus))
+						{
+							$oObject->DBUpdate();
+							$oResult->AddObject(0, 'updated', $oObject, $aShowFields, $bExtendedOutput);
+						}
 					}
-				}				
-				if (count($aMissingMandatory) == 0)
-				{
-					// If all the mandatory fields are already present, just apply the transition silently...
-					if ($oObject->ApplyStimulus($sStimulus))
+					else
 					{
-						$oObject->DBUpdate();
-						$oResult->AddObject(0, 'updated', $oObject, $aShowFields, $bExtendedOutput);
+						// Missing mandatory attributes for the transition
+						$oResult->code = RestResult::INTERNAL_ERROR;
+						$oResult->message = 'Missing mandatory attribute(s) for applying the stimulus: '.implode(', ', $aMissingMandatory).'.';
 					}
 				}
-				else
-				{
-					// Missing mandatory attributes for the transition
-					$oResult->code = RestResult::INTERNAL_ERROR;
-					$oResult->message = 'Missing mandatory attribute(s) for applying the stimulus: '.implode(', ', $aMissingMandatory).'.';
-				}
 			}	
 			break;
 	
@@ -395,13 +436,28 @@ class CoreServices implements iRestServiceProvider
 			$key = RestUtils::GetMandatoryParam($aParams, 'key');
 			$aShowFields = RestUtils::GetFieldList($sClass, $aParams, 'output_fields');
 			$bExtendedOutput = (RestUtils::GetOptionalParam($aParams, 'output_fields', '*') == '*+');
-	
+
 			$oObjectSet = RestUtils::GetObjectSetFromKey($sClass, $key);
-			while ($oObject = $oObjectSet->Fetch())
+			$sTargetClass = $oObjectSet->GetFilter()->GetClass();
+	
+			if (UserRights::IsActionAllowed($sTargetClass, UR_ACTION_READ) != UR_ALLOWED_YES)
 			{
-				$oResult->AddObject(0, '', $oObject, $aShowFields, $bExtendedOutput);
+				$oResult->code = RestResult::UNAUTHORIZED;
+				$oResult->message = "The current user does not have enough permissions for reading data of class $sTargetClass";
+			}
+			elseif (UserRights::IsActionAllowed($sTargetClass, UR_ACTION_BULK_READ) != UR_ALLOWED_YES)
+			{
+				$oResult->code = RestResult::UNAUTHORIZED;
+				$oResult->message = "The current user does not have enough permissions for exporting data of class $sTargetClass";
+			}
+			else
+			{
+				while ($oObject = $oObjectSet->Fetch())
+				{
+					$oResult->AddObject(0, '', $oObject, $aShowFields, $bExtendedOutput);
+				}
+				$oResult->message = "Found: ".$oObjectSet->Count();
 			}
-			$oResult->message = "Found: ".$oObjectSet->Count();
 			break;
 
 		case 'core/delete':
@@ -410,8 +466,23 @@ class CoreServices implements iRestServiceProvider
 			$bSimulate = RestUtils::GetOptionalParam($aParams, 'simulate', false);
 	
 			$oObjectSet = RestUtils::GetObjectSetFromKey($sClass, $key);
-			$aObjects = $oObjectSet->ToArray();
-			$this->DeleteObjects($oResult, $aObjects, $bSimulate);
+			$sTargetClass = $oObjectSet->GetFilter()->GetClass();
+	
+			if (UserRights::IsActionAllowed($sTargetClass, UR_ACTION_DELETE) != UR_ALLOWED_YES)
+			{
+				$oResult->code = RestResult::UNAUTHORIZED;
+				$oResult->message = "The current user does not have enough permissions for deleting data of class $sTargetClass";
+			}
+			elseif (UserRights::IsActionAllowed($sTargetClass, UR_ACTION_DELETE) != UR_ALLOWED_YES)
+			{
+				$oResult->code = RestResult::UNAUTHORIZED;
+				$oResult->message = "The current user does not have enough permissions for massively deleting data of class $sTargetClass";
+			}
+			else
+			{
+				$aObjects = $oObjectSet->ToArray();
+				$this->DeleteObjects($oResult, $aObjects, $bSimulate);
+			}
 			break;
 
 		case 'core/get_related':
@@ -423,7 +494,7 @@ class CoreServices implements iRestServiceProvider
 			$sDirection = RestUtils::GetOptionalParam($aParams, 'direction', null);
 			$bEnableRedundancy = RestUtils::GetOptionalParam($aParams, 'redundancy', false);
 			$bReverse = false;
-			
+
 			if (is_null($sDirection) && ($sRelation == 'depends on'))
 			{
 				// Legacy behavior, consider "depends on" as a forward relation
@@ -525,14 +596,30 @@ class CoreServices implements iRestServiceProvider
 					}
 				}
 			}
+
 			if (count($aIndexByClass) > 0)
 			{
 				$aStats = array();
+				$aUnauthorizedClasses = array();
 				foreach ($aIndexByClass as $sClass => $aIds)
 				{
+					if (UserRights::IsActionAllowed($sClass, UR_ACTION_BULK_READ) != UR_ALLOWED_YES)
+					{
+						$aUnauthorizedClasses[$sClass] = true;
+					}
 					$aStats[] = $sClass.'= '.count($aIds);
 				}
-				$oResult->message = "Scope: ".$oObjectSet->Count()."; Related objects: ".implode(', ', $aStats);
+				if (count($aUnauthorizedClasses) > 0)
+				{
+					$sClasses = implode(', ', array_keys($aUnauthorizedClasses));
+					$oResult = new RestResult();
+					$oResult->code = RestResult::UNAUTHORIZED;
+					$oResult->message = "The current user does not have enough permissions for exporting data of class(es): $sClasses";
+				}
+				else
+				{
+					$oResult->message = "Scope: ".$oObjectSet->Count()."; Related objects: ".implode(', ', $aStats);
+				}
 			}
 			else
 			{