|
1 .. -*- coding: utf-8 -*- |
|
2 |
|
3 Entity type definition |
|
4 ---------------------- |
|
5 |
|
6 An entity type is defined by a Python class which inherits `EntityType`. The |
|
7 class name correponds to the type name. Then the content of the class contains |
|
8 the description of attributes and relations for the defined entity type, |
|
9 by example :: |
|
10 |
|
11 class Personne(EntityType): |
|
12 """A person with the properties and the relations necessarry for my |
|
13 application""" |
|
14 |
|
15 last_name = String(required=True, fulltextindexed=True) |
|
16 first_name = String(required=True, fulltextindexed=True) |
|
17 title = String(vocabulary=('M', 'Mme', 'Mlle')) |
|
18 date_of_birth = Date() |
|
19 works_for = SubjectRelation('Company', cardinality='?*') |
|
20 |
|
21 * the name of the Python attribute corresponds to the name of the attribute |
|
22 or the relation in `CubicWeb` application. |
|
23 |
|
24 * all built-in types are available : `String`, `Int`, `Float`, |
|
25 `Boolean`, `Date`, `Datetime`, `Time`, `Byte`. |
|
26 |
|
27 * each entity type has at least the following meta-relations : |
|
28 |
|
29 - `eid` (`Int`) |
|
30 |
|
31 - `creation_date` (`Datetime`) |
|
32 |
|
33 - `modification_date` (`Datetime`) |
|
34 |
|
35 - `created_by` (`EUser`) (which user created the entity) |
|
36 |
|
37 - `owned_by` (`EUser`) (who does the entity belongs to, by default the |
|
38 creator but not necessarry and it could have multiple owners) |
|
39 |
|
40 - `is` (`EEType`) |
|
41 |
|
42 |
|
43 * it is also possible to define relations of type object by using `ObjectRelation` |
|
44 instead of `SubjectRelation` |
|
45 |
|
46 * the first argument of `SubjectRelation` and `ObjectRelation` gives respectively |
|
47 the object/subject entity type of the relation. This could be : |
|
48 |
|
49 * a string corresponding to an entity type |
|
50 |
|
51 * a tuple of string correponding to multiple entities types |
|
52 |
|
53 * special string such as follows : |
|
54 |
|
55 - "**" : all types of entities |
|
56 - "*" : all types of non-meta entities |
|
57 - "@" : all types of meta entities but not system entities (e.g. used for |
|
58 the basic schema description) |
|
59 |
|
60 * it is possible to use the attribute `meta` to flag an entity type as a `meta` |
|
61 (e.g. used to describe/categorize other entities) |
|
62 |
|
63 * optional properties for attributes and relations : |
|
64 |
|
65 - `description` : string describing an attribute or a relation. By default |
|
66 this string will be used in the editing form of the entity, which means |
|
67 that it is supposed to help the end-user and should be flagged by the |
|
68 function `_` to be properly internationalized. |
|
69 |
|
70 - `constraints` : list of conditions/constraints that the relation needs to |
|
71 satisfy (c.f. `Contraints`_) |
|
72 |
|
73 - `cardinality` : two characters string which specify the cardinality of the |
|
74 relation. The first character defines the cardinality of the relation on |
|
75 the subject, the second on the object of the relation. When a relation |
|
76 has multiple possible subjects or objects, the cardinality applies to all |
|
77 and not on a one to one basis (so it must be consistent...). The possible |
|
78 values are inspired from regular expressions syntax : |
|
79 |
|
80 * `1`: 1..1 |
|
81 * `?`: 0..1 |
|
82 * `+`: 1..n |
|
83 * `*`: 0..n |
|
84 |
|
85 - `meta` : boolean indicating that the relation is a meta-relation (false by |
|
86 default) |
|
87 |
|
88 * optionnal properties for attributes : |
|
89 |
|
90 - `required` : boolean indicating if the attribute is required (false by default) |
|
91 |
|
92 - `unique` : boolean indicating if the value of the attribute has to be unique |
|
93 or not within all entities of the same type (false by default) |
|
94 |
|
95 - `indexed` : boolean indicating if an index needs to be created for this |
|
96 attribute in the database (false by default). This is usefull only if |
|
97 you know that you will have to run numerous searches on the value of this |
|
98 attribute. |
|
99 |
|
100 - `default` : default value of the attribute. In case of date types, the values |
|
101 which could be used correpond to the RQL keywords `TODAY` and `NOW`. |
|
102 |
|
103 - `vocabulary` : specify static possible values of an attribute |
|
104 |
|
105 * optionnal properties of type `String` : |
|
106 |
|
107 - `fulltextindexed` : boolean indicating if the attribute is part of |
|
108 the full text index (false by default) (*applicable on the type `Byte` |
|
109 as well*) |
|
110 |
|
111 - `internationalizable` : boolean indicating if the value of the attribute |
|
112 is internationalizable (false by default) |
|
113 |
|
114 - `maxsize` : integer providing the maximum size of the string (no limit by default) |
|
115 |
|
116 * optionnal properties for relations : |
|
117 |
|
118 - `composite` : string indicating that the subject (composite == 'subject') |
|
119 is composed of the objects of the relations. For the opposite case (when |
|
120 the object is composed of the subjects of the relation), we just need |
|
121 to set 'object' as the value. The composition implies that when the relation |
|
122 is deleted (so when the composite is deleted), the composed are also deleted. |
|
123 |
|
124 Contraints |
|
125 `````````` |
|
126 By default, the available constraints types are : |
|
127 |
|
128 * `SizeConstraint` : allows to specify a minimum and/or maximum size on |
|
129 string (generic case of `maxsize`) |
|
130 |
|
131 * `BoundConstraint` : allows to specify a minimum and/or maximum value on |
|
132 numeric types |
|
133 |
|
134 * `UniqueConstraint` : identical to "unique=True" |
|
135 |
|
136 * `StaticVocabularyConstraint` : identical to "vocabulary=(...)" |
|
137 |
|
138 * `RQLConstraint` : allows to specify a RQL query that needs to be satisfied |
|
139 by the subject and/or the object of the relation. In this query the variables |
|
140 `S` and `O` are reserved for the entities subject and object of the |
|
141 relation. |
|
142 |
|
143 * `RQLVocabularyConstraint` : similar to the previous type of constraint except |
|
144 that it does not express a "strong" constraint, which means it is only used to |
|
145 restrict the values listed in the drop-down menu of editing form, but it does |
|
146 not prevent another entity to be selected |
|
147 |
|
148 |
|
149 Relation definition |
|
150 ------------------- |
|
151 |
|
152 XXX add note about defining relation type / definition |
|
153 |
|
154 A relation is defined by a Python class heriting `RelationType`. The name |
|
155 of the class corresponds to the name of the type. The class then contains |
|
156 a description of the properties of this type of relation, and could as well |
|
157 contains a string for the subject and a string for the object. This allows to create |
|
158 new definition of associated relations, (so that the class can have the |
|
159 definition properties from the relation) by example :: |
|
160 |
|
161 class locked_by(RelationType): |
|
162 """relation on all entities indicating that they are locked""" |
|
163 inlined = True |
|
164 cardinality = '?*' |
|
165 subject = '*' |
|
166 object = 'EUser' |
|
167 |
|
168 In addition to the permissions, the properties of the relation types |
|
169 (shared also by all definition of relation of this type) are : |
|
170 |
|
171 |
|
172 * `inlined` : boolean handling the physical optimization for archiving |
|
173 the relation in the subject entity table, instead of creating a specific |
|
174 table for the relation. This applies to the relation when the cardinality |
|
175 of subject->relation->object is 0..1 (`?`) or 1..1 (`1`) |
|
176 |
|
177 * `symetric` : boolean indication that the relation is symetrical, which |
|
178 means `X relation Y` implies `Y relation X` |
|
179 |
|
180 In the case of simultaneous relations definitions, `subject` and `object` |
|
181 can both be equal to the value of the first argument of `SubjectRelation` |
|
182 and `ObjectRelation`. |
|
183 |
|
184 When a relation is not inlined and not symetrical, and it does not require |
|
185 specific permissions, its definition (by using `SubjectRelation` and |
|
186 `ObjectRelation`) is all we need. |
|
187 |
|
188 |
|
189 The security model |
|
190 ------------------ |
|
191 |
|
192 Le modèle de sécurité de CubicWeb est un modèle fondé sur des `Access |
|
193 Control List`. Les notions sont les suivantes : |
|
194 |
|
195 * utilisateurs et groupes d'utilisateurs |
|
196 * un utilisateur appartient à au moins un groupe |
|
197 * droits (lire, modifier, créer, supprimer) |
|
198 * les droits sont attribués aux groupes (et non aux utilisateurs) |
|
199 |
|
200 Pour CubicWeb plus spécifiquement : |
|
201 |
|
202 * on associe les droits au niveau des schemas d'entites / relations |
|
203 |
|
204 * pour chaque type d'entité, on distingue les droits de lecture, |
|
205 ajout, modification et suppression |
|
206 |
|
207 * pour chaque type de relation, on distingue les droits de lecture, |
|
208 ajout et suppression (on ne peut pas modifer une relation) |
|
209 |
|
210 * les groupes de base sont : Administrateurs, Utilisateurs, Invités |
|
211 |
|
212 * les utilisateurs font par défaut parti du groupe Utilisateurs |
|
213 |
|
214 * on a un groupe virtuel "Utilisateurs Propriétaires", auquel on peut |
|
215 associer uniquement les droits de suppression et de modification |
|
216 |
|
217 * on ne peut pas mettre d'utilisateurs dans ce groupe, ils y sont |
|
218 ajoutés implicitement dans le contexte des objets dont ils sont |
|
219 propriétaires |
|
220 |
|
221 * les droits de ce groupe ne sont vérifiés que sur |
|
222 modification / suppression si tous les autres groupes auxquels |
|
223 l'utilisateur appartient se sont vu interdir l'accès |
|
224 |
|
225 |
|
226 Permissions definition |
|
227 `````````````````````` |
|
228 |
|
229 Define permissions is set through to the attribute `permissions` of entities and |
|
230 relations types. It defines a dictionnary where the keys are the access types |
|
231 (action), and the values are the authorized groups or expressions. |
|
232 |
|
233 For an entity type, the possible actions are `read`, `add`, `update` and |
|
234 `delete`. |
|
235 |
|
236 For a relation type, the possible actions are `read`, `add`, and `delete`. |
|
237 |
|
238 For each access type, a tuple indicates the name of the authorized groups and/or |
|
239 one or multiple RQL expressions to satisfy to grant access. The access is |
|
240 provided once the user is in the listed groups or one of the RQL condition is |
|
241 satisfied. |
|
242 |
|
243 The standard groups are : |
|
244 |
|
245 * `guests` |
|
246 |
|
247 * `users` |
|
248 |
|
249 * `managers` |
|
250 |
|
251 * `owners` : virtual group corresponding to the entity's owner. |
|
252 This can only be used for the actions `update` and `delete` of an entity |
|
253 type. |
|
254 |
|
255 It is also possible to use specific groups if they are defined in the precreate |
|
256 of the cube (``migration/precreate.py``). |
|
257 |
|
258 |
|
259 Use of RQL expression for writing rights |
|
260 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
261 It is possible to define RQL expression to provide update permission |
|
262 (`add`, `delete` and `update`) on relation and entity types. |
|
263 |
|
264 RQL expression for entity type permission : |
|
265 |
|
266 * you have to use the class `ERQLExpression` |
|
267 |
|
268 * the used expression corresponds to the WHERE statement of an RQL query |
|
269 |
|
270 * in this expression, the variables X and U are pre-defined references |
|
271 respectively on the current entity (on which the action is verified) and |
|
272 on the user who send the request |
|
273 |
|
274 * it is possible to use, in this expression, a special relation |
|
275 "has_<ACTION>_permission" where the subject is the user and the |
|
276 object is a any variable, meaning that the user needs to have |
|
277 permission to execute the action <ACTION> on the entities related |
|
278 to this variable |
|
279 |
|
280 For RQL expressions on a relation type, the principles are the same except |
|
281 for the following : |
|
282 |
|
283 * you have to use the class `RQLExpression` in the case of a non-final relation |
|
284 |
|
285 * in the expression, the variables S, O and U are pre-defined references |
|
286 to respectively the subject and the object of the current relation (on |
|
287 which the action is being verified) and the user who executed the query |
|
288 |
|
289 * we can also defined rights on attributes of an entity (non-final relation), |
|
290 knowing that : |
|
291 |
|
292 - to defines RQL expression, we have to use the class `ERQLExpression` |
|
293 in which X represents the entity the attribute belongs to |
|
294 |
|
295 - the permissions `add` and `delete` are equivalent. Only `add`/`read` |
|
296 are actually taken in consideration. |
|
297 |
|
298 In addition to that the entity type `EPermission` from the standard library |
|
299 allow to build very complex and dynamic security architecture. The schema of |
|
300 this entity type is as follow : :: |
|
301 |
|
302 class EPermission(MetaEntityType): |
|
303 """entity type that may be used to construct some advanced security configuration |
|
304 """ |
|
305 name = String(required=True, indexed=True, internationalizable=True, maxsize=100) |
|
306 require_group = SubjectRelation('EGroup', cardinality='+*', |
|
307 description=_('groups to which the permission is granted')) |
|
308 require_state = SubjectRelation('State', |
|
309 description=_("entity'state in which the permission is applyable")) |
|
310 # can be used on any entity |
|
311 require_permission = ObjectRelation('**', cardinality='*1', composite='subject', |
|
312 description=_("link a permission to the entity. This " |
|
313 "permission should be used in the security " |
|
314 "definition of the entity's type to be useful.")) |
|
315 |
|
316 |
|
317 Example of configuration :: |
|
318 |
|
319 |
|
320 ... |
|
321 |
|
322 class Version(EntityType): |
|
323 """a version is defining the content of a particular project's release""" |
|
324 |
|
325 permissions = {'read': ('managers', 'users', 'guests',), |
|
326 'update': ('managers', 'logilab', 'owners',), |
|
327 'delete': ('managers', ), |
|
328 'add': ('managers', 'logilab', |
|
329 ERQLExpression('X version_of PROJ, U in_group G,' |
|
330 'PROJ require_permission P, P name "add_version",' |
|
331 'P require_group G'),)} |
|
332 |
|
333 ... |
|
334 |
|
335 class version_of(RelationType): |
|
336 """link a version to its project. A version is necessarily linked to one and only one project. |
|
337 """ |
|
338 permissions = {'read': ('managers', 'users', 'guests',), |
|
339 'delete': ('managers', ), |
|
340 'add': ('managers', 'logilab', |
|
341 RRQLExpression('O require_permission P, P name "add_version",' |
|
342 'U in_group G, P require_group G'),) |
|
343 } |
|
344 inlined = True |
|
345 |
|
346 This configuration indicates that an entity `EPermission` named |
|
347 "add_version" can be associated to a project and provides rights to create |
|
348 new versions on this project to specific groups. It is important to notice that : |
|
349 |
|
350 * in such case, we have to protect both the entity type "Version" and the relation |
|
351 associating a version to a project ("version_of") |
|
352 |
|
353 * because of the genricity of the entity type `EPermission`, we have to execute |
|
354 a unification with the groups and/or the states if necessary in the expression |
|
355 ("U in_group G, P require_group G" in the above example) |
|
356 |
|
357 Use of RQL expression for reading rights |
|
358 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
359 |
|
360 The principles are the same but with the following restrictions : |
|
361 |
|
362 * we can not use `RRQLExpression` on relation types for reading |
|
363 |
|
364 * special relations "has_<ACTION>_permission" can not be used |
|
365 |
|
366 |
|
367 Note on the use of RQL expression for `add` permission |
|
368 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
369 Potentially, the use of an RQL expression to add an entity or a relation |
|
370 can cause problems for the user interface, because if the expression uses |
|
371 the entity or the relation to create, then we are not able to verify the |
|
372 permissions before we actually add the entity (please note that this is |
|
373 not a problem for the RQL server at all, because the permissions checks are |
|
374 done after the creation). In such case, the permission check methods |
|
375 (check_perm, has_perm) can indicate that the user is not allowed to create |
|
376 this entity but can obtain the permission. |
|
377 To compensate this problem, it is usually necessary, for such case, |
|
378 to use an action that reflects the schema permissions but which enables |
|
379 to check properly the permissions so that it would show up if necessary. |