|
@@ -1,37 +1,115 @@
|
|
1
|
+# -*- coding: utf-8 -*-
|
1
|
2
|
import typing
|
|
3
|
+
|
|
4
|
+from json.decoder import JSONDecodeError
|
|
5
|
+from sqlalchemy.orm.exc import NoResultFound
|
|
6
|
+
|
|
7
|
+from pyramid.request import Request
|
2
|
8
|
from pyramid.security import ALL_PERMISSIONS
|
3
|
9
|
from pyramid.security import Allow
|
4
|
|
-from pyramid.security import Authenticated
|
5
|
|
-from tracim.lib.core.user import UserApi
|
|
10
|
+from pyramid.security import unauthenticated_userid
|
|
11
|
+
|
6
|
12
|
from tracim.models.auth import Group
|
|
13
|
+from tracim.models.auth import User
|
|
14
|
+from tracim.models.data import Workspace
|
|
15
|
+from tracim.models.data import UserRoleInWorkspace
|
|
16
|
+from tracim.lib.core.user import UserApi
|
7
|
17
|
from tracim.lib.core.workspace import WorkspaceApi
|
|
18
|
+from tracim.lib.core.userworkspace import RoleApi
|
8
|
19
|
|
9
|
20
|
# INFO - G.M - 06-04-2018 - Auth for pyramid
|
10
|
21
|
# based on this tutorial : https://docs.pylonsproject.org/projects/pyramid-cookbook/en/latest/auth/basic.html # nopep8
|
|
22
|
+BASIC_AUTH_WEBUI_REALM = "tracim"
|
11
|
23
|
|
|
24
|
+# Global Permissions
|
|
25
|
+ADMIN_PERM = 'admin'
|
|
26
|
+MANAGE_GLOBAL_PERM = 'manage_global'
|
|
27
|
+USER_PERM = 'user'
|
|
28
|
+# Workspace-specific permission
|
|
29
|
+READ_PERM = 'read'
|
|
30
|
+CONTRIBUTE_PERM = 'contribute'
|
|
31
|
+MANAGE_CONTENT_PERM = 'manage_content'
|
|
32
|
+MANAGE_WORKSPACE_PERM = 'manage_workspace'
|
12
|
33
|
|
13
|
|
-def check_credentials(username, password, request) -> typing.Optional[dict]:
|
14
|
|
- permissions = None
|
|
34
|
+
|
|
35
|
+def get_user(request: Request) -> typing.Optional[User]:
|
|
36
|
+ """
|
|
37
|
+ Get current pyramid user from request
|
|
38
|
+ :param request: pyramid request
|
|
39
|
+ :return:
|
|
40
|
+ """
|
15
|
41
|
app_config = request.registry.settings['CFG']
|
16
|
42
|
uapi = UserApi(None, session=request.dbsession, config=app_config)
|
|
43
|
+ user = None
|
17
|
44
|
try:
|
18
|
|
- user = uapi.get_one_by_email(username)
|
19
|
|
- if user.validate_password(password):
|
20
|
|
- permissions = []
|
21
|
|
- for group in user.groups:
|
22
|
|
- permissions.append(group.group_name)
|
23
|
|
- # TODO - G.M - 06-04-2018 - Add workspace specific permission ?
|
24
|
|
- # TODO - G.M - 06-04-2018 - Better catch for exception of bad password, bad
|
25
|
|
- # user
|
26
|
|
- except:
|
|
45
|
+ login = unauthenticated_userid(request)
|
|
46
|
+ user = uapi.get_one_by_email(login)
|
|
47
|
+ except NoResultFound:
|
27
|
48
|
pass
|
|
49
|
+ return user
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+def get_workspace(request: Request) -> typing.Optional[Workspace]:
|
|
53
|
+ """
|
|
54
|
+ Get current workspace from request
|
|
55
|
+ :param request: pyramid request
|
|
56
|
+ :return:
|
|
57
|
+ """
|
|
58
|
+ workspace = None
|
|
59
|
+ try:
|
|
60
|
+ if 'workspace_id' not in request.json_body:
|
|
61
|
+ return None
|
|
62
|
+ workspace_id = request.json_body['workspace_id']
|
|
63
|
+ wapi = WorkspaceApi(current_user=None, session=request.dbsession)
|
|
64
|
+ workspace = wapi.get_one(workspace_id)
|
|
65
|
+ except JSONDecodeError:
|
|
66
|
+ pass
|
|
67
|
+ except NoResultFound:
|
|
68
|
+ pass
|
|
69
|
+ return workspace
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+def check_credentials(
|
|
73
|
+ login: str,
|
|
74
|
+ cleartext_password: str,
|
|
75
|
+ request: Request
|
|
76
|
+) -> typing.Optional[list]:
|
|
77
|
+ """
|
|
78
|
+ Check credential for pyramid basic_auth, checks also for
|
|
79
|
+ global and Workspace related permissions.
|
|
80
|
+ :param login: login of user
|
|
81
|
+ :param cleartext_password: user password in cleartext
|
|
82
|
+ :param request: Pyramid request
|
|
83
|
+ :return: None if auth failed, list of permissions if auth succeed
|
|
84
|
+ """
|
|
85
|
+ user = get_user(request)
|
|
86
|
+
|
|
87
|
+ # Do not accept invalid user
|
|
88
|
+ if not user \
|
|
89
|
+ or user.email != login \
|
|
90
|
+ or not user.validate_password(cleartext_password):
|
|
91
|
+ return None
|
|
92
|
+ permissions = []
|
|
93
|
+
|
|
94
|
+ # Global groups
|
|
95
|
+ for group in user.groups:
|
|
96
|
+ permissions.append(group.group_id)
|
|
97
|
+
|
|
98
|
+ # Current workspace related group
|
|
99
|
+ workspace = get_workspace(request)
|
|
100
|
+ if workspace:
|
|
101
|
+ roleapi = RoleApi(current_user=user, session=request.dbsession)
|
|
102
|
+ role = roleapi.get_one(
|
|
103
|
+ user_id=user.user_id,
|
|
104
|
+ workspace_id=workspace.workspace_id,
|
|
105
|
+ )
|
|
106
|
+ permissions.append(role)
|
|
107
|
+
|
28
|
108
|
return permissions
|
29
|
109
|
|
30
|
110
|
|
31
|
|
-class Root:
|
32
|
|
- # root
|
33
|
|
- __acl__ = (
|
34
|
|
- (Allow, Group.TIM_ADMIN_GROUPNAME, ALL_PERMISSIONS),
|
35
|
|
- (Allow, Group.TIM_MANAGER_GROUPNAME, 'manager'),
|
36
|
|
- (Allow, Group.TIM_USER_GROUPNAME, 'user'),
|
37
|
|
- )
|
|
111
|
+class Root(object):
|
|
112
|
+ """
|
|
113
|
+ Root of all Pyramid requests, used to store global acl
|
|
114
|
+ """
|
|
115
|
+ __acl__ = ()
|