userrightsprofile.class.inc.php 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866
  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. }
  448. protected $m_aAdmins; // id of users being linked to the well-known admin profile
  449. protected $m_aPortalUsers; // id of users being linked to the well-known admin profile
  450. protected $m_aProfiles; // id -> object
  451. protected $m_aUserProfiles; // userid,profileid -> object
  452. protected $m_aUserOrgs; // userid,orgid -> object
  453. // Those arrays could be completed on demand (inheriting parent permissions)
  454. protected $m_aClassActionGrants = null; // profile, class, action -> actiongrantid (or false if NO, or null/missing if undefined)
  455. protected $m_aClassStimulusGrants = array(); // profile, class, stimulus -> permission
  456. // Built on demand, could be optimized if necessary (doing a query for each attribute that needs to be read)
  457. protected $m_aObjectActionGrants = array();
  458. public function ResetCache()
  459. {
  460. // Loaded by Load cache
  461. $this->m_aProfiles = null;
  462. $this->m_aUserProfiles = null;
  463. $this->m_aUserOrgs = null;
  464. $this->m_aAdmins = null;
  465. $this->m_aPortalUsers = null;
  466. // Loaded on demand (time consuming as compared to the others)
  467. $this->m_aClassActionGrants = null;
  468. $this->m_aClassStimulusGrants = null;
  469. $this->m_aObjectActionGrants = array();
  470. }
  471. // Separate load: this cache is much more time consuming while loading
  472. // Thus it is loaded iif required
  473. // Could be improved by specifying the profile id
  474. public function LoadActionGrantCache()
  475. {
  476. if (!is_null($this->m_aClassActionGrants)) return;
  477. $oKPI = new ExecutionKPI();
  478. $oFilter = DBObjectSearch::FromOQL_AllData("SELECT URP_ActionGrant AS p WHERE p.permission = 'yes'");
  479. $aGrants = $oFilter->ToDataArray();
  480. foreach($aGrants as $aGrant)
  481. {
  482. $this->m_aClassActionGrants[$aGrant['profileid']][$aGrant['class']][strtolower($aGrant['action'])] = $aGrant['id'];
  483. }
  484. $oKPI->ComputeAndReport('Load of action grants');
  485. }
  486. public function LoadCache()
  487. {
  488. if (!is_null($this->m_aProfiles)) return;
  489. // Could be loaded in a shared memory (?)
  490. $oKPI = new ExecutionKPI();
  491. $oProfileSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData("SELECT URP_Profiles"));
  492. $this->m_aProfiles = array();
  493. while ($oProfile = $oProfileSet->Fetch())
  494. {
  495. $this->m_aProfiles[$oProfile->GetKey()] = $oProfile;
  496. }
  497. $oUserProfileSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData("SELECT URP_UserProfile"));
  498. $this->m_aUserProfiles = array();
  499. $this->m_aAdmins = array();
  500. $this->m_aPortalUsers = array();
  501. while ($oUserProfile = $oUserProfileSet->Fetch())
  502. {
  503. $this->m_aUserProfiles[$oUserProfile->Get('userid')][$oUserProfile->Get('profileid')] = $oUserProfile;
  504. if ($oUserProfile->Get('profile') == ADMIN_PROFILE_NAME)
  505. {
  506. $this->m_aAdmins[] = $oUserProfile->Get('userid');
  507. }
  508. elseif ($oUserProfile->Get('profile') == PORTAL_PROFILE_NAME)
  509. {
  510. $this->m_aPortalUsers[] = $oUserProfile->Get('userid');
  511. }
  512. }
  513. $oUserOrgSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData("SELECT URP_UserOrg"));
  514. $this->m_aUserOrgs = array();
  515. while ($oUserOrg = $oUserOrgSet->Fetch())
  516. {
  517. $this->m_aUserOrgs[$oUserOrg->Get('userid')][$oUserOrg->Get('allowed_org_id')] = $oUserOrg;
  518. }
  519. $this->m_aClassStimulusGrants = array();
  520. $oStimGrantSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData("SELECT URP_StimulusGrant"));
  521. $this->m_aStimGrants = array();
  522. while ($oStimGrant = $oStimGrantSet->Fetch())
  523. {
  524. $this->m_aClassStimulusGrants[$oStimGrant->Get('profileid')][$oStimGrant->Get('class')][$oStimGrant->Get('stimulus')] = $oStimGrant;
  525. }
  526. $oKPI->ComputeAndReport('Load of user management cache (excepted Action Grants)');
  527. /*
  528. echo "<pre>\n";
  529. print_r($this->m_aProfiles);
  530. print_r($this->m_aUserProfiles);
  531. print_r($this->m_aUserOrgs);
  532. print_r($this->m_aClassActionGrants);
  533. print_r($this->m_aClassStimulusGrants);
  534. echo "</pre>\n";
  535. exit;
  536. */
  537. return true;
  538. }
  539. public function IsAdministrator($oUser)
  540. {
  541. $this->LoadCache();
  542. if (in_array($oUser->GetKey(), $this->m_aAdmins))
  543. {
  544. return true;
  545. }
  546. else
  547. {
  548. return false;
  549. }
  550. }
  551. public function IsPortalUser($oUser)
  552. {
  553. $this->LoadCache();
  554. if (in_array($oUser->GetKey(), $this->m_aPortalUsers))
  555. {
  556. return true;
  557. }
  558. else
  559. {
  560. return false;
  561. }
  562. }
  563. public function GetSelectFilter($oUser, $sClass)
  564. {
  565. $this->LoadCache();
  566. $aObjectPermissions = $this->GetUserActionGrant($oUser, $sClass, UR_ACTION_READ);
  567. if ($aObjectPermissions['permission'] == UR_ALLOWED_NO)
  568. {
  569. return false;
  570. }
  571. // Determine how to position the objects of this class
  572. //
  573. if ($sClass == 'Organization')
  574. {
  575. $sAttCode = 'id';
  576. }
  577. elseif (is_callable("$sClass::MapContextParam"))
  578. {
  579. $sAttCode = eval("return $sClass::MapContextParam('org_id');"); // Returns null when there is no mapping for this parameter
  580. if ($sAttCode == null)
  581. {
  582. return true;
  583. }
  584. }
  585. elseif(MetaModel::IsValidAttCode($sClass, 'org_id'))
  586. {
  587. $sAttCode = 'org_id';
  588. }
  589. else
  590. {
  591. // The objects of this class are not positioned in this dimension
  592. // All of them are visible
  593. return true;
  594. }
  595. $oExpression = new FieldExpression($sAttCode, $sClass);
  596. // Position the user
  597. //
  598. @$aUserOrgs = $this->m_aUserOrgs[$oUser->GetKey()];
  599. if (!isset($aUserOrgs) || count($aUserOrgs) == 0)
  600. {
  601. // No position means 'Everywhere'
  602. return true;
  603. }
  604. $aIds = array_keys($aUserOrgs);
  605. $oListExpr = ListExpression::FromScalars($aIds);
  606. $oCondition = new BinaryExpression($oExpression, 'IN', $oListExpr);
  607. $oFilter = new DBObjectSearch($sClass);
  608. $oFilter->AddConditionExpression($oCondition);
  609. return $oFilter;
  610. }
  611. // This verb has been made public to allow the development of an accurate feedback for the current configuration
  612. public function GetProfileActionGrant($iProfile, $sClass, $sAction)
  613. {
  614. $this->LoadActionGrantCache();
  615. // Note: action is forced lowercase to be more flexible (historical bug)
  616. $sAction = strtolower($sAction);
  617. if (isset($this->m_aClassActionGrants[$iProfile][$sClass][$sAction]))
  618. {
  619. return $this->m_aClassActionGrants[$iProfile][$sClass][$sAction];
  620. }
  621. // Recursively look for the grant record in the class hierarchy
  622. $sParentClass = MetaModel::GetParentPersistentClass($sClass);
  623. if (empty($sParentClass))
  624. {
  625. $iGrant = null;
  626. }
  627. else
  628. {
  629. // Recursively look for the grant record in the class hierarchy
  630. $iGrant = $this->GetProfileActionGrant($iProfile, $sParentClass, $sAction);
  631. }
  632. $this->m_aClassActionGrants[$iProfile][$sClass][$sAction] = $iGrant;
  633. return $iGrant;
  634. }
  635. protected function GetUserActionGrant($oUser, $sClass, $iActionCode)
  636. {
  637. $this->LoadCache();
  638. // load and cache permissions for the current user on the given class
  639. //
  640. $iUser = $oUser->GetKey();
  641. $aTest = @$this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode];
  642. if (is_array($aTest)) return $aTest;
  643. $sAction = self::$m_aActionCodes[$iActionCode];
  644. $iPermission = UR_ALLOWED_NO;
  645. $aAttributes = array();
  646. if (isset($this->m_aUserProfiles[$iUser]))
  647. {
  648. foreach($this->m_aUserProfiles[$iUser] as $iProfile => $oProfile)
  649. {
  650. $iGrant = $this->GetProfileActionGrant($iProfile, $sClass, $sAction);
  651. if (is_null($iGrant) || !$iGrant)
  652. {
  653. continue; // loop to the next profile
  654. }
  655. else
  656. {
  657. $iPermission = UR_ALLOWED_YES;
  658. // update the list of attributes with those allowed for this profile
  659. //
  660. $oSearch = DBObjectSearch::FromOQL_AllData("SELECT URP_AttributeGrant WHERE actiongrantid = :actiongrantid");
  661. $oSet = new DBObjectSet($oSearch, array(), array('actiongrantid' => $iGrant));
  662. $aProfileAttributes = $oSet->GetColumnAsArray('attcode', false);
  663. if (count($aProfileAttributes) == 0)
  664. {
  665. $aAllAttributes = array_keys(MetaModel::ListAttributeDefs($sClass));
  666. $aAttributes = array_merge($aAttributes, $aAllAttributes);
  667. }
  668. else
  669. {
  670. $aAttributes = array_merge($aAttributes, $aProfileAttributes);
  671. }
  672. }
  673. }
  674. }
  675. $aRes = array(
  676. 'permission' => $iPermission,
  677. 'attributes' => $aAttributes,
  678. );
  679. $this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode] = $aRes;
  680. return $aRes;
  681. }
  682. public function IsActionAllowed($oUser, $sClass, $iActionCode, $oInstanceSet = null)
  683. {
  684. $this->LoadCache();
  685. // Note: The object set is ignored because it was interesting to optimize for huge data sets
  686. // and acceptable to consider only the root class of the object set
  687. $aObjectPermissions = $this->GetUserActionGrant($oUser, $sClass, $iActionCode);
  688. return $aObjectPermissions['permission'];
  689. }
  690. public function IsActionAllowedOnAttribute($oUser, $sClass, $sAttCode, $iActionCode, $oInstanceSet = null)
  691. {
  692. $this->LoadCache();
  693. // Note: The object set is ignored because it was interesting to optimize for huge data sets
  694. // and acceptable to consider only the root class of the object set
  695. $aObjectPermissions = $this->GetUserActionGrant($oUser, $sClass, $iActionCode);
  696. $aAttributes = $aObjectPermissions['attributes'];
  697. if (in_array($sAttCode, $aAttributes))
  698. {
  699. return $aObjectPermissions['permission'];
  700. }
  701. else
  702. {
  703. return UR_ALLOWED_NO;
  704. }
  705. }
  706. // This verb has been made public to allow the development of an accurate feedback for the current configuration
  707. public function GetClassStimulusGrant($iProfile, $sClass, $sStimulusCode)
  708. {
  709. $this->LoadCache();
  710. if (isset($this->m_aClassStimulusGrants[$iProfile][$sClass][$sStimulusCode]))
  711. {
  712. return $this->m_aClassStimulusGrants[$iProfile][$sClass][$sStimulusCode];
  713. }
  714. else
  715. {
  716. return null;
  717. }
  718. }
  719. public function IsStimulusAllowed($oUser, $sClass, $sStimulusCode, $oInstanceSet = null)
  720. {
  721. $this->LoadCache();
  722. // Note: this code is VERY close to the code of IsActionAllowed()
  723. $iUser = $oUser->GetKey();
  724. // Note: The object set is ignored because it was interesting to optimize for huge data sets
  725. // and acceptable to consider only the root class of the object set
  726. $iPermission = UR_ALLOWED_NO;
  727. if (isset($this->m_aUserProfiles[$iUser]))
  728. {
  729. foreach($this->m_aUserProfiles[$iUser] as $iProfile => $oProfile)
  730. {
  731. $oGrantRecord = $this->GetClassStimulusGrant($iProfile, $sClass, $sStimulusCode);
  732. if (!is_null($oGrantRecord))
  733. {
  734. // no need to fetch the record, we've requested the records having permission = 'yes'
  735. $iPermission = UR_ALLOWED_YES;
  736. }
  737. }
  738. }
  739. return $iPermission;
  740. }
  741. public function FlushPrivileges()
  742. {
  743. $this->ResetCache();
  744. }
  745. }
  746. UserRights::SelectModule('UserRightsProfile');
  747. ?>