userrightsprofile.class.inc.php 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867
  1. <?php
  2. // Copyright (C) 2010 Combodo SARL
  3. //
  4. // This program is free software; you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation; version 3 of the License.
  7. //
  8. // This program is distributed in the hope that it will be useful,
  9. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. // GNU General Public License for more details.
  12. //
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program; if not, write to the Free Software
  15. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  16. /**
  17. * UserRightsProfile
  18. * User management Module, basing the right on profiles and a matrix (similar to UserRightsMatrix, but profiles and other decorations have been added)
  19. *
  20. * @author Erwan Taloc <erwan.taloc@combodo.com>
  21. * @author Romain Quetiez <romain.quetiez@combodo.com>
  22. * @author Denis Flaven <denis.flaven@combodo.com>
  23. * @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
  24. */
  25. define('ADMIN_PROFILE_NAME', 'Administrator');
  26. define('PORTAL_PROFILE_NAME', 'Portal user');
  27. class UserRightsBaseClassGUI extends cmdbAbstractObject
  28. {
  29. // Whenever something changes, reload the privileges
  30. protected function AfterInsert()
  31. {
  32. UserRights::FlushPrivileges();
  33. }
  34. protected function AfterUpdate()
  35. {
  36. UserRights::FlushPrivileges();
  37. }
  38. protected function AfterDelete()
  39. {
  40. UserRights::FlushPrivileges();
  41. }
  42. }
  43. class UserRightsBaseClass extends DBObject
  44. {
  45. // Whenever something changes, reload the privileges
  46. protected function AfterInsert()
  47. {
  48. UserRights::FlushPrivileges();
  49. }
  50. protected function AfterUpdate()
  51. {
  52. UserRights::FlushPrivileges();
  53. }
  54. protected function AfterDelete()
  55. {
  56. UserRights::FlushPrivileges();
  57. }
  58. }
  59. class URP_Profiles extends UserRightsBaseClassGUI
  60. {
  61. public static function Init()
  62. {
  63. $aParams = array
  64. (
  65. "category" => "addon/userrights",
  66. "key_type" => "autoincrement",
  67. "name_attcode" => "name",
  68. "state_attcode" => "",
  69. "reconc_keys" => array(),
  70. "db_table" => "priv_urp_profiles",
  71. "db_key_field" => "id",
  72. "db_finalclass_field" => "",
  73. "display_template" => "",
  74. );
  75. MetaModel::Init_Params($aParams);
  76. //MetaModel::Init_InheritAttributes();
  77. MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
  78. MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
  79. MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("user_list", array("linked_class"=>"URP_UserProfile", "ext_key_to_me"=>"profileid", "ext_key_to_remote"=>"userid", "allowed_values"=>null, "count_min"=>1, "count_max"=>0, "depends_on"=>array())));
  80. // Display lists
  81. MetaModel::Init_SetZListItems('details', array('name', 'description', 'user_list')); // Attributes to be displayed for the complete details
  82. MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list
  83. // Search criteria
  84. MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
  85. MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
  86. }
  87. protected $m_bCheckReservedNames = true;
  88. protected function DisableCheckOnReservedNames()
  89. {
  90. $this->m_bCheckReservedNames = false;
  91. }
  92. /*
  93. * Create the built-in Administrator profile with its reserved name
  94. */
  95. public static function DoCreateAdminProfile()
  96. {
  97. $oNewObj = MetaModel::NewObject("URP_Profiles");
  98. $oNewObj->Set('name', ADMIN_PROFILE_NAME);
  99. $oNewObj->Set('description', 'Has the rights on everything (bypassing any control)');
  100. $oNewObj->DisableCheckOnReservedNames();
  101. $iNewId = $oNewObj->DBInsertNoReload();
  102. }
  103. /*
  104. * Create the built-in User Portal profile with its reserved name
  105. */
  106. public static function DoCreateUserPortalProfile()
  107. {
  108. $oNewObj = MetaModel::NewObject("URP_Profiles");
  109. $oNewObj->Set('name', PORTAL_PROFILE_NAME);
  110. $oNewObj->Set('description', 'Has the rights to access to the user portal. People having this profile will not be allowed to access the standard application, they will be automatically redirected to the user portal.');
  111. $oNewObj->DisableCheckOnReservedNames();
  112. $iNewId = $oNewObj->DBInsertNoReload();
  113. }
  114. /*
  115. * Overload the standard behavior to preserve reserved names
  116. */
  117. public function DoCheckToWrite()
  118. {
  119. parent::DoCheckToWrite();
  120. if ($this->m_bCheckReservedNames)
  121. {
  122. $aChanges = $this->ListChanges();
  123. if (array_key_exists('name', $aChanges))
  124. {
  125. if ($this->GetOriginal('name') == ADMIN_PROFILE_NAME)
  126. {
  127. $this->m_aCheckIssues[] = "The name of the Administrator profile must not be changed";
  128. }
  129. elseif ($this->Get('name') == ADMIN_PROFILE_NAME)
  130. {
  131. $this->m_aCheckIssues[] = ADMIN_PROFILE_NAME." is a reserved to the built-in Administrator profile";
  132. }
  133. elseif ($this->GetOriginal('name') == PORTAL_PROFILE_NAME)
  134. {
  135. $this->m_aCheckIssues[] = "The name of the User Portal profile must not be changed";
  136. }
  137. elseif ($this->Get('name') == PORTAL_PROFILE_NAME)
  138. {
  139. $this->m_aCheckIssues[] = PORTAL_PROFILE_NAME." is a reserved to the built-in User Portal profile";
  140. }
  141. }
  142. }
  143. }
  144. function GetGrantAsHtml($oUserRights, $sClass, $sAction)
  145. {
  146. $iGrant = $oUserRights->GetProfileActionGrant($this->GetKey(), $sClass, $sAction);
  147. if (!is_null($iGrant))
  148. {
  149. return '<span style="background-color: #ddffdd;">'.Dict::S('UI:UserManagement:ActionAllowed:Yes').'</span>';
  150. }
  151. else
  152. {
  153. return '<span style="background-color: #ffdddd;">'.Dict::S('UI:UserManagement:ActionAllowed:No').'</span>';
  154. }
  155. }
  156. function DoShowGrantSumary($oPage)
  157. {
  158. if ($this->GetName() == "Administrator")
  159. {
  160. // Looks dirty, but ok that's THE ONE
  161. $oPage->p(Dict::S('UI:UserManagement:AdminProfile+'));
  162. return;
  163. }
  164. // Note: for sure, we assume that the instance is derived from UserRightsProfile
  165. $oUserRights = UserRights::GetModuleInstance();
  166. $aDisplayData = array();
  167. foreach (MetaModel::GetClasses('bizmodel') as $sClass)
  168. {
  169. // Skip non instantiable classes
  170. if (MetaModel::IsAbstract($sClass)) continue;
  171. $aStimuli = array();
  172. foreach (MetaModel::EnumStimuli($sClass) as $sStimulusCode => $oStimulus)
  173. {
  174. $oGrant = $oUserRights->GetClassStimulusGrant($this->GetKey(), $sClass, $sStimulusCode);
  175. if (is_object($oGrant) && ($oGrant->Get('permission') == 'yes'))
  176. {
  177. $aStimuli[] = '<span title="'.$sStimulusCode.': '.htmlentities($oStimulus->GetDescription(), ENT_QUOTES, 'UTF-8').'">'.htmlentities($oStimulus->GetLabel(), ENT_QUOTES, 'UTF-8').'</span>';
  178. }
  179. }
  180. $sStimuli = implode(', ', $aStimuli);
  181. $aDisplayData[] = array(
  182. 'class' => MetaModel::GetName($sClass),
  183. 'read' => $this->GetGrantAsHtml($oUserRights, $sClass, 'Read'),
  184. 'bulkread' => $this->GetGrantAsHtml($oUserRights, $sClass, 'Bulk Read'),
  185. 'write' => $this->GetGrantAsHtml($oUserRights, $sClass, 'Modify'),
  186. 'bulkwrite' => $this->GetGrantAsHtml($oUserRights, $sClass, 'Bulk Modify'),
  187. 'delete' => $this->GetGrantAsHtml($oUserRights, $sClass, 'Delete'),
  188. 'bulkdelete' => $this->GetGrantAsHtml($oUserRights, $sClass, 'Bulk Delete'),
  189. 'stimuli' => $sStimuli,
  190. );
  191. }
  192. $aDisplayConfig = array();
  193. $aDisplayConfig['class'] = array('label' => Dict::S('UI:UserManagement:Class'), 'description' => Dict::S('UI:UserManagement:Class+'));
  194. $aDisplayConfig['read'] = array('label' => Dict::S('UI:UserManagement:Action:Read'), 'description' => Dict::S('UI:UserManagement:Action:Read+'));
  195. $aDisplayConfig['bulkread'] = array('label' => Dict::S('UI:UserManagement:Action:BulkRead'), 'description' => Dict::S('UI:UserManagement:Action:BulkRead+'));
  196. $aDisplayConfig['write'] = array('label' => Dict::S('UI:UserManagement:Action:Modify'), 'description' => Dict::S('UI:UserManagement:Action:Modify+'));
  197. $aDisplayConfig['bulkwrite'] = array('label' => Dict::S('UI:UserManagement:Action:BulkModify'), 'description' => Dict::S('UI:UserManagement:Action:BulkModify+'));
  198. $aDisplayConfig['delete'] = array('label' => Dict::S('UI:UserManagement:Action:Delete'), 'description' => Dict::S('UI:UserManagement:Action:Delete+'));
  199. $aDisplayConfig['bulkdelete'] = array('label' => Dict::S('UI:UserManagement:Action:BulkDelete'), 'description' => Dict::S('UI:UserManagement:Action:BulkDelete+'));
  200. $aDisplayConfig['stimuli'] = array('label' => Dict::S('UI:UserManagement:Action:Stimuli'), 'description' => Dict::S('UI:UserManagement:Action:Stimuli+'));
  201. $oPage->table($aDisplayConfig, $aDisplayData);
  202. }
  203. function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
  204. {
  205. parent::DisplayBareRelations($oPage, $bEditMode);
  206. if (!$bEditMode)
  207. {
  208. $oPage->SetCurrentTab(Dict::S('UI:UserManagement:GrantMatrix'));
  209. $this->DoShowGrantSumary($oPage);
  210. }
  211. }
  212. }
  213. class URP_UserProfile extends UserRightsBaseClassGUI
  214. {
  215. public static function Init()
  216. {
  217. $aParams = array
  218. (
  219. "category" => "addon/userrights",
  220. "key_type" => "autoincrement",
  221. "name_attcode" => "userid",
  222. "state_attcode" => "",
  223. "reconc_keys" => array(),
  224. "db_table" => "priv_urp_userprofile",
  225. "db_key_field" => "id",
  226. "db_finalclass_field" => "",
  227. "display_template" => "",
  228. );
  229. MetaModel::Init_Params($aParams);
  230. //MetaModel::Init_InheritAttributes();
  231. MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
  232. MetaModel::Init_AddAttribute(new AttributeExternalField("userlogin", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
  233. MetaModel::Init_AddAttribute(new AttributeExternalKey("profileid", array("targetclass"=>"URP_Profiles", "jointype"=> "", "allowed_values"=>null, "sql"=>"profileid", "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
  234. MetaModel::Init_AddAttribute(new AttributeExternalField("profile", array("allowed_values"=>null, "extkey_attcode"=> 'profileid', "target_attcode"=>"name")));
  235. MetaModel::Init_AddAttribute(new AttributeString("reason", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
  236. // Display lists
  237. MetaModel::Init_SetZListItems('details', array('userid', 'profileid', 'reason')); // Attributes to be displayed for the complete details
  238. MetaModel::Init_SetZListItems('list', array('userid', 'profileid', 'reason')); // Attributes to be displayed for a list
  239. // Search criteria
  240. MetaModel::Init_SetZListItems('standard_search', array('userid', 'profileid')); // Criteria of the std search form
  241. MetaModel::Init_SetZListItems('advanced_search', array('userid', 'profileid')); // Criteria of the advanced search form
  242. }
  243. public function GetName()
  244. {
  245. return Dict::Format('UI:UserManagement:LinkBetween_User_And_Profile', $this->Get('userlogin'), $this->Get('profile'));
  246. }
  247. }
  248. class URP_UserOrg extends UserRightsBaseClassGUI
  249. {
  250. public static function Init()
  251. {
  252. $aParams = array
  253. (
  254. "category" => "addon/userrights",
  255. "key_type" => "autoincrement",
  256. "name_attcode" => "userid",
  257. "state_attcode" => "",
  258. "reconc_keys" => array(),
  259. "db_table" => "priv_urp_userorg",
  260. "db_key_field" => "id",
  261. "db_finalclass_field" => "",
  262. "display_template" => "",
  263. );
  264. MetaModel::Init_Params($aParams);
  265. //MetaModel::Init_InheritAttributes();
  266. MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
  267. MetaModel::Init_AddAttribute(new AttributeExternalField("userlogin", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
  268. MetaModel::Init_AddAttribute(new AttributeExternalKey("allowed_org_id", array("targetclass"=>"Organization", "jointype"=> "", "allowed_values"=>null, "sql"=>"allowed_org_id", "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
  269. MetaModel::Init_AddAttribute(new AttributeExternalField("allowed_org_name", array("allowed_values"=>null, "extkey_attcode"=> 'allowed_org_id', "target_attcode"=>"name")));
  270. MetaModel::Init_AddAttribute(new AttributeString("reason", array("allowed_values"=>null, "sql"=>"reason", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
  271. // Display lists
  272. MetaModel::Init_SetZListItems('details', array('userid', 'allowed_org_id', 'reason')); // Attributes to be displayed for the complete details
  273. MetaModel::Init_SetZListItems('list', array('allowed_org_id', 'reason')); // Attributes to be displayed for a list
  274. // Search criteria
  275. MetaModel::Init_SetZListItems('standard_search', array('userid', 'allowed_org_id')); // Criteria of the std search form
  276. MetaModel::Init_SetZListItems('advanced_search', array('userid', 'allowed_org_id')); // Criteria of the advanced search form
  277. }
  278. public function GetName()
  279. {
  280. return Dict::Format('UI:UserManagement:LinkBetween_User_And_Org', $this->Get('userlogin'), $this->Get('allowed_org_name'));
  281. }
  282. }
  283. class URP_ActionGrant extends UserRightsBaseClass
  284. {
  285. public static function Init()
  286. {
  287. $aParams = array
  288. (
  289. "category" => "addon/userrights",
  290. "key_type" => "autoincrement",
  291. "name_attcode" => "profileid",
  292. "state_attcode" => "",
  293. "reconc_keys" => array(),
  294. "db_table" => "priv_urp_grant_actions",
  295. "db_key_field" => "id",
  296. "db_finalclass_field" => "",
  297. "display_template" => "",
  298. );
  299. MetaModel::Init_Params($aParams);
  300. //MetaModel::Init_InheritAttributes();
  301. // Common to all grant classes (could be factorized by class inheritence, but this has to be benchmarked)
  302. MetaModel::Init_AddAttribute(new AttributeExternalKey("profileid", array("targetclass"=>"URP_Profiles", "jointype"=> "", "allowed_values"=>null, "sql"=>"profileid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
  303. MetaModel::Init_AddAttribute(new AttributeExternalField("profile", array("allowed_values"=>null, "extkey_attcode"=> 'profileid', "target_attcode"=>"name")));
  304. MetaModel::Init_AddAttribute(new AttributeClass("class", array("class_category"=>"", "more_values"=>"", "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
  305. MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
  306. MetaModel::Init_AddAttribute(new AttributeString("action", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
  307. // Display lists
  308. MetaModel::Init_SetZListItems('details', array('profileid', 'class', 'permission', 'action')); // Attributes to be displayed for the complete details
  309. MetaModel::Init_SetZListItems('list', array('class', 'permission', 'action')); // Attributes to be displayed for a list
  310. // Search criteria
  311. MetaModel::Init_SetZListItems('standard_search', array('profileid', 'class', 'permission', 'action')); // Criteria of the std search form
  312. MetaModel::Init_SetZListItems('advanced_search', array('profileid', 'class', 'permission', 'action')); // Criteria of the advanced search form
  313. }
  314. }
  315. class URP_StimulusGrant extends UserRightsBaseClass
  316. {
  317. public static function Init()
  318. {
  319. $aParams = array
  320. (
  321. "category" => "addon/userrights",
  322. "key_type" => "autoincrement",
  323. "name_attcode" => "profileid",
  324. "state_attcode" => "",
  325. "reconc_keys" => array(),
  326. "db_table" => "priv_urp_grant_stimulus",
  327. "db_key_field" => "id",
  328. "db_finalclass_field" => "",
  329. "display_template" => "",
  330. );
  331. MetaModel::Init_Params($aParams);
  332. //MetaModel::Init_InheritAttributes();
  333. // Common to all grant classes (could be factorized by class inheritence, but this has to be benchmarked)
  334. MetaModel::Init_AddAttribute(new AttributeExternalKey("profileid", array("targetclass"=>"URP_Profiles", "jointype"=> "", "allowed_values"=>null, "sql"=>"profileid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
  335. MetaModel::Init_AddAttribute(new AttributeExternalField("profile", array("allowed_values"=>null, "extkey_attcode"=> 'profileid', "target_attcode"=>"name")));
  336. MetaModel::Init_AddAttribute(new AttributeClass("class", array("class_category"=>"", "more_values"=>"", "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
  337. MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
  338. MetaModel::Init_AddAttribute(new AttributeString("stimulus", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
  339. // Display lists
  340. MetaModel::Init_SetZListItems('details', array('profileid', 'class', 'permission', 'stimulus')); // Attributes to be displayed for the complete details
  341. MetaModel::Init_SetZListItems('list', array('class', 'permission', 'stimulus')); // Attributes to be displayed for a list
  342. // Search criteria
  343. MetaModel::Init_SetZListItems('standard_search', array('profileid', 'class', 'permission', 'stimulus')); // Criteria of the std search form
  344. MetaModel::Init_SetZListItems('advanced_search', array('profileid', 'class', 'permission', 'stimulus')); // Criteria of the advanced search form
  345. }
  346. }
  347. class URP_AttributeGrant extends UserRightsBaseClass
  348. {
  349. public static function Init()
  350. {
  351. $aParams = array
  352. (
  353. "category" => "addon/userrights",
  354. "key_type" => "autoincrement",
  355. "name_attcode" => "actiongrantid",
  356. "state_attcode" => "",
  357. "reconc_keys" => array(),
  358. "db_table" => "priv_urp_grant_attributes",
  359. "db_key_field" => "id",
  360. "db_finalclass_field" => "",
  361. "display_template" => "",
  362. );
  363. MetaModel::Init_Params($aParams);
  364. //MetaModel::Init_InheritAttributes();
  365. MetaModel::Init_AddAttribute(new AttributeExternalKey("actiongrantid", array("targetclass"=>"URP_ActionGrant", "jointype"=> "", "allowed_values"=>null, "sql"=>"actiongrantid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
  366. MetaModel::Init_AddAttribute(new AttributeString("attcode", array("allowed_values"=>null, "sql"=>"attcode", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
  367. // Display lists
  368. MetaModel::Init_SetZListItems('details', array('actiongrantid', 'attcode')); // Attributes to be displayed for the complete details
  369. MetaModel::Init_SetZListItems('list', array('attcode')); // Attributes to be displayed for a list
  370. // Search criteria
  371. MetaModel::Init_SetZListItems('standard_search', array('actiongrantid', 'attcode')); // Criteria of the std search form
  372. MetaModel::Init_SetZListItems('advanced_search', array('actiongrantid', 'attcode')); // Criteria of the advanced search form
  373. }
  374. }
  375. class UserRightsProfile extends UserRightsAddOnAPI
  376. {
  377. static public $m_aActionCodes = array(
  378. UR_ACTION_READ => 'read',
  379. UR_ACTION_MODIFY => 'modify',
  380. UR_ACTION_DELETE => 'delete',
  381. UR_ACTION_BULK_READ => 'bulk read',
  382. UR_ACTION_BULK_MODIFY => 'bulk modify',
  383. UR_ACTION_BULK_DELETE => 'bulk delete',
  384. );
  385. // Installation: create the very first user
  386. public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
  387. {
  388. // Create a change to record the history of the User object
  389. $oChange = MetaModel::NewObject("CMDBChange");
  390. $oChange->Set("date", time());
  391. $oChange->Set("userinfo", "Initialization");
  392. $iChangeId = $oChange->DBInsert();
  393. // Support drastic data model changes: no organization class !
  394. if (MetaModel::IsValidClass('Organization'))
  395. {
  396. $oOrg = new Organization();
  397. $oOrg->Set('name', 'My Company/Department');
  398. $oOrg->Set('code', 'SOMECODE');
  399. $iOrgId = $oOrg->DBInsertTrackedNoReload($oChange, true /* skip security */);
  400. }
  401. else
  402. {
  403. $iOrgId = 0;
  404. }
  405. // Support drastic data model changes: no Person class !
  406. if (MetaModel::IsValidClass('Person'))
  407. {
  408. $oContact = new Person();
  409. $oContact->Set('name', 'My last name');
  410. $oContact->Set('first_name', 'My first name');
  411. if (MetaModel::IsValidAttCode('Person', 'org_id'))
  412. {
  413. $oContact->Set('org_id', $iOrgId);
  414. }
  415. $oContact->Set('email', 'my.email@foo.org');
  416. $iContactId = $oContact->DBInsertTrackedNoReload($oChange, true /* skip security */);
  417. }
  418. else
  419. {
  420. $iContactId = 0;
  421. }
  422. $oUser = new UserLocal();
  423. $oUser->Set('login', $sAdminUser);
  424. $oUser->Set('password', $sAdminPwd);
  425. if (MetaModel::IsValidAttCode('UserLocal', 'contactid'))
  426. {
  427. $oUser->Set('contactid', $iContactId);
  428. }
  429. $oUser->Set('language', $sLanguage); // Language was chosen during the installation
  430. // Add this user to the very specific 'admin' profile
  431. $oAdminProfile = MetaModel::GetObjectFromOQL("SELECT URP_Profiles WHERE name = :name", array('name' => ADMIN_PROFILE_NAME), true /*all data*/);
  432. if (is_object($oAdminProfile))
  433. {
  434. $oUserProfile = new URP_UserProfile();
  435. //$oUserProfile->Set('userid', $iUserId);
  436. $oUserProfile->Set('profileid', $oAdminProfile->GetKey());
  437. $oUserProfile->Set('reason', 'By definition, the administrator must have the administrator profile');
  438. //$oUserProfile->DBInsertTrackedNoReload($oChange, true /* skip security */);
  439. $oSet = DBObjectSet::FromObject($oUserProfile);
  440. $oUser->Set('profile_list', $oSet);
  441. }
  442. $iUserId = $oUser->DBInsertTrackedNoReload($oChange, true /* skip security */);
  443. return true;
  444. }
  445. public function Init()
  446. {
  447. MetaModel::RegisterPlugin('userrights', 'ACbyProfile');
  448. }
  449. protected $m_aAdmins; // id of users being linked to the well-known admin profile
  450. protected $m_aPortalUsers; // id of users being linked to the well-known admin profile
  451. protected $m_aProfiles; // id -> object
  452. protected $m_aUserProfiles; // userid,profileid -> object
  453. protected $m_aUserOrgs; // userid,orgid -> object
  454. // Those arrays could be completed on demand (inheriting parent permissions)
  455. protected $m_aClassActionGrants = null; // profile, class, action -> actiongrantid (or false if NO, or null/missing if undefined)
  456. protected $m_aClassStimulusGrants = array(); // profile, class, stimulus -> permission
  457. // Built on demand, could be optimized if necessary (doing a query for each attribute that needs to be read)
  458. protected $m_aObjectActionGrants = array();
  459. public function ResetCache()
  460. {
  461. // Loaded by Load cache
  462. $this->m_aProfiles = null;
  463. $this->m_aUserProfiles = null;
  464. $this->m_aUserOrgs = null;
  465. $this->m_aAdmins = null;
  466. $this->m_aPortalUsers = null;
  467. // Loaded on demand (time consuming as compared to the others)
  468. $this->m_aClassActionGrants = null;
  469. $this->m_aClassStimulusGrants = null;
  470. $this->m_aObjectActionGrants = array();
  471. }
  472. // Separate load: this cache is much more time consuming while loading
  473. // Thus it is loaded iif required
  474. // Could be improved by specifying the profile id
  475. public function LoadActionGrantCache()
  476. {
  477. if (!is_null($this->m_aClassActionGrants)) return;
  478. $oKPI = new ExecutionKPI();
  479. $oFilter = DBObjectSearch::FromOQL_AllData("SELECT URP_ActionGrant AS p WHERE p.permission = 'yes'");
  480. $aGrants = $oFilter->ToDataArray();
  481. foreach($aGrants as $aGrant)
  482. {
  483. $this->m_aClassActionGrants[$aGrant['profileid']][$aGrant['class']][strtolower($aGrant['action'])] = $aGrant['id'];
  484. }
  485. $oKPI->ComputeAndReport('Load of action grants');
  486. }
  487. public function LoadCache()
  488. {
  489. if (!is_null($this->m_aProfiles)) return;
  490. // Could be loaded in a shared memory (?)
  491. $oKPI = new ExecutionKPI();
  492. $oProfileSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData("SELECT URP_Profiles"));
  493. $this->m_aProfiles = array();
  494. while ($oProfile = $oProfileSet->Fetch())
  495. {
  496. $this->m_aProfiles[$oProfile->GetKey()] = $oProfile;
  497. }
  498. $oUserProfileSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData("SELECT URP_UserProfile"));
  499. $this->m_aUserProfiles = array();
  500. $this->m_aAdmins = array();
  501. $this->m_aPortalUsers = array();
  502. while ($oUserProfile = $oUserProfileSet->Fetch())
  503. {
  504. $this->m_aUserProfiles[$oUserProfile->Get('userid')][$oUserProfile->Get('profileid')] = $oUserProfile;
  505. if ($oUserProfile->Get('profile') == ADMIN_PROFILE_NAME)
  506. {
  507. $this->m_aAdmins[] = $oUserProfile->Get('userid');
  508. }
  509. elseif ($oUserProfile->Get('profile') == PORTAL_PROFILE_NAME)
  510. {
  511. $this->m_aPortalUsers[] = $oUserProfile->Get('userid');
  512. }
  513. }
  514. $oUserOrgSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData("SELECT URP_UserOrg"));
  515. $this->m_aUserOrgs = array();
  516. while ($oUserOrg = $oUserOrgSet->Fetch())
  517. {
  518. $this->m_aUserOrgs[$oUserOrg->Get('userid')][$oUserOrg->Get('allowed_org_id')] = $oUserOrg;
  519. }
  520. $this->m_aClassStimulusGrants = array();
  521. $oStimGrantSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData("SELECT URP_StimulusGrant"));
  522. $this->m_aStimGrants = array();
  523. while ($oStimGrant = $oStimGrantSet->Fetch())
  524. {
  525. $this->m_aClassStimulusGrants[$oStimGrant->Get('profileid')][$oStimGrant->Get('class')][$oStimGrant->Get('stimulus')] = $oStimGrant;
  526. }
  527. $oKPI->ComputeAndReport('Load of user management cache (excepted Action Grants)');
  528. /*
  529. echo "<pre>\n";
  530. print_r($this->m_aProfiles);
  531. print_r($this->m_aUserProfiles);
  532. print_r($this->m_aUserOrgs);
  533. print_r($this->m_aClassActionGrants);
  534. print_r($this->m_aClassStimulusGrants);
  535. echo "</pre>\n";
  536. exit;
  537. */
  538. return true;
  539. }
  540. public function IsAdministrator($oUser)
  541. {
  542. $this->LoadCache();
  543. if (in_array($oUser->GetKey(), $this->m_aAdmins))
  544. {
  545. return true;
  546. }
  547. else
  548. {
  549. return false;
  550. }
  551. }
  552. public function IsPortalUser($oUser)
  553. {
  554. $this->LoadCache();
  555. if (in_array($oUser->GetKey(), $this->m_aPortalUsers))
  556. {
  557. return true;
  558. }
  559. else
  560. {
  561. return false;
  562. }
  563. }
  564. public function GetSelectFilter($oUser, $sClass)
  565. {
  566. $this->LoadCache();
  567. $aObjectPermissions = $this->GetUserActionGrant($oUser, $sClass, UR_ACTION_READ);
  568. if ($aObjectPermissions['permission'] == UR_ALLOWED_NO)
  569. {
  570. return false;
  571. }
  572. // Determine how to position the objects of this class
  573. //
  574. if ($sClass == 'Organization')
  575. {
  576. $sAttCode = 'id';
  577. }
  578. elseif (is_callable("$sClass::MapContextParam"))
  579. {
  580. $sAttCode = eval("return $sClass::MapContextParam('org_id');"); // Returns null when there is no mapping for this parameter
  581. if ($sAttCode == null)
  582. {
  583. return true;
  584. }
  585. }
  586. elseif(MetaModel::IsValidAttCode($sClass, 'org_id'))
  587. {
  588. $sAttCode = 'org_id';
  589. }
  590. else
  591. {
  592. // The objects of this class are not positioned in this dimension
  593. // All of them are visible
  594. return true;
  595. }
  596. $oExpression = new FieldExpression($sAttCode, $sClass);
  597. // Position the user
  598. //
  599. @$aUserOrgs = $this->m_aUserOrgs[$oUser->GetKey()];
  600. if (!isset($aUserOrgs) || count($aUserOrgs) == 0)
  601. {
  602. // No position means 'Everywhere'
  603. return true;
  604. }
  605. $aIds = array_keys($aUserOrgs);
  606. $oListExpr = ListExpression::FromScalars($aIds);
  607. $oCondition = new BinaryExpression($oExpression, 'IN', $oListExpr);
  608. $oFilter = new DBObjectSearch($sClass);
  609. $oFilter->AddConditionExpression($oCondition);
  610. return $oFilter;
  611. }
  612. // This verb has been made public to allow the development of an accurate feedback for the current configuration
  613. public function GetProfileActionGrant($iProfile, $sClass, $sAction)
  614. {
  615. $this->LoadActionGrantCache();
  616. // Note: action is forced lowercase to be more flexible (historical bug)
  617. $sAction = strtolower($sAction);
  618. if (isset($this->m_aClassActionGrants[$iProfile][$sClass][$sAction]))
  619. {
  620. return $this->m_aClassActionGrants[$iProfile][$sClass][$sAction];
  621. }
  622. // Recursively look for the grant record in the class hierarchy
  623. $sParentClass = MetaModel::GetParentPersistentClass($sClass);
  624. if (empty($sParentClass))
  625. {
  626. $iGrant = null;
  627. }
  628. else
  629. {
  630. // Recursively look for the grant record in the class hierarchy
  631. $iGrant = $this->GetProfileActionGrant($iProfile, $sParentClass, $sAction);
  632. }
  633. $this->m_aClassActionGrants[$iProfile][$sClass][$sAction] = $iGrant;
  634. return $iGrant;
  635. }
  636. protected function GetUserActionGrant($oUser, $sClass, $iActionCode)
  637. {
  638. $this->LoadCache();
  639. // load and cache permissions for the current user on the given class
  640. //
  641. $iUser = $oUser->GetKey();
  642. $aTest = @$this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode];
  643. if (is_array($aTest)) return $aTest;
  644. $sAction = self::$m_aActionCodes[$iActionCode];
  645. $iPermission = UR_ALLOWED_NO;
  646. $aAttributes = array();
  647. if (isset($this->m_aUserProfiles[$iUser]))
  648. {
  649. foreach($this->m_aUserProfiles[$iUser] as $iProfile => $oProfile)
  650. {
  651. $iGrant = $this->GetProfileActionGrant($iProfile, $sClass, $sAction);
  652. if (is_null($iGrant) || !$iGrant)
  653. {
  654. continue; // loop to the next profile
  655. }
  656. else
  657. {
  658. $iPermission = UR_ALLOWED_YES;
  659. // update the list of attributes with those allowed for this profile
  660. //
  661. $oSearch = DBObjectSearch::FromOQL_AllData("SELECT URP_AttributeGrant WHERE actiongrantid = :actiongrantid");
  662. $oSet = new DBObjectSet($oSearch, array(), array('actiongrantid' => $iGrant));
  663. $aProfileAttributes = $oSet->GetColumnAsArray('attcode', false);
  664. if (count($aProfileAttributes) == 0)
  665. {
  666. $aAllAttributes = array_keys(MetaModel::ListAttributeDefs($sClass));
  667. $aAttributes = array_merge($aAttributes, $aAllAttributes);
  668. }
  669. else
  670. {
  671. $aAttributes = array_merge($aAttributes, $aProfileAttributes);
  672. }
  673. }
  674. }
  675. }
  676. $aRes = array(
  677. 'permission' => $iPermission,
  678. 'attributes' => $aAttributes,
  679. );
  680. $this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode] = $aRes;
  681. return $aRes;
  682. }
  683. public function IsActionAllowed($oUser, $sClass, $iActionCode, $oInstanceSet = null)
  684. {
  685. $this->LoadCache();
  686. // Note: The object set is ignored because it was interesting to optimize for huge data sets
  687. // and acceptable to consider only the root class of the object set
  688. $aObjectPermissions = $this->GetUserActionGrant($oUser, $sClass, $iActionCode);
  689. return $aObjectPermissions['permission'];
  690. }
  691. public function IsActionAllowedOnAttribute($oUser, $sClass, $sAttCode, $iActionCode, $oInstanceSet = null)
  692. {
  693. $this->LoadCache();
  694. // Note: The object set is ignored because it was interesting to optimize for huge data sets
  695. // and acceptable to consider only the root class of the object set
  696. $aObjectPermissions = $this->GetUserActionGrant($oUser, $sClass, $iActionCode);
  697. $aAttributes = $aObjectPermissions['attributes'];
  698. if (in_array($sAttCode, $aAttributes))
  699. {
  700. return $aObjectPermissions['permission'];
  701. }
  702. else
  703. {
  704. return UR_ALLOWED_NO;
  705. }
  706. }
  707. // This verb has been made public to allow the development of an accurate feedback for the current configuration
  708. public function GetClassStimulusGrant($iProfile, $sClass, $sStimulusCode)
  709. {
  710. $this->LoadCache();
  711. if (isset($this->m_aClassStimulusGrants[$iProfile][$sClass][$sStimulusCode]))
  712. {
  713. return $this->m_aClassStimulusGrants[$iProfile][$sClass][$sStimulusCode];
  714. }
  715. else
  716. {
  717. return null;
  718. }
  719. }
  720. public function IsStimulusAllowed($oUser, $sClass, $sStimulusCode, $oInstanceSet = null)
  721. {
  722. $this->LoadCache();
  723. // Note: this code is VERY close to the code of IsActionAllowed()
  724. $iUser = $oUser->GetKey();
  725. // Note: The object set is ignored because it was interesting to optimize for huge data sets
  726. // and acceptable to consider only the root class of the object set
  727. $iPermission = UR_ALLOWED_NO;
  728. if (isset($this->m_aUserProfiles[$iUser]))
  729. {
  730. foreach($this->m_aUserProfiles[$iUser] as $iProfile => $oProfile)
  731. {
  732. $oGrantRecord = $this->GetClassStimulusGrant($iProfile, $sClass, $sStimulusCode);
  733. if (!is_null($oGrantRecord))
  734. {
  735. // no need to fetch the record, we've requested the records having permission = 'yes'
  736. $iPermission = UR_ALLOWED_YES;
  737. }
  738. }
  739. }
  740. return $iPermission;
  741. }
  742. public function FlushPrivileges()
  743. {
  744. $this->ResetCache();
  745. }
  746. }
  747. UserRights::SelectModule('UserRightsProfile');
  748. ?>