Passed
Push — master ( 4a8725...effdde )
by Jordi
04:37
created

bika.lims.api.security.manage_permission_for()   A

Complexity

Conditions 5

Size

Total Lines 28
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 14
dl 0
loc 28
rs 9.2333
c 0
b 0
f 0
cc 5
nop 4
1
# -*- coding: utf-8 -*-
2
#
3
# This file is part of SENAITE.CORE
4
#
5
# Copyright 2018 by it's authors.
6
# Some rights reserved. See LICENSE.rst, CONTRIBUTORS.rst.
7
8
from AccessControl import getSecurityManager
9
from AccessControl.Permission import Permission
10
from bika.lims import api
11
from bika.lims.api.user import get_user
12
from bika.lims.api.user import get_user_id
13
14
15
def get_security_manager():
16
    """Get a security manager for the current thread
17
18
    See `AccessControl.SecurityManagement.getSecurityManager`
19
20
    :returns: Security manager for the current thread
21
    """
22
    return getSecurityManager()
23
24
25
def get_possible_permissions_for(brain_or_object):
26
    """Get the possible permissions for given the object
27
28
    See `IRoleManager.possible_permissions`
29
30
    :param brain_or_object: Catalog brain or object
31
    :returns: List of permissions
32
    """
33
    obj = api.get_object(brain_or_object)
34
    return obj.possible_permissions()
35
36
37
def get_mapped_permissions_for(brain_or_object):
38
    """Get the mapped permissions for the given object
39
40
    A mapped permission is one that is used in the object.
41
42
    Each permission string, e.g. "Field: Edit Remarks" is translated by the
43
    function `AccessControl.Permission.pname` to a valid attribute name:
44
45
    >>> AccessControl.Permission import pname
46
    >>> pname("Field: Edit Result")
47
    _Field__Edit_Result_Permission
48
49
    This attribute is looked up in the object by `getPermissionMapping`:
50
51
    >>> from AccessControl.PermissionMapping import getPermissionMapping
52
    >>> getPermissionMapping("Field: Edit Result", wrapper)
53
    ("Manager", "Sampler")
54
55
    Therefore, only those permissions which have roles mapped on the object
56
    or by objects within the acquisition chain are considered.
57
58
    Code extracted from `IRoleManager.manage_getUserRolesAndPermissions`
59
60
    :param brain_or_object: Catalog brain or object
61
    :returns: List of permissions
62
    """
63
    obj = api.get_object(brain_or_object)
64
    mapping = obj.manage_getPermissionMapping()
65
    return map(lambda item: item["permission_name"], mapping)
66
67
68
def get_allowed_permissions_for(brain_or_object, user=None):
69
    """Get the allowed permissions for the given object
70
71
    Code extracted from `IRoleManager.manage_getUserRolesAndPermissions`
72
73
    :param brain_or_object: Catalog brain or object
74
    :param user: A user ID, user object or None (for the current user)
75
    :returns: List of allowed permissions
76
    """
77
    allowed = []
78
    user = get_user(user)
79
    obj = api.get_object(brain_or_object)
80
    for permission in get_mapped_permissions_for(brain_or_object):
81
        if user.has_permission(permission, obj):
82
            allowed.append(permission)
83
    return allowed
84
85
86
def get_disallowed_permissions_for(brain_or_object, user=None):
87
    """Get the disallowed permissions for the given object
88
89
    Code extracted from `IRoleManager.manage_getUserRolesAndPermissions`
90
91
    :brain_or_object: Catalog brain or object
92
    :param user: A user ID, user object or None (for the current user)
93
    :returns: List of disallowed permissions
94
    """
95
    disallowed = []
96
    user = get_user(user)
97
    obj = api.get_object(brain_or_object)
98
    for permission in get_mapped_permissions_for(brain_or_object):
99
        if not user.has_permission(permission, obj):
100
            disallowed.append(permission)
101
    return disallowed
102
103
104
def check_permission(permission, brain_or_object):
105
    """Check whether the security context allows the given permission on
106
       the given brain or object.
107
108
    N.B.: This includes also acquired permissions
109
110
    :param permission: Permission name
111
    :brain_or_object: Catalog brain or object
112
    :returns: True if the permission is granted
113
    """
114
    sm = get_security_manager()
115
    obj = api.get_object(brain_or_object)
116
    return sm.checkPermission(permission, obj) == 1
117
118
119
def get_permissions_for_role(role, brain_or_object):
120
    """Return the permissions of the role which are granted on the object
121
122
    Code extracted from `IRoleManager.permissionsOfRole`
123
124
    :param role: The role to check the permission
125
    :param brain_or_object: Catalog brain or object
126
    :returns: List of permissions of the role
127
    """
128
    obj = api.get_object(brain_or_object)
129
130
    # Raise an error if the role is invalid
131
    valid_roles = get_valid_roles_for(obj)
132
    if role not in valid_roles:
133
        raise ValueError("The Role '{}' is invalid.".format(role))
134
135
    out = []
136
    for item in obj.ac_inherited_permissions(1):
137
        name, value = item[:2]
138
        # Permission maps a named permission to a set of attribute names
139
        permission = Permission(name, value, obj)
140
        if role in permission.getRoles():
141
            out.append(name)
142
    return out
143
144
145
def get_roles_for_permission(permission, brain_or_object):
146
    """Return the roles of the permission that is granted on the object
147
148
    Code extracted from `IRoleManager.rolesOfPermission`
149
150
    :param permission: The permission to get the roles
151
    :param brain_or_object: Catalog brain or object
152
    :returns: List of roles having the permission
153
    """
154
    obj = api.get_object(brain_or_object)
155
    valid_roles = get_valid_roles_for(obj)
156
    for item in obj.ac_inherited_permissions(1):
157
        name, value = item[:2]
158
        # found the requested permission
159
        if name == permission:
160
            # Permission maps a named permission to a set of attribute names
161
            permission = Permission(name, value, obj)
162
            roles = permission.getRoles()
163
            # return only valid roles that have the permission granted
164
            return filter(lambda r: r in valid_roles, roles)
165
    # Raise an error if the permission is invalid
166
    raise ValueError("The permission {} is invalid.".format(permission))
167
168
169
def get_roles(user=None):
170
    """Get the global defined roles of the user
171
172
    Code extracted from `IRoleManager.manage_getUserRolesAndPermissions`
173
174
    :param user: A user ID, user object or None (for the current user)
175
    :returns: List of global granted roles
176
    """
177
    user = get_user(user)
178
    return sorted(user.getRoles())
179
180
181
def get_local_roles_for(brain_or_object, user=None):
182
    """Get the local defined roles on the context
183
184
    Code extracted from `IRoleManager.get_local_roles_for_userid`
185
186
    :param brain_or_object: Catalog brain or object
187
    :param user: A user ID, user object or None (for the current user)
188
    :returns: List of granted local roles on the given object
189
    """
190
    user_id = get_user_id(user)
191
    obj = api.get_object(brain_or_object)
192
    return sorted(obj.get_local_roles_for_userid(user_id))
193
194
195
def grant_local_roles_for(brain_or_object, roles, user=None):
196
    """Grant local roles for the object
197
198
    Code extracted from `IRoleManager.manage_addLocalRoles`
199
200
    :param brain_or_object: Catalog brain or object
201
    :param user: A user ID, user object or None (for the current user)
202
    :param roles: The local roles to grant for the current user
203
    """
204
    user_id = get_user_id(user)
205
    obj = api.get_object(brain_or_object)
206
207
    if isinstance(roles, basestring):
208
        roles = [roles]
209
210
    obj.manage_addLocalRoles(user_id, roles)
211
    return get_local_roles_for(brain_or_object)
212
213
214
def revoke_local_roles_for(brain_or_object, roles, user=None):
215
    """Revoke local roles for the object
216
217
    Code extracted from `IRoleManager.manage_setLocalRoles`
218
219
    :param brain_or_object: Catalog brain or object
220
    :param roles: The local roles to revoke for the current user
221
    :param user: A user ID, user object or None (for the current user)
222
    """
223
    user_id = get_user_id(user)
224
    obj = api.get_object(brain_or_object)
225
    valid_roles = get_valid_roles_for(obj)
226
    to_grant = list(get_local_roles_for(obj))
227
228
    if isinstance(roles, basestring):
229
        roles = [roles]
230
231
    for role in roles:
232
        if role in to_grant:
233
            if role not in valid_roles:
234
                raise ValueError("The Role '{}' is invalid.".format(role))
235
            # Remove the role
236
            to_grant.remove(role)
237
238
    if len(to_grant) > 0:
239
        obj.manage_setLocalRoles(user_id, to_grant)
240
    else:
241
        obj.manage_delLocalRoles([user_id])
242
    return get_local_roles_for(brain_or_object)
243
244
245
def get_valid_roles_for(brain_or_object):
246
    """Get valid roles from the acquisition chain
247
248
    Code extracted from `IRoleManager`
249
250
    Traverses up the acquisition chain (`obj.__parent__`) and gathers all
251
    `obj.__ac__roles__` tuples
252
253
    :brain_or_object: Catalog brain or object
254
    :returns: List of valid roles
255
    """
256
    obj = api.get_object(brain_or_object)
257
    return sorted(obj.valid_roles())
258
259
260 View Code Duplication
def grant_permission_for(brain_or_object, permission, roles, acquire=0):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
261
    """Grant the permission for the object to the defined roles
262
263
    Code extracted from `IRoleManager.manage_permission`
264
265
    :param brain_or_object: Catalog brain or object
266
    :param permission: The permission to be granted
267
    :param roles: The roles the permission to be granted to
268
    :param acquire: Flag to acquire the permission
269
    """
270
    obj = api.get_object(brain_or_object)
271
    valid_roles = get_valid_roles_for(obj)
272
    to_grant = list(get_roles_for_permission(permission, obj))
273
274
    if isinstance(roles, basestring):
275
        roles = [roles]
276
277
    for role in roles:
278
        if role not in to_grant:
279
            if role not in valid_roles:
280
                raise ValueError("The Role '{}' is invalid.".format(role))
281
            # Append the role
282
            to_grant.append(role)
283
284
    manage_permission_for(obj, permission, to_grant, acquire=acquire)
285
286
287 View Code Duplication
def revoke_permission_for(brain_or_object, permission, roles, acquire=0):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
288
    """Revoke the permission for the object to the defined roles
289
290
    Code extracted from `IRoleManager.manage_permission`
291
292
    :param brain_or_object: Catalog brain or object
293
    :param permission: The permission to be granted
294
    :param roles: The roles the permission to be granted to
295
    :param acquire: Flag to acquire the permission
296
    """
297
    obj = api.get_object(brain_or_object)
298
    valid_roles = get_valid_roles_for(obj)
299
    to_grant = list(get_roles_for_permission(permission, obj))
300
301
    if isinstance(roles, basestring):
302
        roles = [roles]
303
304
    for role in roles:
305
        if role in to_grant:
306
            if role not in valid_roles:
307
                raise ValueError("The Role '{}' is invalid.".format(role))
308
            # Remove the role
309
            to_grant.remove(role)
310
311
    manage_permission_for(obj, permission, to_grant, acquire=acquire)
312
313
314
def manage_permission_for(brain_or_object, permission, roles, acquire=0):
315
    """Change the settings for the given permission.
316
317
    Code extracted from `IRoleManager.manage_permission`
318
319
    :param brain_or_object: Catalog brain or object
320
    :param permission: The permission to be granted
321
    :param roles: The roles the permission to be granted to
322
    :param acquire: Flag to acquire the permission
323
    """
324
    obj = api.get_object(brain_or_object)
325
326
    if isinstance(roles, basestring):
327
        roles = [roles]
328
329
    for item in obj.ac_inherited_permissions(1):
330
        name, value = item[:2]
331
        if name == permission:
332
            permission = Permission(name, value, obj)
333
            if acquire:
334
                roles = list(roles)
335
            else:
336
                roles = tuple(roles)
337
            permission.setRoles(roles)
338
            return
339
340
    # Raise an error if the permission is invalid
341
    raise ValueError("The permission {} is invalid.".format(permission))
342