Show last authors
1 = Row level security =
2
3 Row level security is a way to enable security on a per instance basis.
4
5 Use cases are:
6
7 - user A has right to see record Y, but not to update it
8 - records X, Y, Z are visible only to users A and B
9
10
11 == Architecture ==
12
13 Row level security is controlled by an internal object call "AccessList". An access list is:
14
15 - one or more users
16 - one or more groups
17 - one or more security profile
18
19 An access list is a fairly flexible way to tell if a user has the right to do something on a given entity instance.
20
21
22 A user "has access" to an access list if:
23
24 - he belongs to the list of "users" of the access list
25 - he belongs to a group (as in sysUserGroup) which is in the list of groups of the access list
26 - he has access to a security profile of the access list.
27
28
29 For example:
30
31 Access list 554543 contains:
32
33 - John Doe and Paul Smith
34 - The HR user group
35
36 John Doe, Paul Smith and all the folks from the HR group have "access" to 554543
37
38
39 == Access list usage ==
40
41
42 AccessList may be used in 3 different ways:
43
44 1 - in the sysRead property of every entity.
45
46 Every entity has a sysRead property. This property may be programmatically filled (through a script for example).
47 When the persistence engine reads an entity instance (or row), and the sysRead is not null, then the persistence service will execute a check to make sure that the user has access to the access list id that is in sysRead. If not, a "no access" entity will be returned instead of the actual entity, resulting into the impossibility for the user to access any property of the "protected" entity.
48
49
50 Warning:
51 every attempt to read a property on a no access entity will return null.
52
53
54
55 2 - in the sysWrite property of every entity.
56
57 Every entity has a sysWrite id that may be filled as the id of a sysAccessList. In that case, the entity will be protected against writes (by the persistence service) resulting into security exceptions.
58
59
60 NOTE: For those two use cases (sysRead and sysWrite), the protection is a last barrier protection, resulting into security errors. You should build your user actions to avoid gestating into those (for example by restricting the list of object a user may see by filtering).
61
62
63 3 - by using the System.User.hasListAccess method in visibility scripts of user actions or properties.
64
65 if you have created (calculated) an access list object and stored the reference to the access list or the access list id in an entity, you may use System.User.hasListAccess to check if the current user has "access" to your access list.
66
67
68 == Creating access lists ==
69
70 Access lists can only be created programatically through scripts using the "AccessList" object:
71
72 {{code language="JavaScript"}}
73 var acl = new AccessList();
74
75 acl.addUser(user.sysId);
76 acl.addGroup(grp.sysId);
77
78 var aclId = acl.getSysId(); // retrieve the aclId and stores it
79
80 data.myAccessControlId = aclId
81 {{/code}}
82
83
84 == Why access list are only manipulated through code? ==
85
86 AccessList are designed to be cached in the system (actually the AccessList sysId is cached) and the platform maintains for each logged user a map of the access lists that match and a map of the ones that do not match with this user.
87 Therefore, AccessList are checked on a first check basis only, and subsequent checks are extremely fast. The first one may be slow, and that why we try to maintain a cache.
88
89 In order to limit the memory foot print and make that cache the most efficient as possible, the platform maintains a hash code of the access list and access lists with the same definition are shared.
90
91 So for example 2 access list containing only "Paul Smith" will be merged into one, and only one sysId will be put into the user access list cache.
92
93 This merging mechanism is controlled by the underlying AccessList service. That why it is required to do that by code.
94
95
96
97
98 == A concrete example ==
99
100 Let's imagine an entity called "MyRequest".
101 Let's have another entity called a "Branch" (as in company branch office), and the "Branch" has a list of "Approvers".
102
103 "MyRequest" has a "reference" to a "Branch", and we want only the "Approvers" of the Branch of the Request to be able to "approve".
104
105
106 Solution:
107
108 1 - Create the Branch "entity" with the list of "Approvers" are a one to many ref to "rqEmployee".
109 In the Branch entity, add an AccessList id (as a string) called "ApproversAccessId".
110
111 2 - in the Save operation of the branch entity, we calculate the access list Id for once:
112
113 {{code language="JavaScript"}}
114 var acl = new AccessList();
115 var approvers = data.pfxApprover;
116 for(var i=0; i<approvers.length; i++) {
117 acl.addUser(approvers[i].sysId);
118 }
119
120 // retrieve the access list id
121 data.pfxApproversAccessId = acl.getSysId();
122 {{/code}}
123
124 3 - in the MyRequest entity "approve" user action, we add the visibility script based on the Branch property:
125
126 {{code language="JavaScript"}}
127 pfxBranch != null && System.User.hasListAccess(pfxBranch.pfxApproversAccessId)
128 {{/code}}
This wiki is licensed under a Creative Commons 2.0 license
XWiki Enterprise 9.11.5 - Documentation