Explorar el Código

User Management: removed limitation on the user rights that could not be established without a given object set, and added a feedback in the user details page (grant summary, based on the results returned by the std user management API, thus is reliable)

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@169 a333f486-631f-4898-b8df-5754b55c2be0
romainq hace 15 años
padre
commit
dc1a8c19a1

+ 3 - 3
addons/userrights/userrightsmatrix.class.inc.php

@@ -348,7 +348,7 @@ class UserRightsMatrix extends UserRightsAddOnAPI
 		return $oNullFilter;
 	}
 
-	public function IsActionAllowed($iUserId, $sClass, $iActionCode, dbObjectSet $aInstances)
+	public function IsActionAllowed($iUserId, $sClass, $iActionCode, $oInstanceSet = null)
 	{
 		if (!array_key_exists($iActionCode, self::$m_aActionCodes))
 		{
@@ -376,7 +376,7 @@ class UserRightsMatrix extends UserRightsAddOnAPI
 		return $iRetCode;
 	}
 
-	public function IsActionAllowedOnAttribute($iUserId, $sClass, $sAttCode, $iActionCode, dbObjectSet $aInstances)
+	public function IsActionAllowedOnAttribute($iUserId, $sClass, $sAttCode, $iActionCode, $oInstanceSet = null)
 	{
 		if (!array_key_exists($iActionCode, self::$m_aActionCodes))
 		{
@@ -404,7 +404,7 @@ class UserRightsMatrix extends UserRightsAddOnAPI
 		return $iRetCode;
 	}
 
-	public function IsStimulusAllowed($iUserId, $sClass, $sStimulusCode, dbObjectSet $aInstances)
+	public function IsStimulusAllowed($iUserId, $sClass, $sStimulusCode, $oInstanceSet = null)
 	{
 		$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassStimulusGrant WHERE class = '$sClass' AND stimulus = '$sStimulusCode' AND userid = '$iUserId'"));
 		if ($oSet->Count() < 1)

+ 3 - 3
addons/userrights/userrightsnull.class.inc.php

@@ -59,17 +59,17 @@ class UserRightsNull extends UserRightsAddOnAPI
 		return $oNullFilter;
 	}
 
-	public function IsActionAllowed($iUserId, $sClass, $iActionCode, dbObjectSet $aInstances)
+	public function IsActionAllowed($iUserId, $sClass, $iActionCode, $oInstanceSet = null)
 	{
 		return UR_ALLOWED_YES;
 	}
 
-	public function IsStimulusAllowed($iUserId, $sClass, $sStimulusCode, dbObjectSet $aInstances)
+	public function IsStimulusAllowed($iUserId, $sClass, $sStimulusCode, $oInstanceSet = null)
 	{
 		return UR_ALLOWED_YES;
 	}
 
-	public function IsActionAllowedOnAttribute($iUserId, $sClass, $sAttCode, $iActionCode, dbObjectSet $aInstances)
+	public function IsActionAllowedOnAttribute($iUserId, $sClass, $sAttCode, $iActionCode, $oInstanceSet = null)
 	{
 		return UR_ALLOWED_YES;
 	}

+ 169 - 40
addons/userrights/userrightsprofile.class.inc.php

@@ -66,6 +66,70 @@ class URP_Users extends UserRightsBaseClass
 		MetaModel::Init_SetZListItems('advanced_search', array('login', 'userid')); // Criteria of the advanced search form
 	}
 
+	function GetGrantAsHtml($sClass, $iAction)
+	{
+		if (UserRights::IsActionAllowed($sClass, $iAction, null, $this->GetKey())) 
+		{
+			return '<span style="background-color: #ddffdd;">yes</span>';
+		}
+		else
+		{
+			return '<span style="background-color: #ffdddd;">no</span>';
+		}
+	}
+	
+	function DoShowGrantSumary($oPage)
+	{
+		$iUserId = $this->GetKey();
+		if (UserRights::IsAdministrator($iUserId))
+		{
+			// Looks dirty, but ok that's THE ONE
+			$oPage->p('Has Read/Write access to any object in the database.');
+			return;
+		}
+
+		$aDisplayData = array();
+		foreach (MetaModel::GetClasses('bizmodel') as $sClass)
+		{
+			$aStimuli = array();
+			foreach (MetaModel::EnumStimuli($sClass) as $sStimulusCode => $oStimulus)
+			{
+				if (UserRights::IsStimulusAllowed($sClass, $sStimulusCode, null, $iUserId))
+				{
+					$aStimuli[] = '<span title="'.$sStimulusCode.': '.htmlentities($oStimulus->Get('description')).'">'.htmlentities($oStimulus->Get('label')).'</span>';
+				}
+			}
+			$sStimuli = implode(', ', $aStimuli);
+			
+			$aDisplayData[] = array(
+				'class' => MetaModel::GetName($sClass),
+				'read' => $this->GetGrantAsHtml($sClass, UR_ACTION_READ),
+				'bulkread' => $this->GetGrantAsHtml($sClass, UR_ACTION_BULK_READ),
+				'write' => $this->GetGrantAsHtml($sClass, UR_ACTION_MODIFY),
+				'bulkwrite' => $this->GetGrantAsHtml($sClass, UR_ACTION_BULK_MODIFY),
+				'stimuli' => $sStimuli,
+			);
+		}
+	
+		$aDisplayConfig = array();
+		$aDisplayConfig['class'] = array('label' => 'Class', 'description' => '');
+		$aDisplayConfig['read'] = array('label' => 'Read', 'description' => '');
+		$aDisplayConfig['bulkread'] = array('label' => 'Bulk read', 'description' => 'List objects or export massively');
+		$aDisplayConfig['write'] = array('label' => 'Write', 'description' => 'Create and edit (modify)');
+		$aDisplayConfig['bulkwrite'] = array('label' => 'Bulk write', 'description' => 'Massively create/edit (CSV import)');
+		$aDisplayConfig['stimuli'] = array('label' => 'Stimuli', 'description' => 'Allowed (compound) actions');
+		$oPage->table($aDisplayConfig, $aDisplayData);
+	}
+
+	function DisplayBareRelations(web_page $oPage)
+	{
+		parent::DisplayBareRelations($oPage);
+
+		$oPage->SetCurrentTabContainer('Related Objects');
+
+		$oPage->SetCurrentTab('Grants matrix');
+		$this->DoShowGrantSumary($oPage);		
+	}
 }
 
 
@@ -881,18 +945,26 @@ exit;
 		return $oGrantRecord;
 	}
 
-	protected function GetObjectActionGrant($oUser, $sClass, $iActionCode, $oObject)
+	protected function GetObjectActionGrant($oUser, $sClass, $iActionCode, /*DBObject*/ $oObject = null)
 	{
+		if(is_null($oObject))
+		{
+			$iObjectRef = -999;
+		}
+		else
+		{
+			$iObjectRef = $oObject->GetKey();
+		}
 		// load and cache permissions for the current user on the given object
 		//
-		$aTest = @$this->m_aObjectActionGrants[$oUser->GetKey()][$sClass][$oObject->GetKey][$iActionCode];
+		$aTest = @$this->m_aObjectActionGrants[$oUser->GetKey()][$sClass][$iObjectRef][$iActionCode];
 		if (is_array($aTest)) return $aTest;
 
 		$sAction = self::$m_aActionCodes[$iActionCode];
 
 		$iInstancePermission = UR_ALLOWED_NO;
 		$aAttributes = array();
-		foreach($this->GetMatchingProfiles($oUser, $oObject) as $iProfile)
+		foreach($this->GetMatchingProfiles($oUser, $sClass, $oObject) as $iProfile)
 		{
 			$oGrantRecord = $this->GetClassActionGrant($iProfile, $sClass, $sAction);
 			if (is_null($oGrantRecord))
@@ -924,18 +996,24 @@ exit;
 			'permission' => $iInstancePermission,
 			'attributes' => $aAttributes,
 		);
-		$this->m_aObjectActionGrants[$oUser->GetKey()][$sClass][$oObject->GetKey()][$iActionCode] = $aRes;
+		$this->m_aObjectActionGrants[$oUser->GetKey()][$sClass][$iObjectRef][$iActionCode] = $aRes;
 		return $aRes;
 	}
 	
-	public function IsActionAllowed($iUserId, $sClass, $iActionCode, dbObjectSet $oInstances)
+	public function IsActionAllowed($iUserId, $sClass, $iActionCode, $oInstanceSet = null)
 	{
 		if ($this->IsAdministrator($iUserId)) return true;
 
 		$oUser = $this->m_aUsers[$iUserId];
 
-		$oInstances->Rewind();
-		while($oObject = $oInstances->Fetch())
+		if (is_null($oInstanceSet))
+		{
+			$aObjectPermissions = $this->GetObjectActionGrant($oUser, $sClass, $iActionCode);
+			return $aObjectPermissions['permission'];
+		}
+
+		$oInstanceSet->Rewind();
+		while($oObject = $oInstanceSet->Fetch())
 		{
 			$aObjectPermissions = $this->GetObjectActionGrant($oUser, $sClass, $iActionCode, $oObject);
 
@@ -953,7 +1031,7 @@ exit;
 				$iGlobalPermission = $iInstancePermission;
 			}
 		}
-		$oInstances->Rewind();
+		$oInstanceSet->Rewind();
 
 		if (isset($iGlobalPermission))
 		{
@@ -965,14 +1043,28 @@ exit;
 		}
 	}
 
-	public function IsActionAllowedOnAttribute($iUserId, $sClass, $sAttCode, $iActionCode, dbObjectSet $oInstances)
+	public function IsActionAllowedOnAttribute($iUserId, $sClass, $sAttCode, $iActionCode, $oInstanceSet = null)
 	{
 		if ($this->IsAdministrator($iUserId)) return true;
 
 		$oUser = $this->m_aUsers[$iUserId];
 
-		$oInstances->Rewind();
-		while($oObject = $oInstances->Fetch())
+		if (is_null($oInstanceSet))
+		{
+			$aObjectPermissions = $this->GetObjectActionGrant($oUser, $sClass, $iActionCode);
+			$aAttributes = $aObjectPermissions['attributes'];
+			if (in_array($sAttCode, $aAttributes))
+			{
+				return $aObjectPermissions['permission'];
+			}
+			else
+			{
+				return UR_ALLOWED_NO;
+			}
+		}
+
+		$oInstanceSet->Rewind();
+		while($oObject = $oInstanceSet->Fetch())
 		{
 			$aObjectPermissions = $this->GetObjectActionGrant($oUser, $sClass, $iActionCode, $oObject);
 
@@ -998,7 +1090,7 @@ exit;
 				$iGlobalPermission = $iInstancePermission;
 			}
 		}
-		$oInstances->Rewind();
+		$oInstanceSet->Rewind();
 
 		if (isset($iGlobalPermission))
 		{
@@ -1034,7 +1126,7 @@ exit;
 		return $oGrantRecord;
 	}
 
-	public function IsStimulusAllowed($iUserId, $sClass, $sStimulusCode, dbObjectSet $oInstances)
+	public function IsStimulusAllowed($iUserId, $sClass, $sStimulusCode, $oInstanceSet = null)
 	{
 		if ($this->IsAdministrator($iUserId)) return true;
 
@@ -1042,21 +1134,33 @@ exit;
 
 		// Note: this code is VERY close to the code of IsActionAllowed()
 
-		$oInstances->Rewind();
-		while($oObject = $oInstances->Fetch())
+		if (is_null($oInstanceSet))
 		{
 			$iInstancePermission = UR_ALLOWED_NO;
-			foreach($this->GetMatchingProfiles($oUser, $oObject) as $iProfile)
+			foreach($this->GetMatchingProfiles($oUser, $sClass) as $iProfile)
 			{
-				// Get the permission for this profile/class/stimulus
-				$oSearch = DBObjectSearch::FromOQL("SELECT URP_StimulusGrant WHERE class = :class AND stimulus = :stimulus AND profileid = :profile AND permission = 'yes'");
-				$oSet = new DBObjectSet($oSearch, array(), array('class'=>$sClass, 'stimulus'=>$sStimulusCode, 'profile'=>$iProfile));
-				if ($oSet->Count() < 1)
+				$oGrantRecord = $this->GetClassStimulusGrant($iProfile, $sClass, $sStimulusCode);
+				if (!is_null($oGrantRecord))
 				{
-					return UR_ALLOWED_NO;
+					// no need to fetch the record, we've requested the records having permission = 'yes'
+					$iInstancePermission = UR_ALLOWED_YES;
+				}
+			}
+			return $iInstancePermission;
+		}
+
+		$oInstanceSet->Rewind();
+		while($oObject = $oInstanceSet->Fetch())
+		{
+			$iInstancePermission = UR_ALLOWED_NO;
+			foreach($this->GetMatchingProfiles($oUser, $sClass, $oObject) as $iProfile)
+			{
+				$oGrantRecord = $this->GetClassStimulusGrant($iProfile, $sClass, $sStimulusCode);
+				if (is_null($oGrantRecord))
+				{
+					// no need to fetch the record, we've requested the records having permission = 'yes'
+					$iInstancePermission = UR_ALLOWED_YES;
 				}
-				// no need to fetch the record, we've requested the records having permission = 'yes'
-				$iInstancePermission = UR_ALLOWED_YES;
 			}
 			if (isset($iGlobalPermission))
 			{
@@ -1070,7 +1174,7 @@ exit;
 				$iGlobalPermission = $iInstancePermission;
 			}
 		}
-		$oInstances->Rewind();
+		$oInstanceSet->Rewind();
 
 		if (isset($iGlobalPermission))
 		{
@@ -1095,7 +1199,7 @@ exit;
 		$aObjectProjection = $this->m_aClassProjs[$sClass][$iDimension]->ProjectObject($oObject);
 
 		$aRes = array();
-		if (array_key_exists($iUser, $this->m_aUserProfiles) > 0)
+		if (array_key_exists($iUser, $this->m_aUserProfiles))
 		{
 			foreach ($this->m_aUserProfiles[$iUser] as $iProfile => $oProfile)
 			{
@@ -1128,40 +1232,65 @@ exit;
 
 	protected $m_aMatchingProfiles = array(); // cache of the matching profiles for a given user/object
 	
-	protected function GetMatchingProfiles($oUser, $oObject)
+	protected function GetMatchingProfiles($oUser, $sClass, /*DBObject*/ $oObject = null)
 	{
 		$iUser = $oUser->GetKey();
-		$sClass = get_class($oObject);
-		$iObject = $oObject->GetKey();
+
+		if(is_null($oObject))
+		{
+			$iObjectRef = -999;
+		}
+		else
+		{
+			$iObjectRef = $oObject->GetKey();
+		}
+
 		//
 		// List profiles for which the user projection overlaps the object projection in each and every dimension
 		// Caches the result
 		//
-		$aTest = @$this->m_aMatchingProfiles[$iUser][$sClass][$iObject];
+		$aTest = @$this->m_aMatchingProfiles[$iUser][$sClass][$iObjectRef];
 		if (is_array($aTest))
 		{
 			return $aTest;
 		}
 
-		$aProfileRes = array();
-		foreach ($this->m_aDimensions as $iDimension => $oDimension)
+		if (is_null($oObject))
 		{
-			foreach ($this->GetMatchingProfilesByDim($oUser, $oObject, $oDimension) as $iProfile)
+			if (array_key_exists($iUser, $this->m_aUserProfiles))
+			{
+				$aRes = array_keys($this->m_aUserProfiles[$iUser]);
+			}
+			else
 			{
-				@$aProfileRes[$iProfile] += 1;
+				// no profile has been defined for this user
+				$aRes = array();
 			}
 		}
-
-		$aRes = array();
-		$iDimCount = count($this->m_aDimensions);
-		foreach ($aProfileRes as $iProfile => $iMatches)
+		else
 		{
-			if ($iMatches == $iDimCount)
+			$aProfileRes = array();
+			foreach ($this->m_aDimensions as $iDimension => $oDimension)
 			{
-				$aRes[] = $iProfile;
+				foreach ($this->GetMatchingProfilesByDim($oUser, $oObject, $oDimension) as $iProfile)
+				{
+					@$aProfileRes[$iProfile] += 1;
+				}
+			}
+	
+			$aRes = array();
+			$iDimCount = count($this->m_aDimensions);
+			foreach ($aProfileRes as $iProfile => $iMatches)
+			{
+				if ($iMatches == $iDimCount)
+				{
+					$aRes[] = $iProfile;
+				}
 			}
 		}
-		$this->m_aMatchingProfiles[$iUser][$sClass][$iObject] = $aRes;
+
+		// store into the cache
+		$this->m_aMatchingProfiles[$iUser][$sClass][$iObjectRef] = $aRes;
 		return $aRes; 
 	}
 }

+ 6 - 3
application/nicewebpage.class.inc.php

@@ -30,15 +30,18 @@ class nice_web_page extends web_page
 	}	
 
 	// By Rom, used by CSVImport and Advanced search
-	public function MakeClassesSelect($sName, $sDefaultValue, $iWidthPx)
+	public function MakeClassesSelect($sName, $sDefaultValue, $iWidthPx, $iActionCode = null)
 	{
 		// $aTopLevelClasses = array('bizService', 'bizContact', 'logInfra', 'bizDocument');
 		// These are classes wich root class is cmdbAbstractObject ! 
 		$this->add("<select id=\"select_$sName\" name=\"$sName\">");
 		foreach(MetaModel::GetClasses('bizmodel') as $sClassName)
 		{
-			$sSelected = ($sClassName == $sDefaultValue) ? " SELECTED" : "";
-			$this->add("<option style=\"width: ".$iWidthPx." px;\" value=\"$sClassName\"$sSelected>$sClassName - ".MetaModel::GetClassDescription($sClassName)."</option>");
+			if (is_null($iActionCode) || UserRights::IsActionAllowed($sClassName, $iActionCode))
+			{
+				$sSelected = ($sClassName == $sDefaultValue) ? " SELECTED" : "";
+				$this->add("<option style=\"width: ".$iWidthPx." px;\" value=\"$sClassName\"$sSelected>$sClassName - ".MetaModel::GetClassDescription($sClassName)."</option>");
+			}
 		}
 		$this->add("</select>");
 	}

+ 12 - 12
core/userrights.class.inc.php

@@ -52,9 +52,9 @@ abstract class UserRightsAddOnAPI
 	abstract public function GetUserId($sLogin); // returns the id of the user or false
 	abstract public function GetContactId($sLogin); // returns the id of the "business" user or false
 	abstract public function GetFilter($sLogin, $sClass); // returns a filter object
-	abstract public function IsActionAllowed($iUserId, $sClass, $iActionCode, dbObjectSet $oInstances);
-	abstract public function IsStimulusAllowed($iUserId, $sClass, $sStimulusCode, dbObjectSet $oInstances);
-	abstract public function IsActionAllowedOnAttribute($iUserId, $sClass, $sAttCode, $iActionCode, dbObjectSet $oInstances);
+	abstract public function IsActionAllowed($iUserId, $sClass, $iActionCode, /*dbObjectSet*/ $oInstanceSet = null);
+	abstract public function IsStimulusAllowed($iUserId, $sClass, $sStimulusCode, /*dbObjectSet*/ $oInstanceSet = null);
+	abstract public function IsActionAllowedOnAttribute($iUserId, $sClass, $sAttCode, $iActionCode, /*dbObjectSet*/ $oInstanceSet = null);
 	abstract public function IsAdministrator($iUserId);
 }
 
@@ -211,48 +211,48 @@ class UserRights
 		return self::$m_oAddOn->GetFilter(self::$m_iUserId, $sClass);
 	}
 
-	public static function IsActionAllowed($sClass, $iActionCode, dbObjectSet $oInstances, $iUserId = null)
+	public static function IsActionAllowed($sClass, $iActionCode, /*dbObjectSet*/ $oInstanceSet = null, $iUserId = null)
 	{
 		if (!MetaModel::HasCategory($sClass, 'bizmodel')) return true;
 		if (!self::CheckLogin()) return false;
 
 		if (is_null($iUserId))
 		{
-			return self::$m_oAddOn->IsActionAllowed(self::$m_iUserId, $sClass, $iActionCode, $oInstances);
+			return self::$m_oAddOn->IsActionAllowed(self::$m_iUserId, $sClass, $iActionCode, $oInstanceSet);
 		}
 		else
 		{
-			return self::$m_oAddOn->IsActionAllowed($iUserId, $sClass, $iActionCode, $oInstances);
+			return self::$m_oAddOn->IsActionAllowed($iUserId, $sClass, $iActionCode, $oInstanceSet);
 		}
 	}
 
-	public static function IsStimulusAllowed($sClass, $sStimulusCode, dbObjectSet $oInstances, $iUserId = null)
+	public static function IsStimulusAllowed($sClass, $sStimulusCode, /*dbObjectSet*/ $oInstanceSet = null, $iUserId = null)
 	{
 		if (!MetaModel::HasCategory($sClass, 'bizmodel')) return true;
 		if (!self::CheckLogin()) return false;
 
 		if (is_null($iUserId))
 		{
-			return self::$m_oAddOn->IsStimulusAllowed(self::$m_iUserId, $sClass, $sStimulusCode, $oInstances);
+			return self::$m_oAddOn->IsStimulusAllowed(self::$m_iUserId, $sClass, $sStimulusCode, $oInstanceSet);
 		}
 		else
 		{
-			return self::$m_oAddOn->IsStimulusAllowed($iUserId, $sClass, $sStimulusCode, $oInstances);
+			return self::$m_oAddOn->IsStimulusAllowed($iUserId, $sClass, $sStimulusCode, $oInstanceSet);
 		}
 	}
 
-	public static function IsActionAllowedOnAttribute($sClass, $sAttCode, $iActionCode, dbObjectSet $oInstances, $iUserId = null)
+	public static function IsActionAllowedOnAttribute($sClass, $sAttCode, $iActionCode, /*dbObjectSet*/ $oInstanceSet = null, $iUserId = null)
 	{
 		if (!MetaModel::HasCategory($sClass, 'bizmodel')) return true;
 		if (!self::CheckLogin()) return false;
 
 		if (is_null($iUserId))
 		{
-			return self::$m_oAddOn->IsActionAllowedOnAttribute(self::$m_iUserId, $sClass, $sAttCode, $iActionCode, $oInstances);
+			return self::$m_oAddOn->IsActionAllowedOnAttribute(self::$m_iUserId, $sClass, $sAttCode, $iActionCode, $oInstanceSet);
 		}
 		else
 		{
-			return self::$m_oAddOn->IsActionAllowedOnAttribute($iUserId, $sClass, $sAttCode, $iActionCode, $oInstances);
+			return self::$m_oAddOn->IsActionAllowedOnAttribute($iUserId, $sClass, $sAttCode, $iActionCode, $oInstanceSet);
 		}
 	}
 

+ 1 - 1
pages/advanced_search.php

@@ -31,7 +31,7 @@ function Page1_AskClass($oPage)
     $oPage->add("<form method=\"post\" action=\"\">\n");
 	//$oPage->add("<input type=\"hidden\" name=\"tnut\" value=\"blah\">");
 	$oPage->p("Please select the type of object that you want to look for:");
-    $oPage->MakeClassesSelect("class", "", 50);
+    $oPage->MakeClassesSelect("class", "", 50, UR_ACTION_READ);
     $oPage->add("<input type=\"submit\" name=\"userconfig\" value=\"Configure filters\">\n");
 	$oPage->add("</form>\n");
 }

+ 1 - 1
pages/csvimport.php

@@ -339,7 +339,7 @@ function Do_Welcome($oPage, $sClass)
 	$sCSVData = utils::ReadPostedParam('csvdata');
 
 	$oPage->add("<form method=\"post\" action=\"\">");
-	$oPage->MakeClassesSelect("class", $sClass, 50);
+	$oPage->MakeClassesSelect("class", $sClass, 50, UR_ACTION_MODIFY);
 	$oPage->add("<br/>");
 	$oPage->add("<textarea rows=\"25\" cols=\"100\" name=\"csvdata\" wrap=\"soft\">$sCSVData</textarea>");
 	$oPage->add("<br/>");