Commit ecf07ed41539832f33aad71c8f99002d97444149
1 parent
e79e058b
Exists in
master
and in
3 other branches
Début de mise en place du nouveau système ACL simplifié basé sur les
tableaux $easyACL (pas encore actif)
Showing
4 changed files
with
279 additions
and
16 deletions
Show diff stats
README-LABINVENT.md
... | ... | @@ -47,14 +47,11 @@ Logiciel testé et validé sur les configurations suivantes : |
47 | 47 | |
48 | 48 | VERSION ACTUELLE |
49 | 49 | |
50 | -Date: 30/08/2017 | |
51 | -Version: 2.7.9 | |
52 | - - Renommages plus explicites des fonctions et variables | |
53 | - - Bugfix important sur détection du role "Utilisateur" pour les personnes du ldap qui ne sont pas dans la table utilisateurs !!! | |
54 | - - Creation d'un fake utilisateur pour simuler un utilisateur qui n'est pas dans la table utilisateurs (et tester le cas ci-dessus) | |
55 | - - Ajout de tests avec cet utilisateur | |
50 | +Date: 01/09/2017 | |
51 | +Version: 2.8.0 | |
52 | + - Début de mise en place du nouveau système ACL simplifié basé sur les tableaux $easyACL (pas encore actif) | |
56 | 53 | |
57 | -Version majeure en cours (2.7): https://projects.irap.omp.eu/versions/162 | |
54 | +Version majeure en cours (2.8): https://projects.irap.omp.eu/versions/162 | |
58 | 55 | |
59 | 56 | ROADMAP: https://projects.irap.omp.eu/projects/labinvent/roadmap |
60 | 57 | |
... | ... | @@ -68,6 +65,9 @@ CHANGEMENTS IMPORTANTS (MILESTONES) |
68 | 65 | |
69 | 66 | Liste complète des évolutions: https://gitlab.irap.omp.eu/epallier/labinvent/commits/master |
70 | 67 | |
68 | +??/09/2017 Version: 2.8.X | |
69 | + - Nouveau système ACL simplifié basé sur les tableaux $easyACL | |
70 | + | |
71 | 71 | 30/08/2017 Version: 2.7.9 |
72 | 72 | - fonction intelligente AppController::getUserRole() qui donne le role "Utilisateur" par défaut pour un utilisateur non privilégié |
73 | 73 | - Refactorisation des ACL (authorizations) dans isAuthorized() et beforeFilter() | ... | ... |
src/Controller/AppController.php
... | ... | @@ -55,7 +55,154 @@ class AppController extends Controller { |
55 | 55 | // Current ROLE (by default = "Utilisateur") |
56 | 56 | private $CURRENT_ROLE = null; |
57 | 57 | |
58 | - | |
58 | + // EP 08/2017 | |
59 | + protected $easyACL = array( | |
60 | + | |
61 | + /** Default ACL for ALL (logged) users | |
62 | + * | |
63 | + * Les actions non mentionnées sont accessibles à tous (par défaut), | |
64 | + * exemple 'find', 'index'... | |
65 | + * Ces default ACL peuvent être surchargées pour un profil précis | |
66 | + * (par exemple pour 'USER' qui est plus restreint) | |
67 | + */ | |
68 | + //'ALL' => array ( | |
69 | + 'DEFAULT' => array ( | |
70 | + // 'action' => 'condition for execution' (= 'Y', 'N', or '<condition>'), | |
71 | + // with <condition> like "'field name' == 'value'" | |
72 | + // CRUD actions : | |
73 | + //'edit' => 'N', // update | |
74 | + //'delete' => 'N', | |
75 | + 'autre' => 'Y', | |
76 | + ), | |
77 | + | |
78 | + // Ajoute des ACL plus spécifiques (ci-dessus) pour le profil USER qui est plus restreint | |
79 | + // Les actions absentes ne sont pas surchargées (elles sont exécutées selon les conditions définies pour 'ALL') | |
80 | + 'USER' => array ( | |
81 | + // CRUD actions | |
82 | + 'add' => 'Y', // C | |
83 | + 'index' => 'Y', // R all | |
84 | + 'view' => 'Y', // R one | |
85 | + //'edit' => 'N', // U | |
86 | + 'edit' => 'is_creator', // is_creator = (nom_createur == CURRENT_USER_NAME) | |
87 | + 'delete' => 'N', // D | |
88 | + // OTHER actions | |
89 | + 'find' => 'Y', // create | |
90 | + /* ceci n'a aucun sens car l'action sur le modèle "Pages" s'appelle toujours "display" (et non pas tools, infos, ou printers...) | |
91 | + 'tools' => 'N', | |
92 | + 'infos' => 'N', | |
93 | + 'printers' => 'N', | |
94 | + */ | |
95 | + ), | |
96 | + | |
97 | + // Surcharge des ACL par défaut (ci-dessus) pour le profil RESPONSABLE qui est plus restreint | |
98 | + // Les actions absentes ne sont pas surchargées (elles sont exécutées selon les conditions définies pour 'ALL') | |
99 | + 'RESPONSABLE' => array ( | |
100 | + ), | |
101 | + | |
102 | + // Surcharge des ACL par défaut (ci-dessus) pour le profil ADMIN | |
103 | + 'ADMIN' => array ( | |
104 | + //'add' => 'Y', // create | |
105 | + 'edit' => 'Y', // update | |
106 | + //'delete' => 'Y', // update | |
107 | + ), | |
108 | + | |
109 | + // Surcharge des ACL par défaut (ci-dessus) pour le profil ADMINPLUS | |
110 | + 'ADMINPLUS' => array ( | |
111 | + //'edit' => 'Y', // update | |
112 | + ), | |
113 | + | |
114 | + // Surcharge des ACL par défaut (ci-dessus) pour le profil SUPERADMIN | |
115 | + 'SUPERADMIN' => array ( | |
116 | + //'add' => 'Y', // create | |
117 | + //'edit' => 'Y', // update | |
118 | + 'delete' => 'Y', | |
119 | + ), | |
120 | + ); // $easyACL | |
121 | + | |
122 | + | |
123 | + //@todo | |
124 | + public function startsWith($haystack, $needle) { | |
125 | + return true; | |
126 | + } | |
127 | + //@todo | |
128 | + public function endsWith($haystack, $needle) { | |
129 | + return true; | |
130 | + } | |
131 | + public function evalACL($condition) { | |
132 | + // Simple case | |
133 | + if ($condition == 'Y') return true; | |
134 | + if ($condition == 'F') return false; | |
135 | + // Complex case | |
136 | + //@todo | |
137 | + return true; | |
138 | + } | |
139 | + public function evalSpecificRule($condition, AppController $controller, $user, $role, $action, $id=null) { | |
140 | + // if starts with "&&" eval DEFAULT rule && specific rule | |
141 | + if ($this->startsWith($condition,'&&')) return $this->evalACL($controller->easyACL['DEFAULT'][$action]) && $this->evalACL($condition); | |
142 | + // otherwise, eval only specific rule | |
143 | + return $this->evalACL($condition); | |
144 | + } | |
145 | + /** | |
146 | + * @param AppController $controller // a subclass of AppController (MaterielsController or any other) | |
147 | + * @param array $user | |
148 | + * @param string $role | |
149 | + * @param string $action | |
150 | + * @param string $id | |
151 | + */ | |
152 | + public function isAuthorizedAction(AppController $controller, $user, $role, $action, $id=null) { | |
153 | + | |
154 | + // 1) controller specific (role) rule for action | |
155 | + $condition = $controller->easyACL[$role][$action]; | |
156 | + if (isset($condition)) return $this->evalSpecificRule($condition, $controller, $user, $role, $action); | |
157 | + | |
158 | + // 2) AppController ($this) specific (role) rule for action | |
159 | + $condition = self::easyACL[$role][$action]; | |
160 | + if (isset($condition)) return $this->evalSpecificRule($condition, $this, $user, $role, $action); | |
161 | + | |
162 | + // 3) controller general (DEFAULT) rule for action | |
163 | + $condition = $controller->easyACL['DEFAULT'][$action]; | |
164 | + if (isset($condition)) return $this->evalACL($condition); | |
165 | + | |
166 | + /* | |
167 | + * (RECURSIVE CALL) | |
168 | + * 4) controller previous specific (role) rule for action | |
169 | + * ex: if role is 'SUPER', use 'ADMIN' rule | |
170 | + * ex: if role is 'ADMIN', use 'RESP' rule | |
171 | + * ex: if role is 'RESP', use 'USER' rule | |
172 | + * ex: if role is 'USER', stop recursive call | |
173 | + * Stop recursive call if role is 'USER' => no rule found, so default is authorize (Y) | |
174 | + */ | |
175 | + if ($role == 'USER') return true; | |
176 | + return $this->isAuthorizedAction($controller, $user, $role-1, $action, $id); | |
177 | + | |
178 | + } | |
179 | + | |
180 | + //@todo | |
181 | + public function getMandatoryFieldsForAction($action) { | |
182 | + $fields = []; | |
183 | + // meme fonctionnement recursif que isAuthorizedAction() ci-dessus | |
184 | + return $fields; | |
185 | + } | |
186 | + //@todo | |
187 | + public function getHiddenFieldsForAction($action) { | |
188 | + $fields = []; | |
189 | + // meme fonctionnement recursif que isAuthorizedAction() ci-dessus | |
190 | + return $fields; | |
191 | + } | |
192 | + //@todo | |
193 | + public function getReadOnlyFieldsForAction($action) { | |
194 | + $fields = []; | |
195 | + // meme fonctionnement recursif que isAuthorizedAction() ci-dessus | |
196 | + return $fields; | |
197 | + } | |
198 | + //@todo | |
199 | + public function getDefaultValueFieldsForAction($action) { | |
200 | + $fields = []; | |
201 | + // meme fonctionnement recursif que isAuthorizedAction() ci-dessus | |
202 | + return $fields; | |
203 | + } | |
204 | + | |
205 | + | |
59 | 206 | public static function getRoleLevel($role) { |
60 | 207 | //return $this->allProfiles[$role]; |
61 | 208 | //debug("role is" .$role); |
... | ... | @@ -105,7 +252,7 @@ class AppController extends Controller { |
105 | 252 | $action = $this->getActionPassed(); |
106 | 253 | //$role = $this->getUserRole($user); |
107 | 254 | |
108 | - // Seul Administration (et +) peut ajouter, supprimer ou modifier un organisme | |
255 | + // Seul Administration (et +) peut ajouter, supprimer ou modifier | |
109 | 256 | if( in_array($action,['add','delete','edit'])) { |
110 | 257 | if ($this->USER_IS_ADMIN_AT_LEAST()) return true; |
111 | 258 | // Les autres n'y ont pas accès |
... | ... | @@ -158,8 +305,7 @@ class AppController extends Controller { |
158 | 305 | return true; |
159 | 306 | |
160 | 307 | // ACL : Super-Admin peut accéder à toutes les actions |
161 | - if ($role == 'Super Administrateur') | |
162 | - return true; | |
308 | + if ($role == 'Super Administrateur') return true; | |
163 | 309 | |
164 | 310 | // ACL : Par défaut refuser |
165 | 311 | return false; | ... | ... |
src/Controller/MaterielsController.php
... | ... | @@ -30,7 +30,94 @@ class MaterielsController extends AppController { |
30 | 30 | 'TOBEARCHIVED' |
31 | 31 | ]; |
32 | 32 | |
33 | - //public $role; | |
33 | + // EP 08/2017 | |
34 | + private $FIELDS = array( | |
35 | + 'name', | |
36 | + 'description', | |
37 | + 'prix_ht', | |
38 | + //... | |
39 | + ); | |
40 | + | |
41 | + // EP 08/2017 | |
42 | + protected $easyACL = array( | |
43 | + | |
44 | + /** Default ACL for ALL (logged) users | |
45 | + * | |
46 | + * Les actions non mentionnées sont accessibles à tous (par défaut), | |
47 | + * exemple 'find', 'index'... | |
48 | + * Ces default ACL peuvent être surchargées pour un profil précis | |
49 | + * (par exemple pour 'USER' qui est plus restreint) | |
50 | + */ | |
51 | + //'ALL' => array ( | |
52 | + 'DEFAULT' => array ( | |
53 | + // 'action' => 'condition for execution' (= 'Y', 'N', or '<condition>'), | |
54 | + // with <condition> like "'field name' == 'value'" | |
55 | + // CRUD actions : | |
56 | + //'index' => 'Y', // read all | |
57 | + //'view' => 'Y', // read one | |
58 | + //'add' => 'Y', // create | |
59 | + //'find' => 'Y', // create | |
60 | + 'edit' => '(status == CREATED || status == VALIDATED)', // update | |
61 | + 'delete' => '(status == CREATED)', | |
62 | + 'autre' => 'N', | |
63 | + ), | |
64 | + | |
65 | + // Ajoute des ACL plus spécifiques (ci-dessus) pour le profil USER qui est plus restreint | |
66 | + // Les actions absentes ne sont pas surchargées (elles sont exécutées selon les conditions définies pour 'ALL') | |
67 | + 'USER' => array ( | |
68 | + 'edit' => '=ALL&& (is_creator [[ is_user)', // is_owner = (nom_createur == CURRENT_USER_NAME) | |
69 | + // except fields status, owner, etiquette, and admin data, VALIDATED (only some fields, cf $modifiableFields in View/Materiels/scaffold.form.ctp) | |
70 | + 'delete' => '=ALL&& is_owner', | |
71 | + /* ceci n'a aucun sens car l'action sur le modèle "Pages" s'appelle toujours "display" (et non pas tools, infos, ou printers...) | |
72 | + 'tools' => 'N', | |
73 | + 'infos' => 'N', | |
74 | + 'printers' => 'N', | |
75 | + */ | |
76 | + 'statusCreated' => 'N', // Dé-valider (in-valider), rétrograder le statut (admin+) | |
77 | + 'statusValidated' => 'N', // Valider (admin+) | |
78 | + 'statusToBeArchived' => 'Y', // Demander la sortie de l'inventaire | |
79 | + 'statusArchived' => 'N', // Sortir de l'inventaire, archiver (admin+) | |
80 | + 'execActions' => 'N', // calls updateSelectedStatus() (admin+) | |
81 | + ), | |
82 | + | |
83 | + // Surcharge des ACL par défaut (ci-dessus) pour le profil RESPONSABLE qui est plus restreint | |
84 | + // Les actions absentes ne sont pas surchargées (elles sont exécutées selon les conditions définies pour 'ALL') | |
85 | + 'RESPONSABLE' => array ( | |
86 | + 'edit' => '=ALL&& is_resp', // is_owner = (nom_createur == CURRENT_USER_NAME) | |
87 | + //'delete' => 'is_resp && (status == CREATED)', | |
88 | + // Valider les matos dont il est responsable : | |
89 | + // is_resp = (groupe_thematique == CURRENT_USER_NAME.groupe_thematique [[ groupe_metier == CURRENT_USER_NAME.groupe_metier) | |
90 | + //'statusValidated' => 'N', | |
91 | + ), | |
92 | + | |
93 | + // Surcharge des ACL par défaut (ci-dessus) pour le profil ADMIN | |
94 | + 'ADMIN' => array ( | |
95 | + //'execActions' => 'Y', // calls updateSelectedStatus(), admin+ | |
96 | + //'add' => 'Y', // create | |
97 | + //'edit' => '(status == CREATED || status == VALIDATED)', // update | |
98 | + 'edit' => '=ALL', // update | |
99 | + 'delete' => '=ALL', // update | |
100 | + 'statusCreated' => 'Y', // Dé-valider (in-valider), rétrograder le statut (admin+) | |
101 | + 'statusValidated' => 'Y', // Valider (admin+) | |
102 | + 'statusToBeArchived' => 'Y', // Demander la sortie de l'inventaire | |
103 | + 'statusArchived' => 'Y', // Sortir de l'inventaire, archiver (admin+) | |
104 | + 'execActions' => 'Y', // calls updateSelectedStatus() (admin+) | |
105 | + ), | |
106 | + | |
107 | + // Surcharge des ACL par défaut (ci-dessus) pour le profil ADMINPLUS | |
108 | + 'ADMINPLUS' => array ( | |
109 | + //'edit' => 'Y', // update | |
110 | + ), | |
111 | + | |
112 | + // Surcharge des ACL par défaut (ci-dessus) pour le profil SUPERADMIN | |
113 | + 'SUPERADMIN' => array ( | |
114 | + //'execActions' => 'Y', // calls updateSelectedStatus(), admin+ | |
115 | + //'add' => 'Y', // create | |
116 | + //'edit' => 'Y', // update | |
117 | + //'delete' => 'Y', | |
118 | + ), | |
119 | + ); // $ACL | |
120 | + | |
34 | 121 | |
35 | 122 | /* |
36 | 123 | * EP added 13/6/17 |
... | ... | @@ -44,7 +131,22 @@ class MaterielsController extends AppController { |
44 | 131 | $this->set('CREATED', self::CREATED); |
45 | 132 | $this->set('VALIDATED', self::VALIDATED); |
46 | 133 | $this->set('TOBEARCHIVED', self::TOBEARCHIVED); |
47 | - $this->set('ARCHIVED', self::ARCHIVED); | |
134 | + $this->set('ARCHIVED', self::ARCHIVED); | |
135 | + | |
136 | + /* | |
137 | + * @todo EP 08/2017 Nouvelle organisation des ACL avec $easyACL | |
138 | + * | |
139 | + $mandatoryFields = $this->getMandatoryFieldsForAction($action); | |
140 | + $hiddenFields = $this->getHiddenFieldsForAction($action); | |
141 | + $readOnlyFields = $this->getReadOnlyFieldsForAction($action); | |
142 | + $haveDefaultValueFields = $this->getDefaultValueFieldsForAction($action); | |
143 | + // Seul utile pour la vue 'index' | |
144 | + $this->set('hiddenFields', $hiddenFields); | |
145 | + // Inutiles pour la vue 'index': | |
146 | + $this->set('mandatoryFields', $mandatoryFields); | |
147 | + $this->set('readOnlyFields', $readOnlyFields); | |
148 | + $this->set('haveDefaultValueFields', $haveDefaultValueFields); | |
149 | + */ | |
48 | 150 | } |
49 | 151 | |
50 | 152 | /** |
... | ... | @@ -53,7 +155,6 @@ class MaterielsController extends AppController { |
53 | 155 | * |
54 | 156 | * Give authorization for materiels |
55 | 157 | */ |
56 | - // (EP) TODO: ameliorer ca avec des variables globales IS_VALIDATED, IS_ADMIN, ... | |
57 | 158 | public function isAuthorized($userFromSession) { |
58 | 159 | $user = $userFromSession; |
59 | 160 | $configuration = $this->confLabinvent; |
... | ... | @@ -74,6 +175,14 @@ class MaterielsController extends AppController { |
74 | 175 | $id = $this->getIdPassed(); |
75 | 176 | |
76 | 177 | /* |
178 | + * @todo EP 08/2017 Nouvelle organisation des ACL avec $easyACL | |
179 | + * | |
180 | + * //return $this->isAuthorizedAction($this, $user, $role, $action, $id); | |
181 | + * | |
182 | + * Tout le reste en dessous de cette ligne devient inutile !!! | |
183 | + */ | |
184 | + | |
185 | + /* | |
77 | 186 | * Structure mise en place: |
78 | 187 | * |
79 | 188 | * switch ACTION |
... | ... | @@ -86,7 +195,15 @@ class MaterielsController extends AppController { |
86 | 195 | // INDEX, VIEW, ADD, FIND |
87 | 196 | // ACL: Accessibles à tous ( cf parent::isAuthorized() ) |
88 | 197 | |
89 | - // EDIT | |
198 | + // CREATE (add) | |
199 | + // All roles can 'add' | |
200 | + /* | |
201 | + case 'add': | |
202 | + return true; | |
203 | + break; | |
204 | + */ | |
205 | + | |
206 | + // UPDATE (edit) | |
90 | 207 | //if ($action == 'edit') { |
91 | 208 | case 'edit': |
92 | 209 | //BETTER: | ... | ... |
src/Template/Layout/default.ctp
... | ... | @@ -115,7 +115,7 @@ $cakeDescription = 'Labinvent 2'; |
115 | 115 | </i></td> |
116 | 116 | <td id="version"> |
117 | 117 | <!-- VERSION M.m.f.b (version (M)ajeure, version (m)ineure, numero de nouvelle (f)onctionnalite, numero de (b)ugfix) --> |
118 | - <font color="black">VERSION 2.7.9 (30/08/2017)</font> | |
118 | + <font color="black">VERSION 2.8.0 (01/09/2017)</font> | |
119 | 119 | <br/> |
120 | 120 | <font color="black"><a href="<?php |
121 | 121 | ... | ... |