##// END OF EJS Templates
core: added user-notice logic to push notice messages....
ergo -
r4300:8f93504d default
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
@@ -0,0 +1,35 b''
1 # -*- coding: utf-8 -*-
2
3 import logging
4 from sqlalchemy import *
5
6 from alembic.migration import MigrationContext
7 from alembic.operations import Operations
8 from sqlalchemy import BigInteger
9
10 from rhodecode.lib.dbmigrate.versions import _reset_base
11 from rhodecode.model import init_model_encryption
12
13
14 log = logging.getLogger(__name__)
15
16
17 def upgrade(migrate_engine):
18 """
19 Upgrade operations go here.
20 Don't create your own engine; bind migrate_engine to your metadata
21 """
22 _reset_base(migrate_engine)
23 from rhodecode.lib.dbmigrate.schema import db_4_19_0_0 as db
24
25 init_model_encryption(db)
26 db.UserNotice().__table__.create()
27
28
29 def downgrade(migrate_engine):
30 meta = MetaData()
31 meta.bind = migrate_engine
32
33
34 def fixups(models, _SESSION):
35 pass
@@ -1,57 +1,57 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2019 RhodeCode GmbH
3 # Copyright (C) 2010-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import os
21 import os
22 import sys
22 import sys
23 import platform
23 import platform
24
24
25 VERSION = tuple(open(os.path.join(
25 VERSION = tuple(open(os.path.join(
26 os.path.dirname(__file__), 'VERSION')).read().split('.'))
26 os.path.dirname(__file__), 'VERSION')).read().split('.'))
27
27
28 BACKENDS = {
28 BACKENDS = {
29 'hg': 'Mercurial repository',
29 'hg': 'Mercurial repository',
30 'git': 'Git repository',
30 'git': 'Git repository',
31 'svn': 'Subversion repository',
31 'svn': 'Subversion repository',
32 }
32 }
33
33
34 CELERY_ENABLED = False
34 CELERY_ENABLED = False
35 CELERY_EAGER = False
35 CELERY_EAGER = False
36
36
37 # link to config for pyramid
37 # link to config for pyramid
38 CONFIG = {}
38 CONFIG = {}
39
39
40 # Populated with the settings dictionary from application init in
40 # Populated with the settings dictionary from application init in
41 # rhodecode.conf.environment.load_pyramid_environment
41 # rhodecode.conf.environment.load_pyramid_environment
42 PYRAMID_SETTINGS = {}
42 PYRAMID_SETTINGS = {}
43
43
44 # Linked module for extensions
44 # Linked module for extensions
45 EXTENSIONS = {}
45 EXTENSIONS = {}
46
46
47 __version__ = ('.'.join((str(each) for each in VERSION[:3])))
47 __version__ = ('.'.join((str(each) for each in VERSION[:3])))
48 __dbversion__ = 104 # defines current db version for migrations
48 __dbversion__ = 105 # defines current db version for migrations
49 __platform__ = platform.system()
49 __platform__ = platform.system()
50 __license__ = 'AGPLv3, and Commercial License'
50 __license__ = 'AGPLv3, and Commercial License'
51 __author__ = 'RhodeCode GmbH'
51 __author__ = 'RhodeCode GmbH'
52 __url__ = 'https://code.rhodecode.com'
52 __url__ = 'https://code.rhodecode.com'
53
53
54 is_windows = __platform__ in ['Windows']
54 is_windows = __platform__ in ['Windows']
55 is_unix = not is_windows
55 is_unix = not is_windows
56 is_test = False
56 is_test = False
57 disable_error_handler = False
57 disable_error_handler = False
@@ -1,457 +1,462 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2019 RhodeCode GmbH
3 # Copyright (C) 2016-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21
21
22 from rhodecode.apps._base import ADMIN_PREFIX
22 from rhodecode.apps._base import ADMIN_PREFIX
23
23
24
24
25 def admin_routes(config):
25 def admin_routes(config):
26 """
26 """
27 Admin prefixed routes
27 Admin prefixed routes
28 """
28 """
29
30 config.add_route(
29 config.add_route(
31 name='admin_audit_logs',
30 name='admin_audit_logs',
32 pattern='/audit_logs')
31 pattern='/audit_logs')
33
32
34 config.add_route(
33 config.add_route(
35 name='admin_audit_log_entry',
34 name='admin_audit_log_entry',
36 pattern='/audit_logs/{audit_log_id}')
35 pattern='/audit_logs/{audit_log_id}')
37
36
38 config.add_route(
37 config.add_route(
39 name='pull_requests_global_0', # backward compat
38 name='pull_requests_global_0', # backward compat
40 pattern='/pull_requests/{pull_request_id:\d+}')
39 pattern='/pull_requests/{pull_request_id:\d+}')
41 config.add_route(
40 config.add_route(
42 name='pull_requests_global_1', # backward compat
41 name='pull_requests_global_1', # backward compat
43 pattern='/pull-requests/{pull_request_id:\d+}')
42 pattern='/pull-requests/{pull_request_id:\d+}')
44 config.add_route(
43 config.add_route(
45 name='pull_requests_global',
44 name='pull_requests_global',
46 pattern='/pull-request/{pull_request_id:\d+}')
45 pattern='/pull-request/{pull_request_id:\d+}')
47
46
48 config.add_route(
47 config.add_route(
49 name='admin_settings_open_source',
48 name='admin_settings_open_source',
50 pattern='/settings/open_source')
49 pattern='/settings/open_source')
51 config.add_route(
50 config.add_route(
52 name='admin_settings_vcs_svn_generate_cfg',
51 name='admin_settings_vcs_svn_generate_cfg',
53 pattern='/settings/vcs/svn_generate_cfg')
52 pattern='/settings/vcs/svn_generate_cfg')
54
53
55 config.add_route(
54 config.add_route(
56 name='admin_settings_system',
55 name='admin_settings_system',
57 pattern='/settings/system')
56 pattern='/settings/system')
58 config.add_route(
57 config.add_route(
59 name='admin_settings_system_update',
58 name='admin_settings_system_update',
60 pattern='/settings/system/updates')
59 pattern='/settings/system/updates')
61
60
62 config.add_route(
61 config.add_route(
63 name='admin_settings_exception_tracker',
62 name='admin_settings_exception_tracker',
64 pattern='/settings/exceptions')
63 pattern='/settings/exceptions')
65 config.add_route(
64 config.add_route(
66 name='admin_settings_exception_tracker_delete_all',
65 name='admin_settings_exception_tracker_delete_all',
67 pattern='/settings/exceptions/delete')
66 pattern='/settings/exceptions/delete')
68 config.add_route(
67 config.add_route(
69 name='admin_settings_exception_tracker_show',
68 name='admin_settings_exception_tracker_show',
70 pattern='/settings/exceptions/{exception_id}')
69 pattern='/settings/exceptions/{exception_id}')
71 config.add_route(
70 config.add_route(
72 name='admin_settings_exception_tracker_delete',
71 name='admin_settings_exception_tracker_delete',
73 pattern='/settings/exceptions/{exception_id}/delete')
72 pattern='/settings/exceptions/{exception_id}/delete')
74
73
75 config.add_route(
74 config.add_route(
76 name='admin_settings_sessions',
75 name='admin_settings_sessions',
77 pattern='/settings/sessions')
76 pattern='/settings/sessions')
78 config.add_route(
77 config.add_route(
79 name='admin_settings_sessions_cleanup',
78 name='admin_settings_sessions_cleanup',
80 pattern='/settings/sessions/cleanup')
79 pattern='/settings/sessions/cleanup')
81
80
82 config.add_route(
81 config.add_route(
83 name='admin_settings_process_management',
82 name='admin_settings_process_management',
84 pattern='/settings/process_management')
83 pattern='/settings/process_management')
85 config.add_route(
84 config.add_route(
86 name='admin_settings_process_management_data',
85 name='admin_settings_process_management_data',
87 pattern='/settings/process_management/data')
86 pattern='/settings/process_management/data')
88 config.add_route(
87 config.add_route(
89 name='admin_settings_process_management_signal',
88 name='admin_settings_process_management_signal',
90 pattern='/settings/process_management/signal')
89 pattern='/settings/process_management/signal')
91 config.add_route(
90 config.add_route(
92 name='admin_settings_process_management_master_signal',
91 name='admin_settings_process_management_master_signal',
93 pattern='/settings/process_management/master_signal')
92 pattern='/settings/process_management/master_signal')
94
93
95 # default settings
94 # default settings
96 config.add_route(
95 config.add_route(
97 name='admin_defaults_repositories',
96 name='admin_defaults_repositories',
98 pattern='/defaults/repositories')
97 pattern='/defaults/repositories')
99 config.add_route(
98 config.add_route(
100 name='admin_defaults_repositories_update',
99 name='admin_defaults_repositories_update',
101 pattern='/defaults/repositories/update')
100 pattern='/defaults/repositories/update')
102
101
103 # admin settings
102 # admin settings
104
103
105 config.add_route(
104 config.add_route(
106 name='admin_settings',
105 name='admin_settings',
107 pattern='/settings')
106 pattern='/settings')
108 config.add_route(
107 config.add_route(
109 name='admin_settings_update',
108 name='admin_settings_update',
110 pattern='/settings/update')
109 pattern='/settings/update')
111
110
112 config.add_route(
111 config.add_route(
113 name='admin_settings_global',
112 name='admin_settings_global',
114 pattern='/settings/global')
113 pattern='/settings/global')
115 config.add_route(
114 config.add_route(
116 name='admin_settings_global_update',
115 name='admin_settings_global_update',
117 pattern='/settings/global/update')
116 pattern='/settings/global/update')
118
117
119 config.add_route(
118 config.add_route(
120 name='admin_settings_vcs',
119 name='admin_settings_vcs',
121 pattern='/settings/vcs')
120 pattern='/settings/vcs')
122 config.add_route(
121 config.add_route(
123 name='admin_settings_vcs_update',
122 name='admin_settings_vcs_update',
124 pattern='/settings/vcs/update')
123 pattern='/settings/vcs/update')
125 config.add_route(
124 config.add_route(
126 name='admin_settings_vcs_svn_pattern_delete',
125 name='admin_settings_vcs_svn_pattern_delete',
127 pattern='/settings/vcs/svn_pattern_delete')
126 pattern='/settings/vcs/svn_pattern_delete')
128
127
129 config.add_route(
128 config.add_route(
130 name='admin_settings_mapping',
129 name='admin_settings_mapping',
131 pattern='/settings/mapping')
130 pattern='/settings/mapping')
132 config.add_route(
131 config.add_route(
133 name='admin_settings_mapping_update',
132 name='admin_settings_mapping_update',
134 pattern='/settings/mapping/update')
133 pattern='/settings/mapping/update')
135
134
136 config.add_route(
135 config.add_route(
137 name='admin_settings_visual',
136 name='admin_settings_visual',
138 pattern='/settings/visual')
137 pattern='/settings/visual')
139 config.add_route(
138 config.add_route(
140 name='admin_settings_visual_update',
139 name='admin_settings_visual_update',
141 pattern='/settings/visual/update')
140 pattern='/settings/visual/update')
142
141
143 config.add_route(
142 config.add_route(
144 name='admin_settings_issuetracker',
143 name='admin_settings_issuetracker',
145 pattern='/settings/issue-tracker')
144 pattern='/settings/issue-tracker')
146 config.add_route(
145 config.add_route(
147 name='admin_settings_issuetracker_update',
146 name='admin_settings_issuetracker_update',
148 pattern='/settings/issue-tracker/update')
147 pattern='/settings/issue-tracker/update')
149 config.add_route(
148 config.add_route(
150 name='admin_settings_issuetracker_test',
149 name='admin_settings_issuetracker_test',
151 pattern='/settings/issue-tracker/test')
150 pattern='/settings/issue-tracker/test')
152 config.add_route(
151 config.add_route(
153 name='admin_settings_issuetracker_delete',
152 name='admin_settings_issuetracker_delete',
154 pattern='/settings/issue-tracker/delete')
153 pattern='/settings/issue-tracker/delete')
155
154
156 config.add_route(
155 config.add_route(
157 name='admin_settings_email',
156 name='admin_settings_email',
158 pattern='/settings/email')
157 pattern='/settings/email')
159 config.add_route(
158 config.add_route(
160 name='admin_settings_email_update',
159 name='admin_settings_email_update',
161 pattern='/settings/email/update')
160 pattern='/settings/email/update')
162
161
163 config.add_route(
162 config.add_route(
164 name='admin_settings_hooks',
163 name='admin_settings_hooks',
165 pattern='/settings/hooks')
164 pattern='/settings/hooks')
166 config.add_route(
165 config.add_route(
167 name='admin_settings_hooks_update',
166 name='admin_settings_hooks_update',
168 pattern='/settings/hooks/update')
167 pattern='/settings/hooks/update')
169 config.add_route(
168 config.add_route(
170 name='admin_settings_hooks_delete',
169 name='admin_settings_hooks_delete',
171 pattern='/settings/hooks/delete')
170 pattern='/settings/hooks/delete')
172
171
173 config.add_route(
172 config.add_route(
174 name='admin_settings_search',
173 name='admin_settings_search',
175 pattern='/settings/search')
174 pattern='/settings/search')
176
175
177 config.add_route(
176 config.add_route(
178 name='admin_settings_labs',
177 name='admin_settings_labs',
179 pattern='/settings/labs')
178 pattern='/settings/labs')
180 config.add_route(
179 config.add_route(
181 name='admin_settings_labs_update',
180 name='admin_settings_labs_update',
182 pattern='/settings/labs/update')
181 pattern='/settings/labs/update')
183
182
184 # Automation EE feature
183 # Automation EE feature
185 config.add_route(
184 config.add_route(
186 'admin_settings_automation',
185 'admin_settings_automation',
187 pattern=ADMIN_PREFIX + '/settings/automation')
186 pattern=ADMIN_PREFIX + '/settings/automation')
188
187
189 # global permissions
188 # global permissions
190
189
191 config.add_route(
190 config.add_route(
192 name='admin_permissions_application',
191 name='admin_permissions_application',
193 pattern='/permissions/application')
192 pattern='/permissions/application')
194 config.add_route(
193 config.add_route(
195 name='admin_permissions_application_update',
194 name='admin_permissions_application_update',
196 pattern='/permissions/application/update')
195 pattern='/permissions/application/update')
197
196
198 config.add_route(
197 config.add_route(
199 name='admin_permissions_global',
198 name='admin_permissions_global',
200 pattern='/permissions/global')
199 pattern='/permissions/global')
201 config.add_route(
200 config.add_route(
202 name='admin_permissions_global_update',
201 name='admin_permissions_global_update',
203 pattern='/permissions/global/update')
202 pattern='/permissions/global/update')
204
203
205 config.add_route(
204 config.add_route(
206 name='admin_permissions_object',
205 name='admin_permissions_object',
207 pattern='/permissions/object')
206 pattern='/permissions/object')
208 config.add_route(
207 config.add_route(
209 name='admin_permissions_object_update',
208 name='admin_permissions_object_update',
210 pattern='/permissions/object/update')
209 pattern='/permissions/object/update')
211
210
212 # Branch perms EE feature
211 # Branch perms EE feature
213 config.add_route(
212 config.add_route(
214 name='admin_permissions_branch',
213 name='admin_permissions_branch',
215 pattern='/permissions/branch')
214 pattern='/permissions/branch')
216
215
217 config.add_route(
216 config.add_route(
218 name='admin_permissions_ips',
217 name='admin_permissions_ips',
219 pattern='/permissions/ips')
218 pattern='/permissions/ips')
220
219
221 config.add_route(
220 config.add_route(
222 name='admin_permissions_overview',
221 name='admin_permissions_overview',
223 pattern='/permissions/overview')
222 pattern='/permissions/overview')
224
223
225 config.add_route(
224 config.add_route(
226 name='admin_permissions_auth_token_access',
225 name='admin_permissions_auth_token_access',
227 pattern='/permissions/auth_token_access')
226 pattern='/permissions/auth_token_access')
228
227
229 config.add_route(
228 config.add_route(
230 name='admin_permissions_ssh_keys',
229 name='admin_permissions_ssh_keys',
231 pattern='/permissions/ssh_keys')
230 pattern='/permissions/ssh_keys')
232 config.add_route(
231 config.add_route(
233 name='admin_permissions_ssh_keys_data',
232 name='admin_permissions_ssh_keys_data',
234 pattern='/permissions/ssh_keys/data')
233 pattern='/permissions/ssh_keys/data')
235 config.add_route(
234 config.add_route(
236 name='admin_permissions_ssh_keys_update',
235 name='admin_permissions_ssh_keys_update',
237 pattern='/permissions/ssh_keys/update')
236 pattern='/permissions/ssh_keys/update')
238
237
239 # users admin
238 # users admin
240 config.add_route(
239 config.add_route(
241 name='users',
240 name='users',
242 pattern='/users')
241 pattern='/users')
243
242
244 config.add_route(
243 config.add_route(
245 name='users_data',
244 name='users_data',
246 pattern='/users_data')
245 pattern='/users_data')
247
246
248 config.add_route(
247 config.add_route(
249 name='users_create',
248 name='users_create',
250 pattern='/users/create')
249 pattern='/users/create')
251
250
252 config.add_route(
251 config.add_route(
253 name='users_new',
252 name='users_new',
254 pattern='/users/new')
253 pattern='/users/new')
255
254
256 # user management
255 # user management
257 config.add_route(
256 config.add_route(
258 name='user_edit',
257 name='user_edit',
259 pattern='/users/{user_id:\d+}/edit',
258 pattern='/users/{user_id:\d+}/edit',
260 user_route=True)
259 user_route=True)
261 config.add_route(
260 config.add_route(
262 name='user_edit_advanced',
261 name='user_edit_advanced',
263 pattern='/users/{user_id:\d+}/edit/advanced',
262 pattern='/users/{user_id:\d+}/edit/advanced',
264 user_route=True)
263 user_route=True)
265 config.add_route(
264 config.add_route(
266 name='user_edit_global_perms',
265 name='user_edit_global_perms',
267 pattern='/users/{user_id:\d+}/edit/global_permissions',
266 pattern='/users/{user_id:\d+}/edit/global_permissions',
268 user_route=True)
267 user_route=True)
269 config.add_route(
268 config.add_route(
270 name='user_edit_global_perms_update',
269 name='user_edit_global_perms_update',
271 pattern='/users/{user_id:\d+}/edit/global_permissions/update',
270 pattern='/users/{user_id:\d+}/edit/global_permissions/update',
272 user_route=True)
271 user_route=True)
273 config.add_route(
272 config.add_route(
274 name='user_update',
273 name='user_update',
275 pattern='/users/{user_id:\d+}/update',
274 pattern='/users/{user_id:\d+}/update',
276 user_route=True)
275 user_route=True)
277 config.add_route(
276 config.add_route(
278 name='user_delete',
277 name='user_delete',
279 pattern='/users/{user_id:\d+}/delete',
278 pattern='/users/{user_id:\d+}/delete',
280 user_route=True)
279 user_route=True)
281 config.add_route(
280 config.add_route(
282 name='user_enable_force_password_reset',
281 name='user_enable_force_password_reset',
283 pattern='/users/{user_id:\d+}/password_reset_enable',
282 pattern='/users/{user_id:\d+}/password_reset_enable',
284 user_route=True)
283 user_route=True)
285 config.add_route(
284 config.add_route(
286 name='user_disable_force_password_reset',
285 name='user_disable_force_password_reset',
287 pattern='/users/{user_id:\d+}/password_reset_disable',
286 pattern='/users/{user_id:\d+}/password_reset_disable',
288 user_route=True)
287 user_route=True)
289 config.add_route(
288 config.add_route(
290 name='user_create_personal_repo_group',
289 name='user_create_personal_repo_group',
291 pattern='/users/{user_id:\d+}/create_repo_group',
290 pattern='/users/{user_id:\d+}/create_repo_group',
292 user_route=True)
291 user_route=True)
293
292
293 # user notice
294 config.add_route(
295 name='user_notice_dismiss',
296 pattern='/users/{user_id:\d+}/notice_dismiss',
297 user_route=True)
298
294 # user auth tokens
299 # user auth tokens
295 config.add_route(
300 config.add_route(
296 name='edit_user_auth_tokens',
301 name='edit_user_auth_tokens',
297 pattern='/users/{user_id:\d+}/edit/auth_tokens',
302 pattern='/users/{user_id:\d+}/edit/auth_tokens',
298 user_route=True)
303 user_route=True)
299 config.add_route(
304 config.add_route(
300 name='edit_user_auth_tokens_add',
305 name='edit_user_auth_tokens_add',
301 pattern='/users/{user_id:\d+}/edit/auth_tokens/new',
306 pattern='/users/{user_id:\d+}/edit/auth_tokens/new',
302 user_route=True)
307 user_route=True)
303 config.add_route(
308 config.add_route(
304 name='edit_user_auth_tokens_delete',
309 name='edit_user_auth_tokens_delete',
305 pattern='/users/{user_id:\d+}/edit/auth_tokens/delete',
310 pattern='/users/{user_id:\d+}/edit/auth_tokens/delete',
306 user_route=True)
311 user_route=True)
307
312
308 # user ssh keys
313 # user ssh keys
309 config.add_route(
314 config.add_route(
310 name='edit_user_ssh_keys',
315 name='edit_user_ssh_keys',
311 pattern='/users/{user_id:\d+}/edit/ssh_keys',
316 pattern='/users/{user_id:\d+}/edit/ssh_keys',
312 user_route=True)
317 user_route=True)
313 config.add_route(
318 config.add_route(
314 name='edit_user_ssh_keys_generate_keypair',
319 name='edit_user_ssh_keys_generate_keypair',
315 pattern='/users/{user_id:\d+}/edit/ssh_keys/generate',
320 pattern='/users/{user_id:\d+}/edit/ssh_keys/generate',
316 user_route=True)
321 user_route=True)
317 config.add_route(
322 config.add_route(
318 name='edit_user_ssh_keys_add',
323 name='edit_user_ssh_keys_add',
319 pattern='/users/{user_id:\d+}/edit/ssh_keys/new',
324 pattern='/users/{user_id:\d+}/edit/ssh_keys/new',
320 user_route=True)
325 user_route=True)
321 config.add_route(
326 config.add_route(
322 name='edit_user_ssh_keys_delete',
327 name='edit_user_ssh_keys_delete',
323 pattern='/users/{user_id:\d+}/edit/ssh_keys/delete',
328 pattern='/users/{user_id:\d+}/edit/ssh_keys/delete',
324 user_route=True)
329 user_route=True)
325
330
326 # user emails
331 # user emails
327 config.add_route(
332 config.add_route(
328 name='edit_user_emails',
333 name='edit_user_emails',
329 pattern='/users/{user_id:\d+}/edit/emails',
334 pattern='/users/{user_id:\d+}/edit/emails',
330 user_route=True)
335 user_route=True)
331 config.add_route(
336 config.add_route(
332 name='edit_user_emails_add',
337 name='edit_user_emails_add',
333 pattern='/users/{user_id:\d+}/edit/emails/new',
338 pattern='/users/{user_id:\d+}/edit/emails/new',
334 user_route=True)
339 user_route=True)
335 config.add_route(
340 config.add_route(
336 name='edit_user_emails_delete',
341 name='edit_user_emails_delete',
337 pattern='/users/{user_id:\d+}/edit/emails/delete',
342 pattern='/users/{user_id:\d+}/edit/emails/delete',
338 user_route=True)
343 user_route=True)
339
344
340 # user IPs
345 # user IPs
341 config.add_route(
346 config.add_route(
342 name='edit_user_ips',
347 name='edit_user_ips',
343 pattern='/users/{user_id:\d+}/edit/ips',
348 pattern='/users/{user_id:\d+}/edit/ips',
344 user_route=True)
349 user_route=True)
345 config.add_route(
350 config.add_route(
346 name='edit_user_ips_add',
351 name='edit_user_ips_add',
347 pattern='/users/{user_id:\d+}/edit/ips/new',
352 pattern='/users/{user_id:\d+}/edit/ips/new',
348 user_route_with_default=True) # enabled for default user too
353 user_route_with_default=True) # enabled for default user too
349 config.add_route(
354 config.add_route(
350 name='edit_user_ips_delete',
355 name='edit_user_ips_delete',
351 pattern='/users/{user_id:\d+}/edit/ips/delete',
356 pattern='/users/{user_id:\d+}/edit/ips/delete',
352 user_route_with_default=True) # enabled for default user too
357 user_route_with_default=True) # enabled for default user too
353
358
354 # user perms
359 # user perms
355 config.add_route(
360 config.add_route(
356 name='edit_user_perms_summary',
361 name='edit_user_perms_summary',
357 pattern='/users/{user_id:\d+}/edit/permissions_summary',
362 pattern='/users/{user_id:\d+}/edit/permissions_summary',
358 user_route=True)
363 user_route=True)
359 config.add_route(
364 config.add_route(
360 name='edit_user_perms_summary_json',
365 name='edit_user_perms_summary_json',
361 pattern='/users/{user_id:\d+}/edit/permissions_summary/json',
366 pattern='/users/{user_id:\d+}/edit/permissions_summary/json',
362 user_route=True)
367 user_route=True)
363
368
364 # user user groups management
369 # user user groups management
365 config.add_route(
370 config.add_route(
366 name='edit_user_groups_management',
371 name='edit_user_groups_management',
367 pattern='/users/{user_id:\d+}/edit/groups_management',
372 pattern='/users/{user_id:\d+}/edit/groups_management',
368 user_route=True)
373 user_route=True)
369
374
370 config.add_route(
375 config.add_route(
371 name='edit_user_groups_management_updates',
376 name='edit_user_groups_management_updates',
372 pattern='/users/{user_id:\d+}/edit/edit_user_groups_management/updates',
377 pattern='/users/{user_id:\d+}/edit/edit_user_groups_management/updates',
373 user_route=True)
378 user_route=True)
374
379
375 # user audit logs
380 # user audit logs
376 config.add_route(
381 config.add_route(
377 name='edit_user_audit_logs',
382 name='edit_user_audit_logs',
378 pattern='/users/{user_id:\d+}/edit/audit', user_route=True)
383 pattern='/users/{user_id:\d+}/edit/audit', user_route=True)
379
384
380 config.add_route(
385 config.add_route(
381 name='edit_user_audit_logs_download',
386 name='edit_user_audit_logs_download',
382 pattern='/users/{user_id:\d+}/edit/audit/download', user_route=True)
387 pattern='/users/{user_id:\d+}/edit/audit/download', user_route=True)
383
388
384 # user caches
389 # user caches
385 config.add_route(
390 config.add_route(
386 name='edit_user_caches',
391 name='edit_user_caches',
387 pattern='/users/{user_id:\d+}/edit/caches',
392 pattern='/users/{user_id:\d+}/edit/caches',
388 user_route=True)
393 user_route=True)
389 config.add_route(
394 config.add_route(
390 name='edit_user_caches_update',
395 name='edit_user_caches_update',
391 pattern='/users/{user_id:\d+}/edit/caches/update',
396 pattern='/users/{user_id:\d+}/edit/caches/update',
392 user_route=True)
397 user_route=True)
393
398
394 # user-groups admin
399 # user-groups admin
395 config.add_route(
400 config.add_route(
396 name='user_groups',
401 name='user_groups',
397 pattern='/user_groups')
402 pattern='/user_groups')
398
403
399 config.add_route(
404 config.add_route(
400 name='user_groups_data',
405 name='user_groups_data',
401 pattern='/user_groups_data')
406 pattern='/user_groups_data')
402
407
403 config.add_route(
408 config.add_route(
404 name='user_groups_new',
409 name='user_groups_new',
405 pattern='/user_groups/new')
410 pattern='/user_groups/new')
406
411
407 config.add_route(
412 config.add_route(
408 name='user_groups_create',
413 name='user_groups_create',
409 pattern='/user_groups/create')
414 pattern='/user_groups/create')
410
415
411 # repos admin
416 # repos admin
412 config.add_route(
417 config.add_route(
413 name='repos',
418 name='repos',
414 pattern='/repos')
419 pattern='/repos')
415
420
416 config.add_route(
421 config.add_route(
417 name='repos_data',
422 name='repos_data',
418 pattern='/repos_data')
423 pattern='/repos_data')
419
424
420 config.add_route(
425 config.add_route(
421 name='repo_new',
426 name='repo_new',
422 pattern='/repos/new')
427 pattern='/repos/new')
423
428
424 config.add_route(
429 config.add_route(
425 name='repo_create',
430 name='repo_create',
426 pattern='/repos/create')
431 pattern='/repos/create')
427
432
428 # repo groups admin
433 # repo groups admin
429 config.add_route(
434 config.add_route(
430 name='repo_groups',
435 name='repo_groups',
431 pattern='/repo_groups')
436 pattern='/repo_groups')
432
437
433 config.add_route(
438 config.add_route(
434 name='repo_groups_data',
439 name='repo_groups_data',
435 pattern='/repo_groups_data')
440 pattern='/repo_groups_data')
436
441
437 config.add_route(
442 config.add_route(
438 name='repo_group_new',
443 name='repo_group_new',
439 pattern='/repo_group/new')
444 pattern='/repo_group/new')
440
445
441 config.add_route(
446 config.add_route(
442 name='repo_group_create',
447 name='repo_group_create',
443 pattern='/repo_group/create')
448 pattern='/repo_group/create')
444
449
445
450
446 def includeme(config):
451 def includeme(config):
447 from rhodecode.apps._base.navigation import includeme as nav_includeme
452 from rhodecode.apps._base.navigation import includeme as nav_includeme
448
453
449 # Create admin navigation registry and add it to the pyramid registry.
454 # Create admin navigation registry and add it to the pyramid registry.
450 nav_includeme(config)
455 nav_includeme(config)
451
456
452 # main admin routes
457 # main admin routes
453 config.add_route(name='admin_home', pattern=ADMIN_PREFIX)
458 config.add_route(name='admin_home', pattern=ADMIN_PREFIX)
454 config.include(admin_routes, route_prefix=ADMIN_PREFIX)
459 config.include(admin_routes, route_prefix=ADMIN_PREFIX)
455
460
456 # Scan module for configuration decorators.
461 # Scan module for configuration decorators.
457 config.scan('.views', ignore='.tests')
462 config.scan('.views', ignore='.tests')
@@ -1,1336 +1,1362 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2019 RhodeCode GmbH
3 # Copyright (C) 2016-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22 import datetime
22 import datetime
23 import formencode
23 import formencode
24 import formencode.htmlfill
24 import formencode.htmlfill
25
25
26 from pyramid.httpexceptions import HTTPFound
26 from pyramid.httpexceptions import HTTPFound
27 from pyramid.view import view_config
27 from pyramid.view import view_config
28 from pyramid.renderers import render
28 from pyramid.renderers import render
29 from pyramid.response import Response
29 from pyramid.response import Response
30
30
31 from rhodecode import events
31 from rhodecode import events
32 from rhodecode.apps._base import BaseAppView, DataGridAppView, UserAppView
32 from rhodecode.apps._base import BaseAppView, DataGridAppView, UserAppView
33 from rhodecode.apps.ssh_support import SshKeyFileChangeEvent
33 from rhodecode.apps.ssh_support import SshKeyFileChangeEvent
34 from rhodecode.authentication.base import get_authn_registry, RhodeCodeExternalAuthPlugin
34 from rhodecode.authentication.base import get_authn_registry, RhodeCodeExternalAuthPlugin
35 from rhodecode.authentication.plugins import auth_rhodecode
35 from rhodecode.authentication.plugins import auth_rhodecode
36 from rhodecode.events import trigger
36 from rhodecode.events import trigger
37 from rhodecode.model.db import true
37 from rhodecode.model.db import true, UserNotice
38
38
39 from rhodecode.lib import audit_logger, rc_cache
39 from rhodecode.lib import audit_logger, rc_cache
40 from rhodecode.lib.exceptions import (
40 from rhodecode.lib.exceptions import (
41 UserCreationError, UserOwnsReposException, UserOwnsRepoGroupsException,
41 UserCreationError, UserOwnsReposException, UserOwnsRepoGroupsException,
42 UserOwnsUserGroupsException, DefaultUserException)
42 UserOwnsUserGroupsException, DefaultUserException)
43 from rhodecode.lib.ext_json import json
43 from rhodecode.lib.ext_json import json
44 from rhodecode.lib.auth import (
44 from rhodecode.lib.auth import (
45 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
45 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
46 from rhodecode.lib import helpers as h
46 from rhodecode.lib import helpers as h
47 from rhodecode.lib.helpers import SqlPage
47 from rhodecode.lib.helpers import SqlPage
48 from rhodecode.lib.utils2 import safe_int, safe_unicode, AttributeDict
48 from rhodecode.lib.utils2 import safe_int, safe_unicode, AttributeDict
49 from rhodecode.model.auth_token import AuthTokenModel
49 from rhodecode.model.auth_token import AuthTokenModel
50 from rhodecode.model.forms import (
50 from rhodecode.model.forms import (
51 UserForm, UserIndividualPermissionsForm, UserPermissionsForm,
51 UserForm, UserIndividualPermissionsForm, UserPermissionsForm,
52 UserExtraEmailForm, UserExtraIpForm)
52 UserExtraEmailForm, UserExtraIpForm)
53 from rhodecode.model.permission import PermissionModel
53 from rhodecode.model.permission import PermissionModel
54 from rhodecode.model.repo_group import RepoGroupModel
54 from rhodecode.model.repo_group import RepoGroupModel
55 from rhodecode.model.ssh_key import SshKeyModel
55 from rhodecode.model.ssh_key import SshKeyModel
56 from rhodecode.model.user import UserModel
56 from rhodecode.model.user import UserModel
57 from rhodecode.model.user_group import UserGroupModel
57 from rhodecode.model.user_group import UserGroupModel
58 from rhodecode.model.db import (
58 from rhodecode.model.db import (
59 or_, coalesce,IntegrityError, User, UserGroup, UserIpMap, UserEmailMap,
59 or_, coalesce,IntegrityError, User, UserGroup, UserIpMap, UserEmailMap,
60 UserApiKeys, UserSshKeys, RepoGroup)
60 UserApiKeys, UserSshKeys, RepoGroup)
61 from rhodecode.model.meta import Session
61 from rhodecode.model.meta import Session
62
62
63 log = logging.getLogger(__name__)
63 log = logging.getLogger(__name__)
64
64
65
65
66 class AdminUsersView(BaseAppView, DataGridAppView):
66 class AdminUsersView(BaseAppView, DataGridAppView):
67
67
68 def load_default_context(self):
68 def load_default_context(self):
69 c = self._get_local_tmpl_context()
69 c = self._get_local_tmpl_context()
70 return c
70 return c
71
71
72 @LoginRequired()
72 @LoginRequired()
73 @HasPermissionAllDecorator('hg.admin')
73 @HasPermissionAllDecorator('hg.admin')
74 @view_config(
74 @view_config(
75 route_name='users', request_method='GET',
75 route_name='users', request_method='GET',
76 renderer='rhodecode:templates/admin/users/users.mako')
76 renderer='rhodecode:templates/admin/users/users.mako')
77 def users_list(self):
77 def users_list(self):
78 c = self.load_default_context()
78 c = self.load_default_context()
79 return self._get_template_context(c)
79 return self._get_template_context(c)
80
80
81 @LoginRequired()
81 @LoginRequired()
82 @HasPermissionAllDecorator('hg.admin')
82 @HasPermissionAllDecorator('hg.admin')
83 @view_config(
83 @view_config(
84 # renderer defined below
84 # renderer defined below
85 route_name='users_data', request_method='GET',
85 route_name='users_data', request_method='GET',
86 renderer='json_ext', xhr=True)
86 renderer='json_ext', xhr=True)
87 def users_list_data(self):
87 def users_list_data(self):
88 self.load_default_context()
88 self.load_default_context()
89 column_map = {
89 column_map = {
90 'first_name': 'name',
90 'first_name': 'name',
91 'last_name': 'lastname',
91 'last_name': 'lastname',
92 }
92 }
93 draw, start, limit = self._extract_chunk(self.request)
93 draw, start, limit = self._extract_chunk(self.request)
94 search_q, order_by, order_dir = self._extract_ordering(
94 search_q, order_by, order_dir = self._extract_ordering(
95 self.request, column_map=column_map)
95 self.request, column_map=column_map)
96 _render = self.request.get_partial_renderer(
96 _render = self.request.get_partial_renderer(
97 'rhodecode:templates/data_table/_dt_elements.mako')
97 'rhodecode:templates/data_table/_dt_elements.mako')
98
98
99 def user_actions(user_id, username):
99 def user_actions(user_id, username):
100 return _render("user_actions", user_id, username)
100 return _render("user_actions", user_id, username)
101
101
102 users_data_total_count = User.query()\
102 users_data_total_count = User.query()\
103 .filter(User.username != User.DEFAULT_USER) \
103 .filter(User.username != User.DEFAULT_USER) \
104 .count()
104 .count()
105
105
106 users_data_total_inactive_count = User.query()\
106 users_data_total_inactive_count = User.query()\
107 .filter(User.username != User.DEFAULT_USER) \
107 .filter(User.username != User.DEFAULT_USER) \
108 .filter(User.active != true())\
108 .filter(User.active != true())\
109 .count()
109 .count()
110
110
111 # json generate
111 # json generate
112 base_q = User.query().filter(User.username != User.DEFAULT_USER)
112 base_q = User.query().filter(User.username != User.DEFAULT_USER)
113 base_inactive_q = base_q.filter(User.active != true())
113 base_inactive_q = base_q.filter(User.active != true())
114
114
115 if search_q:
115 if search_q:
116 like_expression = u'%{}%'.format(safe_unicode(search_q))
116 like_expression = u'%{}%'.format(safe_unicode(search_q))
117 base_q = base_q.filter(or_(
117 base_q = base_q.filter(or_(
118 User.username.ilike(like_expression),
118 User.username.ilike(like_expression),
119 User._email.ilike(like_expression),
119 User._email.ilike(like_expression),
120 User.name.ilike(like_expression),
120 User.name.ilike(like_expression),
121 User.lastname.ilike(like_expression),
121 User.lastname.ilike(like_expression),
122 ))
122 ))
123 base_inactive_q = base_q.filter(User.active != true())
123 base_inactive_q = base_q.filter(User.active != true())
124
124
125 users_data_total_filtered_count = base_q.count()
125 users_data_total_filtered_count = base_q.count()
126 users_data_total_filtered_inactive_count = base_inactive_q.count()
126 users_data_total_filtered_inactive_count = base_inactive_q.count()
127
127
128 sort_col = getattr(User, order_by, None)
128 sort_col = getattr(User, order_by, None)
129 if sort_col:
129 if sort_col:
130 if order_dir == 'asc':
130 if order_dir == 'asc':
131 # handle null values properly to order by NULL last
131 # handle null values properly to order by NULL last
132 if order_by in ['last_activity']:
132 if order_by in ['last_activity']:
133 sort_col = coalesce(sort_col, datetime.date.max)
133 sort_col = coalesce(sort_col, datetime.date.max)
134 sort_col = sort_col.asc()
134 sort_col = sort_col.asc()
135 else:
135 else:
136 # handle null values properly to order by NULL last
136 # handle null values properly to order by NULL last
137 if order_by in ['last_activity']:
137 if order_by in ['last_activity']:
138 sort_col = coalesce(sort_col, datetime.date.min)
138 sort_col = coalesce(sort_col, datetime.date.min)
139 sort_col = sort_col.desc()
139 sort_col = sort_col.desc()
140
140
141 base_q = base_q.order_by(sort_col)
141 base_q = base_q.order_by(sort_col)
142 base_q = base_q.offset(start).limit(limit)
142 base_q = base_q.offset(start).limit(limit)
143
143
144 users_list = base_q.all()
144 users_list = base_q.all()
145
145
146 users_data = []
146 users_data = []
147 for user in users_list:
147 for user in users_list:
148 users_data.append({
148 users_data.append({
149 "username": h.gravatar_with_user(self.request, user.username),
149 "username": h.gravatar_with_user(self.request, user.username),
150 "email": user.email,
150 "email": user.email,
151 "first_name": user.first_name,
151 "first_name": user.first_name,
152 "last_name": user.last_name,
152 "last_name": user.last_name,
153 "last_login": h.format_date(user.last_login),
153 "last_login": h.format_date(user.last_login),
154 "last_activity": h.format_date(user.last_activity),
154 "last_activity": h.format_date(user.last_activity),
155 "active": h.bool2icon(user.active),
155 "active": h.bool2icon(user.active),
156 "active_raw": user.active,
156 "active_raw": user.active,
157 "admin": h.bool2icon(user.admin),
157 "admin": h.bool2icon(user.admin),
158 "extern_type": user.extern_type,
158 "extern_type": user.extern_type,
159 "extern_name": user.extern_name,
159 "extern_name": user.extern_name,
160 "action": user_actions(user.user_id, user.username),
160 "action": user_actions(user.user_id, user.username),
161 })
161 })
162 data = ({
162 data = ({
163 'draw': draw,
163 'draw': draw,
164 'data': users_data,
164 'data': users_data,
165 'recordsTotal': users_data_total_count,
165 'recordsTotal': users_data_total_count,
166 'recordsFiltered': users_data_total_filtered_count,
166 'recordsFiltered': users_data_total_filtered_count,
167 'recordsTotalInactive': users_data_total_inactive_count,
167 'recordsTotalInactive': users_data_total_inactive_count,
168 'recordsFilteredInactive': users_data_total_filtered_inactive_count
168 'recordsFilteredInactive': users_data_total_filtered_inactive_count
169 })
169 })
170
170
171 return data
171 return data
172
172
173 def _set_personal_repo_group_template_vars(self, c_obj):
173 def _set_personal_repo_group_template_vars(self, c_obj):
174 DummyUser = AttributeDict({
174 DummyUser = AttributeDict({
175 'username': '${username}',
175 'username': '${username}',
176 'user_id': '${user_id}',
176 'user_id': '${user_id}',
177 })
177 })
178 c_obj.default_create_repo_group = RepoGroupModel() \
178 c_obj.default_create_repo_group = RepoGroupModel() \
179 .get_default_create_personal_repo_group()
179 .get_default_create_personal_repo_group()
180 c_obj.personal_repo_group_name = RepoGroupModel() \
180 c_obj.personal_repo_group_name = RepoGroupModel() \
181 .get_personal_group_name(DummyUser)
181 .get_personal_group_name(DummyUser)
182
182
183 @LoginRequired()
183 @LoginRequired()
184 @HasPermissionAllDecorator('hg.admin')
184 @HasPermissionAllDecorator('hg.admin')
185 @view_config(
185 @view_config(
186 route_name='users_new', request_method='GET',
186 route_name='users_new', request_method='GET',
187 renderer='rhodecode:templates/admin/users/user_add.mako')
187 renderer='rhodecode:templates/admin/users/user_add.mako')
188 def users_new(self):
188 def users_new(self):
189 _ = self.request.translate
189 _ = self.request.translate
190 c = self.load_default_context()
190 c = self.load_default_context()
191 c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.uid
191 c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.uid
192 self._set_personal_repo_group_template_vars(c)
192 self._set_personal_repo_group_template_vars(c)
193 return self._get_template_context(c)
193 return self._get_template_context(c)
194
194
195 @LoginRequired()
195 @LoginRequired()
196 @HasPermissionAllDecorator('hg.admin')
196 @HasPermissionAllDecorator('hg.admin')
197 @CSRFRequired()
197 @CSRFRequired()
198 @view_config(
198 @view_config(
199 route_name='users_create', request_method='POST',
199 route_name='users_create', request_method='POST',
200 renderer='rhodecode:templates/admin/users/user_add.mako')
200 renderer='rhodecode:templates/admin/users/user_add.mako')
201 def users_create(self):
201 def users_create(self):
202 _ = self.request.translate
202 _ = self.request.translate
203 c = self.load_default_context()
203 c = self.load_default_context()
204 c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.uid
204 c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.uid
205 user_model = UserModel()
205 user_model = UserModel()
206 user_form = UserForm(self.request.translate)()
206 user_form = UserForm(self.request.translate)()
207 try:
207 try:
208 form_result = user_form.to_python(dict(self.request.POST))
208 form_result = user_form.to_python(dict(self.request.POST))
209 user = user_model.create(form_result)
209 user = user_model.create(form_result)
210 Session().flush()
210 Session().flush()
211 creation_data = user.get_api_data()
211 creation_data = user.get_api_data()
212 username = form_result['username']
212 username = form_result['username']
213
213
214 audit_logger.store_web(
214 audit_logger.store_web(
215 'user.create', action_data={'data': creation_data},
215 'user.create', action_data={'data': creation_data},
216 user=c.rhodecode_user)
216 user=c.rhodecode_user)
217
217
218 user_link = h.link_to(
218 user_link = h.link_to(
219 h.escape(username),
219 h.escape(username),
220 h.route_path('user_edit', user_id=user.user_id))
220 h.route_path('user_edit', user_id=user.user_id))
221 h.flash(h.literal(_('Created user %(user_link)s')
221 h.flash(h.literal(_('Created user %(user_link)s')
222 % {'user_link': user_link}), category='success')
222 % {'user_link': user_link}), category='success')
223 Session().commit()
223 Session().commit()
224 except formencode.Invalid as errors:
224 except formencode.Invalid as errors:
225 self._set_personal_repo_group_template_vars(c)
225 self._set_personal_repo_group_template_vars(c)
226 data = render(
226 data = render(
227 'rhodecode:templates/admin/users/user_add.mako',
227 'rhodecode:templates/admin/users/user_add.mako',
228 self._get_template_context(c), self.request)
228 self._get_template_context(c), self.request)
229 html = formencode.htmlfill.render(
229 html = formencode.htmlfill.render(
230 data,
230 data,
231 defaults=errors.value,
231 defaults=errors.value,
232 errors=errors.error_dict or {},
232 errors=errors.error_dict or {},
233 prefix_error=False,
233 prefix_error=False,
234 encoding="UTF-8",
234 encoding="UTF-8",
235 force_defaults=False
235 force_defaults=False
236 )
236 )
237 return Response(html)
237 return Response(html)
238 except UserCreationError as e:
238 except UserCreationError as e:
239 h.flash(e, 'error')
239 h.flash(e, 'error')
240 except Exception:
240 except Exception:
241 log.exception("Exception creation of user")
241 log.exception("Exception creation of user")
242 h.flash(_('Error occurred during creation of user %s')
242 h.flash(_('Error occurred during creation of user %s')
243 % self.request.POST.get('username'), category='error')
243 % self.request.POST.get('username'), category='error')
244 raise HTTPFound(h.route_path('users'))
244 raise HTTPFound(h.route_path('users'))
245
245
246
246
247 class UsersView(UserAppView):
247 class UsersView(UserAppView):
248 ALLOW_SCOPED_TOKENS = False
248 ALLOW_SCOPED_TOKENS = False
249 """
249 """
250 This view has alternative version inside EE, if modified please take a look
250 This view has alternative version inside EE, if modified please take a look
251 in there as well.
251 in there as well.
252 """
252 """
253
253
254 def get_auth_plugins(self):
254 def get_auth_plugins(self):
255 valid_plugins = []
255 valid_plugins = []
256 authn_registry = get_authn_registry(self.request.registry)
256 authn_registry = get_authn_registry(self.request.registry)
257 for plugin in authn_registry.get_plugins_for_authentication():
257 for plugin in authn_registry.get_plugins_for_authentication():
258 if isinstance(plugin, RhodeCodeExternalAuthPlugin):
258 if isinstance(plugin, RhodeCodeExternalAuthPlugin):
259 valid_plugins.append(plugin)
259 valid_plugins.append(plugin)
260 elif plugin.name == 'rhodecode':
260 elif plugin.name == 'rhodecode':
261 valid_plugins.append(plugin)
261 valid_plugins.append(plugin)
262
262
263 # extend our choices if user has set a bound plugin which isn't enabled at the
263 # extend our choices if user has set a bound plugin which isn't enabled at the
264 # moment
264 # moment
265 extern_type = self.db_user.extern_type
265 extern_type = self.db_user.extern_type
266 if extern_type not in [x.uid for x in valid_plugins]:
266 if extern_type not in [x.uid for x in valid_plugins]:
267 try:
267 try:
268 plugin = authn_registry.get_plugin_by_uid(extern_type)
268 plugin = authn_registry.get_plugin_by_uid(extern_type)
269 if plugin:
269 if plugin:
270 valid_plugins.append(plugin)
270 valid_plugins.append(plugin)
271
271
272 except Exception:
272 except Exception:
273 log.exception(
273 log.exception(
274 'Could not extend user plugins with `{}`'.format(extern_type))
274 'Could not extend user plugins with `{}`'.format(extern_type))
275 return valid_plugins
275 return valid_plugins
276
276
277 def load_default_context(self):
277 def load_default_context(self):
278 req = self.request
278 req = self.request
279
279
280 c = self._get_local_tmpl_context()
280 c = self._get_local_tmpl_context()
281 c.allow_scoped_tokens = self.ALLOW_SCOPED_TOKENS
281 c.allow_scoped_tokens = self.ALLOW_SCOPED_TOKENS
282 c.allowed_languages = [
282 c.allowed_languages = [
283 ('en', 'English (en)'),
283 ('en', 'English (en)'),
284 ('de', 'German (de)'),
284 ('de', 'German (de)'),
285 ('fr', 'French (fr)'),
285 ('fr', 'French (fr)'),
286 ('it', 'Italian (it)'),
286 ('it', 'Italian (it)'),
287 ('ja', 'Japanese (ja)'),
287 ('ja', 'Japanese (ja)'),
288 ('pl', 'Polish (pl)'),
288 ('pl', 'Polish (pl)'),
289 ('pt', 'Portuguese (pt)'),
289 ('pt', 'Portuguese (pt)'),
290 ('ru', 'Russian (ru)'),
290 ('ru', 'Russian (ru)'),
291 ('zh', 'Chinese (zh)'),
291 ('zh', 'Chinese (zh)'),
292 ]
292 ]
293
293
294 c.allowed_extern_types = [
294 c.allowed_extern_types = [
295 (x.uid, x.get_display_name()) for x in self.get_auth_plugins()
295 (x.uid, x.get_display_name()) for x in self.get_auth_plugins()
296 ]
296 ]
297
297
298 c.available_permissions = req.registry.settings['available_permissions']
298 c.available_permissions = req.registry.settings['available_permissions']
299 PermissionModel().set_global_permission_choices(
299 PermissionModel().set_global_permission_choices(
300 c, gettext_translator=req.translate)
300 c, gettext_translator=req.translate)
301
301
302 return c
302 return c
303
303
304 @LoginRequired()
304 @LoginRequired()
305 @HasPermissionAllDecorator('hg.admin')
305 @HasPermissionAllDecorator('hg.admin')
306 @CSRFRequired()
306 @CSRFRequired()
307 @view_config(
307 @view_config(
308 route_name='user_update', request_method='POST',
308 route_name='user_update', request_method='POST',
309 renderer='rhodecode:templates/admin/users/user_edit.mako')
309 renderer='rhodecode:templates/admin/users/user_edit.mako')
310 def user_update(self):
310 def user_update(self):
311 _ = self.request.translate
311 _ = self.request.translate
312 c = self.load_default_context()
312 c = self.load_default_context()
313
313
314 user_id = self.db_user_id
314 user_id = self.db_user_id
315 c.user = self.db_user
315 c.user = self.db_user
316
316
317 c.active = 'profile'
317 c.active = 'profile'
318 c.extern_type = c.user.extern_type
318 c.extern_type = c.user.extern_type
319 c.extern_name = c.user.extern_name
319 c.extern_name = c.user.extern_name
320 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
320 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
321 available_languages = [x[0] for x in c.allowed_languages]
321 available_languages = [x[0] for x in c.allowed_languages]
322 _form = UserForm(self.request.translate, edit=True,
322 _form = UserForm(self.request.translate, edit=True,
323 available_languages=available_languages,
323 available_languages=available_languages,
324 old_data={'user_id': user_id,
324 old_data={'user_id': user_id,
325 'email': c.user.email})()
325 'email': c.user.email})()
326 form_result = {}
326 form_result = {}
327 old_values = c.user.get_api_data()
327 old_values = c.user.get_api_data()
328 try:
328 try:
329 form_result = _form.to_python(dict(self.request.POST))
329 form_result = _form.to_python(dict(self.request.POST))
330 skip_attrs = ['extern_name']
330 skip_attrs = ['extern_name']
331 # TODO: plugin should define if username can be updated
331 # TODO: plugin should define if username can be updated
332 if c.extern_type != "rhodecode":
332 if c.extern_type != "rhodecode":
333 # forbid updating username for external accounts
333 # forbid updating username for external accounts
334 skip_attrs.append('username')
334 skip_attrs.append('username')
335
335
336 UserModel().update_user(
336 UserModel().update_user(
337 user_id, skip_attrs=skip_attrs, **form_result)
337 user_id, skip_attrs=skip_attrs, **form_result)
338
338
339 audit_logger.store_web(
339 audit_logger.store_web(
340 'user.edit', action_data={'old_data': old_values},
340 'user.edit', action_data={'old_data': old_values},
341 user=c.rhodecode_user)
341 user=c.rhodecode_user)
342
342
343 Session().commit()
343 Session().commit()
344 h.flash(_('User updated successfully'), category='success')
344 h.flash(_('User updated successfully'), category='success')
345 except formencode.Invalid as errors:
345 except formencode.Invalid as errors:
346 data = render(
346 data = render(
347 'rhodecode:templates/admin/users/user_edit.mako',
347 'rhodecode:templates/admin/users/user_edit.mako',
348 self._get_template_context(c), self.request)
348 self._get_template_context(c), self.request)
349 html = formencode.htmlfill.render(
349 html = formencode.htmlfill.render(
350 data,
350 data,
351 defaults=errors.value,
351 defaults=errors.value,
352 errors=errors.error_dict or {},
352 errors=errors.error_dict or {},
353 prefix_error=False,
353 prefix_error=False,
354 encoding="UTF-8",
354 encoding="UTF-8",
355 force_defaults=False
355 force_defaults=False
356 )
356 )
357 return Response(html)
357 return Response(html)
358 except UserCreationError as e:
358 except UserCreationError as e:
359 h.flash(e, 'error')
359 h.flash(e, 'error')
360 except Exception:
360 except Exception:
361 log.exception("Exception updating user")
361 log.exception("Exception updating user")
362 h.flash(_('Error occurred during update of user %s')
362 h.flash(_('Error occurred during update of user %s')
363 % form_result.get('username'), category='error')
363 % form_result.get('username'), category='error')
364 raise HTTPFound(h.route_path('user_edit', user_id=user_id))
364 raise HTTPFound(h.route_path('user_edit', user_id=user_id))
365
365
366 @LoginRequired()
366 @LoginRequired()
367 @HasPermissionAllDecorator('hg.admin')
367 @HasPermissionAllDecorator('hg.admin')
368 @CSRFRequired()
368 @CSRFRequired()
369 @view_config(
369 @view_config(
370 route_name='user_delete', request_method='POST',
370 route_name='user_delete', request_method='POST',
371 renderer='rhodecode:templates/admin/users/user_edit.mako')
371 renderer='rhodecode:templates/admin/users/user_edit.mako')
372 def user_delete(self):
372 def user_delete(self):
373 _ = self.request.translate
373 _ = self.request.translate
374 c = self.load_default_context()
374 c = self.load_default_context()
375 c.user = self.db_user
375 c.user = self.db_user
376
376
377 _repos = c.user.repositories
377 _repos = c.user.repositories
378 _repo_groups = c.user.repository_groups
378 _repo_groups = c.user.repository_groups
379 _user_groups = c.user.user_groups
379 _user_groups = c.user.user_groups
380 _artifacts = c.user.artifacts
380 _artifacts = c.user.artifacts
381
381
382 handle_repos = None
382 handle_repos = None
383 handle_repo_groups = None
383 handle_repo_groups = None
384 handle_user_groups = None
384 handle_user_groups = None
385 handle_artifacts = None
385 handle_artifacts = None
386
386
387 # calls for flash of handle based on handle case detach or delete
387 # calls for flash of handle based on handle case detach or delete
388 def set_handle_flash_repos():
388 def set_handle_flash_repos():
389 handle = handle_repos
389 handle = handle_repos
390 if handle == 'detach':
390 if handle == 'detach':
391 h.flash(_('Detached %s repositories') % len(_repos),
391 h.flash(_('Detached %s repositories') % len(_repos),
392 category='success')
392 category='success')
393 elif handle == 'delete':
393 elif handle == 'delete':
394 h.flash(_('Deleted %s repositories') % len(_repos),
394 h.flash(_('Deleted %s repositories') % len(_repos),
395 category='success')
395 category='success')
396
396
397 def set_handle_flash_repo_groups():
397 def set_handle_flash_repo_groups():
398 handle = handle_repo_groups
398 handle = handle_repo_groups
399 if handle == 'detach':
399 if handle == 'detach':
400 h.flash(_('Detached %s repository groups') % len(_repo_groups),
400 h.flash(_('Detached %s repository groups') % len(_repo_groups),
401 category='success')
401 category='success')
402 elif handle == 'delete':
402 elif handle == 'delete':
403 h.flash(_('Deleted %s repository groups') % len(_repo_groups),
403 h.flash(_('Deleted %s repository groups') % len(_repo_groups),
404 category='success')
404 category='success')
405
405
406 def set_handle_flash_user_groups():
406 def set_handle_flash_user_groups():
407 handle = handle_user_groups
407 handle = handle_user_groups
408 if handle == 'detach':
408 if handle == 'detach':
409 h.flash(_('Detached %s user groups') % len(_user_groups),
409 h.flash(_('Detached %s user groups') % len(_user_groups),
410 category='success')
410 category='success')
411 elif handle == 'delete':
411 elif handle == 'delete':
412 h.flash(_('Deleted %s user groups') % len(_user_groups),
412 h.flash(_('Deleted %s user groups') % len(_user_groups),
413 category='success')
413 category='success')
414
414
415 def set_handle_flash_artifacts():
415 def set_handle_flash_artifacts():
416 handle = handle_artifacts
416 handle = handle_artifacts
417 if handle == 'detach':
417 if handle == 'detach':
418 h.flash(_('Detached %s artifacts') % len(_artifacts),
418 h.flash(_('Detached %s artifacts') % len(_artifacts),
419 category='success')
419 category='success')
420 elif handle == 'delete':
420 elif handle == 'delete':
421 h.flash(_('Deleted %s artifacts') % len(_artifacts),
421 h.flash(_('Deleted %s artifacts') % len(_artifacts),
422 category='success')
422 category='success')
423
423
424 if _repos and self.request.POST.get('user_repos'):
424 if _repos and self.request.POST.get('user_repos'):
425 handle_repos = self.request.POST['user_repos']
425 handle_repos = self.request.POST['user_repos']
426
426
427 if _repo_groups and self.request.POST.get('user_repo_groups'):
427 if _repo_groups and self.request.POST.get('user_repo_groups'):
428 handle_repo_groups = self.request.POST['user_repo_groups']
428 handle_repo_groups = self.request.POST['user_repo_groups']
429
429
430 if _user_groups and self.request.POST.get('user_user_groups'):
430 if _user_groups and self.request.POST.get('user_user_groups'):
431 handle_user_groups = self.request.POST['user_user_groups']
431 handle_user_groups = self.request.POST['user_user_groups']
432
432
433 if _artifacts and self.request.POST.get('user_artifacts'):
433 if _artifacts and self.request.POST.get('user_artifacts'):
434 handle_artifacts = self.request.POST['user_artifacts']
434 handle_artifacts = self.request.POST['user_artifacts']
435
435
436 old_values = c.user.get_api_data()
436 old_values = c.user.get_api_data()
437
437
438 try:
438 try:
439 UserModel().delete(c.user, handle_repos=handle_repos,
439 UserModel().delete(c.user, handle_repos=handle_repos,
440 handle_repo_groups=handle_repo_groups,
440 handle_repo_groups=handle_repo_groups,
441 handle_user_groups=handle_user_groups,
441 handle_user_groups=handle_user_groups,
442 handle_artifacts=handle_artifacts)
442 handle_artifacts=handle_artifacts)
443
443
444 audit_logger.store_web(
444 audit_logger.store_web(
445 'user.delete', action_data={'old_data': old_values},
445 'user.delete', action_data={'old_data': old_values},
446 user=c.rhodecode_user)
446 user=c.rhodecode_user)
447
447
448 Session().commit()
448 Session().commit()
449 set_handle_flash_repos()
449 set_handle_flash_repos()
450 set_handle_flash_repo_groups()
450 set_handle_flash_repo_groups()
451 set_handle_flash_user_groups()
451 set_handle_flash_user_groups()
452 set_handle_flash_artifacts()
452 set_handle_flash_artifacts()
453 username = h.escape(old_values['username'])
453 username = h.escape(old_values['username'])
454 h.flash(_('Successfully deleted user `{}`').format(username), category='success')
454 h.flash(_('Successfully deleted user `{}`').format(username), category='success')
455 except (UserOwnsReposException, UserOwnsRepoGroupsException,
455 except (UserOwnsReposException, UserOwnsRepoGroupsException,
456 UserOwnsUserGroupsException, DefaultUserException) as e:
456 UserOwnsUserGroupsException, DefaultUserException) as e:
457 h.flash(e, category='warning')
457 h.flash(e, category='warning')
458 except Exception:
458 except Exception:
459 log.exception("Exception during deletion of user")
459 log.exception("Exception during deletion of user")
460 h.flash(_('An error occurred during deletion of user'),
460 h.flash(_('An error occurred during deletion of user'),
461 category='error')
461 category='error')
462 raise HTTPFound(h.route_path('users'))
462 raise HTTPFound(h.route_path('users'))
463
463
464 @LoginRequired()
464 @LoginRequired()
465 @HasPermissionAllDecorator('hg.admin')
465 @HasPermissionAllDecorator('hg.admin')
466 @view_config(
466 @view_config(
467 route_name='user_edit', request_method='GET',
467 route_name='user_edit', request_method='GET',
468 renderer='rhodecode:templates/admin/users/user_edit.mako')
468 renderer='rhodecode:templates/admin/users/user_edit.mako')
469 def user_edit(self):
469 def user_edit(self):
470 _ = self.request.translate
470 _ = self.request.translate
471 c = self.load_default_context()
471 c = self.load_default_context()
472 c.user = self.db_user
472 c.user = self.db_user
473
473
474 c.active = 'profile'
474 c.active = 'profile'
475 c.extern_type = c.user.extern_type
475 c.extern_type = c.user.extern_type
476 c.extern_name = c.user.extern_name
476 c.extern_name = c.user.extern_name
477 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
477 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
478
478
479 defaults = c.user.get_dict()
479 defaults = c.user.get_dict()
480 defaults.update({'language': c.user.user_data.get('language')})
480 defaults.update({'language': c.user.user_data.get('language')})
481
481
482 data = render(
482 data = render(
483 'rhodecode:templates/admin/users/user_edit.mako',
483 'rhodecode:templates/admin/users/user_edit.mako',
484 self._get_template_context(c), self.request)
484 self._get_template_context(c), self.request)
485 html = formencode.htmlfill.render(
485 html = formencode.htmlfill.render(
486 data,
486 data,
487 defaults=defaults,
487 defaults=defaults,
488 encoding="UTF-8",
488 encoding="UTF-8",
489 force_defaults=False
489 force_defaults=False
490 )
490 )
491 return Response(html)
491 return Response(html)
492
492
493 @LoginRequired()
493 @LoginRequired()
494 @HasPermissionAllDecorator('hg.admin')
494 @HasPermissionAllDecorator('hg.admin')
495 @view_config(
495 @view_config(
496 route_name='user_edit_advanced', request_method='GET',
496 route_name='user_edit_advanced', request_method='GET',
497 renderer='rhodecode:templates/admin/users/user_edit.mako')
497 renderer='rhodecode:templates/admin/users/user_edit.mako')
498 def user_edit_advanced(self):
498 def user_edit_advanced(self):
499 _ = self.request.translate
499 _ = self.request.translate
500 c = self.load_default_context()
500 c = self.load_default_context()
501
501
502 user_id = self.db_user_id
502 user_id = self.db_user_id
503 c.user = self.db_user
503 c.user = self.db_user
504
504
505 c.active = 'advanced'
505 c.active = 'advanced'
506 c.personal_repo_group = RepoGroup.get_user_personal_repo_group(user_id)
506 c.personal_repo_group = RepoGroup.get_user_personal_repo_group(user_id)
507 c.personal_repo_group_name = RepoGroupModel()\
507 c.personal_repo_group_name = RepoGroupModel()\
508 .get_personal_group_name(c.user)
508 .get_personal_group_name(c.user)
509
509
510 c.user_to_review_rules = sorted(
510 c.user_to_review_rules = sorted(
511 (x.user for x in c.user.user_review_rules),
511 (x.user for x in c.user.user_review_rules),
512 key=lambda u: u.username.lower())
512 key=lambda u: u.username.lower())
513
513
514 c.first_admin = User.get_first_super_admin()
514 c.first_admin = User.get_first_super_admin()
515 defaults = c.user.get_dict()
515 defaults = c.user.get_dict()
516
516
517 # Interim workaround if the user participated on any pull requests as a
517 # Interim workaround if the user participated on any pull requests as a
518 # reviewer.
518 # reviewer.
519 has_review = len(c.user.reviewer_pull_requests)
519 has_review = len(c.user.reviewer_pull_requests)
520 c.can_delete_user = not has_review
520 c.can_delete_user = not has_review
521 c.can_delete_user_message = ''
521 c.can_delete_user_message = ''
522 inactive_link = h.link_to(
522 inactive_link = h.link_to(
523 'inactive', h.route_path('user_edit', user_id=user_id, _anchor='active'))
523 'inactive', h.route_path('user_edit', user_id=user_id, _anchor='active'))
524 if has_review == 1:
524 if has_review == 1:
525 c.can_delete_user_message = h.literal(_(
525 c.can_delete_user_message = h.literal(_(
526 'The user participates as reviewer in {} pull request and '
526 'The user participates as reviewer in {} pull request and '
527 'cannot be deleted. \nYou can set the user to '
527 'cannot be deleted. \nYou can set the user to '
528 '"{}" instead of deleting it.').format(
528 '"{}" instead of deleting it.').format(
529 has_review, inactive_link))
529 has_review, inactive_link))
530 elif has_review:
530 elif has_review:
531 c.can_delete_user_message = h.literal(_(
531 c.can_delete_user_message = h.literal(_(
532 'The user participates as reviewer in {} pull requests and '
532 'The user participates as reviewer in {} pull requests and '
533 'cannot be deleted. \nYou can set the user to '
533 'cannot be deleted. \nYou can set the user to '
534 '"{}" instead of deleting it.').format(
534 '"{}" instead of deleting it.').format(
535 has_review, inactive_link))
535 has_review, inactive_link))
536
536
537 data = render(
537 data = render(
538 'rhodecode:templates/admin/users/user_edit.mako',
538 'rhodecode:templates/admin/users/user_edit.mako',
539 self._get_template_context(c), self.request)
539 self._get_template_context(c), self.request)
540 html = formencode.htmlfill.render(
540 html = formencode.htmlfill.render(
541 data,
541 data,
542 defaults=defaults,
542 defaults=defaults,
543 encoding="UTF-8",
543 encoding="UTF-8",
544 force_defaults=False
544 force_defaults=False
545 )
545 )
546 return Response(html)
546 return Response(html)
547
547
548 @LoginRequired()
548 @LoginRequired()
549 @HasPermissionAllDecorator('hg.admin')
549 @HasPermissionAllDecorator('hg.admin')
550 @view_config(
550 @view_config(
551 route_name='user_edit_global_perms', request_method='GET',
551 route_name='user_edit_global_perms', request_method='GET',
552 renderer='rhodecode:templates/admin/users/user_edit.mako')
552 renderer='rhodecode:templates/admin/users/user_edit.mako')
553 def user_edit_global_perms(self):
553 def user_edit_global_perms(self):
554 _ = self.request.translate
554 _ = self.request.translate
555 c = self.load_default_context()
555 c = self.load_default_context()
556 c.user = self.db_user
556 c.user = self.db_user
557
557
558 c.active = 'global_perms'
558 c.active = 'global_perms'
559
559
560 c.default_user = User.get_default_user()
560 c.default_user = User.get_default_user()
561 defaults = c.user.get_dict()
561 defaults = c.user.get_dict()
562 defaults.update(c.default_user.get_default_perms(suffix='_inherited'))
562 defaults.update(c.default_user.get_default_perms(suffix='_inherited'))
563 defaults.update(c.default_user.get_default_perms())
563 defaults.update(c.default_user.get_default_perms())
564 defaults.update(c.user.get_default_perms())
564 defaults.update(c.user.get_default_perms())
565
565
566 data = render(
566 data = render(
567 'rhodecode:templates/admin/users/user_edit.mako',
567 'rhodecode:templates/admin/users/user_edit.mako',
568 self._get_template_context(c), self.request)
568 self._get_template_context(c), self.request)
569 html = formencode.htmlfill.render(
569 html = formencode.htmlfill.render(
570 data,
570 data,
571 defaults=defaults,
571 defaults=defaults,
572 encoding="UTF-8",
572 encoding="UTF-8",
573 force_defaults=False
573 force_defaults=False
574 )
574 )
575 return Response(html)
575 return Response(html)
576
576
577 @LoginRequired()
577 @LoginRequired()
578 @HasPermissionAllDecorator('hg.admin')
578 @HasPermissionAllDecorator('hg.admin')
579 @CSRFRequired()
579 @CSRFRequired()
580 @view_config(
580 @view_config(
581 route_name='user_edit_global_perms_update', request_method='POST',
581 route_name='user_edit_global_perms_update', request_method='POST',
582 renderer='rhodecode:templates/admin/users/user_edit.mako')
582 renderer='rhodecode:templates/admin/users/user_edit.mako')
583 def user_edit_global_perms_update(self):
583 def user_edit_global_perms_update(self):
584 _ = self.request.translate
584 _ = self.request.translate
585 c = self.load_default_context()
585 c = self.load_default_context()
586
586
587 user_id = self.db_user_id
587 user_id = self.db_user_id
588 c.user = self.db_user
588 c.user = self.db_user
589
589
590 c.active = 'global_perms'
590 c.active = 'global_perms'
591 try:
591 try:
592 # first stage that verifies the checkbox
592 # first stage that verifies the checkbox
593 _form = UserIndividualPermissionsForm(self.request.translate)
593 _form = UserIndividualPermissionsForm(self.request.translate)
594 form_result = _form.to_python(dict(self.request.POST))
594 form_result = _form.to_python(dict(self.request.POST))
595 inherit_perms = form_result['inherit_default_permissions']
595 inherit_perms = form_result['inherit_default_permissions']
596 c.user.inherit_default_permissions = inherit_perms
596 c.user.inherit_default_permissions = inherit_perms
597 Session().add(c.user)
597 Session().add(c.user)
598
598
599 if not inherit_perms:
599 if not inherit_perms:
600 # only update the individual ones if we un check the flag
600 # only update the individual ones if we un check the flag
601 _form = UserPermissionsForm(
601 _form = UserPermissionsForm(
602 self.request.translate,
602 self.request.translate,
603 [x[0] for x in c.repo_create_choices],
603 [x[0] for x in c.repo_create_choices],
604 [x[0] for x in c.repo_create_on_write_choices],
604 [x[0] for x in c.repo_create_on_write_choices],
605 [x[0] for x in c.repo_group_create_choices],
605 [x[0] for x in c.repo_group_create_choices],
606 [x[0] for x in c.user_group_create_choices],
606 [x[0] for x in c.user_group_create_choices],
607 [x[0] for x in c.fork_choices],
607 [x[0] for x in c.fork_choices],
608 [x[0] for x in c.inherit_default_permission_choices])()
608 [x[0] for x in c.inherit_default_permission_choices])()
609
609
610 form_result = _form.to_python(dict(self.request.POST))
610 form_result = _form.to_python(dict(self.request.POST))
611 form_result.update({'perm_user_id': c.user.user_id})
611 form_result.update({'perm_user_id': c.user.user_id})
612
612
613 PermissionModel().update_user_permissions(form_result)
613 PermissionModel().update_user_permissions(form_result)
614
614
615 # TODO(marcink): implement global permissions
615 # TODO(marcink): implement global permissions
616 # audit_log.store_web('user.edit.permissions')
616 # audit_log.store_web('user.edit.permissions')
617
617
618 Session().commit()
618 Session().commit()
619
619
620 h.flash(_('User global permissions updated successfully'),
620 h.flash(_('User global permissions updated successfully'),
621 category='success')
621 category='success')
622
622
623 except formencode.Invalid as errors:
623 except formencode.Invalid as errors:
624 data = render(
624 data = render(
625 'rhodecode:templates/admin/users/user_edit.mako',
625 'rhodecode:templates/admin/users/user_edit.mako',
626 self._get_template_context(c), self.request)
626 self._get_template_context(c), self.request)
627 html = formencode.htmlfill.render(
627 html = formencode.htmlfill.render(
628 data,
628 data,
629 defaults=errors.value,
629 defaults=errors.value,
630 errors=errors.error_dict or {},
630 errors=errors.error_dict or {},
631 prefix_error=False,
631 prefix_error=False,
632 encoding="UTF-8",
632 encoding="UTF-8",
633 force_defaults=False
633 force_defaults=False
634 )
634 )
635 return Response(html)
635 return Response(html)
636 except Exception:
636 except Exception:
637 log.exception("Exception during permissions saving")
637 log.exception("Exception during permissions saving")
638 h.flash(_('An error occurred during permissions saving'),
638 h.flash(_('An error occurred during permissions saving'),
639 category='error')
639 category='error')
640
640
641 affected_user_ids = [user_id]
641 affected_user_ids = [user_id]
642 PermissionModel().trigger_permission_flush(affected_user_ids)
642 PermissionModel().trigger_permission_flush(affected_user_ids)
643 raise HTTPFound(h.route_path('user_edit_global_perms', user_id=user_id))
643 raise HTTPFound(h.route_path('user_edit_global_perms', user_id=user_id))
644
644
645 @LoginRequired()
645 @LoginRequired()
646 @HasPermissionAllDecorator('hg.admin')
646 @HasPermissionAllDecorator('hg.admin')
647 @CSRFRequired()
647 @CSRFRequired()
648 @view_config(
648 @view_config(
649 route_name='user_enable_force_password_reset', request_method='POST',
649 route_name='user_enable_force_password_reset', request_method='POST',
650 renderer='rhodecode:templates/admin/users/user_edit.mako')
650 renderer='rhodecode:templates/admin/users/user_edit.mako')
651 def user_enable_force_password_reset(self):
651 def user_enable_force_password_reset(self):
652 _ = self.request.translate
652 _ = self.request.translate
653 c = self.load_default_context()
653 c = self.load_default_context()
654
654
655 user_id = self.db_user_id
655 user_id = self.db_user_id
656 c.user = self.db_user
656 c.user = self.db_user
657
657
658 try:
658 try:
659 c.user.update_userdata(force_password_change=True)
659 c.user.update_userdata(force_password_change=True)
660
660
661 msg = _('Force password change enabled for user')
661 msg = _('Force password change enabled for user')
662 audit_logger.store_web('user.edit.password_reset.enabled',
662 audit_logger.store_web('user.edit.password_reset.enabled',
663 user=c.rhodecode_user)
663 user=c.rhodecode_user)
664
664
665 Session().commit()
665 Session().commit()
666 h.flash(msg, category='success')
666 h.flash(msg, category='success')
667 except Exception:
667 except Exception:
668 log.exception("Exception during password reset for user")
668 log.exception("Exception during password reset for user")
669 h.flash(_('An error occurred during password reset for user'),
669 h.flash(_('An error occurred during password reset for user'),
670 category='error')
670 category='error')
671
671
672 raise HTTPFound(h.route_path('user_edit_advanced', user_id=user_id))
672 raise HTTPFound(h.route_path('user_edit_advanced', user_id=user_id))
673
673
674 @LoginRequired()
674 @LoginRequired()
675 @HasPermissionAllDecorator('hg.admin')
675 @HasPermissionAllDecorator('hg.admin')
676 @CSRFRequired()
676 @CSRFRequired()
677 @view_config(
677 @view_config(
678 route_name='user_disable_force_password_reset', request_method='POST',
678 route_name='user_disable_force_password_reset', request_method='POST',
679 renderer='rhodecode:templates/admin/users/user_edit.mako')
679 renderer='rhodecode:templates/admin/users/user_edit.mako')
680 def user_disable_force_password_reset(self):
680 def user_disable_force_password_reset(self):
681 _ = self.request.translate
681 _ = self.request.translate
682 c = self.load_default_context()
682 c = self.load_default_context()
683
683
684 user_id = self.db_user_id
684 user_id = self.db_user_id
685 c.user = self.db_user
685 c.user = self.db_user
686
686
687 try:
687 try:
688 c.user.update_userdata(force_password_change=False)
688 c.user.update_userdata(force_password_change=False)
689
689
690 msg = _('Force password change disabled for user')
690 msg = _('Force password change disabled for user')
691 audit_logger.store_web(
691 audit_logger.store_web(
692 'user.edit.password_reset.disabled',
692 'user.edit.password_reset.disabled',
693 user=c.rhodecode_user)
693 user=c.rhodecode_user)
694
694
695 Session().commit()
695 Session().commit()
696 h.flash(msg, category='success')
696 h.flash(msg, category='success')
697 except Exception:
697 except Exception:
698 log.exception("Exception during password reset for user")
698 log.exception("Exception during password reset for user")
699 h.flash(_('An error occurred during password reset for user'),
699 h.flash(_('An error occurred during password reset for user'),
700 category='error')
700 category='error')
701
701
702 raise HTTPFound(h.route_path('user_edit_advanced', user_id=user_id))
702 raise HTTPFound(h.route_path('user_edit_advanced', user_id=user_id))
703
703
704 @LoginRequired()
704 @LoginRequired()
705 @HasPermissionAllDecorator('hg.admin')
705 @HasPermissionAllDecorator('hg.admin')
706 @CSRFRequired()
706 @CSRFRequired()
707 @view_config(
707 @view_config(
708 route_name='user_notice_dismiss', request_method='POST',
709 renderer='json_ext', xhr=True)
710 def user_notice_dismiss(self):
711 _ = self.request.translate
712 c = self.load_default_context()
713
714 user_id = self.db_user_id
715 c.user = self.db_user
716 user_notice_id = safe_int(self.request.POST.get('notice_id'))
717 notice = UserNotice().query()\
718 .filter(UserNotice.user_id == user_id)\
719 .filter(UserNotice.user_notice_id == user_notice_id)\
720 .scalar()
721 read = False
722 if notice:
723 notice.notice_read = True
724 Session().add(notice)
725 Session().commit()
726 read = True
727
728 return {'notice': user_notice_id, 'read': read}
729
730 @LoginRequired()
731 @HasPermissionAllDecorator('hg.admin')
732 @CSRFRequired()
733 @view_config(
708 route_name='user_create_personal_repo_group', request_method='POST',
734 route_name='user_create_personal_repo_group', request_method='POST',
709 renderer='rhodecode:templates/admin/users/user_edit.mako')
735 renderer='rhodecode:templates/admin/users/user_edit.mako')
710 def user_create_personal_repo_group(self):
736 def user_create_personal_repo_group(self):
711 """
737 """
712 Create personal repository group for this user
738 Create personal repository group for this user
713 """
739 """
714 from rhodecode.model.repo_group import RepoGroupModel
740 from rhodecode.model.repo_group import RepoGroupModel
715
741
716 _ = self.request.translate
742 _ = self.request.translate
717 c = self.load_default_context()
743 c = self.load_default_context()
718
744
719 user_id = self.db_user_id
745 user_id = self.db_user_id
720 c.user = self.db_user
746 c.user = self.db_user
721
747
722 personal_repo_group = RepoGroup.get_user_personal_repo_group(
748 personal_repo_group = RepoGroup.get_user_personal_repo_group(
723 c.user.user_id)
749 c.user.user_id)
724 if personal_repo_group:
750 if personal_repo_group:
725 raise HTTPFound(h.route_path('user_edit_advanced', user_id=user_id))
751 raise HTTPFound(h.route_path('user_edit_advanced', user_id=user_id))
726
752
727 personal_repo_group_name = RepoGroupModel().get_personal_group_name(c.user)
753 personal_repo_group_name = RepoGroupModel().get_personal_group_name(c.user)
728 named_personal_group = RepoGroup.get_by_group_name(
754 named_personal_group = RepoGroup.get_by_group_name(
729 personal_repo_group_name)
755 personal_repo_group_name)
730 try:
756 try:
731
757
732 if named_personal_group and named_personal_group.user_id == c.user.user_id:
758 if named_personal_group and named_personal_group.user_id == c.user.user_id:
733 # migrate the same named group, and mark it as personal
759 # migrate the same named group, and mark it as personal
734 named_personal_group.personal = True
760 named_personal_group.personal = True
735 Session().add(named_personal_group)
761 Session().add(named_personal_group)
736 Session().commit()
762 Session().commit()
737 msg = _('Linked repository group `%s` as personal' % (
763 msg = _('Linked repository group `%s` as personal' % (
738 personal_repo_group_name,))
764 personal_repo_group_name,))
739 h.flash(msg, category='success')
765 h.flash(msg, category='success')
740 elif not named_personal_group:
766 elif not named_personal_group:
741 RepoGroupModel().create_personal_repo_group(c.user)
767 RepoGroupModel().create_personal_repo_group(c.user)
742
768
743 msg = _('Created repository group `%s`' % (
769 msg = _('Created repository group `%s`' % (
744 personal_repo_group_name,))
770 personal_repo_group_name,))
745 h.flash(msg, category='success')
771 h.flash(msg, category='success')
746 else:
772 else:
747 msg = _('Repository group `%s` is already taken' % (
773 msg = _('Repository group `%s` is already taken' % (
748 personal_repo_group_name,))
774 personal_repo_group_name,))
749 h.flash(msg, category='warning')
775 h.flash(msg, category='warning')
750 except Exception:
776 except Exception:
751 log.exception("Exception during repository group creation")
777 log.exception("Exception during repository group creation")
752 msg = _(
778 msg = _(
753 'An error occurred during repository group creation for user')
779 'An error occurred during repository group creation for user')
754 h.flash(msg, category='error')
780 h.flash(msg, category='error')
755 Session().rollback()
781 Session().rollback()
756
782
757 raise HTTPFound(h.route_path('user_edit_advanced', user_id=user_id))
783 raise HTTPFound(h.route_path('user_edit_advanced', user_id=user_id))
758
784
759 @LoginRequired()
785 @LoginRequired()
760 @HasPermissionAllDecorator('hg.admin')
786 @HasPermissionAllDecorator('hg.admin')
761 @view_config(
787 @view_config(
762 route_name='edit_user_auth_tokens', request_method='GET',
788 route_name='edit_user_auth_tokens', request_method='GET',
763 renderer='rhodecode:templates/admin/users/user_edit.mako')
789 renderer='rhodecode:templates/admin/users/user_edit.mako')
764 def auth_tokens(self):
790 def auth_tokens(self):
765 _ = self.request.translate
791 _ = self.request.translate
766 c = self.load_default_context()
792 c = self.load_default_context()
767 c.user = self.db_user
793 c.user = self.db_user
768
794
769 c.active = 'auth_tokens'
795 c.active = 'auth_tokens'
770
796
771 c.lifetime_values = AuthTokenModel.get_lifetime_values(translator=_)
797 c.lifetime_values = AuthTokenModel.get_lifetime_values(translator=_)
772 c.role_values = [
798 c.role_values = [
773 (x, AuthTokenModel.cls._get_role_name(x))
799 (x, AuthTokenModel.cls._get_role_name(x))
774 for x in AuthTokenModel.cls.ROLES]
800 for x in AuthTokenModel.cls.ROLES]
775 c.role_options = [(c.role_values, _("Role"))]
801 c.role_options = [(c.role_values, _("Role"))]
776 c.user_auth_tokens = AuthTokenModel().get_auth_tokens(
802 c.user_auth_tokens = AuthTokenModel().get_auth_tokens(
777 c.user.user_id, show_expired=True)
803 c.user.user_id, show_expired=True)
778 c.role_vcs = AuthTokenModel.cls.ROLE_VCS
804 c.role_vcs = AuthTokenModel.cls.ROLE_VCS
779 return self._get_template_context(c)
805 return self._get_template_context(c)
780
806
781 def maybe_attach_token_scope(self, token):
807 def maybe_attach_token_scope(self, token):
782 # implemented in EE edition
808 # implemented in EE edition
783 pass
809 pass
784
810
785 @LoginRequired()
811 @LoginRequired()
786 @HasPermissionAllDecorator('hg.admin')
812 @HasPermissionAllDecorator('hg.admin')
787 @CSRFRequired()
813 @CSRFRequired()
788 @view_config(
814 @view_config(
789 route_name='edit_user_auth_tokens_add', request_method='POST')
815 route_name='edit_user_auth_tokens_add', request_method='POST')
790 def auth_tokens_add(self):
816 def auth_tokens_add(self):
791 _ = self.request.translate
817 _ = self.request.translate
792 c = self.load_default_context()
818 c = self.load_default_context()
793
819
794 user_id = self.db_user_id
820 user_id = self.db_user_id
795 c.user = self.db_user
821 c.user = self.db_user
796
822
797 user_data = c.user.get_api_data()
823 user_data = c.user.get_api_data()
798 lifetime = safe_int(self.request.POST.get('lifetime'), -1)
824 lifetime = safe_int(self.request.POST.get('lifetime'), -1)
799 description = self.request.POST.get('description')
825 description = self.request.POST.get('description')
800 role = self.request.POST.get('role')
826 role = self.request.POST.get('role')
801
827
802 token = UserModel().add_auth_token(
828 token = UserModel().add_auth_token(
803 user=c.user.user_id,
829 user=c.user.user_id,
804 lifetime_minutes=lifetime, role=role, description=description,
830 lifetime_minutes=lifetime, role=role, description=description,
805 scope_callback=self.maybe_attach_token_scope)
831 scope_callback=self.maybe_attach_token_scope)
806 token_data = token.get_api_data()
832 token_data = token.get_api_data()
807
833
808 audit_logger.store_web(
834 audit_logger.store_web(
809 'user.edit.token.add', action_data={
835 'user.edit.token.add', action_data={
810 'data': {'token': token_data, 'user': user_data}},
836 'data': {'token': token_data, 'user': user_data}},
811 user=self._rhodecode_user, )
837 user=self._rhodecode_user, )
812 Session().commit()
838 Session().commit()
813
839
814 h.flash(_("Auth token successfully created"), category='success')
840 h.flash(_("Auth token successfully created"), category='success')
815 return HTTPFound(h.route_path('edit_user_auth_tokens', user_id=user_id))
841 return HTTPFound(h.route_path('edit_user_auth_tokens', user_id=user_id))
816
842
817 @LoginRequired()
843 @LoginRequired()
818 @HasPermissionAllDecorator('hg.admin')
844 @HasPermissionAllDecorator('hg.admin')
819 @CSRFRequired()
845 @CSRFRequired()
820 @view_config(
846 @view_config(
821 route_name='edit_user_auth_tokens_delete', request_method='POST')
847 route_name='edit_user_auth_tokens_delete', request_method='POST')
822 def auth_tokens_delete(self):
848 def auth_tokens_delete(self):
823 _ = self.request.translate
849 _ = self.request.translate
824 c = self.load_default_context()
850 c = self.load_default_context()
825
851
826 user_id = self.db_user_id
852 user_id = self.db_user_id
827 c.user = self.db_user
853 c.user = self.db_user
828
854
829 user_data = c.user.get_api_data()
855 user_data = c.user.get_api_data()
830
856
831 del_auth_token = self.request.POST.get('del_auth_token')
857 del_auth_token = self.request.POST.get('del_auth_token')
832
858
833 if del_auth_token:
859 if del_auth_token:
834 token = UserApiKeys.get_or_404(del_auth_token)
860 token = UserApiKeys.get_or_404(del_auth_token)
835 token_data = token.get_api_data()
861 token_data = token.get_api_data()
836
862
837 AuthTokenModel().delete(del_auth_token, c.user.user_id)
863 AuthTokenModel().delete(del_auth_token, c.user.user_id)
838 audit_logger.store_web(
864 audit_logger.store_web(
839 'user.edit.token.delete', action_data={
865 'user.edit.token.delete', action_data={
840 'data': {'token': token_data, 'user': user_data}},
866 'data': {'token': token_data, 'user': user_data}},
841 user=self._rhodecode_user,)
867 user=self._rhodecode_user,)
842 Session().commit()
868 Session().commit()
843 h.flash(_("Auth token successfully deleted"), category='success')
869 h.flash(_("Auth token successfully deleted"), category='success')
844
870
845 return HTTPFound(h.route_path('edit_user_auth_tokens', user_id=user_id))
871 return HTTPFound(h.route_path('edit_user_auth_tokens', user_id=user_id))
846
872
847 @LoginRequired()
873 @LoginRequired()
848 @HasPermissionAllDecorator('hg.admin')
874 @HasPermissionAllDecorator('hg.admin')
849 @view_config(
875 @view_config(
850 route_name='edit_user_ssh_keys', request_method='GET',
876 route_name='edit_user_ssh_keys', request_method='GET',
851 renderer='rhodecode:templates/admin/users/user_edit.mako')
877 renderer='rhodecode:templates/admin/users/user_edit.mako')
852 def ssh_keys(self):
878 def ssh_keys(self):
853 _ = self.request.translate
879 _ = self.request.translate
854 c = self.load_default_context()
880 c = self.load_default_context()
855 c.user = self.db_user
881 c.user = self.db_user
856
882
857 c.active = 'ssh_keys'
883 c.active = 'ssh_keys'
858 c.default_key = self.request.GET.get('default_key')
884 c.default_key = self.request.GET.get('default_key')
859 c.user_ssh_keys = SshKeyModel().get_ssh_keys(c.user.user_id)
885 c.user_ssh_keys = SshKeyModel().get_ssh_keys(c.user.user_id)
860 return self._get_template_context(c)
886 return self._get_template_context(c)
861
887
862 @LoginRequired()
888 @LoginRequired()
863 @HasPermissionAllDecorator('hg.admin')
889 @HasPermissionAllDecorator('hg.admin')
864 @view_config(
890 @view_config(
865 route_name='edit_user_ssh_keys_generate_keypair', request_method='GET',
891 route_name='edit_user_ssh_keys_generate_keypair', request_method='GET',
866 renderer='rhodecode:templates/admin/users/user_edit.mako')
892 renderer='rhodecode:templates/admin/users/user_edit.mako')
867 def ssh_keys_generate_keypair(self):
893 def ssh_keys_generate_keypair(self):
868 _ = self.request.translate
894 _ = self.request.translate
869 c = self.load_default_context()
895 c = self.load_default_context()
870
896
871 c.user = self.db_user
897 c.user = self.db_user
872
898
873 c.active = 'ssh_keys_generate'
899 c.active = 'ssh_keys_generate'
874 comment = 'RhodeCode-SSH {}'.format(c.user.email or '')
900 comment = 'RhodeCode-SSH {}'.format(c.user.email or '')
875 private_format = self.request.GET.get('private_format') \
901 private_format = self.request.GET.get('private_format') \
876 or SshKeyModel.DEFAULT_PRIVATE_KEY_FORMAT
902 or SshKeyModel.DEFAULT_PRIVATE_KEY_FORMAT
877 c.private, c.public = SshKeyModel().generate_keypair(
903 c.private, c.public = SshKeyModel().generate_keypair(
878 comment=comment, private_format=private_format)
904 comment=comment, private_format=private_format)
879
905
880 return self._get_template_context(c)
906 return self._get_template_context(c)
881
907
882 @LoginRequired()
908 @LoginRequired()
883 @HasPermissionAllDecorator('hg.admin')
909 @HasPermissionAllDecorator('hg.admin')
884 @CSRFRequired()
910 @CSRFRequired()
885 @view_config(
911 @view_config(
886 route_name='edit_user_ssh_keys_add', request_method='POST')
912 route_name='edit_user_ssh_keys_add', request_method='POST')
887 def ssh_keys_add(self):
913 def ssh_keys_add(self):
888 _ = self.request.translate
914 _ = self.request.translate
889 c = self.load_default_context()
915 c = self.load_default_context()
890
916
891 user_id = self.db_user_id
917 user_id = self.db_user_id
892 c.user = self.db_user
918 c.user = self.db_user
893
919
894 user_data = c.user.get_api_data()
920 user_data = c.user.get_api_data()
895 key_data = self.request.POST.get('key_data')
921 key_data = self.request.POST.get('key_data')
896 description = self.request.POST.get('description')
922 description = self.request.POST.get('description')
897
923
898 fingerprint = 'unknown'
924 fingerprint = 'unknown'
899 try:
925 try:
900 if not key_data:
926 if not key_data:
901 raise ValueError('Please add a valid public key')
927 raise ValueError('Please add a valid public key')
902
928
903 key = SshKeyModel().parse_key(key_data.strip())
929 key = SshKeyModel().parse_key(key_data.strip())
904 fingerprint = key.hash_md5()
930 fingerprint = key.hash_md5()
905
931
906 ssh_key = SshKeyModel().create(
932 ssh_key = SshKeyModel().create(
907 c.user.user_id, fingerprint, key.keydata, description)
933 c.user.user_id, fingerprint, key.keydata, description)
908 ssh_key_data = ssh_key.get_api_data()
934 ssh_key_data = ssh_key.get_api_data()
909
935
910 audit_logger.store_web(
936 audit_logger.store_web(
911 'user.edit.ssh_key.add', action_data={
937 'user.edit.ssh_key.add', action_data={
912 'data': {'ssh_key': ssh_key_data, 'user': user_data}},
938 'data': {'ssh_key': ssh_key_data, 'user': user_data}},
913 user=self._rhodecode_user, )
939 user=self._rhodecode_user, )
914 Session().commit()
940 Session().commit()
915
941
916 # Trigger an event on change of keys.
942 # Trigger an event on change of keys.
917 trigger(SshKeyFileChangeEvent(), self.request.registry)
943 trigger(SshKeyFileChangeEvent(), self.request.registry)
918
944
919 h.flash(_("Ssh Key successfully created"), category='success')
945 h.flash(_("Ssh Key successfully created"), category='success')
920
946
921 except IntegrityError:
947 except IntegrityError:
922 log.exception("Exception during ssh key saving")
948 log.exception("Exception during ssh key saving")
923 err = 'Such key with fingerprint `{}` already exists, ' \
949 err = 'Such key with fingerprint `{}` already exists, ' \
924 'please use a different one'.format(fingerprint)
950 'please use a different one'.format(fingerprint)
925 h.flash(_('An error occurred during ssh key saving: {}').format(err),
951 h.flash(_('An error occurred during ssh key saving: {}').format(err),
926 category='error')
952 category='error')
927 except Exception as e:
953 except Exception as e:
928 log.exception("Exception during ssh key saving")
954 log.exception("Exception during ssh key saving")
929 h.flash(_('An error occurred during ssh key saving: {}').format(e),
955 h.flash(_('An error occurred during ssh key saving: {}').format(e),
930 category='error')
956 category='error')
931
957
932 return HTTPFound(
958 return HTTPFound(
933 h.route_path('edit_user_ssh_keys', user_id=user_id))
959 h.route_path('edit_user_ssh_keys', user_id=user_id))
934
960
935 @LoginRequired()
961 @LoginRequired()
936 @HasPermissionAllDecorator('hg.admin')
962 @HasPermissionAllDecorator('hg.admin')
937 @CSRFRequired()
963 @CSRFRequired()
938 @view_config(
964 @view_config(
939 route_name='edit_user_ssh_keys_delete', request_method='POST')
965 route_name='edit_user_ssh_keys_delete', request_method='POST')
940 def ssh_keys_delete(self):
966 def ssh_keys_delete(self):
941 _ = self.request.translate
967 _ = self.request.translate
942 c = self.load_default_context()
968 c = self.load_default_context()
943
969
944 user_id = self.db_user_id
970 user_id = self.db_user_id
945 c.user = self.db_user
971 c.user = self.db_user
946
972
947 user_data = c.user.get_api_data()
973 user_data = c.user.get_api_data()
948
974
949 del_ssh_key = self.request.POST.get('del_ssh_key')
975 del_ssh_key = self.request.POST.get('del_ssh_key')
950
976
951 if del_ssh_key:
977 if del_ssh_key:
952 ssh_key = UserSshKeys.get_or_404(del_ssh_key)
978 ssh_key = UserSshKeys.get_or_404(del_ssh_key)
953 ssh_key_data = ssh_key.get_api_data()
979 ssh_key_data = ssh_key.get_api_data()
954
980
955 SshKeyModel().delete(del_ssh_key, c.user.user_id)
981 SshKeyModel().delete(del_ssh_key, c.user.user_id)
956 audit_logger.store_web(
982 audit_logger.store_web(
957 'user.edit.ssh_key.delete', action_data={
983 'user.edit.ssh_key.delete', action_data={
958 'data': {'ssh_key': ssh_key_data, 'user': user_data}},
984 'data': {'ssh_key': ssh_key_data, 'user': user_data}},
959 user=self._rhodecode_user,)
985 user=self._rhodecode_user,)
960 Session().commit()
986 Session().commit()
961 # Trigger an event on change of keys.
987 # Trigger an event on change of keys.
962 trigger(SshKeyFileChangeEvent(), self.request.registry)
988 trigger(SshKeyFileChangeEvent(), self.request.registry)
963 h.flash(_("Ssh key successfully deleted"), category='success')
989 h.flash(_("Ssh key successfully deleted"), category='success')
964
990
965 return HTTPFound(h.route_path('edit_user_ssh_keys', user_id=user_id))
991 return HTTPFound(h.route_path('edit_user_ssh_keys', user_id=user_id))
966
992
967 @LoginRequired()
993 @LoginRequired()
968 @HasPermissionAllDecorator('hg.admin')
994 @HasPermissionAllDecorator('hg.admin')
969 @view_config(
995 @view_config(
970 route_name='edit_user_emails', request_method='GET',
996 route_name='edit_user_emails', request_method='GET',
971 renderer='rhodecode:templates/admin/users/user_edit.mako')
997 renderer='rhodecode:templates/admin/users/user_edit.mako')
972 def emails(self):
998 def emails(self):
973 _ = self.request.translate
999 _ = self.request.translate
974 c = self.load_default_context()
1000 c = self.load_default_context()
975 c.user = self.db_user
1001 c.user = self.db_user
976
1002
977 c.active = 'emails'
1003 c.active = 'emails'
978 c.user_email_map = UserEmailMap.query() \
1004 c.user_email_map = UserEmailMap.query() \
979 .filter(UserEmailMap.user == c.user).all()
1005 .filter(UserEmailMap.user == c.user).all()
980
1006
981 return self._get_template_context(c)
1007 return self._get_template_context(c)
982
1008
983 @LoginRequired()
1009 @LoginRequired()
984 @HasPermissionAllDecorator('hg.admin')
1010 @HasPermissionAllDecorator('hg.admin')
985 @CSRFRequired()
1011 @CSRFRequired()
986 @view_config(
1012 @view_config(
987 route_name='edit_user_emails_add', request_method='POST')
1013 route_name='edit_user_emails_add', request_method='POST')
988 def emails_add(self):
1014 def emails_add(self):
989 _ = self.request.translate
1015 _ = self.request.translate
990 c = self.load_default_context()
1016 c = self.load_default_context()
991
1017
992 user_id = self.db_user_id
1018 user_id = self.db_user_id
993 c.user = self.db_user
1019 c.user = self.db_user
994
1020
995 email = self.request.POST.get('new_email')
1021 email = self.request.POST.get('new_email')
996 user_data = c.user.get_api_data()
1022 user_data = c.user.get_api_data()
997 try:
1023 try:
998
1024
999 form = UserExtraEmailForm(self.request.translate)()
1025 form = UserExtraEmailForm(self.request.translate)()
1000 data = form.to_python({'email': email})
1026 data = form.to_python({'email': email})
1001 email = data['email']
1027 email = data['email']
1002
1028
1003 UserModel().add_extra_email(c.user.user_id, email)
1029 UserModel().add_extra_email(c.user.user_id, email)
1004 audit_logger.store_web(
1030 audit_logger.store_web(
1005 'user.edit.email.add',
1031 'user.edit.email.add',
1006 action_data={'email': email, 'user': user_data},
1032 action_data={'email': email, 'user': user_data},
1007 user=self._rhodecode_user)
1033 user=self._rhodecode_user)
1008 Session().commit()
1034 Session().commit()
1009 h.flash(_("Added new email address `%s` for user account") % email,
1035 h.flash(_("Added new email address `%s` for user account") % email,
1010 category='success')
1036 category='success')
1011 except formencode.Invalid as error:
1037 except formencode.Invalid as error:
1012 h.flash(h.escape(error.error_dict['email']), category='error')
1038 h.flash(h.escape(error.error_dict['email']), category='error')
1013 except IntegrityError:
1039 except IntegrityError:
1014 log.warning("Email %s already exists", email)
1040 log.warning("Email %s already exists", email)
1015 h.flash(_('Email `{}` is already registered for another user.').format(email),
1041 h.flash(_('Email `{}` is already registered for another user.').format(email),
1016 category='error')
1042 category='error')
1017 except Exception:
1043 except Exception:
1018 log.exception("Exception during email saving")
1044 log.exception("Exception during email saving")
1019 h.flash(_('An error occurred during email saving'),
1045 h.flash(_('An error occurred during email saving'),
1020 category='error')
1046 category='error')
1021 raise HTTPFound(h.route_path('edit_user_emails', user_id=user_id))
1047 raise HTTPFound(h.route_path('edit_user_emails', user_id=user_id))
1022
1048
1023 @LoginRequired()
1049 @LoginRequired()
1024 @HasPermissionAllDecorator('hg.admin')
1050 @HasPermissionAllDecorator('hg.admin')
1025 @CSRFRequired()
1051 @CSRFRequired()
1026 @view_config(
1052 @view_config(
1027 route_name='edit_user_emails_delete', request_method='POST')
1053 route_name='edit_user_emails_delete', request_method='POST')
1028 def emails_delete(self):
1054 def emails_delete(self):
1029 _ = self.request.translate
1055 _ = self.request.translate
1030 c = self.load_default_context()
1056 c = self.load_default_context()
1031
1057
1032 user_id = self.db_user_id
1058 user_id = self.db_user_id
1033 c.user = self.db_user
1059 c.user = self.db_user
1034
1060
1035 email_id = self.request.POST.get('del_email_id')
1061 email_id = self.request.POST.get('del_email_id')
1036 user_model = UserModel()
1062 user_model = UserModel()
1037
1063
1038 email = UserEmailMap.query().get(email_id).email
1064 email = UserEmailMap.query().get(email_id).email
1039 user_data = c.user.get_api_data()
1065 user_data = c.user.get_api_data()
1040 user_model.delete_extra_email(c.user.user_id, email_id)
1066 user_model.delete_extra_email(c.user.user_id, email_id)
1041 audit_logger.store_web(
1067 audit_logger.store_web(
1042 'user.edit.email.delete',
1068 'user.edit.email.delete',
1043 action_data={'email': email, 'user': user_data},
1069 action_data={'email': email, 'user': user_data},
1044 user=self._rhodecode_user)
1070 user=self._rhodecode_user)
1045 Session().commit()
1071 Session().commit()
1046 h.flash(_("Removed email address from user account"),
1072 h.flash(_("Removed email address from user account"),
1047 category='success')
1073 category='success')
1048 raise HTTPFound(h.route_path('edit_user_emails', user_id=user_id))
1074 raise HTTPFound(h.route_path('edit_user_emails', user_id=user_id))
1049
1075
1050 @LoginRequired()
1076 @LoginRequired()
1051 @HasPermissionAllDecorator('hg.admin')
1077 @HasPermissionAllDecorator('hg.admin')
1052 @view_config(
1078 @view_config(
1053 route_name='edit_user_ips', request_method='GET',
1079 route_name='edit_user_ips', request_method='GET',
1054 renderer='rhodecode:templates/admin/users/user_edit.mako')
1080 renderer='rhodecode:templates/admin/users/user_edit.mako')
1055 def ips(self):
1081 def ips(self):
1056 _ = self.request.translate
1082 _ = self.request.translate
1057 c = self.load_default_context()
1083 c = self.load_default_context()
1058 c.user = self.db_user
1084 c.user = self.db_user
1059
1085
1060 c.active = 'ips'
1086 c.active = 'ips'
1061 c.user_ip_map = UserIpMap.query() \
1087 c.user_ip_map = UserIpMap.query() \
1062 .filter(UserIpMap.user == c.user).all()
1088 .filter(UserIpMap.user == c.user).all()
1063
1089
1064 c.inherit_default_ips = c.user.inherit_default_permissions
1090 c.inherit_default_ips = c.user.inherit_default_permissions
1065 c.default_user_ip_map = UserIpMap.query() \
1091 c.default_user_ip_map = UserIpMap.query() \
1066 .filter(UserIpMap.user == User.get_default_user()).all()
1092 .filter(UserIpMap.user == User.get_default_user()).all()
1067
1093
1068 return self._get_template_context(c)
1094 return self._get_template_context(c)
1069
1095
1070 @LoginRequired()
1096 @LoginRequired()
1071 @HasPermissionAllDecorator('hg.admin')
1097 @HasPermissionAllDecorator('hg.admin')
1072 @CSRFRequired()
1098 @CSRFRequired()
1073 @view_config(
1099 @view_config(
1074 route_name='edit_user_ips_add', request_method='POST')
1100 route_name='edit_user_ips_add', request_method='POST')
1075 # NOTE(marcink): this view is allowed for default users, as we can
1101 # NOTE(marcink): this view is allowed for default users, as we can
1076 # edit their IP white list
1102 # edit their IP white list
1077 def ips_add(self):
1103 def ips_add(self):
1078 _ = self.request.translate
1104 _ = self.request.translate
1079 c = self.load_default_context()
1105 c = self.load_default_context()
1080
1106
1081 user_id = self.db_user_id
1107 user_id = self.db_user_id
1082 c.user = self.db_user
1108 c.user = self.db_user
1083
1109
1084 user_model = UserModel()
1110 user_model = UserModel()
1085 desc = self.request.POST.get('description')
1111 desc = self.request.POST.get('description')
1086 try:
1112 try:
1087 ip_list = user_model.parse_ip_range(
1113 ip_list = user_model.parse_ip_range(
1088 self.request.POST.get('new_ip'))
1114 self.request.POST.get('new_ip'))
1089 except Exception as e:
1115 except Exception as e:
1090 ip_list = []
1116 ip_list = []
1091 log.exception("Exception during ip saving")
1117 log.exception("Exception during ip saving")
1092 h.flash(_('An error occurred during ip saving:%s' % (e,)),
1118 h.flash(_('An error occurred during ip saving:%s' % (e,)),
1093 category='error')
1119 category='error')
1094 added = []
1120 added = []
1095 user_data = c.user.get_api_data()
1121 user_data = c.user.get_api_data()
1096 for ip in ip_list:
1122 for ip in ip_list:
1097 try:
1123 try:
1098 form = UserExtraIpForm(self.request.translate)()
1124 form = UserExtraIpForm(self.request.translate)()
1099 data = form.to_python({'ip': ip})
1125 data = form.to_python({'ip': ip})
1100 ip = data['ip']
1126 ip = data['ip']
1101
1127
1102 user_model.add_extra_ip(c.user.user_id, ip, desc)
1128 user_model.add_extra_ip(c.user.user_id, ip, desc)
1103 audit_logger.store_web(
1129 audit_logger.store_web(
1104 'user.edit.ip.add',
1130 'user.edit.ip.add',
1105 action_data={'ip': ip, 'user': user_data},
1131 action_data={'ip': ip, 'user': user_data},
1106 user=self._rhodecode_user)
1132 user=self._rhodecode_user)
1107 Session().commit()
1133 Session().commit()
1108 added.append(ip)
1134 added.append(ip)
1109 except formencode.Invalid as error:
1135 except formencode.Invalid as error:
1110 msg = error.error_dict['ip']
1136 msg = error.error_dict['ip']
1111 h.flash(msg, category='error')
1137 h.flash(msg, category='error')
1112 except Exception:
1138 except Exception:
1113 log.exception("Exception during ip saving")
1139 log.exception("Exception during ip saving")
1114 h.flash(_('An error occurred during ip saving'),
1140 h.flash(_('An error occurred during ip saving'),
1115 category='error')
1141 category='error')
1116 if added:
1142 if added:
1117 h.flash(
1143 h.flash(
1118 _("Added ips %s to user whitelist") % (', '.join(ip_list), ),
1144 _("Added ips %s to user whitelist") % (', '.join(ip_list), ),
1119 category='success')
1145 category='success')
1120 if 'default_user' in self.request.POST:
1146 if 'default_user' in self.request.POST:
1121 # case for editing global IP list we do it for 'DEFAULT' user
1147 # case for editing global IP list we do it for 'DEFAULT' user
1122 raise HTTPFound(h.route_path('admin_permissions_ips'))
1148 raise HTTPFound(h.route_path('admin_permissions_ips'))
1123 raise HTTPFound(h.route_path('edit_user_ips', user_id=user_id))
1149 raise HTTPFound(h.route_path('edit_user_ips', user_id=user_id))
1124
1150
1125 @LoginRequired()
1151 @LoginRequired()
1126 @HasPermissionAllDecorator('hg.admin')
1152 @HasPermissionAllDecorator('hg.admin')
1127 @CSRFRequired()
1153 @CSRFRequired()
1128 @view_config(
1154 @view_config(
1129 route_name='edit_user_ips_delete', request_method='POST')
1155 route_name='edit_user_ips_delete', request_method='POST')
1130 # NOTE(marcink): this view is allowed for default users, as we can
1156 # NOTE(marcink): this view is allowed for default users, as we can
1131 # edit their IP white list
1157 # edit their IP white list
1132 def ips_delete(self):
1158 def ips_delete(self):
1133 _ = self.request.translate
1159 _ = self.request.translate
1134 c = self.load_default_context()
1160 c = self.load_default_context()
1135
1161
1136 user_id = self.db_user_id
1162 user_id = self.db_user_id
1137 c.user = self.db_user
1163 c.user = self.db_user
1138
1164
1139 ip_id = self.request.POST.get('del_ip_id')
1165 ip_id = self.request.POST.get('del_ip_id')
1140 user_model = UserModel()
1166 user_model = UserModel()
1141 user_data = c.user.get_api_data()
1167 user_data = c.user.get_api_data()
1142 ip = UserIpMap.query().get(ip_id).ip_addr
1168 ip = UserIpMap.query().get(ip_id).ip_addr
1143 user_model.delete_extra_ip(c.user.user_id, ip_id)
1169 user_model.delete_extra_ip(c.user.user_id, ip_id)
1144 audit_logger.store_web(
1170 audit_logger.store_web(
1145 'user.edit.ip.delete', action_data={'ip': ip, 'user': user_data},
1171 'user.edit.ip.delete', action_data={'ip': ip, 'user': user_data},
1146 user=self._rhodecode_user)
1172 user=self._rhodecode_user)
1147 Session().commit()
1173 Session().commit()
1148 h.flash(_("Removed ip address from user whitelist"), category='success')
1174 h.flash(_("Removed ip address from user whitelist"), category='success')
1149
1175
1150 if 'default_user' in self.request.POST:
1176 if 'default_user' in self.request.POST:
1151 # case for editing global IP list we do it for 'DEFAULT' user
1177 # case for editing global IP list we do it for 'DEFAULT' user
1152 raise HTTPFound(h.route_path('admin_permissions_ips'))
1178 raise HTTPFound(h.route_path('admin_permissions_ips'))
1153 raise HTTPFound(h.route_path('edit_user_ips', user_id=user_id))
1179 raise HTTPFound(h.route_path('edit_user_ips', user_id=user_id))
1154
1180
1155 @LoginRequired()
1181 @LoginRequired()
1156 @HasPermissionAllDecorator('hg.admin')
1182 @HasPermissionAllDecorator('hg.admin')
1157 @view_config(
1183 @view_config(
1158 route_name='edit_user_groups_management', request_method='GET',
1184 route_name='edit_user_groups_management', request_method='GET',
1159 renderer='rhodecode:templates/admin/users/user_edit.mako')
1185 renderer='rhodecode:templates/admin/users/user_edit.mako')
1160 def groups_management(self):
1186 def groups_management(self):
1161 c = self.load_default_context()
1187 c = self.load_default_context()
1162 c.user = self.db_user
1188 c.user = self.db_user
1163 c.data = c.user.group_member
1189 c.data = c.user.group_member
1164
1190
1165 groups = [UserGroupModel.get_user_groups_as_dict(group.users_group)
1191 groups = [UserGroupModel.get_user_groups_as_dict(group.users_group)
1166 for group in c.user.group_member]
1192 for group in c.user.group_member]
1167 c.groups = json.dumps(groups)
1193 c.groups = json.dumps(groups)
1168 c.active = 'groups'
1194 c.active = 'groups'
1169
1195
1170 return self._get_template_context(c)
1196 return self._get_template_context(c)
1171
1197
1172 @LoginRequired()
1198 @LoginRequired()
1173 @HasPermissionAllDecorator('hg.admin')
1199 @HasPermissionAllDecorator('hg.admin')
1174 @CSRFRequired()
1200 @CSRFRequired()
1175 @view_config(
1201 @view_config(
1176 route_name='edit_user_groups_management_updates', request_method='POST')
1202 route_name='edit_user_groups_management_updates', request_method='POST')
1177 def groups_management_updates(self):
1203 def groups_management_updates(self):
1178 _ = self.request.translate
1204 _ = self.request.translate
1179 c = self.load_default_context()
1205 c = self.load_default_context()
1180
1206
1181 user_id = self.db_user_id
1207 user_id = self.db_user_id
1182 c.user = self.db_user
1208 c.user = self.db_user
1183
1209
1184 user_groups = set(self.request.POST.getall('users_group_id'))
1210 user_groups = set(self.request.POST.getall('users_group_id'))
1185 user_groups_objects = []
1211 user_groups_objects = []
1186
1212
1187 for ugid in user_groups:
1213 for ugid in user_groups:
1188 user_groups_objects.append(
1214 user_groups_objects.append(
1189 UserGroupModel().get_group(safe_int(ugid)))
1215 UserGroupModel().get_group(safe_int(ugid)))
1190 user_group_model = UserGroupModel()
1216 user_group_model = UserGroupModel()
1191 added_to_groups, removed_from_groups = \
1217 added_to_groups, removed_from_groups = \
1192 user_group_model.change_groups(c.user, user_groups_objects)
1218 user_group_model.change_groups(c.user, user_groups_objects)
1193
1219
1194 user_data = c.user.get_api_data()
1220 user_data = c.user.get_api_data()
1195 for user_group_id in added_to_groups:
1221 for user_group_id in added_to_groups:
1196 user_group = UserGroup.get(user_group_id)
1222 user_group = UserGroup.get(user_group_id)
1197 old_values = user_group.get_api_data()
1223 old_values = user_group.get_api_data()
1198 audit_logger.store_web(
1224 audit_logger.store_web(
1199 'user_group.edit.member.add',
1225 'user_group.edit.member.add',
1200 action_data={'user': user_data, 'old_data': old_values},
1226 action_data={'user': user_data, 'old_data': old_values},
1201 user=self._rhodecode_user)
1227 user=self._rhodecode_user)
1202
1228
1203 for user_group_id in removed_from_groups:
1229 for user_group_id in removed_from_groups:
1204 user_group = UserGroup.get(user_group_id)
1230 user_group = UserGroup.get(user_group_id)
1205 old_values = user_group.get_api_data()
1231 old_values = user_group.get_api_data()
1206 audit_logger.store_web(
1232 audit_logger.store_web(
1207 'user_group.edit.member.delete',
1233 'user_group.edit.member.delete',
1208 action_data={'user': user_data, 'old_data': old_values},
1234 action_data={'user': user_data, 'old_data': old_values},
1209 user=self._rhodecode_user)
1235 user=self._rhodecode_user)
1210
1236
1211 Session().commit()
1237 Session().commit()
1212 c.active = 'user_groups_management'
1238 c.active = 'user_groups_management'
1213 h.flash(_("Groups successfully changed"), category='success')
1239 h.flash(_("Groups successfully changed"), category='success')
1214
1240
1215 return HTTPFound(h.route_path(
1241 return HTTPFound(h.route_path(
1216 'edit_user_groups_management', user_id=user_id))
1242 'edit_user_groups_management', user_id=user_id))
1217
1243
1218 @LoginRequired()
1244 @LoginRequired()
1219 @HasPermissionAllDecorator('hg.admin')
1245 @HasPermissionAllDecorator('hg.admin')
1220 @view_config(
1246 @view_config(
1221 route_name='edit_user_audit_logs', request_method='GET',
1247 route_name='edit_user_audit_logs', request_method='GET',
1222 renderer='rhodecode:templates/admin/users/user_edit.mako')
1248 renderer='rhodecode:templates/admin/users/user_edit.mako')
1223 def user_audit_logs(self):
1249 def user_audit_logs(self):
1224 _ = self.request.translate
1250 _ = self.request.translate
1225 c = self.load_default_context()
1251 c = self.load_default_context()
1226 c.user = self.db_user
1252 c.user = self.db_user
1227
1253
1228 c.active = 'audit'
1254 c.active = 'audit'
1229
1255
1230 p = safe_int(self.request.GET.get('page', 1), 1)
1256 p = safe_int(self.request.GET.get('page', 1), 1)
1231
1257
1232 filter_term = self.request.GET.get('filter')
1258 filter_term = self.request.GET.get('filter')
1233 user_log = UserModel().get_user_log(c.user, filter_term)
1259 user_log = UserModel().get_user_log(c.user, filter_term)
1234
1260
1235 def url_generator(page_num):
1261 def url_generator(page_num):
1236 query_params = {
1262 query_params = {
1237 'page': page_num
1263 'page': page_num
1238 }
1264 }
1239 if filter_term:
1265 if filter_term:
1240 query_params['filter'] = filter_term
1266 query_params['filter'] = filter_term
1241 return self.request.current_route_path(_query=query_params)
1267 return self.request.current_route_path(_query=query_params)
1242
1268
1243 c.audit_logs = SqlPage(
1269 c.audit_logs = SqlPage(
1244 user_log, page=p, items_per_page=10, url_maker=url_generator)
1270 user_log, page=p, items_per_page=10, url_maker=url_generator)
1245 c.filter_term = filter_term
1271 c.filter_term = filter_term
1246 return self._get_template_context(c)
1272 return self._get_template_context(c)
1247
1273
1248 @LoginRequired()
1274 @LoginRequired()
1249 @HasPermissionAllDecorator('hg.admin')
1275 @HasPermissionAllDecorator('hg.admin')
1250 @view_config(
1276 @view_config(
1251 route_name='edit_user_audit_logs_download', request_method='GET',
1277 route_name='edit_user_audit_logs_download', request_method='GET',
1252 renderer='string')
1278 renderer='string')
1253 def user_audit_logs_download(self):
1279 def user_audit_logs_download(self):
1254 _ = self.request.translate
1280 _ = self.request.translate
1255 c = self.load_default_context()
1281 c = self.load_default_context()
1256 c.user = self.db_user
1282 c.user = self.db_user
1257
1283
1258 user_log = UserModel().get_user_log(c.user, filter_term=None)
1284 user_log = UserModel().get_user_log(c.user, filter_term=None)
1259
1285
1260 audit_log_data = {}
1286 audit_log_data = {}
1261 for entry in user_log:
1287 for entry in user_log:
1262 audit_log_data[entry.user_log_id] = entry.get_dict()
1288 audit_log_data[entry.user_log_id] = entry.get_dict()
1263
1289
1264 response = Response(json.dumps(audit_log_data, indent=4))
1290 response = Response(json.dumps(audit_log_data, indent=4))
1265 response.content_disposition = str(
1291 response.content_disposition = str(
1266 'attachment; filename=%s' % 'user_{}_audit_logs.json'.format(c.user.user_id))
1292 'attachment; filename=%s' % 'user_{}_audit_logs.json'.format(c.user.user_id))
1267 response.content_type = 'application/json'
1293 response.content_type = 'application/json'
1268
1294
1269 return response
1295 return response
1270
1296
1271 @LoginRequired()
1297 @LoginRequired()
1272 @HasPermissionAllDecorator('hg.admin')
1298 @HasPermissionAllDecorator('hg.admin')
1273 @view_config(
1299 @view_config(
1274 route_name='edit_user_perms_summary', request_method='GET',
1300 route_name='edit_user_perms_summary', request_method='GET',
1275 renderer='rhodecode:templates/admin/users/user_edit.mako')
1301 renderer='rhodecode:templates/admin/users/user_edit.mako')
1276 def user_perms_summary(self):
1302 def user_perms_summary(self):
1277 _ = self.request.translate
1303 _ = self.request.translate
1278 c = self.load_default_context()
1304 c = self.load_default_context()
1279 c.user = self.db_user
1305 c.user = self.db_user
1280
1306
1281 c.active = 'perms_summary'
1307 c.active = 'perms_summary'
1282 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
1308 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
1283
1309
1284 return self._get_template_context(c)
1310 return self._get_template_context(c)
1285
1311
1286 @LoginRequired()
1312 @LoginRequired()
1287 @HasPermissionAllDecorator('hg.admin')
1313 @HasPermissionAllDecorator('hg.admin')
1288 @view_config(
1314 @view_config(
1289 route_name='edit_user_perms_summary_json', request_method='GET',
1315 route_name='edit_user_perms_summary_json', request_method='GET',
1290 renderer='json_ext')
1316 renderer='json_ext')
1291 def user_perms_summary_json(self):
1317 def user_perms_summary_json(self):
1292 self.load_default_context()
1318 self.load_default_context()
1293 perm_user = self.db_user.AuthUser(ip_addr=self.request.remote_addr)
1319 perm_user = self.db_user.AuthUser(ip_addr=self.request.remote_addr)
1294
1320
1295 return perm_user.permissions
1321 return perm_user.permissions
1296
1322
1297 @LoginRequired()
1323 @LoginRequired()
1298 @HasPermissionAllDecorator('hg.admin')
1324 @HasPermissionAllDecorator('hg.admin')
1299 @view_config(
1325 @view_config(
1300 route_name='edit_user_caches', request_method='GET',
1326 route_name='edit_user_caches', request_method='GET',
1301 renderer='rhodecode:templates/admin/users/user_edit.mako')
1327 renderer='rhodecode:templates/admin/users/user_edit.mako')
1302 def user_caches(self):
1328 def user_caches(self):
1303 _ = self.request.translate
1329 _ = self.request.translate
1304 c = self.load_default_context()
1330 c = self.load_default_context()
1305 c.user = self.db_user
1331 c.user = self.db_user
1306
1332
1307 c.active = 'caches'
1333 c.active = 'caches'
1308 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
1334 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
1309
1335
1310 cache_namespace_uid = 'cache_user_auth.{}'.format(self.db_user.user_id)
1336 cache_namespace_uid = 'cache_user_auth.{}'.format(self.db_user.user_id)
1311 c.region = rc_cache.get_or_create_region('cache_perms', cache_namespace_uid)
1337 c.region = rc_cache.get_or_create_region('cache_perms', cache_namespace_uid)
1312 c.backend = c.region.backend
1338 c.backend = c.region.backend
1313 c.user_keys = sorted(c.region.backend.list_keys(prefix=cache_namespace_uid))
1339 c.user_keys = sorted(c.region.backend.list_keys(prefix=cache_namespace_uid))
1314
1340
1315 return self._get_template_context(c)
1341 return self._get_template_context(c)
1316
1342
1317 @LoginRequired()
1343 @LoginRequired()
1318 @HasPermissionAllDecorator('hg.admin')
1344 @HasPermissionAllDecorator('hg.admin')
1319 @CSRFRequired()
1345 @CSRFRequired()
1320 @view_config(
1346 @view_config(
1321 route_name='edit_user_caches_update', request_method='POST')
1347 route_name='edit_user_caches_update', request_method='POST')
1322 def user_caches_update(self):
1348 def user_caches_update(self):
1323 _ = self.request.translate
1349 _ = self.request.translate
1324 c = self.load_default_context()
1350 c = self.load_default_context()
1325 c.user = self.db_user
1351 c.user = self.db_user
1326
1352
1327 c.active = 'caches'
1353 c.active = 'caches'
1328 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
1354 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
1329
1355
1330 cache_namespace_uid = 'cache_user_auth.{}'.format(self.db_user.user_id)
1356 cache_namespace_uid = 'cache_user_auth.{}'.format(self.db_user.user_id)
1331 del_keys = rc_cache.clear_cache_namespace('cache_perms', cache_namespace_uid)
1357 del_keys = rc_cache.clear_cache_namespace('cache_perms', cache_namespace_uid)
1332
1358
1333 h.flash(_("Deleted {} cache keys").format(del_keys), category='success')
1359 h.flash(_("Deleted {} cache keys").format(del_keys), category='success')
1334
1360
1335 return HTTPFound(h.route_path(
1361 return HTTPFound(h.route_path(
1336 'edit_user_caches', user_id=c.user.user_id))
1362 'edit_user_caches', user_id=c.user.user_id))
@@ -1,2413 +1,2446 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2019 RhodeCode GmbH
3 # Copyright (C) 2010-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 authentication and permission libraries
22 authentication and permission libraries
23 """
23 """
24
24
25 import os
25 import os
26
27 import colander
26 import time
28 import time
27 import collections
29 import collections
28 import fnmatch
30 import fnmatch
29 import hashlib
31 import hashlib
30 import itertools
32 import itertools
31 import logging
33 import logging
32 import random
34 import random
33 import traceback
35 import traceback
34 from functools import wraps
36 from functools import wraps
35
37
36 import ipaddress
38 import ipaddress
37
39
38 from pyramid.httpexceptions import HTTPForbidden, HTTPFound, HTTPNotFound
40 from pyramid.httpexceptions import HTTPForbidden, HTTPFound, HTTPNotFound
39 from sqlalchemy.orm.exc import ObjectDeletedError
41 from sqlalchemy.orm.exc import ObjectDeletedError
40 from sqlalchemy.orm import joinedload
42 from sqlalchemy.orm import joinedload
41 from zope.cachedescriptors.property import Lazy as LazyProperty
43 from zope.cachedescriptors.property import Lazy as LazyProperty
42
44
43 import rhodecode
45 import rhodecode
44 from rhodecode.model import meta
46 from rhodecode.model import meta
45 from rhodecode.model.meta import Session
47 from rhodecode.model.meta import Session
46 from rhodecode.model.user import UserModel
48 from rhodecode.model.user import UserModel
47 from rhodecode.model.db import (
49 from rhodecode.model.db import (
48 User, Repository, Permission, UserToPerm, UserGroupToPerm, UserGroupMember,
50 false, User, Repository, Permission, UserToPerm, UserGroupToPerm, UserGroupMember,
49 UserIpMap, UserApiKeys, RepoGroup, UserGroup)
51 UserIpMap, UserApiKeys, RepoGroup, UserGroup, UserNotice)
50 from rhodecode.lib import rc_cache
52 from rhodecode.lib import rc_cache
51 from rhodecode.lib.utils2 import safe_unicode, aslist, safe_str, md5, safe_int, sha1
53 from rhodecode.lib.utils2 import safe_unicode, aslist, safe_str, md5, safe_int, sha1
52 from rhodecode.lib.utils import (
54 from rhodecode.lib.utils import (
53 get_repo_slug, get_repo_group_slug, get_user_group_slug)
55 get_repo_slug, get_repo_group_slug, get_user_group_slug)
54 from rhodecode.lib.caching_query import FromCache
56 from rhodecode.lib.caching_query import FromCache
55
57
56
57 if rhodecode.is_unix:
58 if rhodecode.is_unix:
58 import bcrypt
59 import bcrypt
59
60
60 log = logging.getLogger(__name__)
61 log = logging.getLogger(__name__)
61
62
62 csrf_token_key = "csrf_token"
63 csrf_token_key = "csrf_token"
63
64
64
65
65 class PasswordGenerator(object):
66 class PasswordGenerator(object):
66 """
67 """
67 This is a simple class for generating password from different sets of
68 This is a simple class for generating password from different sets of
68 characters
69 characters
69 usage::
70 usage::
70 passwd_gen = PasswordGenerator()
71 passwd_gen = PasswordGenerator()
71 #print 8-letter password containing only big and small letters
72 #print 8-letter password containing only big and small letters
72 of alphabet
73 of alphabet
73 passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
74 passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
74 """
75 """
75 ALPHABETS_NUM = r'''1234567890'''
76 ALPHABETS_NUM = r'''1234567890'''
76 ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''
77 ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''
77 ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''
78 ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''
78 ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?'''
79 ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?'''
79 ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL \
80 ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL \
80 + ALPHABETS_NUM + ALPHABETS_SPECIAL
81 + ALPHABETS_NUM + ALPHABETS_SPECIAL
81 ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM
82 ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM
82 ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
83 ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
83 ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM
84 ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM
84 ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM
85 ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM
85
86
86 def __init__(self, passwd=''):
87 def __init__(self, passwd=''):
87 self.passwd = passwd
88 self.passwd = passwd
88
89
89 def gen_password(self, length, type_=None):
90 def gen_password(self, length, type_=None):
90 if type_ is None:
91 if type_ is None:
91 type_ = self.ALPHABETS_FULL
92 type_ = self.ALPHABETS_FULL
92 self.passwd = ''.join([random.choice(type_) for _ in range(length)])
93 self.passwd = ''.join([random.choice(type_) for _ in range(length)])
93 return self.passwd
94 return self.passwd
94
95
95
96
96 class _RhodeCodeCryptoBase(object):
97 class _RhodeCodeCryptoBase(object):
97 ENC_PREF = None
98 ENC_PREF = None
98
99
99 def hash_create(self, str_):
100 def hash_create(self, str_):
100 """
101 """
101 hash the string using
102 hash the string using
102
103
103 :param str_: password to hash
104 :param str_: password to hash
104 """
105 """
105 raise NotImplementedError
106 raise NotImplementedError
106
107
107 def hash_check_with_upgrade(self, password, hashed):
108 def hash_check_with_upgrade(self, password, hashed):
108 """
109 """
109 Returns tuple in which first element is boolean that states that
110 Returns tuple in which first element is boolean that states that
110 given password matches it's hashed version, and the second is new hash
111 given password matches it's hashed version, and the second is new hash
111 of the password, in case this password should be migrated to new
112 of the password, in case this password should be migrated to new
112 cipher.
113 cipher.
113 """
114 """
114 checked_hash = self.hash_check(password, hashed)
115 checked_hash = self.hash_check(password, hashed)
115 return checked_hash, None
116 return checked_hash, None
116
117
117 def hash_check(self, password, hashed):
118 def hash_check(self, password, hashed):
118 """
119 """
119 Checks matching password with it's hashed value.
120 Checks matching password with it's hashed value.
120
121
121 :param password: password
122 :param password: password
122 :param hashed: password in hashed form
123 :param hashed: password in hashed form
123 """
124 """
124 raise NotImplementedError
125 raise NotImplementedError
125
126
126 def _assert_bytes(self, value):
127 def _assert_bytes(self, value):
127 """
128 """
128 Passing in an `unicode` object can lead to hard to detect issues
129 Passing in an `unicode` object can lead to hard to detect issues
129 if passwords contain non-ascii characters. Doing a type check
130 if passwords contain non-ascii characters. Doing a type check
130 during runtime, so that such mistakes are detected early on.
131 during runtime, so that such mistakes are detected early on.
131 """
132 """
132 if not isinstance(value, str):
133 if not isinstance(value, str):
133 raise TypeError(
134 raise TypeError(
134 "Bytestring required as input, got %r." % (value, ))
135 "Bytestring required as input, got %r." % (value, ))
135
136
136
137
137 class _RhodeCodeCryptoBCrypt(_RhodeCodeCryptoBase):
138 class _RhodeCodeCryptoBCrypt(_RhodeCodeCryptoBase):
138 ENC_PREF = ('$2a$10', '$2b$10')
139 ENC_PREF = ('$2a$10', '$2b$10')
139
140
140 def hash_create(self, str_):
141 def hash_create(self, str_):
141 self._assert_bytes(str_)
142 self._assert_bytes(str_)
142 return bcrypt.hashpw(str_, bcrypt.gensalt(10))
143 return bcrypt.hashpw(str_, bcrypt.gensalt(10))
143
144
144 def hash_check_with_upgrade(self, password, hashed):
145 def hash_check_with_upgrade(self, password, hashed):
145 """
146 """
146 Returns tuple in which first element is boolean that states that
147 Returns tuple in which first element is boolean that states that
147 given password matches it's hashed version, and the second is new hash
148 given password matches it's hashed version, and the second is new hash
148 of the password, in case this password should be migrated to new
149 of the password, in case this password should be migrated to new
149 cipher.
150 cipher.
150
151
151 This implements special upgrade logic which works like that:
152 This implements special upgrade logic which works like that:
152 - check if the given password == bcrypted hash, if yes then we
153 - check if the given password == bcrypted hash, if yes then we
153 properly used password and it was already in bcrypt. Proceed
154 properly used password and it was already in bcrypt. Proceed
154 without any changes
155 without any changes
155 - if bcrypt hash check is not working try with sha256. If hash compare
156 - if bcrypt hash check is not working try with sha256. If hash compare
156 is ok, it means we using correct but old hashed password. indicate
157 is ok, it means we using correct but old hashed password. indicate
157 hash change and proceed
158 hash change and proceed
158 """
159 """
159
160
160 new_hash = None
161 new_hash = None
161
162
162 # regular pw check
163 # regular pw check
163 password_match_bcrypt = self.hash_check(password, hashed)
164 password_match_bcrypt = self.hash_check(password, hashed)
164
165
165 # now we want to know if the password was maybe from sha256
166 # now we want to know if the password was maybe from sha256
166 # basically calling _RhodeCodeCryptoSha256().hash_check()
167 # basically calling _RhodeCodeCryptoSha256().hash_check()
167 if not password_match_bcrypt:
168 if not password_match_bcrypt:
168 if _RhodeCodeCryptoSha256().hash_check(password, hashed):
169 if _RhodeCodeCryptoSha256().hash_check(password, hashed):
169 new_hash = self.hash_create(password) # make new bcrypt hash
170 new_hash = self.hash_create(password) # make new bcrypt hash
170 password_match_bcrypt = True
171 password_match_bcrypt = True
171
172
172 return password_match_bcrypt, new_hash
173 return password_match_bcrypt, new_hash
173
174
174 def hash_check(self, password, hashed):
175 def hash_check(self, password, hashed):
175 """
176 """
176 Checks matching password with it's hashed value.
177 Checks matching password with it's hashed value.
177
178
178 :param password: password
179 :param password: password
179 :param hashed: password in hashed form
180 :param hashed: password in hashed form
180 """
181 """
181 self._assert_bytes(password)
182 self._assert_bytes(password)
182 try:
183 try:
183 return bcrypt.hashpw(password, hashed) == hashed
184 return bcrypt.hashpw(password, hashed) == hashed
184 except ValueError as e:
185 except ValueError as e:
185 # we're having a invalid salt here probably, we should not crash
186 # we're having a invalid salt here probably, we should not crash
186 # just return with False as it would be a wrong password.
187 # just return with False as it would be a wrong password.
187 log.debug('Failed to check password hash using bcrypt %s',
188 log.debug('Failed to check password hash using bcrypt %s',
188 safe_str(e))
189 safe_str(e))
189
190
190 return False
191 return False
191
192
192
193
193 class _RhodeCodeCryptoSha256(_RhodeCodeCryptoBase):
194 class _RhodeCodeCryptoSha256(_RhodeCodeCryptoBase):
194 ENC_PREF = '_'
195 ENC_PREF = '_'
195
196
196 def hash_create(self, str_):
197 def hash_create(self, str_):
197 self._assert_bytes(str_)
198 self._assert_bytes(str_)
198 return hashlib.sha256(str_).hexdigest()
199 return hashlib.sha256(str_).hexdigest()
199
200
200 def hash_check(self, password, hashed):
201 def hash_check(self, password, hashed):
201 """
202 """
202 Checks matching password with it's hashed value.
203 Checks matching password with it's hashed value.
203
204
204 :param password: password
205 :param password: password
205 :param hashed: password in hashed form
206 :param hashed: password in hashed form
206 """
207 """
207 self._assert_bytes(password)
208 self._assert_bytes(password)
208 return hashlib.sha256(password).hexdigest() == hashed
209 return hashlib.sha256(password).hexdigest() == hashed
209
210
210
211
211 class _RhodeCodeCryptoTest(_RhodeCodeCryptoBase):
212 class _RhodeCodeCryptoTest(_RhodeCodeCryptoBase):
212 ENC_PREF = '_'
213 ENC_PREF = '_'
213
214
214 def hash_create(self, str_):
215 def hash_create(self, str_):
215 self._assert_bytes(str_)
216 self._assert_bytes(str_)
216 return sha1(str_)
217 return sha1(str_)
217
218
218 def hash_check(self, password, hashed):
219 def hash_check(self, password, hashed):
219 """
220 """
220 Checks matching password with it's hashed value.
221 Checks matching password with it's hashed value.
221
222
222 :param password: password
223 :param password: password
223 :param hashed: password in hashed form
224 :param hashed: password in hashed form
224 """
225 """
225 self._assert_bytes(password)
226 self._assert_bytes(password)
226 return sha1(password) == hashed
227 return sha1(password) == hashed
227
228
228
229
229 def crypto_backend():
230 def crypto_backend():
230 """
231 """
231 Return the matching crypto backend.
232 Return the matching crypto backend.
232
233
233 Selection is based on if we run tests or not, we pick sha1-test backend to run
234 Selection is based on if we run tests or not, we pick sha1-test backend to run
234 tests faster since BCRYPT is expensive to calculate
235 tests faster since BCRYPT is expensive to calculate
235 """
236 """
236 if rhodecode.is_test:
237 if rhodecode.is_test:
237 RhodeCodeCrypto = _RhodeCodeCryptoTest()
238 RhodeCodeCrypto = _RhodeCodeCryptoTest()
238 else:
239 else:
239 RhodeCodeCrypto = _RhodeCodeCryptoBCrypt()
240 RhodeCodeCrypto = _RhodeCodeCryptoBCrypt()
240
241
241 return RhodeCodeCrypto
242 return RhodeCodeCrypto
242
243
243
244
244 def get_crypt_password(password):
245 def get_crypt_password(password):
245 """
246 """
246 Create the hash of `password` with the active crypto backend.
247 Create the hash of `password` with the active crypto backend.
247
248
248 :param password: The cleartext password.
249 :param password: The cleartext password.
249 :type password: unicode
250 :type password: unicode
250 """
251 """
251 password = safe_str(password)
252 password = safe_str(password)
252 return crypto_backend().hash_create(password)
253 return crypto_backend().hash_create(password)
253
254
254
255
255 def check_password(password, hashed):
256 def check_password(password, hashed):
256 """
257 """
257 Check if the value in `password` matches the hash in `hashed`.
258 Check if the value in `password` matches the hash in `hashed`.
258
259
259 :param password: The cleartext password.
260 :param password: The cleartext password.
260 :type password: unicode
261 :type password: unicode
261
262
262 :param hashed: The expected hashed version of the password.
263 :param hashed: The expected hashed version of the password.
263 :type hashed: The hash has to be passed in in text representation.
264 :type hashed: The hash has to be passed in in text representation.
264 """
265 """
265 password = safe_str(password)
266 password = safe_str(password)
266 return crypto_backend().hash_check(password, hashed)
267 return crypto_backend().hash_check(password, hashed)
267
268
268
269
269 def generate_auth_token(data, salt=None):
270 def generate_auth_token(data, salt=None):
270 """
271 """
271 Generates API KEY from given string
272 Generates API KEY from given string
272 """
273 """
273
274
274 if salt is None:
275 if salt is None:
275 salt = os.urandom(16)
276 salt = os.urandom(16)
276 return hashlib.sha1(safe_str(data) + salt).hexdigest()
277 return hashlib.sha1(safe_str(data) + salt).hexdigest()
277
278
278
279
279 def get_came_from(request):
280 def get_came_from(request):
280 """
281 """
281 get query_string+path from request sanitized after removing auth_token
282 get query_string+path from request sanitized after removing auth_token
282 """
283 """
283 _req = request
284 _req = request
284
285
285 path = _req.path
286 path = _req.path
286 if 'auth_token' in _req.GET:
287 if 'auth_token' in _req.GET:
287 # sanitize the request and remove auth_token for redirection
288 # sanitize the request and remove auth_token for redirection
288 _req.GET.pop('auth_token')
289 _req.GET.pop('auth_token')
289 qs = _req.query_string
290 qs = _req.query_string
290 if qs:
291 if qs:
291 path += '?' + qs
292 path += '?' + qs
292
293
293 return path
294 return path
294
295
295
296
296 class CookieStoreWrapper(object):
297 class CookieStoreWrapper(object):
297
298
298 def __init__(self, cookie_store):
299 def __init__(self, cookie_store):
299 self.cookie_store = cookie_store
300 self.cookie_store = cookie_store
300
301
301 def __repr__(self):
302 def __repr__(self):
302 return 'CookieStore<%s>' % (self.cookie_store)
303 return 'CookieStore<%s>' % (self.cookie_store)
303
304
304 def get(self, key, other=None):
305 def get(self, key, other=None):
305 if isinstance(self.cookie_store, dict):
306 if isinstance(self.cookie_store, dict):
306 return self.cookie_store.get(key, other)
307 return self.cookie_store.get(key, other)
307 elif isinstance(self.cookie_store, AuthUser):
308 elif isinstance(self.cookie_store, AuthUser):
308 return self.cookie_store.__dict__.get(key, other)
309 return self.cookie_store.__dict__.get(key, other)
309
310
310
311
311 def _cached_perms_data(user_id, scope, user_is_admin,
312 def _cached_perms_data(user_id, scope, user_is_admin,
312 user_inherit_default_permissions, explicit, algo,
313 user_inherit_default_permissions, explicit, algo,
313 calculate_super_admin):
314 calculate_super_admin):
314
315
315 permissions = PermissionCalculator(
316 permissions = PermissionCalculator(
316 user_id, scope, user_is_admin, user_inherit_default_permissions,
317 user_id, scope, user_is_admin, user_inherit_default_permissions,
317 explicit, algo, calculate_super_admin)
318 explicit, algo, calculate_super_admin)
318 return permissions.calculate()
319 return permissions.calculate()
319
320
320
321
321 class PermOrigin(object):
322 class PermOrigin(object):
322 SUPER_ADMIN = 'superadmin'
323 SUPER_ADMIN = 'superadmin'
323 ARCHIVED = 'archived'
324 ARCHIVED = 'archived'
324
325
325 REPO_USER = 'user:%s'
326 REPO_USER = 'user:%s'
326 REPO_USERGROUP = 'usergroup:%s'
327 REPO_USERGROUP = 'usergroup:%s'
327 REPO_OWNER = 'repo.owner'
328 REPO_OWNER = 'repo.owner'
328 REPO_DEFAULT = 'repo.default'
329 REPO_DEFAULT = 'repo.default'
329 REPO_DEFAULT_NO_INHERIT = 'repo.default.no.inherit'
330 REPO_DEFAULT_NO_INHERIT = 'repo.default.no.inherit'
330 REPO_PRIVATE = 'repo.private'
331 REPO_PRIVATE = 'repo.private'
331
332
332 REPOGROUP_USER = 'user:%s'
333 REPOGROUP_USER = 'user:%s'
333 REPOGROUP_USERGROUP = 'usergroup:%s'
334 REPOGROUP_USERGROUP = 'usergroup:%s'
334 REPOGROUP_OWNER = 'group.owner'
335 REPOGROUP_OWNER = 'group.owner'
335 REPOGROUP_DEFAULT = 'group.default'
336 REPOGROUP_DEFAULT = 'group.default'
336 REPOGROUP_DEFAULT_NO_INHERIT = 'group.default.no.inherit'
337 REPOGROUP_DEFAULT_NO_INHERIT = 'group.default.no.inherit'
337
338
338 USERGROUP_USER = 'user:%s'
339 USERGROUP_USER = 'user:%s'
339 USERGROUP_USERGROUP = 'usergroup:%s'
340 USERGROUP_USERGROUP = 'usergroup:%s'
340 USERGROUP_OWNER = 'usergroup.owner'
341 USERGROUP_OWNER = 'usergroup.owner'
341 USERGROUP_DEFAULT = 'usergroup.default'
342 USERGROUP_DEFAULT = 'usergroup.default'
342 USERGROUP_DEFAULT_NO_INHERIT = 'usergroup.default.no.inherit'
343 USERGROUP_DEFAULT_NO_INHERIT = 'usergroup.default.no.inherit'
343
344
344
345
345 class PermOriginDict(dict):
346 class PermOriginDict(dict):
346 """
347 """
347 A special dict used for tracking permissions along with their origins.
348 A special dict used for tracking permissions along with their origins.
348
349
349 `__setitem__` has been overridden to expect a tuple(perm, origin)
350 `__setitem__` has been overridden to expect a tuple(perm, origin)
350 `__getitem__` will return only the perm
351 `__getitem__` will return only the perm
351 `.perm_origin_stack` will return the stack of (perm, origin) set per key
352 `.perm_origin_stack` will return the stack of (perm, origin) set per key
352
353
353 >>> perms = PermOriginDict()
354 >>> perms = PermOriginDict()
354 >>> perms['resource'] = 'read', 'default', 1
355 >>> perms['resource'] = 'read', 'default', 1
355 >>> perms['resource']
356 >>> perms['resource']
356 'read'
357 'read'
357 >>> perms['resource'] = 'write', 'admin', 2
358 >>> perms['resource'] = 'write', 'admin', 2
358 >>> perms['resource']
359 >>> perms['resource']
359 'write'
360 'write'
360 >>> perms.perm_origin_stack
361 >>> perms.perm_origin_stack
361 {'resource': [('read', 'default', 1), ('write', 'admin', 2)]}
362 {'resource': [('read', 'default', 1), ('write', 'admin', 2)]}
362 """
363 """
363
364
364 def __init__(self, *args, **kw):
365 def __init__(self, *args, **kw):
365 dict.__init__(self, *args, **kw)
366 dict.__init__(self, *args, **kw)
366 self.perm_origin_stack = collections.OrderedDict()
367 self.perm_origin_stack = collections.OrderedDict()
367
368
368 def __setitem__(self, key, (perm, origin, obj_id)):
369 def __setitem__(self, key, (perm, origin, obj_id)):
369 self.perm_origin_stack.setdefault(key, []).append(
370 self.perm_origin_stack.setdefault(key, []).append(
370 (perm, origin, obj_id))
371 (perm, origin, obj_id))
371 dict.__setitem__(self, key, perm)
372 dict.__setitem__(self, key, perm)
372
373
373
374
374 class BranchPermOriginDict(PermOriginDict):
375 class BranchPermOriginDict(PermOriginDict):
375 """
376 """
376 Dedicated branch permissions dict, with tracking of patterns and origins.
377 Dedicated branch permissions dict, with tracking of patterns and origins.
377
378
378 >>> perms = BranchPermOriginDict()
379 >>> perms = BranchPermOriginDict()
379 >>> perms['resource'] = '*pattern', 'read', 'default'
380 >>> perms['resource'] = '*pattern', 'read', 'default'
380 >>> perms['resource']
381 >>> perms['resource']
381 {'*pattern': 'read'}
382 {'*pattern': 'read'}
382 >>> perms['resource'] = '*pattern', 'write', 'admin'
383 >>> perms['resource'] = '*pattern', 'write', 'admin'
383 >>> perms['resource']
384 >>> perms['resource']
384 {'*pattern': 'write'}
385 {'*pattern': 'write'}
385 >>> perms.perm_origin_stack
386 >>> perms.perm_origin_stack
386 {'resource': {'*pattern': [('read', 'default'), ('write', 'admin')]}}
387 {'resource': {'*pattern': [('read', 'default'), ('write', 'admin')]}}
387 """
388 """
388 def __setitem__(self, key, (pattern, perm, origin)):
389 def __setitem__(self, key, (pattern, perm, origin)):
389
390
390 self.perm_origin_stack.setdefault(key, {}) \
391 self.perm_origin_stack.setdefault(key, {}) \
391 .setdefault(pattern, []).append((perm, origin))
392 .setdefault(pattern, []).append((perm, origin))
392
393
393 if key in self:
394 if key in self:
394 self[key].__setitem__(pattern, perm)
395 self[key].__setitem__(pattern, perm)
395 else:
396 else:
396 patterns = collections.OrderedDict()
397 patterns = collections.OrderedDict()
397 patterns[pattern] = perm
398 patterns[pattern] = perm
398 dict.__setitem__(self, key, patterns)
399 dict.__setitem__(self, key, patterns)
399
400
400
401
401 class PermissionCalculator(object):
402 class PermissionCalculator(object):
402
403
403 def __init__(
404 def __init__(
404 self, user_id, scope, user_is_admin,
405 self, user_id, scope, user_is_admin,
405 user_inherit_default_permissions, explicit, algo,
406 user_inherit_default_permissions, explicit, algo,
406 calculate_super_admin_as_user=False):
407 calculate_super_admin_as_user=False):
407
408
408 self.user_id = user_id
409 self.user_id = user_id
409 self.user_is_admin = user_is_admin
410 self.user_is_admin = user_is_admin
410 self.inherit_default_permissions = user_inherit_default_permissions
411 self.inherit_default_permissions = user_inherit_default_permissions
411 self.explicit = explicit
412 self.explicit = explicit
412 self.algo = algo
413 self.algo = algo
413 self.calculate_super_admin_as_user = calculate_super_admin_as_user
414 self.calculate_super_admin_as_user = calculate_super_admin_as_user
414
415
415 scope = scope or {}
416 scope = scope or {}
416 self.scope_repo_id = scope.get('repo_id')
417 self.scope_repo_id = scope.get('repo_id')
417 self.scope_repo_group_id = scope.get('repo_group_id')
418 self.scope_repo_group_id = scope.get('repo_group_id')
418 self.scope_user_group_id = scope.get('user_group_id')
419 self.scope_user_group_id = scope.get('user_group_id')
419
420
420 self.default_user_id = User.get_default_user(cache=True).user_id
421 self.default_user_id = User.get_default_user(cache=True).user_id
421
422
422 self.permissions_repositories = PermOriginDict()
423 self.permissions_repositories = PermOriginDict()
423 self.permissions_repository_groups = PermOriginDict()
424 self.permissions_repository_groups = PermOriginDict()
424 self.permissions_user_groups = PermOriginDict()
425 self.permissions_user_groups = PermOriginDict()
425 self.permissions_repository_branches = BranchPermOriginDict()
426 self.permissions_repository_branches = BranchPermOriginDict()
426 self.permissions_global = set()
427 self.permissions_global = set()
427
428
428 self.default_repo_perms = Permission.get_default_repo_perms(
429 self.default_repo_perms = Permission.get_default_repo_perms(
429 self.default_user_id, self.scope_repo_id)
430 self.default_user_id, self.scope_repo_id)
430 self.default_repo_groups_perms = Permission.get_default_group_perms(
431 self.default_repo_groups_perms = Permission.get_default_group_perms(
431 self.default_user_id, self.scope_repo_group_id)
432 self.default_user_id, self.scope_repo_group_id)
432 self.default_user_group_perms = \
433 self.default_user_group_perms = \
433 Permission.get_default_user_group_perms(
434 Permission.get_default_user_group_perms(
434 self.default_user_id, self.scope_user_group_id)
435 self.default_user_id, self.scope_user_group_id)
435
436
436 # default branch perms
437 # default branch perms
437 self.default_branch_repo_perms = \
438 self.default_branch_repo_perms = \
438 Permission.get_default_repo_branch_perms(
439 Permission.get_default_repo_branch_perms(
439 self.default_user_id, self.scope_repo_id)
440 self.default_user_id, self.scope_repo_id)
440
441
441 def calculate(self):
442 def calculate(self):
442 if self.user_is_admin and not self.calculate_super_admin_as_user:
443 if self.user_is_admin and not self.calculate_super_admin_as_user:
443 return self._calculate_admin_permissions()
444 return self._calculate_admin_permissions()
444
445
445 self._calculate_global_default_permissions()
446 self._calculate_global_default_permissions()
446 self._calculate_global_permissions()
447 self._calculate_global_permissions()
447 self._calculate_default_permissions()
448 self._calculate_default_permissions()
448 self._calculate_repository_permissions()
449 self._calculate_repository_permissions()
449 self._calculate_repository_branch_permissions()
450 self._calculate_repository_branch_permissions()
450 self._calculate_repository_group_permissions()
451 self._calculate_repository_group_permissions()
451 self._calculate_user_group_permissions()
452 self._calculate_user_group_permissions()
452 return self._permission_structure()
453 return self._permission_structure()
453
454
454 def _calculate_admin_permissions(self):
455 def _calculate_admin_permissions(self):
455 """
456 """
456 admin user have all default rights for repositories
457 admin user have all default rights for repositories
457 and groups set to admin
458 and groups set to admin
458 """
459 """
459 self.permissions_global.add('hg.admin')
460 self.permissions_global.add('hg.admin')
460 self.permissions_global.add('hg.create.write_on_repogroup.true')
461 self.permissions_global.add('hg.create.write_on_repogroup.true')
461
462
462 # repositories
463 # repositories
463 for perm in self.default_repo_perms:
464 for perm in self.default_repo_perms:
464 r_k = perm.UserRepoToPerm.repository.repo_name
465 r_k = perm.UserRepoToPerm.repository.repo_name
465 obj_id = perm.UserRepoToPerm.repository.repo_id
466 obj_id = perm.UserRepoToPerm.repository.repo_id
466 archived = perm.UserRepoToPerm.repository.archived
467 archived = perm.UserRepoToPerm.repository.archived
467 p = 'repository.admin'
468 p = 'repository.admin'
468 self.permissions_repositories[r_k] = p, PermOrigin.SUPER_ADMIN, obj_id
469 self.permissions_repositories[r_k] = p, PermOrigin.SUPER_ADMIN, obj_id
469 # special case for archived repositories, which we block still even for
470 # special case for archived repositories, which we block still even for
470 # super admins
471 # super admins
471 if archived:
472 if archived:
472 p = 'repository.read'
473 p = 'repository.read'
473 self.permissions_repositories[r_k] = p, PermOrigin.ARCHIVED, obj_id
474 self.permissions_repositories[r_k] = p, PermOrigin.ARCHIVED, obj_id
474
475
475 # repository groups
476 # repository groups
476 for perm in self.default_repo_groups_perms:
477 for perm in self.default_repo_groups_perms:
477 rg_k = perm.UserRepoGroupToPerm.group.group_name
478 rg_k = perm.UserRepoGroupToPerm.group.group_name
478 obj_id = perm.UserRepoGroupToPerm.group.group_id
479 obj_id = perm.UserRepoGroupToPerm.group.group_id
479 p = 'group.admin'
480 p = 'group.admin'
480 self.permissions_repository_groups[rg_k] = p, PermOrigin.SUPER_ADMIN, obj_id
481 self.permissions_repository_groups[rg_k] = p, PermOrigin.SUPER_ADMIN, obj_id
481
482
482 # user groups
483 # user groups
483 for perm in self.default_user_group_perms:
484 for perm in self.default_user_group_perms:
484 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
485 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
485 obj_id = perm.UserUserGroupToPerm.user_group.users_group_id
486 obj_id = perm.UserUserGroupToPerm.user_group.users_group_id
486 p = 'usergroup.admin'
487 p = 'usergroup.admin'
487 self.permissions_user_groups[u_k] = p, PermOrigin.SUPER_ADMIN, obj_id
488 self.permissions_user_groups[u_k] = p, PermOrigin.SUPER_ADMIN, obj_id
488
489
489 # branch permissions
490 # branch permissions
490 # since super-admin also can have custom rule permissions
491 # since super-admin also can have custom rule permissions
491 # we *always* need to calculate those inherited from default, and also explicit
492 # we *always* need to calculate those inherited from default, and also explicit
492 self._calculate_default_permissions_repository_branches(
493 self._calculate_default_permissions_repository_branches(
493 user_inherit_object_permissions=False)
494 user_inherit_object_permissions=False)
494 self._calculate_repository_branch_permissions()
495 self._calculate_repository_branch_permissions()
495
496
496 return self._permission_structure()
497 return self._permission_structure()
497
498
498 def _calculate_global_default_permissions(self):
499 def _calculate_global_default_permissions(self):
499 """
500 """
500 global permissions taken from the default user
501 global permissions taken from the default user
501 """
502 """
502 default_global_perms = UserToPerm.query()\
503 default_global_perms = UserToPerm.query()\
503 .filter(UserToPerm.user_id == self.default_user_id)\
504 .filter(UserToPerm.user_id == self.default_user_id)\
504 .options(joinedload(UserToPerm.permission))
505 .options(joinedload(UserToPerm.permission))
505
506
506 for perm in default_global_perms:
507 for perm in default_global_perms:
507 self.permissions_global.add(perm.permission.permission_name)
508 self.permissions_global.add(perm.permission.permission_name)
508
509
509 if self.user_is_admin:
510 if self.user_is_admin:
510 self.permissions_global.add('hg.admin')
511 self.permissions_global.add('hg.admin')
511 self.permissions_global.add('hg.create.write_on_repogroup.true')
512 self.permissions_global.add('hg.create.write_on_repogroup.true')
512
513
513 def _calculate_global_permissions(self):
514 def _calculate_global_permissions(self):
514 """
515 """
515 Set global system permissions with user permissions or permissions
516 Set global system permissions with user permissions or permissions
516 taken from the user groups of the current user.
517 taken from the user groups of the current user.
517
518
518 The permissions include repo creating, repo group creating, forking
519 The permissions include repo creating, repo group creating, forking
519 etc.
520 etc.
520 """
521 """
521
522
522 # now we read the defined permissions and overwrite what we have set
523 # now we read the defined permissions and overwrite what we have set
523 # before those can be configured from groups or users explicitly.
524 # before those can be configured from groups or users explicitly.
524
525
525 # In case we want to extend this list we should make sure
526 # In case we want to extend this list we should make sure
526 # this is in sync with User.DEFAULT_USER_PERMISSIONS definitions
527 # this is in sync with User.DEFAULT_USER_PERMISSIONS definitions
527 _configurable = frozenset([
528 _configurable = frozenset([
528 'hg.fork.none', 'hg.fork.repository',
529 'hg.fork.none', 'hg.fork.repository',
529 'hg.create.none', 'hg.create.repository',
530 'hg.create.none', 'hg.create.repository',
530 'hg.usergroup.create.false', 'hg.usergroup.create.true',
531 'hg.usergroup.create.false', 'hg.usergroup.create.true',
531 'hg.repogroup.create.false', 'hg.repogroup.create.true',
532 'hg.repogroup.create.false', 'hg.repogroup.create.true',
532 'hg.create.write_on_repogroup.false', 'hg.create.write_on_repogroup.true',
533 'hg.create.write_on_repogroup.false', 'hg.create.write_on_repogroup.true',
533 'hg.inherit_default_perms.false', 'hg.inherit_default_perms.true'
534 'hg.inherit_default_perms.false', 'hg.inherit_default_perms.true'
534 ])
535 ])
535
536
536 # USER GROUPS comes first user group global permissions
537 # USER GROUPS comes first user group global permissions
537 user_perms_from_users_groups = Session().query(UserGroupToPerm)\
538 user_perms_from_users_groups = Session().query(UserGroupToPerm)\
538 .options(joinedload(UserGroupToPerm.permission))\
539 .options(joinedload(UserGroupToPerm.permission))\
539 .join((UserGroupMember, UserGroupToPerm.users_group_id ==
540 .join((UserGroupMember, UserGroupToPerm.users_group_id ==
540 UserGroupMember.users_group_id))\
541 UserGroupMember.users_group_id))\
541 .filter(UserGroupMember.user_id == self.user_id)\
542 .filter(UserGroupMember.user_id == self.user_id)\
542 .order_by(UserGroupToPerm.users_group_id)\
543 .order_by(UserGroupToPerm.users_group_id)\
543 .all()
544 .all()
544
545
545 # need to group here by groups since user can be in more than
546 # need to group here by groups since user can be in more than
546 # one group, so we get all groups
547 # one group, so we get all groups
547 _explicit_grouped_perms = [
548 _explicit_grouped_perms = [
548 [x, list(y)] for x, y in
549 [x, list(y)] for x, y in
549 itertools.groupby(user_perms_from_users_groups,
550 itertools.groupby(user_perms_from_users_groups,
550 lambda _x: _x.users_group)]
551 lambda _x: _x.users_group)]
551
552
552 for gr, perms in _explicit_grouped_perms:
553 for gr, perms in _explicit_grouped_perms:
553 # since user can be in multiple groups iterate over them and
554 # since user can be in multiple groups iterate over them and
554 # select the lowest permissions first (more explicit)
555 # select the lowest permissions first (more explicit)
555 # TODO(marcink): do this^^
556 # TODO(marcink): do this^^
556
557
557 # group doesn't inherit default permissions so we actually set them
558 # group doesn't inherit default permissions so we actually set them
558 if not gr.inherit_default_permissions:
559 if not gr.inherit_default_permissions:
559 # NEED TO IGNORE all previously set configurable permissions
560 # NEED TO IGNORE all previously set configurable permissions
560 # and replace them with explicitly set from this user
561 # and replace them with explicitly set from this user
561 # group permissions
562 # group permissions
562 self.permissions_global = self.permissions_global.difference(
563 self.permissions_global = self.permissions_global.difference(
563 _configurable)
564 _configurable)
564 for perm in perms:
565 for perm in perms:
565 self.permissions_global.add(perm.permission.permission_name)
566 self.permissions_global.add(perm.permission.permission_name)
566
567
567 # user explicit global permissions
568 # user explicit global permissions
568 user_perms = Session().query(UserToPerm)\
569 user_perms = Session().query(UserToPerm)\
569 .options(joinedload(UserToPerm.permission))\
570 .options(joinedload(UserToPerm.permission))\
570 .filter(UserToPerm.user_id == self.user_id).all()
571 .filter(UserToPerm.user_id == self.user_id).all()
571
572
572 if not self.inherit_default_permissions:
573 if not self.inherit_default_permissions:
573 # NEED TO IGNORE all configurable permissions and
574 # NEED TO IGNORE all configurable permissions and
574 # replace them with explicitly set from this user permissions
575 # replace them with explicitly set from this user permissions
575 self.permissions_global = self.permissions_global.difference(
576 self.permissions_global = self.permissions_global.difference(
576 _configurable)
577 _configurable)
577 for perm in user_perms:
578 for perm in user_perms:
578 self.permissions_global.add(perm.permission.permission_name)
579 self.permissions_global.add(perm.permission.permission_name)
579
580
580 def _calculate_default_permissions_repositories(self, user_inherit_object_permissions):
581 def _calculate_default_permissions_repositories(self, user_inherit_object_permissions):
581 for perm in self.default_repo_perms:
582 for perm in self.default_repo_perms:
582 r_k = perm.UserRepoToPerm.repository.repo_name
583 r_k = perm.UserRepoToPerm.repository.repo_name
583 obj_id = perm.UserRepoToPerm.repository.repo_id
584 obj_id = perm.UserRepoToPerm.repository.repo_id
584 archived = perm.UserRepoToPerm.repository.archived
585 archived = perm.UserRepoToPerm.repository.archived
585 p = perm.Permission.permission_name
586 p = perm.Permission.permission_name
586 o = PermOrigin.REPO_DEFAULT
587 o = PermOrigin.REPO_DEFAULT
587 self.permissions_repositories[r_k] = p, o, obj_id
588 self.permissions_repositories[r_k] = p, o, obj_id
588
589
589 # if we decide this user isn't inheriting permissions from
590 # if we decide this user isn't inheriting permissions from
590 # default user we set him to .none so only explicit
591 # default user we set him to .none so only explicit
591 # permissions work
592 # permissions work
592 if not user_inherit_object_permissions:
593 if not user_inherit_object_permissions:
593 p = 'repository.none'
594 p = 'repository.none'
594 o = PermOrigin.REPO_DEFAULT_NO_INHERIT
595 o = PermOrigin.REPO_DEFAULT_NO_INHERIT
595 self.permissions_repositories[r_k] = p, o, obj_id
596 self.permissions_repositories[r_k] = p, o, obj_id
596
597
597 if perm.Repository.private and not (
598 if perm.Repository.private and not (
598 perm.Repository.user_id == self.user_id):
599 perm.Repository.user_id == self.user_id):
599 # disable defaults for private repos,
600 # disable defaults for private repos,
600 p = 'repository.none'
601 p = 'repository.none'
601 o = PermOrigin.REPO_PRIVATE
602 o = PermOrigin.REPO_PRIVATE
602 self.permissions_repositories[r_k] = p, o, obj_id
603 self.permissions_repositories[r_k] = p, o, obj_id
603
604
604 elif perm.Repository.user_id == self.user_id:
605 elif perm.Repository.user_id == self.user_id:
605 # set admin if owner
606 # set admin if owner
606 p = 'repository.admin'
607 p = 'repository.admin'
607 o = PermOrigin.REPO_OWNER
608 o = PermOrigin.REPO_OWNER
608 self.permissions_repositories[r_k] = p, o, obj_id
609 self.permissions_repositories[r_k] = p, o, obj_id
609
610
610 if self.user_is_admin:
611 if self.user_is_admin:
611 p = 'repository.admin'
612 p = 'repository.admin'
612 o = PermOrigin.SUPER_ADMIN
613 o = PermOrigin.SUPER_ADMIN
613 self.permissions_repositories[r_k] = p, o, obj_id
614 self.permissions_repositories[r_k] = p, o, obj_id
614
615
615 # finally in case of archived repositories, we downgrade higher
616 # finally in case of archived repositories, we downgrade higher
616 # permissions to read
617 # permissions to read
617 if archived:
618 if archived:
618 current_perm = self.permissions_repositories[r_k]
619 current_perm = self.permissions_repositories[r_k]
619 if current_perm in ['repository.write', 'repository.admin']:
620 if current_perm in ['repository.write', 'repository.admin']:
620 p = 'repository.read'
621 p = 'repository.read'
621 o = PermOrigin.ARCHIVED
622 o = PermOrigin.ARCHIVED
622 self.permissions_repositories[r_k] = p, o, obj_id
623 self.permissions_repositories[r_k] = p, o, obj_id
623
624
624 def _calculate_default_permissions_repository_branches(self, user_inherit_object_permissions):
625 def _calculate_default_permissions_repository_branches(self, user_inherit_object_permissions):
625 for perm in self.default_branch_repo_perms:
626 for perm in self.default_branch_repo_perms:
626
627
627 r_k = perm.UserRepoToPerm.repository.repo_name
628 r_k = perm.UserRepoToPerm.repository.repo_name
628 p = perm.Permission.permission_name
629 p = perm.Permission.permission_name
629 pattern = perm.UserToRepoBranchPermission.branch_pattern
630 pattern = perm.UserToRepoBranchPermission.branch_pattern
630 o = PermOrigin.REPO_USER % perm.UserRepoToPerm.user.username
631 o = PermOrigin.REPO_USER % perm.UserRepoToPerm.user.username
631
632
632 if not self.explicit:
633 if not self.explicit:
633 cur_perm = self.permissions_repository_branches.get(r_k)
634 cur_perm = self.permissions_repository_branches.get(r_k)
634 if cur_perm:
635 if cur_perm:
635 cur_perm = cur_perm[pattern]
636 cur_perm = cur_perm[pattern]
636 cur_perm = cur_perm or 'branch.none'
637 cur_perm = cur_perm or 'branch.none'
637
638
638 p = self._choose_permission(p, cur_perm)
639 p = self._choose_permission(p, cur_perm)
639
640
640 # NOTE(marcink): register all pattern/perm instances in this
641 # NOTE(marcink): register all pattern/perm instances in this
641 # special dict that aggregates entries
642 # special dict that aggregates entries
642 self.permissions_repository_branches[r_k] = pattern, p, o
643 self.permissions_repository_branches[r_k] = pattern, p, o
643
644
644 def _calculate_default_permissions_repository_groups(self, user_inherit_object_permissions):
645 def _calculate_default_permissions_repository_groups(self, user_inherit_object_permissions):
645 for perm in self.default_repo_groups_perms:
646 for perm in self.default_repo_groups_perms:
646 rg_k = perm.UserRepoGroupToPerm.group.group_name
647 rg_k = perm.UserRepoGroupToPerm.group.group_name
647 obj_id = perm.UserRepoGroupToPerm.group.group_id
648 obj_id = perm.UserRepoGroupToPerm.group.group_id
648 p = perm.Permission.permission_name
649 p = perm.Permission.permission_name
649 o = PermOrigin.REPOGROUP_DEFAULT
650 o = PermOrigin.REPOGROUP_DEFAULT
650 self.permissions_repository_groups[rg_k] = p, o, obj_id
651 self.permissions_repository_groups[rg_k] = p, o, obj_id
651
652
652 # if we decide this user isn't inheriting permissions from default
653 # if we decide this user isn't inheriting permissions from default
653 # user we set him to .none so only explicit permissions work
654 # user we set him to .none so only explicit permissions work
654 if not user_inherit_object_permissions:
655 if not user_inherit_object_permissions:
655 p = 'group.none'
656 p = 'group.none'
656 o = PermOrigin.REPOGROUP_DEFAULT_NO_INHERIT
657 o = PermOrigin.REPOGROUP_DEFAULT_NO_INHERIT
657 self.permissions_repository_groups[rg_k] = p, o, obj_id
658 self.permissions_repository_groups[rg_k] = p, o, obj_id
658
659
659 if perm.RepoGroup.user_id == self.user_id:
660 if perm.RepoGroup.user_id == self.user_id:
660 # set admin if owner
661 # set admin if owner
661 p = 'group.admin'
662 p = 'group.admin'
662 o = PermOrigin.REPOGROUP_OWNER
663 o = PermOrigin.REPOGROUP_OWNER
663 self.permissions_repository_groups[rg_k] = p, o, obj_id
664 self.permissions_repository_groups[rg_k] = p, o, obj_id
664
665
665 if self.user_is_admin:
666 if self.user_is_admin:
666 p = 'group.admin'
667 p = 'group.admin'
667 o = PermOrigin.SUPER_ADMIN
668 o = PermOrigin.SUPER_ADMIN
668 self.permissions_repository_groups[rg_k] = p, o, obj_id
669 self.permissions_repository_groups[rg_k] = p, o, obj_id
669
670
670 def _calculate_default_permissions_user_groups(self, user_inherit_object_permissions):
671 def _calculate_default_permissions_user_groups(self, user_inherit_object_permissions):
671 for perm in self.default_user_group_perms:
672 for perm in self.default_user_group_perms:
672 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
673 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
673 obj_id = perm.UserUserGroupToPerm.user_group.users_group_id
674 obj_id = perm.UserUserGroupToPerm.user_group.users_group_id
674 p = perm.Permission.permission_name
675 p = perm.Permission.permission_name
675 o = PermOrigin.USERGROUP_DEFAULT
676 o = PermOrigin.USERGROUP_DEFAULT
676 self.permissions_user_groups[u_k] = p, o, obj_id
677 self.permissions_user_groups[u_k] = p, o, obj_id
677
678
678 # if we decide this user isn't inheriting permissions from default
679 # if we decide this user isn't inheriting permissions from default
679 # user we set him to .none so only explicit permissions work
680 # user we set him to .none so only explicit permissions work
680 if not user_inherit_object_permissions:
681 if not user_inherit_object_permissions:
681 p = 'usergroup.none'
682 p = 'usergroup.none'
682 o = PermOrigin.USERGROUP_DEFAULT_NO_INHERIT
683 o = PermOrigin.USERGROUP_DEFAULT_NO_INHERIT
683 self.permissions_user_groups[u_k] = p, o, obj_id
684 self.permissions_user_groups[u_k] = p, o, obj_id
684
685
685 if perm.UserGroup.user_id == self.user_id:
686 if perm.UserGroup.user_id == self.user_id:
686 # set admin if owner
687 # set admin if owner
687 p = 'usergroup.admin'
688 p = 'usergroup.admin'
688 o = PermOrigin.USERGROUP_OWNER
689 o = PermOrigin.USERGROUP_OWNER
689 self.permissions_user_groups[u_k] = p, o, obj_id
690 self.permissions_user_groups[u_k] = p, o, obj_id
690
691
691 if self.user_is_admin:
692 if self.user_is_admin:
692 p = 'usergroup.admin'
693 p = 'usergroup.admin'
693 o = PermOrigin.SUPER_ADMIN
694 o = PermOrigin.SUPER_ADMIN
694 self.permissions_user_groups[u_k] = p, o, obj_id
695 self.permissions_user_groups[u_k] = p, o, obj_id
695
696
696 def _calculate_default_permissions(self):
697 def _calculate_default_permissions(self):
697 """
698 """
698 Set default user permissions for repositories, repository branches,
699 Set default user permissions for repositories, repository branches,
699 repository groups, user groups taken from the default user.
700 repository groups, user groups taken from the default user.
700
701
701 Calculate inheritance of object permissions based on what we have now
702 Calculate inheritance of object permissions based on what we have now
702 in GLOBAL permissions. We check if .false is in GLOBAL since this is
703 in GLOBAL permissions. We check if .false is in GLOBAL since this is
703 explicitly set. Inherit is the opposite of .false being there.
704 explicitly set. Inherit is the opposite of .false being there.
704
705
705 .. note::
706 .. note::
706
707
707 the syntax is little bit odd but what we need to check here is
708 the syntax is little bit odd but what we need to check here is
708 the opposite of .false permission being in the list so even for
709 the opposite of .false permission being in the list so even for
709 inconsistent state when both .true/.false is there
710 inconsistent state when both .true/.false is there
710 .false is more important
711 .false is more important
711
712
712 """
713 """
713 user_inherit_object_permissions = not ('hg.inherit_default_perms.false'
714 user_inherit_object_permissions = not ('hg.inherit_default_perms.false'
714 in self.permissions_global)
715 in self.permissions_global)
715
716
716 # default permissions inherited from `default` user permissions
717 # default permissions inherited from `default` user permissions
717 self._calculate_default_permissions_repositories(
718 self._calculate_default_permissions_repositories(
718 user_inherit_object_permissions)
719 user_inherit_object_permissions)
719
720
720 self._calculate_default_permissions_repository_branches(
721 self._calculate_default_permissions_repository_branches(
721 user_inherit_object_permissions)
722 user_inherit_object_permissions)
722
723
723 self._calculate_default_permissions_repository_groups(
724 self._calculate_default_permissions_repository_groups(
724 user_inherit_object_permissions)
725 user_inherit_object_permissions)
725
726
726 self._calculate_default_permissions_user_groups(
727 self._calculate_default_permissions_user_groups(
727 user_inherit_object_permissions)
728 user_inherit_object_permissions)
728
729
729 def _calculate_repository_permissions(self):
730 def _calculate_repository_permissions(self):
730 """
731 """
731 Repository access permissions for the current user.
732 Repository access permissions for the current user.
732
733
733 Check if the user is part of user groups for this repository and
734 Check if the user is part of user groups for this repository and
734 fill in the permission from it. `_choose_permission` decides of which
735 fill in the permission from it. `_choose_permission` decides of which
735 permission should be selected based on selected method.
736 permission should be selected based on selected method.
736 """
737 """
737
738
738 # user group for repositories permissions
739 # user group for repositories permissions
739 user_repo_perms_from_user_group = Permission\
740 user_repo_perms_from_user_group = Permission\
740 .get_default_repo_perms_from_user_group(
741 .get_default_repo_perms_from_user_group(
741 self.user_id, self.scope_repo_id)
742 self.user_id, self.scope_repo_id)
742
743
743 multiple_counter = collections.defaultdict(int)
744 multiple_counter = collections.defaultdict(int)
744 for perm in user_repo_perms_from_user_group:
745 for perm in user_repo_perms_from_user_group:
745 r_k = perm.UserGroupRepoToPerm.repository.repo_name
746 r_k = perm.UserGroupRepoToPerm.repository.repo_name
746 obj_id = perm.UserGroupRepoToPerm.repository.repo_id
747 obj_id = perm.UserGroupRepoToPerm.repository.repo_id
747 multiple_counter[r_k] += 1
748 multiple_counter[r_k] += 1
748 p = perm.Permission.permission_name
749 p = perm.Permission.permission_name
749 o = PermOrigin.REPO_USERGROUP % perm.UserGroupRepoToPerm\
750 o = PermOrigin.REPO_USERGROUP % perm.UserGroupRepoToPerm\
750 .users_group.users_group_name
751 .users_group.users_group_name
751
752
752 if multiple_counter[r_k] > 1:
753 if multiple_counter[r_k] > 1:
753 cur_perm = self.permissions_repositories[r_k]
754 cur_perm = self.permissions_repositories[r_k]
754 p = self._choose_permission(p, cur_perm)
755 p = self._choose_permission(p, cur_perm)
755
756
756 self.permissions_repositories[r_k] = p, o, obj_id
757 self.permissions_repositories[r_k] = p, o, obj_id
757
758
758 if perm.Repository.user_id == self.user_id:
759 if perm.Repository.user_id == self.user_id:
759 # set admin if owner
760 # set admin if owner
760 p = 'repository.admin'
761 p = 'repository.admin'
761 o = PermOrigin.REPO_OWNER
762 o = PermOrigin.REPO_OWNER
762 self.permissions_repositories[r_k] = p, o, obj_id
763 self.permissions_repositories[r_k] = p, o, obj_id
763
764
764 if self.user_is_admin:
765 if self.user_is_admin:
765 p = 'repository.admin'
766 p = 'repository.admin'
766 o = PermOrigin.SUPER_ADMIN
767 o = PermOrigin.SUPER_ADMIN
767 self.permissions_repositories[r_k] = p, o, obj_id
768 self.permissions_repositories[r_k] = p, o, obj_id
768
769
769 # user explicit permissions for repositories, overrides any specified
770 # user explicit permissions for repositories, overrides any specified
770 # by the group permission
771 # by the group permission
771 user_repo_perms = Permission.get_default_repo_perms(
772 user_repo_perms = Permission.get_default_repo_perms(
772 self.user_id, self.scope_repo_id)
773 self.user_id, self.scope_repo_id)
773 for perm in user_repo_perms:
774 for perm in user_repo_perms:
774 r_k = perm.UserRepoToPerm.repository.repo_name
775 r_k = perm.UserRepoToPerm.repository.repo_name
775 obj_id = perm.UserRepoToPerm.repository.repo_id
776 obj_id = perm.UserRepoToPerm.repository.repo_id
776 p = perm.Permission.permission_name
777 p = perm.Permission.permission_name
777 o = PermOrigin.REPO_USER % perm.UserRepoToPerm.user.username
778 o = PermOrigin.REPO_USER % perm.UserRepoToPerm.user.username
778
779
779 if not self.explicit:
780 if not self.explicit:
780 cur_perm = self.permissions_repositories.get(
781 cur_perm = self.permissions_repositories.get(
781 r_k, 'repository.none')
782 r_k, 'repository.none')
782 p = self._choose_permission(p, cur_perm)
783 p = self._choose_permission(p, cur_perm)
783
784
784 self.permissions_repositories[r_k] = p, o, obj_id
785 self.permissions_repositories[r_k] = p, o, obj_id
785
786
786 if perm.Repository.user_id == self.user_id:
787 if perm.Repository.user_id == self.user_id:
787 # set admin if owner
788 # set admin if owner
788 p = 'repository.admin'
789 p = 'repository.admin'
789 o = PermOrigin.REPO_OWNER
790 o = PermOrigin.REPO_OWNER
790 self.permissions_repositories[r_k] = p, o, obj_id
791 self.permissions_repositories[r_k] = p, o, obj_id
791
792
792 if self.user_is_admin:
793 if self.user_is_admin:
793 p = 'repository.admin'
794 p = 'repository.admin'
794 o = PermOrigin.SUPER_ADMIN
795 o = PermOrigin.SUPER_ADMIN
795 self.permissions_repositories[r_k] = p, o, obj_id
796 self.permissions_repositories[r_k] = p, o, obj_id
796
797
797 def _calculate_repository_branch_permissions(self):
798 def _calculate_repository_branch_permissions(self):
798 # user group for repositories permissions
799 # user group for repositories permissions
799 user_repo_branch_perms_from_user_group = Permission\
800 user_repo_branch_perms_from_user_group = Permission\
800 .get_default_repo_branch_perms_from_user_group(
801 .get_default_repo_branch_perms_from_user_group(
801 self.user_id, self.scope_repo_id)
802 self.user_id, self.scope_repo_id)
802
803
803 multiple_counter = collections.defaultdict(int)
804 multiple_counter = collections.defaultdict(int)
804 for perm in user_repo_branch_perms_from_user_group:
805 for perm in user_repo_branch_perms_from_user_group:
805 r_k = perm.UserGroupRepoToPerm.repository.repo_name
806 r_k = perm.UserGroupRepoToPerm.repository.repo_name
806 p = perm.Permission.permission_name
807 p = perm.Permission.permission_name
807 pattern = perm.UserGroupToRepoBranchPermission.branch_pattern
808 pattern = perm.UserGroupToRepoBranchPermission.branch_pattern
808 o = PermOrigin.REPO_USERGROUP % perm.UserGroupRepoToPerm\
809 o = PermOrigin.REPO_USERGROUP % perm.UserGroupRepoToPerm\
809 .users_group.users_group_name
810 .users_group.users_group_name
810
811
811 multiple_counter[r_k] += 1
812 multiple_counter[r_k] += 1
812 if multiple_counter[r_k] > 1:
813 if multiple_counter[r_k] > 1:
813 cur_perm = self.permissions_repository_branches[r_k][pattern]
814 cur_perm = self.permissions_repository_branches[r_k][pattern]
814 p = self._choose_permission(p, cur_perm)
815 p = self._choose_permission(p, cur_perm)
815
816
816 self.permissions_repository_branches[r_k] = pattern, p, o
817 self.permissions_repository_branches[r_k] = pattern, p, o
817
818
818 # user explicit branch permissions for repositories, overrides
819 # user explicit branch permissions for repositories, overrides
819 # any specified by the group permission
820 # any specified by the group permission
820 user_repo_branch_perms = Permission.get_default_repo_branch_perms(
821 user_repo_branch_perms = Permission.get_default_repo_branch_perms(
821 self.user_id, self.scope_repo_id)
822 self.user_id, self.scope_repo_id)
822
823
823 for perm in user_repo_branch_perms:
824 for perm in user_repo_branch_perms:
824
825
825 r_k = perm.UserRepoToPerm.repository.repo_name
826 r_k = perm.UserRepoToPerm.repository.repo_name
826 p = perm.Permission.permission_name
827 p = perm.Permission.permission_name
827 pattern = perm.UserToRepoBranchPermission.branch_pattern
828 pattern = perm.UserToRepoBranchPermission.branch_pattern
828 o = PermOrigin.REPO_USER % perm.UserRepoToPerm.user.username
829 o = PermOrigin.REPO_USER % perm.UserRepoToPerm.user.username
829
830
830 if not self.explicit:
831 if not self.explicit:
831 cur_perm = self.permissions_repository_branches.get(r_k)
832 cur_perm = self.permissions_repository_branches.get(r_k)
832 if cur_perm:
833 if cur_perm:
833 cur_perm = cur_perm[pattern]
834 cur_perm = cur_perm[pattern]
834 cur_perm = cur_perm or 'branch.none'
835 cur_perm = cur_perm or 'branch.none'
835 p = self._choose_permission(p, cur_perm)
836 p = self._choose_permission(p, cur_perm)
836
837
837 # NOTE(marcink): register all pattern/perm instances in this
838 # NOTE(marcink): register all pattern/perm instances in this
838 # special dict that aggregates entries
839 # special dict that aggregates entries
839 self.permissions_repository_branches[r_k] = pattern, p, o
840 self.permissions_repository_branches[r_k] = pattern, p, o
840
841
841 def _calculate_repository_group_permissions(self):
842 def _calculate_repository_group_permissions(self):
842 """
843 """
843 Repository group permissions for the current user.
844 Repository group permissions for the current user.
844
845
845 Check if the user is part of user groups for repository groups and
846 Check if the user is part of user groups for repository groups and
846 fill in the permissions from it. `_choose_permission` decides of which
847 fill in the permissions from it. `_choose_permission` decides of which
847 permission should be selected based on selected method.
848 permission should be selected based on selected method.
848 """
849 """
849 # user group for repo groups permissions
850 # user group for repo groups permissions
850 user_repo_group_perms_from_user_group = Permission\
851 user_repo_group_perms_from_user_group = Permission\
851 .get_default_group_perms_from_user_group(
852 .get_default_group_perms_from_user_group(
852 self.user_id, self.scope_repo_group_id)
853 self.user_id, self.scope_repo_group_id)
853
854
854 multiple_counter = collections.defaultdict(int)
855 multiple_counter = collections.defaultdict(int)
855 for perm in user_repo_group_perms_from_user_group:
856 for perm in user_repo_group_perms_from_user_group:
856 rg_k = perm.UserGroupRepoGroupToPerm.group.group_name
857 rg_k = perm.UserGroupRepoGroupToPerm.group.group_name
857 obj_id = perm.UserGroupRepoGroupToPerm.group.group_id
858 obj_id = perm.UserGroupRepoGroupToPerm.group.group_id
858 multiple_counter[rg_k] += 1
859 multiple_counter[rg_k] += 1
859 o = PermOrigin.REPOGROUP_USERGROUP % perm.UserGroupRepoGroupToPerm\
860 o = PermOrigin.REPOGROUP_USERGROUP % perm.UserGroupRepoGroupToPerm\
860 .users_group.users_group_name
861 .users_group.users_group_name
861 p = perm.Permission.permission_name
862 p = perm.Permission.permission_name
862
863
863 if multiple_counter[rg_k] > 1:
864 if multiple_counter[rg_k] > 1:
864 cur_perm = self.permissions_repository_groups[rg_k]
865 cur_perm = self.permissions_repository_groups[rg_k]
865 p = self._choose_permission(p, cur_perm)
866 p = self._choose_permission(p, cur_perm)
866 self.permissions_repository_groups[rg_k] = p, o, obj_id
867 self.permissions_repository_groups[rg_k] = p, o, obj_id
867
868
868 if perm.RepoGroup.user_id == self.user_id:
869 if perm.RepoGroup.user_id == self.user_id:
869 # set admin if owner, even for member of other user group
870 # set admin if owner, even for member of other user group
870 p = 'group.admin'
871 p = 'group.admin'
871 o = PermOrigin.REPOGROUP_OWNER
872 o = PermOrigin.REPOGROUP_OWNER
872 self.permissions_repository_groups[rg_k] = p, o, obj_id
873 self.permissions_repository_groups[rg_k] = p, o, obj_id
873
874
874 if self.user_is_admin:
875 if self.user_is_admin:
875 p = 'group.admin'
876 p = 'group.admin'
876 o = PermOrigin.SUPER_ADMIN
877 o = PermOrigin.SUPER_ADMIN
877 self.permissions_repository_groups[rg_k] = p, o, obj_id
878 self.permissions_repository_groups[rg_k] = p, o, obj_id
878
879
879 # user explicit permissions for repository groups
880 # user explicit permissions for repository groups
880 user_repo_groups_perms = Permission.get_default_group_perms(
881 user_repo_groups_perms = Permission.get_default_group_perms(
881 self.user_id, self.scope_repo_group_id)
882 self.user_id, self.scope_repo_group_id)
882 for perm in user_repo_groups_perms:
883 for perm in user_repo_groups_perms:
883 rg_k = perm.UserRepoGroupToPerm.group.group_name
884 rg_k = perm.UserRepoGroupToPerm.group.group_name
884 obj_id = perm.UserRepoGroupToPerm.group.group_id
885 obj_id = perm.UserRepoGroupToPerm.group.group_id
885 o = PermOrigin.REPOGROUP_USER % perm.UserRepoGroupToPerm\
886 o = PermOrigin.REPOGROUP_USER % perm.UserRepoGroupToPerm\
886 .user.username
887 .user.username
887 p = perm.Permission.permission_name
888 p = perm.Permission.permission_name
888
889
889 if not self.explicit:
890 if not self.explicit:
890 cur_perm = self.permissions_repository_groups.get(rg_k, 'group.none')
891 cur_perm = self.permissions_repository_groups.get(rg_k, 'group.none')
891 p = self._choose_permission(p, cur_perm)
892 p = self._choose_permission(p, cur_perm)
892
893
893 self.permissions_repository_groups[rg_k] = p, o, obj_id
894 self.permissions_repository_groups[rg_k] = p, o, obj_id
894
895
895 if perm.RepoGroup.user_id == self.user_id:
896 if perm.RepoGroup.user_id == self.user_id:
896 # set admin if owner
897 # set admin if owner
897 p = 'group.admin'
898 p = 'group.admin'
898 o = PermOrigin.REPOGROUP_OWNER
899 o = PermOrigin.REPOGROUP_OWNER
899 self.permissions_repository_groups[rg_k] = p, o, obj_id
900 self.permissions_repository_groups[rg_k] = p, o, obj_id
900
901
901 if self.user_is_admin:
902 if self.user_is_admin:
902 p = 'group.admin'
903 p = 'group.admin'
903 o = PermOrigin.SUPER_ADMIN
904 o = PermOrigin.SUPER_ADMIN
904 self.permissions_repository_groups[rg_k] = p, o, obj_id
905 self.permissions_repository_groups[rg_k] = p, o, obj_id
905
906
906 def _calculate_user_group_permissions(self):
907 def _calculate_user_group_permissions(self):
907 """
908 """
908 User group permissions for the current user.
909 User group permissions for the current user.
909 """
910 """
910 # user group for user group permissions
911 # user group for user group permissions
911 user_group_from_user_group = Permission\
912 user_group_from_user_group = Permission\
912 .get_default_user_group_perms_from_user_group(
913 .get_default_user_group_perms_from_user_group(
913 self.user_id, self.scope_user_group_id)
914 self.user_id, self.scope_user_group_id)
914
915
915 multiple_counter = collections.defaultdict(int)
916 multiple_counter = collections.defaultdict(int)
916 for perm in user_group_from_user_group:
917 for perm in user_group_from_user_group:
917 ug_k = perm.UserGroupUserGroupToPerm.target_user_group.users_group_name
918 ug_k = perm.UserGroupUserGroupToPerm.target_user_group.users_group_name
918 obj_id = perm.UserGroupUserGroupToPerm.target_user_group.users_group_id
919 obj_id = perm.UserGroupUserGroupToPerm.target_user_group.users_group_id
919 multiple_counter[ug_k] += 1
920 multiple_counter[ug_k] += 1
920 o = PermOrigin.USERGROUP_USERGROUP % perm.UserGroupUserGroupToPerm\
921 o = PermOrigin.USERGROUP_USERGROUP % perm.UserGroupUserGroupToPerm\
921 .user_group.users_group_name
922 .user_group.users_group_name
922 p = perm.Permission.permission_name
923 p = perm.Permission.permission_name
923
924
924 if multiple_counter[ug_k] > 1:
925 if multiple_counter[ug_k] > 1:
925 cur_perm = self.permissions_user_groups[ug_k]
926 cur_perm = self.permissions_user_groups[ug_k]
926 p = self._choose_permission(p, cur_perm)
927 p = self._choose_permission(p, cur_perm)
927
928
928 self.permissions_user_groups[ug_k] = p, o, obj_id
929 self.permissions_user_groups[ug_k] = p, o, obj_id
929
930
930 if perm.UserGroup.user_id == self.user_id:
931 if perm.UserGroup.user_id == self.user_id:
931 # set admin if owner, even for member of other user group
932 # set admin if owner, even for member of other user group
932 p = 'usergroup.admin'
933 p = 'usergroup.admin'
933 o = PermOrigin.USERGROUP_OWNER
934 o = PermOrigin.USERGROUP_OWNER
934 self.permissions_user_groups[ug_k] = p, o, obj_id
935 self.permissions_user_groups[ug_k] = p, o, obj_id
935
936
936 if self.user_is_admin:
937 if self.user_is_admin:
937 p = 'usergroup.admin'
938 p = 'usergroup.admin'
938 o = PermOrigin.SUPER_ADMIN
939 o = PermOrigin.SUPER_ADMIN
939 self.permissions_user_groups[ug_k] = p, o, obj_id
940 self.permissions_user_groups[ug_k] = p, o, obj_id
940
941
941 # user explicit permission for user groups
942 # user explicit permission for user groups
942 user_user_groups_perms = Permission.get_default_user_group_perms(
943 user_user_groups_perms = Permission.get_default_user_group_perms(
943 self.user_id, self.scope_user_group_id)
944 self.user_id, self.scope_user_group_id)
944 for perm in user_user_groups_perms:
945 for perm in user_user_groups_perms:
945 ug_k = perm.UserUserGroupToPerm.user_group.users_group_name
946 ug_k = perm.UserUserGroupToPerm.user_group.users_group_name
946 obj_id = perm.UserUserGroupToPerm.user_group.users_group_id
947 obj_id = perm.UserUserGroupToPerm.user_group.users_group_id
947 o = PermOrigin.USERGROUP_USER % perm.UserUserGroupToPerm\
948 o = PermOrigin.USERGROUP_USER % perm.UserUserGroupToPerm\
948 .user.username
949 .user.username
949 p = perm.Permission.permission_name
950 p = perm.Permission.permission_name
950
951
951 if not self.explicit:
952 if not self.explicit:
952 cur_perm = self.permissions_user_groups.get(ug_k, 'usergroup.none')
953 cur_perm = self.permissions_user_groups.get(ug_k, 'usergroup.none')
953 p = self._choose_permission(p, cur_perm)
954 p = self._choose_permission(p, cur_perm)
954
955
955 self.permissions_user_groups[ug_k] = p, o, obj_id
956 self.permissions_user_groups[ug_k] = p, o, obj_id
956
957
957 if perm.UserGroup.user_id == self.user_id:
958 if perm.UserGroup.user_id == self.user_id:
958 # set admin if owner
959 # set admin if owner
959 p = 'usergroup.admin'
960 p = 'usergroup.admin'
960 o = PermOrigin.USERGROUP_OWNER
961 o = PermOrigin.USERGROUP_OWNER
961 self.permissions_user_groups[ug_k] = p, o, obj_id
962 self.permissions_user_groups[ug_k] = p, o, obj_id
962
963
963 if self.user_is_admin:
964 if self.user_is_admin:
964 p = 'usergroup.admin'
965 p = 'usergroup.admin'
965 o = PermOrigin.SUPER_ADMIN
966 o = PermOrigin.SUPER_ADMIN
966 self.permissions_user_groups[ug_k] = p, o, obj_id
967 self.permissions_user_groups[ug_k] = p, o, obj_id
967
968
968 def _choose_permission(self, new_perm, cur_perm):
969 def _choose_permission(self, new_perm, cur_perm):
969 new_perm_val = Permission.PERM_WEIGHTS[new_perm]
970 new_perm_val = Permission.PERM_WEIGHTS[new_perm]
970 cur_perm_val = Permission.PERM_WEIGHTS[cur_perm]
971 cur_perm_val = Permission.PERM_WEIGHTS[cur_perm]
971 if self.algo == 'higherwin':
972 if self.algo == 'higherwin':
972 if new_perm_val > cur_perm_val:
973 if new_perm_val > cur_perm_val:
973 return new_perm
974 return new_perm
974 return cur_perm
975 return cur_perm
975 elif self.algo == 'lowerwin':
976 elif self.algo == 'lowerwin':
976 if new_perm_val < cur_perm_val:
977 if new_perm_val < cur_perm_val:
977 return new_perm
978 return new_perm
978 return cur_perm
979 return cur_perm
979
980
980 def _permission_structure(self):
981 def _permission_structure(self):
981 return {
982 return {
982 'global': self.permissions_global,
983 'global': self.permissions_global,
983 'repositories': self.permissions_repositories,
984 'repositories': self.permissions_repositories,
984 'repository_branches': self.permissions_repository_branches,
985 'repository_branches': self.permissions_repository_branches,
985 'repositories_groups': self.permissions_repository_groups,
986 'repositories_groups': self.permissions_repository_groups,
986 'user_groups': self.permissions_user_groups,
987 'user_groups': self.permissions_user_groups,
987 }
988 }
988
989
989
990
990 def allowed_auth_token_access(view_name, auth_token, whitelist=None):
991 def allowed_auth_token_access(view_name, auth_token, whitelist=None):
991 """
992 """
992 Check if given controller_name is in whitelist of auth token access
993 Check if given controller_name is in whitelist of auth token access
993 """
994 """
994 if not whitelist:
995 if not whitelist:
995 from rhodecode import CONFIG
996 from rhodecode import CONFIG
996 whitelist = aslist(
997 whitelist = aslist(
997 CONFIG.get('api_access_controllers_whitelist'), sep=',')
998 CONFIG.get('api_access_controllers_whitelist'), sep=',')
998 # backward compat translation
999 # backward compat translation
999 compat = {
1000 compat = {
1000 # old controller, new VIEW
1001 # old controller, new VIEW
1001 'ChangesetController:*': 'RepoCommitsView:*',
1002 'ChangesetController:*': 'RepoCommitsView:*',
1002 'ChangesetController:changeset_patch': 'RepoCommitsView:repo_commit_patch',
1003 'ChangesetController:changeset_patch': 'RepoCommitsView:repo_commit_patch',
1003 'ChangesetController:changeset_raw': 'RepoCommitsView:repo_commit_raw',
1004 'ChangesetController:changeset_raw': 'RepoCommitsView:repo_commit_raw',
1004 'FilesController:raw': 'RepoCommitsView:repo_commit_raw',
1005 'FilesController:raw': 'RepoCommitsView:repo_commit_raw',
1005 'FilesController:archivefile': 'RepoFilesView:repo_archivefile',
1006 'FilesController:archivefile': 'RepoFilesView:repo_archivefile',
1006 'GistsController:*': 'GistView:*',
1007 'GistsController:*': 'GistView:*',
1007 }
1008 }
1008
1009
1009 log.debug(
1010 log.debug(
1010 'Allowed views for AUTH TOKEN access: %s', whitelist)
1011 'Allowed views for AUTH TOKEN access: %s', whitelist)
1011 auth_token_access_valid = False
1012 auth_token_access_valid = False
1012
1013
1013 for entry in whitelist:
1014 for entry in whitelist:
1014 token_match = True
1015 token_match = True
1015 if entry in compat:
1016 if entry in compat:
1016 # translate from old Controllers to Pyramid Views
1017 # translate from old Controllers to Pyramid Views
1017 entry = compat[entry]
1018 entry = compat[entry]
1018
1019
1019 if '@' in entry:
1020 if '@' in entry:
1020 # specific AuthToken
1021 # specific AuthToken
1021 entry, allowed_token = entry.split('@', 1)
1022 entry, allowed_token = entry.split('@', 1)
1022 token_match = auth_token == allowed_token
1023 token_match = auth_token == allowed_token
1023
1024
1024 if fnmatch.fnmatch(view_name, entry) and token_match:
1025 if fnmatch.fnmatch(view_name, entry) and token_match:
1025 auth_token_access_valid = True
1026 auth_token_access_valid = True
1026 break
1027 break
1027
1028
1028 if auth_token_access_valid:
1029 if auth_token_access_valid:
1029 log.debug('view: `%s` matches entry in whitelist: %s',
1030 log.debug('view: `%s` matches entry in whitelist: %s',
1030 view_name, whitelist)
1031 view_name, whitelist)
1031
1032
1032 else:
1033 else:
1033 msg = ('view: `%s` does *NOT* match any entry in whitelist: %s'
1034 msg = ('view: `%s` does *NOT* match any entry in whitelist: %s'
1034 % (view_name, whitelist))
1035 % (view_name, whitelist))
1035 if auth_token:
1036 if auth_token:
1036 # if we use auth token key and don't have access it's a warning
1037 # if we use auth token key and don't have access it's a warning
1037 log.warning(msg)
1038 log.warning(msg)
1038 else:
1039 else:
1039 log.debug(msg)
1040 log.debug(msg)
1040
1041
1041 return auth_token_access_valid
1042 return auth_token_access_valid
1042
1043
1043
1044
1044 class AuthUser(object):
1045 class AuthUser(object):
1045 """
1046 """
1046 A simple object that handles all attributes of user in RhodeCode
1047 A simple object that handles all attributes of user in RhodeCode
1047
1048
1048 It does lookup based on API key,given user, or user present in session
1049 It does lookup based on API key,given user, or user present in session
1049 Then it fills all required information for such user. It also checks if
1050 Then it fills all required information for such user. It also checks if
1050 anonymous access is enabled and if so, it returns default user as logged in
1051 anonymous access is enabled and if so, it returns default user as logged in
1051 """
1052 """
1052 GLOBAL_PERMS = [x[0] for x in Permission.PERMS]
1053 GLOBAL_PERMS = [x[0] for x in Permission.PERMS]
1053 repo_read_perms = ['repository.read', 'repository.admin', 'repository.write']
1054 repo_read_perms = ['repository.read', 'repository.admin', 'repository.write']
1054 repo_group_read_perms = ['group.read', 'group.write', 'group.admin']
1055 repo_group_read_perms = ['group.read', 'group.write', 'group.admin']
1055 user_group_read_perms = ['usergroup.read', 'usergroup.write', 'usergroup.admin']
1056 user_group_read_perms = ['usergroup.read', 'usergroup.write', 'usergroup.admin']
1056
1057
1057 def __init__(self, user_id=None, api_key=None, username=None, ip_addr=None):
1058 def __init__(self, user_id=None, api_key=None, username=None, ip_addr=None):
1058
1059
1059 self.user_id = user_id
1060 self.user_id = user_id
1060 self._api_key = api_key
1061 self._api_key = api_key
1061
1062
1062 self.api_key = None
1063 self.api_key = None
1063 self.username = username
1064 self.username = username
1064 self.ip_addr = ip_addr
1065 self.ip_addr = ip_addr
1065 self.name = ''
1066 self.name = ''
1066 self.lastname = ''
1067 self.lastname = ''
1067 self.first_name = ''
1068 self.first_name = ''
1068 self.last_name = ''
1069 self.last_name = ''
1069 self.email = ''
1070 self.email = ''
1070 self.is_authenticated = False
1071 self.is_authenticated = False
1071 self.admin = False
1072 self.admin = False
1072 self.inherit_default_permissions = False
1073 self.inherit_default_permissions = False
1073 self.password = ''
1074 self.password = ''
1074
1075
1075 self.anonymous_user = None # propagated on propagate_data
1076 self.anonymous_user = None # propagated on propagate_data
1076 self.propagate_data()
1077 self.propagate_data()
1077 self._instance = None
1078 self._instance = None
1078 self._permissions_scoped_cache = {} # used to bind scoped calculation
1079 self._permissions_scoped_cache = {} # used to bind scoped calculation
1079
1080
1080 @LazyProperty
1081 @LazyProperty
1081 def permissions(self):
1082 def permissions(self):
1082 return self.get_perms(user=self, cache=None)
1083 return self.get_perms(user=self, cache=None)
1083
1084
1084 @LazyProperty
1085 @LazyProperty
1085 def permissions_safe(self):
1086 def permissions_safe(self):
1086 """
1087 """
1087 Filtered permissions excluding not allowed repositories
1088 Filtered permissions excluding not allowed repositories
1088 """
1089 """
1089 perms = self.get_perms(user=self, cache=None)
1090 perms = self.get_perms(user=self, cache=None)
1090
1091
1091 perms['repositories'] = {
1092 perms['repositories'] = {
1092 k: v for k, v in perms['repositories'].items()
1093 k: v for k, v in perms['repositories'].items()
1093 if v != 'repository.none'}
1094 if v != 'repository.none'}
1094 perms['repositories_groups'] = {
1095 perms['repositories_groups'] = {
1095 k: v for k, v in perms['repositories_groups'].items()
1096 k: v for k, v in perms['repositories_groups'].items()
1096 if v != 'group.none'}
1097 if v != 'group.none'}
1097 perms['user_groups'] = {
1098 perms['user_groups'] = {
1098 k: v for k, v in perms['user_groups'].items()
1099 k: v for k, v in perms['user_groups'].items()
1099 if v != 'usergroup.none'}
1100 if v != 'usergroup.none'}
1100 perms['repository_branches'] = {
1101 perms['repository_branches'] = {
1101 k: v for k, v in perms['repository_branches'].iteritems()
1102 k: v for k, v in perms['repository_branches'].iteritems()
1102 if v != 'branch.none'}
1103 if v != 'branch.none'}
1103 return perms
1104 return perms
1104
1105
1105 @LazyProperty
1106 @LazyProperty
1106 def permissions_full_details(self):
1107 def permissions_full_details(self):
1107 return self.get_perms(
1108 return self.get_perms(
1108 user=self, cache=None, calculate_super_admin=True)
1109 user=self, cache=None, calculate_super_admin=True)
1109
1110
1110 def permissions_with_scope(self, scope):
1111 def permissions_with_scope(self, scope):
1111 """
1112 """
1112 Call the get_perms function with scoped data. The scope in that function
1113 Call the get_perms function with scoped data. The scope in that function
1113 narrows the SQL calls to the given ID of objects resulting in fetching
1114 narrows the SQL calls to the given ID of objects resulting in fetching
1114 Just particular permission we want to obtain. If scope is an empty dict
1115 Just particular permission we want to obtain. If scope is an empty dict
1115 then it basically narrows the scope to GLOBAL permissions only.
1116 then it basically narrows the scope to GLOBAL permissions only.
1116
1117
1117 :param scope: dict
1118 :param scope: dict
1118 """
1119 """
1119 if 'repo_name' in scope:
1120 if 'repo_name' in scope:
1120 obj = Repository.get_by_repo_name(scope['repo_name'])
1121 obj = Repository.get_by_repo_name(scope['repo_name'])
1121 if obj:
1122 if obj:
1122 scope['repo_id'] = obj.repo_id
1123 scope['repo_id'] = obj.repo_id
1123 _scope = collections.OrderedDict()
1124 _scope = collections.OrderedDict()
1124 _scope['repo_id'] = -1
1125 _scope['repo_id'] = -1
1125 _scope['user_group_id'] = -1
1126 _scope['user_group_id'] = -1
1126 _scope['repo_group_id'] = -1
1127 _scope['repo_group_id'] = -1
1127
1128
1128 for k in sorted(scope.keys()):
1129 for k in sorted(scope.keys()):
1129 _scope[k] = scope[k]
1130 _scope[k] = scope[k]
1130
1131
1131 # store in cache to mimic how the @LazyProperty works,
1132 # store in cache to mimic how the @LazyProperty works,
1132 # the difference here is that we use the unique key calculated
1133 # the difference here is that we use the unique key calculated
1133 # from params and values
1134 # from params and values
1134 return self.get_perms(user=self, cache=None, scope=_scope)
1135 return self.get_perms(user=self, cache=None, scope=_scope)
1135
1136
1136 def get_instance(self):
1137 def get_instance(self):
1137 return User.get(self.user_id)
1138 return User.get(self.user_id)
1138
1139
1139 def propagate_data(self):
1140 def propagate_data(self):
1140 """
1141 """
1141 Fills in user data and propagates values to this instance. Maps fetched
1142 Fills in user data and propagates values to this instance. Maps fetched
1142 user attributes to this class instance attributes
1143 user attributes to this class instance attributes
1143 """
1144 """
1144 log.debug('AuthUser: starting data propagation for new potential user')
1145 log.debug('AuthUser: starting data propagation for new potential user')
1145 user_model = UserModel()
1146 user_model = UserModel()
1146 anon_user = self.anonymous_user = User.get_default_user(cache=True)
1147 anon_user = self.anonymous_user = User.get_default_user(cache=True)
1147 is_user_loaded = False
1148 is_user_loaded = False
1148
1149
1149 # lookup by userid
1150 # lookup by userid
1150 if self.user_id is not None and self.user_id != anon_user.user_id:
1151 if self.user_id is not None and self.user_id != anon_user.user_id:
1151 log.debug('Trying Auth User lookup by USER ID: `%s`', self.user_id)
1152 log.debug('Trying Auth User lookup by USER ID: `%s`', self.user_id)
1152 is_user_loaded = user_model.fill_data(self, user_id=self.user_id)
1153 is_user_loaded = user_model.fill_data(self, user_id=self.user_id)
1153
1154
1154 # try go get user by api key
1155 # try go get user by api key
1155 elif self._api_key and self._api_key != anon_user.api_key:
1156 elif self._api_key and self._api_key != anon_user.api_key:
1156 log.debug('Trying Auth User lookup by API KEY: `...%s`', self._api_key[-4:])
1157 log.debug('Trying Auth User lookup by API KEY: `...%s`', self._api_key[-4:])
1157 is_user_loaded = user_model.fill_data(self, api_key=self._api_key)
1158 is_user_loaded = user_model.fill_data(self, api_key=self._api_key)
1158
1159
1159 # lookup by username
1160 # lookup by username
1160 elif self.username:
1161 elif self.username:
1161 log.debug('Trying Auth User lookup by USER NAME: `%s`', self.username)
1162 log.debug('Trying Auth User lookup by USER NAME: `%s`', self.username)
1162 is_user_loaded = user_model.fill_data(self, username=self.username)
1163 is_user_loaded = user_model.fill_data(self, username=self.username)
1163 else:
1164 else:
1164 log.debug('No data in %s that could been used to log in', self)
1165 log.debug('No data in %s that could been used to log in', self)
1165
1166
1166 if not is_user_loaded:
1167 if not is_user_loaded:
1167 log.debug(
1168 log.debug(
1168 'Failed to load user. Fallback to default user %s', anon_user)
1169 'Failed to load user. Fallback to default user %s', anon_user)
1169 # if we cannot authenticate user try anonymous
1170 # if we cannot authenticate user try anonymous
1170 if anon_user.active:
1171 if anon_user.active:
1171 log.debug('default user is active, using it as a session user')
1172 log.debug('default user is active, using it as a session user')
1172 user_model.fill_data(self, user_id=anon_user.user_id)
1173 user_model.fill_data(self, user_id=anon_user.user_id)
1173 # then we set this user is logged in
1174 # then we set this user is logged in
1174 self.is_authenticated = True
1175 self.is_authenticated = True
1175 else:
1176 else:
1176 log.debug('default user is NOT active')
1177 log.debug('default user is NOT active')
1177 # in case of disabled anonymous user we reset some of the
1178 # in case of disabled anonymous user we reset some of the
1178 # parameters so such user is "corrupted", skipping the fill_data
1179 # parameters so such user is "corrupted", skipping the fill_data
1179 for attr in ['user_id', 'username', 'admin', 'active']:
1180 for attr in ['user_id', 'username', 'admin', 'active']:
1180 setattr(self, attr, None)
1181 setattr(self, attr, None)
1181 self.is_authenticated = False
1182 self.is_authenticated = False
1182
1183
1183 if not self.username:
1184 if not self.username:
1184 self.username = 'None'
1185 self.username = 'None'
1185
1186
1186 log.debug('AuthUser: propagated user is now %s', self)
1187 log.debug('AuthUser: propagated user is now %s', self)
1187
1188
1188 def get_perms(self, user, scope=None, explicit=True, algo='higherwin',
1189 def get_perms(self, user, scope=None, explicit=True, algo='higherwin',
1189 calculate_super_admin=False, cache=None):
1190 calculate_super_admin=False, cache=None):
1190 """
1191 """
1191 Fills user permission attribute with permissions taken from database
1192 Fills user permission attribute with permissions taken from database
1192 works for permissions given for repositories, and for permissions that
1193 works for permissions given for repositories, and for permissions that
1193 are granted to groups
1194 are granted to groups
1194
1195
1195 :param user: instance of User object from database
1196 :param user: instance of User object from database
1196 :param explicit: In case there are permissions both for user and a group
1197 :param explicit: In case there are permissions both for user and a group
1197 that user is part of, explicit flag will defiine if user will
1198 that user is part of, explicit flag will defiine if user will
1198 explicitly override permissions from group, if it's False it will
1199 explicitly override permissions from group, if it's False it will
1199 make decision based on the algo
1200 make decision based on the algo
1200 :param algo: algorithm to decide what permission should be choose if
1201 :param algo: algorithm to decide what permission should be choose if
1201 it's multiple defined, eg user in two different groups. It also
1202 it's multiple defined, eg user in two different groups. It also
1202 decides if explicit flag is turned off how to specify the permission
1203 decides if explicit flag is turned off how to specify the permission
1203 for case when user is in a group + have defined separate permission
1204 for case when user is in a group + have defined separate permission
1204 :param calculate_super_admin: calculate permissions for super-admin in the
1205 :param calculate_super_admin: calculate permissions for super-admin in the
1205 same way as for regular user without speedups
1206 same way as for regular user without speedups
1206 :param cache: Use caching for calculation, None = let the cache backend decide
1207 :param cache: Use caching for calculation, None = let the cache backend decide
1207 """
1208 """
1208 user_id = user.user_id
1209 user_id = user.user_id
1209 user_is_admin = user.is_admin
1210 user_is_admin = user.is_admin
1210
1211
1211 # inheritance of global permissions like create repo/fork repo etc
1212 # inheritance of global permissions like create repo/fork repo etc
1212 user_inherit_default_permissions = user.inherit_default_permissions
1213 user_inherit_default_permissions = user.inherit_default_permissions
1213
1214
1214 cache_seconds = safe_int(
1215 cache_seconds = safe_int(
1215 rhodecode.CONFIG.get('rc_cache.cache_perms.expiration_time'))
1216 rhodecode.CONFIG.get('rc_cache.cache_perms.expiration_time'))
1216
1217
1217 if cache is None:
1218 if cache is None:
1218 # let the backend cache decide
1219 # let the backend cache decide
1219 cache_on = cache_seconds > 0
1220 cache_on = cache_seconds > 0
1220 else:
1221 else:
1221 cache_on = cache
1222 cache_on = cache
1222
1223
1223 log.debug(
1224 log.debug(
1224 'Computing PERMISSION tree for user %s scope `%s` '
1225 'Computing PERMISSION tree for user %s scope `%s` '
1225 'with caching: %s[TTL: %ss]', user, scope, cache_on, cache_seconds or 0)
1226 'with caching: %s[TTL: %ss]', user, scope, cache_on, cache_seconds or 0)
1226
1227
1227 cache_namespace_uid = 'cache_user_auth.{}'.format(user_id)
1228 cache_namespace_uid = 'cache_user_auth.{}'.format(user_id)
1228 region = rc_cache.get_or_create_region('cache_perms', cache_namespace_uid)
1229 region = rc_cache.get_or_create_region('cache_perms', cache_namespace_uid)
1229
1230
1230 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid,
1231 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid,
1231 condition=cache_on)
1232 condition=cache_on)
1232 def compute_perm_tree(cache_name, cache_ver,
1233 def compute_perm_tree(cache_name, cache_ver,
1233 user_id, scope, user_is_admin,user_inherit_default_permissions,
1234 user_id, scope, user_is_admin,user_inherit_default_permissions,
1234 explicit, algo, calculate_super_admin):
1235 explicit, algo, calculate_super_admin):
1235 return _cached_perms_data(
1236 return _cached_perms_data(
1236 user_id, scope, user_is_admin, user_inherit_default_permissions,
1237 user_id, scope, user_is_admin, user_inherit_default_permissions,
1237 explicit, algo, calculate_super_admin)
1238 explicit, algo, calculate_super_admin)
1238
1239
1239 start = time.time()
1240 start = time.time()
1240 result = compute_perm_tree(
1241 result = compute_perm_tree(
1241 'permissions', 'v1', user_id, scope, user_is_admin,
1242 'permissions', 'v1', user_id, scope, user_is_admin,
1242 user_inherit_default_permissions, explicit, algo,
1243 user_inherit_default_permissions, explicit, algo,
1243 calculate_super_admin)
1244 calculate_super_admin)
1244
1245
1245 result_repr = []
1246 result_repr = []
1246 for k in result:
1247 for k in result:
1247 result_repr.append((k, len(result[k])))
1248 result_repr.append((k, len(result[k])))
1248 total = time.time() - start
1249 total = time.time() - start
1249 log.debug('PERMISSION tree for user %s computed in %.4fs: %s',
1250 log.debug('PERMISSION tree for user %s computed in %.4fs: %s',
1250 user, total, result_repr)
1251 user, total, result_repr)
1251
1252
1252 return result
1253 return result
1253
1254
1254 @property
1255 @property
1255 def is_default(self):
1256 def is_default(self):
1256 return self.username == User.DEFAULT_USER
1257 return self.username == User.DEFAULT_USER
1257
1258
1258 @property
1259 @property
1259 def is_admin(self):
1260 def is_admin(self):
1260 return self.admin
1261 return self.admin
1261
1262
1262 @property
1263 @property
1263 def is_user_object(self):
1264 def is_user_object(self):
1264 return self.user_id is not None
1265 return self.user_id is not None
1265
1266
1266 @property
1267 @property
1267 def repositories_admin(self):
1268 def repositories_admin(self):
1268 """
1269 """
1269 Returns list of repositories you're an admin of
1270 Returns list of repositories you're an admin of
1270 """
1271 """
1271 return [
1272 return [
1272 x[0] for x in self.permissions['repositories'].items()
1273 x[0] for x in self.permissions['repositories'].items()
1273 if x[1] == 'repository.admin']
1274 if x[1] == 'repository.admin']
1274
1275
1275 @property
1276 @property
1276 def repository_groups_admin(self):
1277 def repository_groups_admin(self):
1277 """
1278 """
1278 Returns list of repository groups you're an admin of
1279 Returns list of repository groups you're an admin of
1279 """
1280 """
1280 return [
1281 return [
1281 x[0] for x in self.permissions['repositories_groups'].items()
1282 x[0] for x in self.permissions['repositories_groups'].items()
1282 if x[1] == 'group.admin']
1283 if x[1] == 'group.admin']
1283
1284
1284 @property
1285 @property
1285 def user_groups_admin(self):
1286 def user_groups_admin(self):
1286 """
1287 """
1287 Returns list of user groups you're an admin of
1288 Returns list of user groups you're an admin of
1288 """
1289 """
1289 return [
1290 return [
1290 x[0] for x in self.permissions['user_groups'].items()
1291 x[0] for x in self.permissions['user_groups'].items()
1291 if x[1] == 'usergroup.admin']
1292 if x[1] == 'usergroup.admin']
1292
1293
1293 def repo_acl_ids_from_stack(self, perms=None, prefix_filter=None, cache=False):
1294 def repo_acl_ids_from_stack(self, perms=None, prefix_filter=None, cache=False):
1294 if not perms:
1295 if not perms:
1295 perms = AuthUser.repo_read_perms
1296 perms = AuthUser.repo_read_perms
1296 allowed_ids = []
1297 allowed_ids = []
1297 for k, stack_data in self.permissions['repositories'].perm_origin_stack.items():
1298 for k, stack_data in self.permissions['repositories'].perm_origin_stack.items():
1298 perm, origin, obj_id = stack_data[-1] # last item is the current permission
1299 perm, origin, obj_id = stack_data[-1] # last item is the current permission
1299 if prefix_filter and not k.startswith(prefix_filter):
1300 if prefix_filter and not k.startswith(prefix_filter):
1300 continue
1301 continue
1301 if perm in perms:
1302 if perm in perms:
1302 allowed_ids.append(obj_id)
1303 allowed_ids.append(obj_id)
1303 return allowed_ids
1304 return allowed_ids
1304
1305
1305 def repo_acl_ids(self, perms=None, name_filter=None, cache=False):
1306 def repo_acl_ids(self, perms=None, name_filter=None, cache=False):
1306 """
1307 """
1307 Returns list of repository ids that user have access to based on given
1308 Returns list of repository ids that user have access to based on given
1308 perms. The cache flag should be only used in cases that are used for
1309 perms. The cache flag should be only used in cases that are used for
1309 display purposes, NOT IN ANY CASE for permission checks.
1310 display purposes, NOT IN ANY CASE for permission checks.
1310 """
1311 """
1311 from rhodecode.model.scm import RepoList
1312 from rhodecode.model.scm import RepoList
1312 if not perms:
1313 if not perms:
1313 perms = AuthUser.repo_read_perms
1314 perms = AuthUser.repo_read_perms
1314
1315
1315 def _cached_repo_acl(user_id, perm_def, _name_filter):
1316 def _cached_repo_acl(user_id, perm_def, _name_filter):
1316 qry = Repository.query()
1317 qry = Repository.query()
1317 if _name_filter:
1318 if _name_filter:
1318 ilike_expression = u'%{}%'.format(safe_unicode(_name_filter))
1319 ilike_expression = u'%{}%'.format(safe_unicode(_name_filter))
1319 qry = qry.filter(
1320 qry = qry.filter(
1320 Repository.repo_name.ilike(ilike_expression))
1321 Repository.repo_name.ilike(ilike_expression))
1321
1322
1322 return [x.repo_id for x in
1323 return [x.repo_id for x in
1323 RepoList(qry, perm_set=perm_def, extra_kwargs={'user': self})]
1324 RepoList(qry, perm_set=perm_def, extra_kwargs={'user': self})]
1324
1325
1325 return _cached_repo_acl(self.user_id, perms, name_filter)
1326 return _cached_repo_acl(self.user_id, perms, name_filter)
1326
1327
1327 def repo_group_acl_ids_from_stack(self, perms=None, prefix_filter=None, cache=False):
1328 def repo_group_acl_ids_from_stack(self, perms=None, prefix_filter=None, cache=False):
1328 if not perms:
1329 if not perms:
1329 perms = AuthUser.repo_group_read_perms
1330 perms = AuthUser.repo_group_read_perms
1330 allowed_ids = []
1331 allowed_ids = []
1331 for k, stack_data in self.permissions['repositories_groups'].perm_origin_stack.items():
1332 for k, stack_data in self.permissions['repositories_groups'].perm_origin_stack.items():
1332 perm, origin, obj_id = stack_data[-1] # last item is the current permission
1333 perm, origin, obj_id = stack_data[-1] # last item is the current permission
1333 if prefix_filter and not k.startswith(prefix_filter):
1334 if prefix_filter and not k.startswith(prefix_filter):
1334 continue
1335 continue
1335 if perm in perms:
1336 if perm in perms:
1336 allowed_ids.append(obj_id)
1337 allowed_ids.append(obj_id)
1337 return allowed_ids
1338 return allowed_ids
1338
1339
1339 def repo_group_acl_ids(self, perms=None, name_filter=None, cache=False):
1340 def repo_group_acl_ids(self, perms=None, name_filter=None, cache=False):
1340 """
1341 """
1341 Returns list of repository group ids that user have access to based on given
1342 Returns list of repository group ids that user have access to based on given
1342 perms. The cache flag should be only used in cases that are used for
1343 perms. The cache flag should be only used in cases that are used for
1343 display purposes, NOT IN ANY CASE for permission checks.
1344 display purposes, NOT IN ANY CASE for permission checks.
1344 """
1345 """
1345 from rhodecode.model.scm import RepoGroupList
1346 from rhodecode.model.scm import RepoGroupList
1346 if not perms:
1347 if not perms:
1347 perms = AuthUser.repo_group_read_perms
1348 perms = AuthUser.repo_group_read_perms
1348
1349
1349 def _cached_repo_group_acl(user_id, perm_def, _name_filter):
1350 def _cached_repo_group_acl(user_id, perm_def, _name_filter):
1350 qry = RepoGroup.query()
1351 qry = RepoGroup.query()
1351 if _name_filter:
1352 if _name_filter:
1352 ilike_expression = u'%{}%'.format(safe_unicode(_name_filter))
1353 ilike_expression = u'%{}%'.format(safe_unicode(_name_filter))
1353 qry = qry.filter(
1354 qry = qry.filter(
1354 RepoGroup.group_name.ilike(ilike_expression))
1355 RepoGroup.group_name.ilike(ilike_expression))
1355
1356
1356 return [x.group_id for x in
1357 return [x.group_id for x in
1357 RepoGroupList(qry, perm_set=perm_def, extra_kwargs={'user': self})]
1358 RepoGroupList(qry, perm_set=perm_def, extra_kwargs={'user': self})]
1358
1359
1359 return _cached_repo_group_acl(self.user_id, perms, name_filter)
1360 return _cached_repo_group_acl(self.user_id, perms, name_filter)
1360
1361
1361 def user_group_acl_ids_from_stack(self, perms=None, cache=False):
1362 def user_group_acl_ids_from_stack(self, perms=None, cache=False):
1362 if not perms:
1363 if not perms:
1363 perms = AuthUser.user_group_read_perms
1364 perms = AuthUser.user_group_read_perms
1364 allowed_ids = []
1365 allowed_ids = []
1365 for k, stack_data in self.permissions['user_groups'].perm_origin_stack.items():
1366 for k, stack_data in self.permissions['user_groups'].perm_origin_stack.items():
1366 perm, origin, obj_id = stack_data[-1] # last item is the current permission
1367 perm, origin, obj_id = stack_data[-1] # last item is the current permission
1367 if perm in perms:
1368 if perm in perms:
1368 allowed_ids.append(obj_id)
1369 allowed_ids.append(obj_id)
1369 return allowed_ids
1370 return allowed_ids
1370
1371
1371 def user_group_acl_ids(self, perms=None, name_filter=None, cache=False):
1372 def user_group_acl_ids(self, perms=None, name_filter=None, cache=False):
1372 """
1373 """
1373 Returns list of user group ids that user have access to based on given
1374 Returns list of user group ids that user have access to based on given
1374 perms. The cache flag should be only used in cases that are used for
1375 perms. The cache flag should be only used in cases that are used for
1375 display purposes, NOT IN ANY CASE for permission checks.
1376 display purposes, NOT IN ANY CASE for permission checks.
1376 """
1377 """
1377 from rhodecode.model.scm import UserGroupList
1378 from rhodecode.model.scm import UserGroupList
1378 if not perms:
1379 if not perms:
1379 perms = AuthUser.user_group_read_perms
1380 perms = AuthUser.user_group_read_perms
1380
1381
1381 def _cached_user_group_acl(user_id, perm_def, name_filter):
1382 def _cached_user_group_acl(user_id, perm_def, name_filter):
1382 qry = UserGroup.query()
1383 qry = UserGroup.query()
1383 if name_filter:
1384 if name_filter:
1384 ilike_expression = u'%{}%'.format(safe_unicode(name_filter))
1385 ilike_expression = u'%{}%'.format(safe_unicode(name_filter))
1385 qry = qry.filter(
1386 qry = qry.filter(
1386 UserGroup.users_group_name.ilike(ilike_expression))
1387 UserGroup.users_group_name.ilike(ilike_expression))
1387
1388
1388 return [x.users_group_id for x in
1389 return [x.users_group_id for x in
1389 UserGroupList(qry, perm_set=perm_def, extra_kwargs={'user': self})]
1390 UserGroupList(qry, perm_set=perm_def, extra_kwargs={'user': self})]
1390
1391
1391 return _cached_user_group_acl(self.user_id, perms, name_filter)
1392 return _cached_user_group_acl(self.user_id, perms, name_filter)
1392
1393
1393 @property
1394 @property
1394 def ip_allowed(self):
1395 def ip_allowed(self):
1395 """
1396 """
1396 Checks if ip_addr used in constructor is allowed from defined list of
1397 Checks if ip_addr used in constructor is allowed from defined list of
1397 allowed ip_addresses for user
1398 allowed ip_addresses for user
1398
1399
1399 :returns: boolean, True if ip is in allowed ip range
1400 :returns: boolean, True if ip is in allowed ip range
1400 """
1401 """
1401 # check IP
1402 # check IP
1402 inherit = self.inherit_default_permissions
1403 inherit = self.inherit_default_permissions
1403 return AuthUser.check_ip_allowed(self.user_id, self.ip_addr,
1404 return AuthUser.check_ip_allowed(self.user_id, self.ip_addr,
1404 inherit_from_default=inherit)
1405 inherit_from_default=inherit)
1405 @property
1406 @property
1406 def personal_repo_group(self):
1407 def personal_repo_group(self):
1407 return RepoGroup.get_user_personal_repo_group(self.user_id)
1408 return RepoGroup.get_user_personal_repo_group(self.user_id)
1408
1409
1409 @LazyProperty
1410 @LazyProperty
1410 def feed_token(self):
1411 def feed_token(self):
1411 return self.get_instance().feed_token
1412 return self.get_instance().feed_token
1412
1413
1413 @LazyProperty
1414 @LazyProperty
1414 def artifact_token(self):
1415 def artifact_token(self):
1415 return self.get_instance().artifact_token
1416 return self.get_instance().artifact_token
1416
1417
1417 @classmethod
1418 @classmethod
1418 def check_ip_allowed(cls, user_id, ip_addr, inherit_from_default):
1419 def check_ip_allowed(cls, user_id, ip_addr, inherit_from_default):
1419 allowed_ips = AuthUser.get_allowed_ips(
1420 allowed_ips = AuthUser.get_allowed_ips(
1420 user_id, cache=True, inherit_from_default=inherit_from_default)
1421 user_id, cache=True, inherit_from_default=inherit_from_default)
1421 if check_ip_access(source_ip=ip_addr, allowed_ips=allowed_ips):
1422 if check_ip_access(source_ip=ip_addr, allowed_ips=allowed_ips):
1422 log.debug('IP:%s for user %s is in range of %s',
1423 log.debug('IP:%s for user %s is in range of %s',
1423 ip_addr, user_id, allowed_ips)
1424 ip_addr, user_id, allowed_ips)
1424 return True
1425 return True
1425 else:
1426 else:
1426 log.info('Access for IP:%s forbidden for user %s, '
1427 log.info('Access for IP:%s forbidden for user %s, '
1427 'not in %s', ip_addr, user_id, allowed_ips)
1428 'not in %s', ip_addr, user_id, allowed_ips)
1428 return False
1429 return False
1429
1430
1430 def get_branch_permissions(self, repo_name, perms=None):
1431 def get_branch_permissions(self, repo_name, perms=None):
1431 perms = perms or self.permissions_with_scope({'repo_name': repo_name})
1432 perms = perms or self.permissions_with_scope({'repo_name': repo_name})
1432 branch_perms = perms.get('repository_branches', {})
1433 branch_perms = perms.get('repository_branches', {})
1433 if not branch_perms:
1434 if not branch_perms:
1434 return {}
1435 return {}
1435 repo_branch_perms = branch_perms.get(repo_name)
1436 repo_branch_perms = branch_perms.get(repo_name)
1436 return repo_branch_perms or {}
1437 return repo_branch_perms or {}
1437
1438
1438 def get_rule_and_branch_permission(self, repo_name, branch_name):
1439 def get_rule_and_branch_permission(self, repo_name, branch_name):
1439 """
1440 """
1440 Check if this AuthUser has defined any permissions for branches. If any of
1441 Check if this AuthUser has defined any permissions for branches. If any of
1441 the rules match in order, we return the matching permissions
1442 the rules match in order, we return the matching permissions
1442 """
1443 """
1443
1444
1444 rule = default_perm = ''
1445 rule = default_perm = ''
1445
1446
1446 repo_branch_perms = self.get_branch_permissions(repo_name=repo_name)
1447 repo_branch_perms = self.get_branch_permissions(repo_name=repo_name)
1447 if not repo_branch_perms:
1448 if not repo_branch_perms:
1448 return rule, default_perm
1449 return rule, default_perm
1449
1450
1450 # now calculate the permissions
1451 # now calculate the permissions
1451 for pattern, branch_perm in repo_branch_perms.items():
1452 for pattern, branch_perm in repo_branch_perms.items():
1452 if fnmatch.fnmatch(branch_name, pattern):
1453 if fnmatch.fnmatch(branch_name, pattern):
1453 rule = '`{}`=>{}'.format(pattern, branch_perm)
1454 rule = '`{}`=>{}'.format(pattern, branch_perm)
1454 return rule, branch_perm
1455 return rule, branch_perm
1455
1456
1456 return rule, default_perm
1457 return rule, default_perm
1457
1458
1459 def get_notice_messages(self):
1460
1461 notice_level = 'notice-error'
1462 notice_messages = []
1463 if self.is_default:
1464 return [], notice_level
1465
1466 notices = UserNotice.query()\
1467 .filter(UserNotice.user_id == self.user_id)\
1468 .filter(UserNotice.notice_read == false())\
1469 .all()
1470
1471 try:
1472 for entry in notices:
1473
1474 msg = {
1475 'msg_id': entry.user_notice_id,
1476 'level': entry.notification_level,
1477 'subject': entry.notice_subject,
1478 'body': entry.notice_body,
1479 }
1480 notice_messages.append(msg)
1481
1482 log.debug('Got user %s %s messages', self, len(notice_messages))
1483
1484 levels = [x['level'] for x in notice_messages]
1485 notice_level = 'notice-error' if 'error' in levels else 'notice-warning'
1486 except Exception:
1487 pass
1488
1489 return notice_messages, notice_level
1490
1458 def __repr__(self):
1491 def __repr__(self):
1459 return "<AuthUser('id:%s[%s] ip:%s auth:%s')>"\
1492 return "<AuthUser('id:%s[%s] ip:%s auth:%s')>"\
1460 % (self.user_id, self.username, self.ip_addr, self.is_authenticated)
1493 % (self.user_id, self.username, self.ip_addr, self.is_authenticated)
1461
1494
1462 def set_authenticated(self, authenticated=True):
1495 def set_authenticated(self, authenticated=True):
1463 if self.user_id != self.anonymous_user.user_id:
1496 if self.user_id != self.anonymous_user.user_id:
1464 self.is_authenticated = authenticated
1497 self.is_authenticated = authenticated
1465
1498
1466 def get_cookie_store(self):
1499 def get_cookie_store(self):
1467 return {
1500 return {
1468 'username': self.username,
1501 'username': self.username,
1469 'password': md5(self.password or ''),
1502 'password': md5(self.password or ''),
1470 'user_id': self.user_id,
1503 'user_id': self.user_id,
1471 'is_authenticated': self.is_authenticated
1504 'is_authenticated': self.is_authenticated
1472 }
1505 }
1473
1506
1474 @classmethod
1507 @classmethod
1475 def from_cookie_store(cls, cookie_store):
1508 def from_cookie_store(cls, cookie_store):
1476 """
1509 """
1477 Creates AuthUser from a cookie store
1510 Creates AuthUser from a cookie store
1478
1511
1479 :param cls:
1512 :param cls:
1480 :param cookie_store:
1513 :param cookie_store:
1481 """
1514 """
1482 user_id = cookie_store.get('user_id')
1515 user_id = cookie_store.get('user_id')
1483 username = cookie_store.get('username')
1516 username = cookie_store.get('username')
1484 api_key = cookie_store.get('api_key')
1517 api_key = cookie_store.get('api_key')
1485 return AuthUser(user_id, api_key, username)
1518 return AuthUser(user_id, api_key, username)
1486
1519
1487 @classmethod
1520 @classmethod
1488 def get_allowed_ips(cls, user_id, cache=False, inherit_from_default=False):
1521 def get_allowed_ips(cls, user_id, cache=False, inherit_from_default=False):
1489 _set = set()
1522 _set = set()
1490
1523
1491 if inherit_from_default:
1524 if inherit_from_default:
1492 def_user_id = User.get_default_user(cache=True).user_id
1525 def_user_id = User.get_default_user(cache=True).user_id
1493 default_ips = UserIpMap.query().filter(UserIpMap.user_id == def_user_id)
1526 default_ips = UserIpMap.query().filter(UserIpMap.user_id == def_user_id)
1494 if cache:
1527 if cache:
1495 default_ips = default_ips.options(
1528 default_ips = default_ips.options(
1496 FromCache("sql_cache_short", "get_user_ips_default"))
1529 FromCache("sql_cache_short", "get_user_ips_default"))
1497
1530
1498 # populate from default user
1531 # populate from default user
1499 for ip in default_ips:
1532 for ip in default_ips:
1500 try:
1533 try:
1501 _set.add(ip.ip_addr)
1534 _set.add(ip.ip_addr)
1502 except ObjectDeletedError:
1535 except ObjectDeletedError:
1503 # since we use heavy caching sometimes it happens that
1536 # since we use heavy caching sometimes it happens that
1504 # we get deleted objects here, we just skip them
1537 # we get deleted objects here, we just skip them
1505 pass
1538 pass
1506
1539
1507 # NOTE:(marcink) we don't want to load any rules for empty
1540 # NOTE:(marcink) we don't want to load any rules for empty
1508 # user_id which is the case of access of non logged users when anonymous
1541 # user_id which is the case of access of non logged users when anonymous
1509 # access is disabled
1542 # access is disabled
1510 user_ips = []
1543 user_ips = []
1511 if user_id:
1544 if user_id:
1512 user_ips = UserIpMap.query().filter(UserIpMap.user_id == user_id)
1545 user_ips = UserIpMap.query().filter(UserIpMap.user_id == user_id)
1513 if cache:
1546 if cache:
1514 user_ips = user_ips.options(
1547 user_ips = user_ips.options(
1515 FromCache("sql_cache_short", "get_user_ips_%s" % user_id))
1548 FromCache("sql_cache_short", "get_user_ips_%s" % user_id))
1516
1549
1517 for ip in user_ips:
1550 for ip in user_ips:
1518 try:
1551 try:
1519 _set.add(ip.ip_addr)
1552 _set.add(ip.ip_addr)
1520 except ObjectDeletedError:
1553 except ObjectDeletedError:
1521 # since we use heavy caching sometimes it happens that we get
1554 # since we use heavy caching sometimes it happens that we get
1522 # deleted objects here, we just skip them
1555 # deleted objects here, we just skip them
1523 pass
1556 pass
1524 return _set or {ip for ip in ['0.0.0.0/0', '::/0']}
1557 return _set or {ip for ip in ['0.0.0.0/0', '::/0']}
1525
1558
1526
1559
1527 def set_available_permissions(settings):
1560 def set_available_permissions(settings):
1528 """
1561 """
1529 This function will propagate pyramid settings with all available defined
1562 This function will propagate pyramid settings with all available defined
1530 permission given in db. We don't want to check each time from db for new
1563 permission given in db. We don't want to check each time from db for new
1531 permissions since adding a new permission also requires application restart
1564 permissions since adding a new permission also requires application restart
1532 ie. to decorate new views with the newly created permission
1565 ie. to decorate new views with the newly created permission
1533
1566
1534 :param settings: current pyramid registry.settings
1567 :param settings: current pyramid registry.settings
1535
1568
1536 """
1569 """
1537 log.debug('auth: getting information about all available permissions')
1570 log.debug('auth: getting information about all available permissions')
1538 try:
1571 try:
1539 sa = meta.Session
1572 sa = meta.Session
1540 all_perms = sa.query(Permission).all()
1573 all_perms = sa.query(Permission).all()
1541 settings.setdefault('available_permissions',
1574 settings.setdefault('available_permissions',
1542 [x.permission_name for x in all_perms])
1575 [x.permission_name for x in all_perms])
1543 log.debug('auth: set available permissions')
1576 log.debug('auth: set available permissions')
1544 except Exception:
1577 except Exception:
1545 log.exception('Failed to fetch permissions from the database.')
1578 log.exception('Failed to fetch permissions from the database.')
1546 raise
1579 raise
1547
1580
1548
1581
1549 def get_csrf_token(session, force_new=False, save_if_missing=True):
1582 def get_csrf_token(session, force_new=False, save_if_missing=True):
1550 """
1583 """
1551 Return the current authentication token, creating one if one doesn't
1584 Return the current authentication token, creating one if one doesn't
1552 already exist and the save_if_missing flag is present.
1585 already exist and the save_if_missing flag is present.
1553
1586
1554 :param session: pass in the pyramid session, else we use the global ones
1587 :param session: pass in the pyramid session, else we use the global ones
1555 :param force_new: force to re-generate the token and store it in session
1588 :param force_new: force to re-generate the token and store it in session
1556 :param save_if_missing: save the newly generated token if it's missing in
1589 :param save_if_missing: save the newly generated token if it's missing in
1557 session
1590 session
1558 """
1591 """
1559 # NOTE(marcink): probably should be replaced with below one from pyramid 1.9
1592 # NOTE(marcink): probably should be replaced with below one from pyramid 1.9
1560 # from pyramid.csrf import get_csrf_token
1593 # from pyramid.csrf import get_csrf_token
1561
1594
1562 if (csrf_token_key not in session and save_if_missing) or force_new:
1595 if (csrf_token_key not in session and save_if_missing) or force_new:
1563 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
1596 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
1564 session[csrf_token_key] = token
1597 session[csrf_token_key] = token
1565 if hasattr(session, 'save'):
1598 if hasattr(session, 'save'):
1566 session.save()
1599 session.save()
1567 return session.get(csrf_token_key)
1600 return session.get(csrf_token_key)
1568
1601
1569
1602
1570 def get_request(perm_class_instance):
1603 def get_request(perm_class_instance):
1571 from pyramid.threadlocal import get_current_request
1604 from pyramid.threadlocal import get_current_request
1572 pyramid_request = get_current_request()
1605 pyramid_request = get_current_request()
1573 return pyramid_request
1606 return pyramid_request
1574
1607
1575
1608
1576 # CHECK DECORATORS
1609 # CHECK DECORATORS
1577 class CSRFRequired(object):
1610 class CSRFRequired(object):
1578 """
1611 """
1579 Decorator for authenticating a form
1612 Decorator for authenticating a form
1580
1613
1581 This decorator uses an authorization token stored in the client's
1614 This decorator uses an authorization token stored in the client's
1582 session for prevention of certain Cross-site request forgery (CSRF)
1615 session for prevention of certain Cross-site request forgery (CSRF)
1583 attacks (See
1616 attacks (See
1584 http://en.wikipedia.org/wiki/Cross-site_request_forgery for more
1617 http://en.wikipedia.org/wiki/Cross-site_request_forgery for more
1585 information).
1618 information).
1586
1619
1587 For use with the ``secure_form`` helper functions.
1620 For use with the ``secure_form`` helper functions.
1588
1621
1589 """
1622 """
1590 def __init__(self, token=csrf_token_key, header='X-CSRF-Token', except_methods=None):
1623 def __init__(self, token=csrf_token_key, header='X-CSRF-Token', except_methods=None):
1591 self.token = token
1624 self.token = token
1592 self.header = header
1625 self.header = header
1593 self.except_methods = except_methods or []
1626 self.except_methods = except_methods or []
1594
1627
1595 def __call__(self, func):
1628 def __call__(self, func):
1596 return get_cython_compat_decorator(self.__wrapper, func)
1629 return get_cython_compat_decorator(self.__wrapper, func)
1597
1630
1598 def _get_csrf(self, _request):
1631 def _get_csrf(self, _request):
1599 return _request.POST.get(self.token, _request.headers.get(self.header))
1632 return _request.POST.get(self.token, _request.headers.get(self.header))
1600
1633
1601 def check_csrf(self, _request, cur_token):
1634 def check_csrf(self, _request, cur_token):
1602 supplied_token = self._get_csrf(_request)
1635 supplied_token = self._get_csrf(_request)
1603 return supplied_token and supplied_token == cur_token
1636 return supplied_token and supplied_token == cur_token
1604
1637
1605 def _get_request(self):
1638 def _get_request(self):
1606 return get_request(self)
1639 return get_request(self)
1607
1640
1608 def __wrapper(self, func, *fargs, **fkwargs):
1641 def __wrapper(self, func, *fargs, **fkwargs):
1609 request = self._get_request()
1642 request = self._get_request()
1610
1643
1611 if request.method in self.except_methods:
1644 if request.method in self.except_methods:
1612 return func(*fargs, **fkwargs)
1645 return func(*fargs, **fkwargs)
1613
1646
1614 cur_token = get_csrf_token(request.session, save_if_missing=False)
1647 cur_token = get_csrf_token(request.session, save_if_missing=False)
1615 if self.check_csrf(request, cur_token):
1648 if self.check_csrf(request, cur_token):
1616 if request.POST.get(self.token):
1649 if request.POST.get(self.token):
1617 del request.POST[self.token]
1650 del request.POST[self.token]
1618 return func(*fargs, **fkwargs)
1651 return func(*fargs, **fkwargs)
1619 else:
1652 else:
1620 reason = 'token-missing'
1653 reason = 'token-missing'
1621 supplied_token = self._get_csrf(request)
1654 supplied_token = self._get_csrf(request)
1622 if supplied_token and cur_token != supplied_token:
1655 if supplied_token and cur_token != supplied_token:
1623 reason = 'token-mismatch [%s:%s]' % (
1656 reason = 'token-mismatch [%s:%s]' % (
1624 cur_token or ''[:6], supplied_token or ''[:6])
1657 cur_token or ''[:6], supplied_token or ''[:6])
1625
1658
1626 csrf_message = \
1659 csrf_message = \
1627 ("Cross-site request forgery detected, request denied. See "
1660 ("Cross-site request forgery detected, request denied. See "
1628 "http://en.wikipedia.org/wiki/Cross-site_request_forgery for "
1661 "http://en.wikipedia.org/wiki/Cross-site_request_forgery for "
1629 "more information.")
1662 "more information.")
1630 log.warn('Cross-site request forgery detected, request %r DENIED: %s '
1663 log.warn('Cross-site request forgery detected, request %r DENIED: %s '
1631 'REMOTE_ADDR:%s, HEADERS:%s' % (
1664 'REMOTE_ADDR:%s, HEADERS:%s' % (
1632 request, reason, request.remote_addr, request.headers))
1665 request, reason, request.remote_addr, request.headers))
1633
1666
1634 raise HTTPForbidden(explanation=csrf_message)
1667 raise HTTPForbidden(explanation=csrf_message)
1635
1668
1636
1669
1637 class LoginRequired(object):
1670 class LoginRequired(object):
1638 """
1671 """
1639 Must be logged in to execute this function else
1672 Must be logged in to execute this function else
1640 redirect to login page
1673 redirect to login page
1641
1674
1642 :param api_access: if enabled this checks only for valid auth token
1675 :param api_access: if enabled this checks only for valid auth token
1643 and grants access based on valid token
1676 and grants access based on valid token
1644 """
1677 """
1645 def __init__(self, auth_token_access=None):
1678 def __init__(self, auth_token_access=None):
1646 self.auth_token_access = auth_token_access
1679 self.auth_token_access = auth_token_access
1647 if self.auth_token_access:
1680 if self.auth_token_access:
1648 valid_type = set(auth_token_access).intersection(set(UserApiKeys.ROLES))
1681 valid_type = set(auth_token_access).intersection(set(UserApiKeys.ROLES))
1649 if not valid_type:
1682 if not valid_type:
1650 raise ValueError('auth_token_access must be on of {}, got {}'.format(
1683 raise ValueError('auth_token_access must be on of {}, got {}'.format(
1651 UserApiKeys.ROLES, auth_token_access))
1684 UserApiKeys.ROLES, auth_token_access))
1652
1685
1653 def __call__(self, func):
1686 def __call__(self, func):
1654 return get_cython_compat_decorator(self.__wrapper, func)
1687 return get_cython_compat_decorator(self.__wrapper, func)
1655
1688
1656 def _get_request(self):
1689 def _get_request(self):
1657 return get_request(self)
1690 return get_request(self)
1658
1691
1659 def __wrapper(self, func, *fargs, **fkwargs):
1692 def __wrapper(self, func, *fargs, **fkwargs):
1660 from rhodecode.lib import helpers as h
1693 from rhodecode.lib import helpers as h
1661 cls = fargs[0]
1694 cls = fargs[0]
1662 user = cls._rhodecode_user
1695 user = cls._rhodecode_user
1663 request = self._get_request()
1696 request = self._get_request()
1664 _ = request.translate
1697 _ = request.translate
1665
1698
1666 loc = "%s:%s" % (cls.__class__.__name__, func.__name__)
1699 loc = "%s:%s" % (cls.__class__.__name__, func.__name__)
1667 log.debug('Starting login restriction checks for user: %s', user)
1700 log.debug('Starting login restriction checks for user: %s', user)
1668 # check if our IP is allowed
1701 # check if our IP is allowed
1669 ip_access_valid = True
1702 ip_access_valid = True
1670 if not user.ip_allowed:
1703 if not user.ip_allowed:
1671 h.flash(h.literal(_('IP {} not allowed'.format(user.ip_addr))),
1704 h.flash(h.literal(_('IP {} not allowed'.format(user.ip_addr))),
1672 category='warning')
1705 category='warning')
1673 ip_access_valid = False
1706 ip_access_valid = False
1674
1707
1675 # we used stored token that is extract from GET or URL param (if any)
1708 # we used stored token that is extract from GET or URL param (if any)
1676 _auth_token = request.user_auth_token
1709 _auth_token = request.user_auth_token
1677
1710
1678 # check if we used an AUTH_TOKEN and it's a valid one
1711 # check if we used an AUTH_TOKEN and it's a valid one
1679 # defined white-list of controllers which API access will be enabled
1712 # defined white-list of controllers which API access will be enabled
1680 whitelist = None
1713 whitelist = None
1681 if self.auth_token_access:
1714 if self.auth_token_access:
1682 # since this location is allowed by @LoginRequired decorator it's our
1715 # since this location is allowed by @LoginRequired decorator it's our
1683 # only whitelist
1716 # only whitelist
1684 whitelist = [loc]
1717 whitelist = [loc]
1685 auth_token_access_valid = allowed_auth_token_access(
1718 auth_token_access_valid = allowed_auth_token_access(
1686 loc, whitelist=whitelist, auth_token=_auth_token)
1719 loc, whitelist=whitelist, auth_token=_auth_token)
1687
1720
1688 # explicit controller is enabled or API is in our whitelist
1721 # explicit controller is enabled or API is in our whitelist
1689 if auth_token_access_valid:
1722 if auth_token_access_valid:
1690 log.debug('Checking AUTH TOKEN access for %s', cls)
1723 log.debug('Checking AUTH TOKEN access for %s', cls)
1691 db_user = user.get_instance()
1724 db_user = user.get_instance()
1692
1725
1693 if db_user:
1726 if db_user:
1694 if self.auth_token_access:
1727 if self.auth_token_access:
1695 roles = self.auth_token_access
1728 roles = self.auth_token_access
1696 else:
1729 else:
1697 roles = [UserApiKeys.ROLE_HTTP]
1730 roles = [UserApiKeys.ROLE_HTTP]
1698 log.debug('AUTH TOKEN: checking auth for user %s and roles %s',
1731 log.debug('AUTH TOKEN: checking auth for user %s and roles %s',
1699 db_user, roles)
1732 db_user, roles)
1700 token_match = db_user.authenticate_by_token(
1733 token_match = db_user.authenticate_by_token(
1701 _auth_token, roles=roles)
1734 _auth_token, roles=roles)
1702 else:
1735 else:
1703 log.debug('Unable to fetch db instance for auth user: %s', user)
1736 log.debug('Unable to fetch db instance for auth user: %s', user)
1704 token_match = False
1737 token_match = False
1705
1738
1706 if _auth_token and token_match:
1739 if _auth_token and token_match:
1707 auth_token_access_valid = True
1740 auth_token_access_valid = True
1708 log.debug('AUTH TOKEN ****%s is VALID', _auth_token[-4:])
1741 log.debug('AUTH TOKEN ****%s is VALID', _auth_token[-4:])
1709 else:
1742 else:
1710 auth_token_access_valid = False
1743 auth_token_access_valid = False
1711 if not _auth_token:
1744 if not _auth_token:
1712 log.debug("AUTH TOKEN *NOT* present in request")
1745 log.debug("AUTH TOKEN *NOT* present in request")
1713 else:
1746 else:
1714 log.warning("AUTH TOKEN ****%s *NOT* valid", _auth_token[-4:])
1747 log.warning("AUTH TOKEN ****%s *NOT* valid", _auth_token[-4:])
1715
1748
1716 log.debug('Checking if %s is authenticated @ %s', user.username, loc)
1749 log.debug('Checking if %s is authenticated @ %s', user.username, loc)
1717 reason = 'RHODECODE_AUTH' if user.is_authenticated \
1750 reason = 'RHODECODE_AUTH' if user.is_authenticated \
1718 else 'AUTH_TOKEN_AUTH'
1751 else 'AUTH_TOKEN_AUTH'
1719
1752
1720 if ip_access_valid and (
1753 if ip_access_valid and (
1721 user.is_authenticated or auth_token_access_valid):
1754 user.is_authenticated or auth_token_access_valid):
1722 log.info('user %s authenticating with:%s IS authenticated on func %s',
1755 log.info('user %s authenticating with:%s IS authenticated on func %s',
1723 user, reason, loc)
1756 user, reason, loc)
1724
1757
1725 return func(*fargs, **fkwargs)
1758 return func(*fargs, **fkwargs)
1726 else:
1759 else:
1727 log.warning(
1760 log.warning(
1728 'user %s authenticating with:%s NOT authenticated on '
1761 'user %s authenticating with:%s NOT authenticated on '
1729 'func: %s: IP_ACCESS:%s AUTH_TOKEN_ACCESS:%s',
1762 'func: %s: IP_ACCESS:%s AUTH_TOKEN_ACCESS:%s',
1730 user, reason, loc, ip_access_valid, auth_token_access_valid)
1763 user, reason, loc, ip_access_valid, auth_token_access_valid)
1731 # we preserve the get PARAM
1764 # we preserve the get PARAM
1732 came_from = get_came_from(request)
1765 came_from = get_came_from(request)
1733
1766
1734 log.debug('redirecting to login page with %s', came_from)
1767 log.debug('redirecting to login page with %s', came_from)
1735 raise HTTPFound(
1768 raise HTTPFound(
1736 h.route_path('login', _query={'came_from': came_from}))
1769 h.route_path('login', _query={'came_from': came_from}))
1737
1770
1738
1771
1739 class NotAnonymous(object):
1772 class NotAnonymous(object):
1740 """
1773 """
1741 Must be logged in to execute this function else
1774 Must be logged in to execute this function else
1742 redirect to login page
1775 redirect to login page
1743 """
1776 """
1744
1777
1745 def __call__(self, func):
1778 def __call__(self, func):
1746 return get_cython_compat_decorator(self.__wrapper, func)
1779 return get_cython_compat_decorator(self.__wrapper, func)
1747
1780
1748 def _get_request(self):
1781 def _get_request(self):
1749 return get_request(self)
1782 return get_request(self)
1750
1783
1751 def __wrapper(self, func, *fargs, **fkwargs):
1784 def __wrapper(self, func, *fargs, **fkwargs):
1752 import rhodecode.lib.helpers as h
1785 import rhodecode.lib.helpers as h
1753 cls = fargs[0]
1786 cls = fargs[0]
1754 self.user = cls._rhodecode_user
1787 self.user = cls._rhodecode_user
1755 request = self._get_request()
1788 request = self._get_request()
1756 _ = request.translate
1789 _ = request.translate
1757 log.debug('Checking if user is not anonymous @%s', cls)
1790 log.debug('Checking if user is not anonymous @%s', cls)
1758
1791
1759 anonymous = self.user.username == User.DEFAULT_USER
1792 anonymous = self.user.username == User.DEFAULT_USER
1760
1793
1761 if anonymous:
1794 if anonymous:
1762 came_from = get_came_from(request)
1795 came_from = get_came_from(request)
1763 h.flash(_('You need to be a registered user to '
1796 h.flash(_('You need to be a registered user to '
1764 'perform this action'),
1797 'perform this action'),
1765 category='warning')
1798 category='warning')
1766 raise HTTPFound(
1799 raise HTTPFound(
1767 h.route_path('login', _query={'came_from': came_from}))
1800 h.route_path('login', _query={'came_from': came_from}))
1768 else:
1801 else:
1769 return func(*fargs, **fkwargs)
1802 return func(*fargs, **fkwargs)
1770
1803
1771
1804
1772 class PermsDecorator(object):
1805 class PermsDecorator(object):
1773 """
1806 """
1774 Base class for controller decorators, we extract the current user from
1807 Base class for controller decorators, we extract the current user from
1775 the class itself, which has it stored in base controllers
1808 the class itself, which has it stored in base controllers
1776 """
1809 """
1777
1810
1778 def __init__(self, *required_perms):
1811 def __init__(self, *required_perms):
1779 self.required_perms = set(required_perms)
1812 self.required_perms = set(required_perms)
1780
1813
1781 def __call__(self, func):
1814 def __call__(self, func):
1782 return get_cython_compat_decorator(self.__wrapper, func)
1815 return get_cython_compat_decorator(self.__wrapper, func)
1783
1816
1784 def _get_request(self):
1817 def _get_request(self):
1785 return get_request(self)
1818 return get_request(self)
1786
1819
1787 def __wrapper(self, func, *fargs, **fkwargs):
1820 def __wrapper(self, func, *fargs, **fkwargs):
1788 import rhodecode.lib.helpers as h
1821 import rhodecode.lib.helpers as h
1789 cls = fargs[0]
1822 cls = fargs[0]
1790 _user = cls._rhodecode_user
1823 _user = cls._rhodecode_user
1791 request = self._get_request()
1824 request = self._get_request()
1792 _ = request.translate
1825 _ = request.translate
1793
1826
1794 log.debug('checking %s permissions %s for %s %s',
1827 log.debug('checking %s permissions %s for %s %s',
1795 self.__class__.__name__, self.required_perms, cls, _user)
1828 self.__class__.__name__, self.required_perms, cls, _user)
1796
1829
1797 if self.check_permissions(_user):
1830 if self.check_permissions(_user):
1798 log.debug('Permission granted for %s %s', cls, _user)
1831 log.debug('Permission granted for %s %s', cls, _user)
1799 return func(*fargs, **fkwargs)
1832 return func(*fargs, **fkwargs)
1800
1833
1801 else:
1834 else:
1802 log.debug('Permission denied for %s %s', cls, _user)
1835 log.debug('Permission denied for %s %s', cls, _user)
1803 anonymous = _user.username == User.DEFAULT_USER
1836 anonymous = _user.username == User.DEFAULT_USER
1804
1837
1805 if anonymous:
1838 if anonymous:
1806 came_from = get_came_from(self._get_request())
1839 came_from = get_came_from(self._get_request())
1807 h.flash(_('You need to be signed in to view this page'),
1840 h.flash(_('You need to be signed in to view this page'),
1808 category='warning')
1841 category='warning')
1809 raise HTTPFound(
1842 raise HTTPFound(
1810 h.route_path('login', _query={'came_from': came_from}))
1843 h.route_path('login', _query={'came_from': came_from}))
1811
1844
1812 else:
1845 else:
1813 # redirect with 404 to prevent resource discovery
1846 # redirect with 404 to prevent resource discovery
1814 raise HTTPNotFound()
1847 raise HTTPNotFound()
1815
1848
1816 def check_permissions(self, user):
1849 def check_permissions(self, user):
1817 """Dummy function for overriding"""
1850 """Dummy function for overriding"""
1818 raise NotImplementedError(
1851 raise NotImplementedError(
1819 'You have to write this function in child class')
1852 'You have to write this function in child class')
1820
1853
1821
1854
1822 class HasPermissionAllDecorator(PermsDecorator):
1855 class HasPermissionAllDecorator(PermsDecorator):
1823 """
1856 """
1824 Checks for access permission for all given predicates. All of them
1857 Checks for access permission for all given predicates. All of them
1825 have to be meet in order to fulfill the request
1858 have to be meet in order to fulfill the request
1826 """
1859 """
1827
1860
1828 def check_permissions(self, user):
1861 def check_permissions(self, user):
1829 perms = user.permissions_with_scope({})
1862 perms = user.permissions_with_scope({})
1830 if self.required_perms.issubset(perms['global']):
1863 if self.required_perms.issubset(perms['global']):
1831 return True
1864 return True
1832 return False
1865 return False
1833
1866
1834
1867
1835 class HasPermissionAnyDecorator(PermsDecorator):
1868 class HasPermissionAnyDecorator(PermsDecorator):
1836 """
1869 """
1837 Checks for access permission for any of given predicates. In order to
1870 Checks for access permission for any of given predicates. In order to
1838 fulfill the request any of predicates must be meet
1871 fulfill the request any of predicates must be meet
1839 """
1872 """
1840
1873
1841 def check_permissions(self, user):
1874 def check_permissions(self, user):
1842 perms = user.permissions_with_scope({})
1875 perms = user.permissions_with_scope({})
1843 if self.required_perms.intersection(perms['global']):
1876 if self.required_perms.intersection(perms['global']):
1844 return True
1877 return True
1845 return False
1878 return False
1846
1879
1847
1880
1848 class HasRepoPermissionAllDecorator(PermsDecorator):
1881 class HasRepoPermissionAllDecorator(PermsDecorator):
1849 """
1882 """
1850 Checks for access permission for all given predicates for specific
1883 Checks for access permission for all given predicates for specific
1851 repository. All of them have to be meet in order to fulfill the request
1884 repository. All of them have to be meet in order to fulfill the request
1852 """
1885 """
1853 def _get_repo_name(self):
1886 def _get_repo_name(self):
1854 _request = self._get_request()
1887 _request = self._get_request()
1855 return get_repo_slug(_request)
1888 return get_repo_slug(_request)
1856
1889
1857 def check_permissions(self, user):
1890 def check_permissions(self, user):
1858 perms = user.permissions
1891 perms = user.permissions
1859 repo_name = self._get_repo_name()
1892 repo_name = self._get_repo_name()
1860
1893
1861 try:
1894 try:
1862 user_perms = {perms['repositories'][repo_name]}
1895 user_perms = {perms['repositories'][repo_name]}
1863 except KeyError:
1896 except KeyError:
1864 log.debug('cannot locate repo with name: `%s` in permissions defs',
1897 log.debug('cannot locate repo with name: `%s` in permissions defs',
1865 repo_name)
1898 repo_name)
1866 return False
1899 return False
1867
1900
1868 log.debug('checking `%s` permissions for repo `%s`',
1901 log.debug('checking `%s` permissions for repo `%s`',
1869 user_perms, repo_name)
1902 user_perms, repo_name)
1870 if self.required_perms.issubset(user_perms):
1903 if self.required_perms.issubset(user_perms):
1871 return True
1904 return True
1872 return False
1905 return False
1873
1906
1874
1907
1875 class HasRepoPermissionAnyDecorator(PermsDecorator):
1908 class HasRepoPermissionAnyDecorator(PermsDecorator):
1876 """
1909 """
1877 Checks for access permission for any of given predicates for specific
1910 Checks for access permission for any of given predicates for specific
1878 repository. In order to fulfill the request any of predicates must be meet
1911 repository. In order to fulfill the request any of predicates must be meet
1879 """
1912 """
1880 def _get_repo_name(self):
1913 def _get_repo_name(self):
1881 _request = self._get_request()
1914 _request = self._get_request()
1882 return get_repo_slug(_request)
1915 return get_repo_slug(_request)
1883
1916
1884 def check_permissions(self, user):
1917 def check_permissions(self, user):
1885 perms = user.permissions
1918 perms = user.permissions
1886 repo_name = self._get_repo_name()
1919 repo_name = self._get_repo_name()
1887
1920
1888 try:
1921 try:
1889 user_perms = {perms['repositories'][repo_name]}
1922 user_perms = {perms['repositories'][repo_name]}
1890 except KeyError:
1923 except KeyError:
1891 log.debug(
1924 log.debug(
1892 'cannot locate repo with name: `%s` in permissions defs',
1925 'cannot locate repo with name: `%s` in permissions defs',
1893 repo_name)
1926 repo_name)
1894 return False
1927 return False
1895
1928
1896 log.debug('checking `%s` permissions for repo `%s`',
1929 log.debug('checking `%s` permissions for repo `%s`',
1897 user_perms, repo_name)
1930 user_perms, repo_name)
1898 if self.required_perms.intersection(user_perms):
1931 if self.required_perms.intersection(user_perms):
1899 return True
1932 return True
1900 return False
1933 return False
1901
1934
1902
1935
1903 class HasRepoGroupPermissionAllDecorator(PermsDecorator):
1936 class HasRepoGroupPermissionAllDecorator(PermsDecorator):
1904 """
1937 """
1905 Checks for access permission for all given predicates for specific
1938 Checks for access permission for all given predicates for specific
1906 repository group. All of them have to be meet in order to
1939 repository group. All of them have to be meet in order to
1907 fulfill the request
1940 fulfill the request
1908 """
1941 """
1909 def _get_repo_group_name(self):
1942 def _get_repo_group_name(self):
1910 _request = self._get_request()
1943 _request = self._get_request()
1911 return get_repo_group_slug(_request)
1944 return get_repo_group_slug(_request)
1912
1945
1913 def check_permissions(self, user):
1946 def check_permissions(self, user):
1914 perms = user.permissions
1947 perms = user.permissions
1915 group_name = self._get_repo_group_name()
1948 group_name = self._get_repo_group_name()
1916 try:
1949 try:
1917 user_perms = {perms['repositories_groups'][group_name]}
1950 user_perms = {perms['repositories_groups'][group_name]}
1918 except KeyError:
1951 except KeyError:
1919 log.debug(
1952 log.debug(
1920 'cannot locate repo group with name: `%s` in permissions defs',
1953 'cannot locate repo group with name: `%s` in permissions defs',
1921 group_name)
1954 group_name)
1922 return False
1955 return False
1923
1956
1924 log.debug('checking `%s` permissions for repo group `%s`',
1957 log.debug('checking `%s` permissions for repo group `%s`',
1925 user_perms, group_name)
1958 user_perms, group_name)
1926 if self.required_perms.issubset(user_perms):
1959 if self.required_perms.issubset(user_perms):
1927 return True
1960 return True
1928 return False
1961 return False
1929
1962
1930
1963
1931 class HasRepoGroupPermissionAnyDecorator(PermsDecorator):
1964 class HasRepoGroupPermissionAnyDecorator(PermsDecorator):
1932 """
1965 """
1933 Checks for access permission for any of given predicates for specific
1966 Checks for access permission for any of given predicates for specific
1934 repository group. In order to fulfill the request any
1967 repository group. In order to fulfill the request any
1935 of predicates must be met
1968 of predicates must be met
1936 """
1969 """
1937 def _get_repo_group_name(self):
1970 def _get_repo_group_name(self):
1938 _request = self._get_request()
1971 _request = self._get_request()
1939 return get_repo_group_slug(_request)
1972 return get_repo_group_slug(_request)
1940
1973
1941 def check_permissions(self, user):
1974 def check_permissions(self, user):
1942 perms = user.permissions
1975 perms = user.permissions
1943 group_name = self._get_repo_group_name()
1976 group_name = self._get_repo_group_name()
1944
1977
1945 try:
1978 try:
1946 user_perms = {perms['repositories_groups'][group_name]}
1979 user_perms = {perms['repositories_groups'][group_name]}
1947 except KeyError:
1980 except KeyError:
1948 log.debug(
1981 log.debug(
1949 'cannot locate repo group with name: `%s` in permissions defs',
1982 'cannot locate repo group with name: `%s` in permissions defs',
1950 group_name)
1983 group_name)
1951 return False
1984 return False
1952
1985
1953 log.debug('checking `%s` permissions for repo group `%s`',
1986 log.debug('checking `%s` permissions for repo group `%s`',
1954 user_perms, group_name)
1987 user_perms, group_name)
1955 if self.required_perms.intersection(user_perms):
1988 if self.required_perms.intersection(user_perms):
1956 return True
1989 return True
1957 return False
1990 return False
1958
1991
1959
1992
1960 class HasUserGroupPermissionAllDecorator(PermsDecorator):
1993 class HasUserGroupPermissionAllDecorator(PermsDecorator):
1961 """
1994 """
1962 Checks for access permission for all given predicates for specific
1995 Checks for access permission for all given predicates for specific
1963 user group. All of them have to be meet in order to fulfill the request
1996 user group. All of them have to be meet in order to fulfill the request
1964 """
1997 """
1965 def _get_user_group_name(self):
1998 def _get_user_group_name(self):
1966 _request = self._get_request()
1999 _request = self._get_request()
1967 return get_user_group_slug(_request)
2000 return get_user_group_slug(_request)
1968
2001
1969 def check_permissions(self, user):
2002 def check_permissions(self, user):
1970 perms = user.permissions
2003 perms = user.permissions
1971 group_name = self._get_user_group_name()
2004 group_name = self._get_user_group_name()
1972 try:
2005 try:
1973 user_perms = {perms['user_groups'][group_name]}
2006 user_perms = {perms['user_groups'][group_name]}
1974 except KeyError:
2007 except KeyError:
1975 return False
2008 return False
1976
2009
1977 if self.required_perms.issubset(user_perms):
2010 if self.required_perms.issubset(user_perms):
1978 return True
2011 return True
1979 return False
2012 return False
1980
2013
1981
2014
1982 class HasUserGroupPermissionAnyDecorator(PermsDecorator):
2015 class HasUserGroupPermissionAnyDecorator(PermsDecorator):
1983 """
2016 """
1984 Checks for access permission for any of given predicates for specific
2017 Checks for access permission for any of given predicates for specific
1985 user group. In order to fulfill the request any of predicates must be meet
2018 user group. In order to fulfill the request any of predicates must be meet
1986 """
2019 """
1987 def _get_user_group_name(self):
2020 def _get_user_group_name(self):
1988 _request = self._get_request()
2021 _request = self._get_request()
1989 return get_user_group_slug(_request)
2022 return get_user_group_slug(_request)
1990
2023
1991 def check_permissions(self, user):
2024 def check_permissions(self, user):
1992 perms = user.permissions
2025 perms = user.permissions
1993 group_name = self._get_user_group_name()
2026 group_name = self._get_user_group_name()
1994 try:
2027 try:
1995 user_perms = {perms['user_groups'][group_name]}
2028 user_perms = {perms['user_groups'][group_name]}
1996 except KeyError:
2029 except KeyError:
1997 return False
2030 return False
1998
2031
1999 if self.required_perms.intersection(user_perms):
2032 if self.required_perms.intersection(user_perms):
2000 return True
2033 return True
2001 return False
2034 return False
2002
2035
2003
2036
2004 # CHECK FUNCTIONS
2037 # CHECK FUNCTIONS
2005 class PermsFunction(object):
2038 class PermsFunction(object):
2006 """Base function for other check functions"""
2039 """Base function for other check functions"""
2007
2040
2008 def __init__(self, *perms):
2041 def __init__(self, *perms):
2009 self.required_perms = set(perms)
2042 self.required_perms = set(perms)
2010 self.repo_name = None
2043 self.repo_name = None
2011 self.repo_group_name = None
2044 self.repo_group_name = None
2012 self.user_group_name = None
2045 self.user_group_name = None
2013
2046
2014 def __bool__(self):
2047 def __bool__(self):
2015 import inspect
2048 import inspect
2016 frame = inspect.currentframe()
2049 frame = inspect.currentframe()
2017 stack_trace = traceback.format_stack(frame)
2050 stack_trace = traceback.format_stack(frame)
2018 log.error('Checking bool value on a class instance of perm '
2051 log.error('Checking bool value on a class instance of perm '
2019 'function is not allowed: %s', ''.join(stack_trace))
2052 'function is not allowed: %s', ''.join(stack_trace))
2020 # rather than throwing errors, here we always return False so if by
2053 # rather than throwing errors, here we always return False so if by
2021 # accident someone checks truth for just an instance it will always end
2054 # accident someone checks truth for just an instance it will always end
2022 # up in returning False
2055 # up in returning False
2023 return False
2056 return False
2024 __nonzero__ = __bool__
2057 __nonzero__ = __bool__
2025
2058
2026 def __call__(self, check_location='', user=None):
2059 def __call__(self, check_location='', user=None):
2027 if not user:
2060 if not user:
2028 log.debug('Using user attribute from global request')
2061 log.debug('Using user attribute from global request')
2029 request = self._get_request()
2062 request = self._get_request()
2030 user = request.user
2063 user = request.user
2031
2064
2032 # init auth user if not already given
2065 # init auth user if not already given
2033 if not isinstance(user, AuthUser):
2066 if not isinstance(user, AuthUser):
2034 log.debug('Wrapping user %s into AuthUser', user)
2067 log.debug('Wrapping user %s into AuthUser', user)
2035 user = AuthUser(user.user_id)
2068 user = AuthUser(user.user_id)
2036
2069
2037 cls_name = self.__class__.__name__
2070 cls_name = self.__class__.__name__
2038 check_scope = self._get_check_scope(cls_name)
2071 check_scope = self._get_check_scope(cls_name)
2039 check_location = check_location or 'unspecified location'
2072 check_location = check_location or 'unspecified location'
2040
2073
2041 log.debug('checking cls:%s %s usr:%s %s @ %s', cls_name,
2074 log.debug('checking cls:%s %s usr:%s %s @ %s', cls_name,
2042 self.required_perms, user, check_scope, check_location)
2075 self.required_perms, user, check_scope, check_location)
2043 if not user:
2076 if not user:
2044 log.warning('Empty user given for permission check')
2077 log.warning('Empty user given for permission check')
2045 return False
2078 return False
2046
2079
2047 if self.check_permissions(user):
2080 if self.check_permissions(user):
2048 log.debug('Permission to repo:`%s` GRANTED for user:`%s` @ %s',
2081 log.debug('Permission to repo:`%s` GRANTED for user:`%s` @ %s',
2049 check_scope, user, check_location)
2082 check_scope, user, check_location)
2050 return True
2083 return True
2051
2084
2052 else:
2085 else:
2053 log.debug('Permission to repo:`%s` DENIED for user:`%s` @ %s',
2086 log.debug('Permission to repo:`%s` DENIED for user:`%s` @ %s',
2054 check_scope, user, check_location)
2087 check_scope, user, check_location)
2055 return False
2088 return False
2056
2089
2057 def _get_request(self):
2090 def _get_request(self):
2058 return get_request(self)
2091 return get_request(self)
2059
2092
2060 def _get_check_scope(self, cls_name):
2093 def _get_check_scope(self, cls_name):
2061 return {
2094 return {
2062 'HasPermissionAll': 'GLOBAL',
2095 'HasPermissionAll': 'GLOBAL',
2063 'HasPermissionAny': 'GLOBAL',
2096 'HasPermissionAny': 'GLOBAL',
2064 'HasRepoPermissionAll': 'repo:%s' % self.repo_name,
2097 'HasRepoPermissionAll': 'repo:%s' % self.repo_name,
2065 'HasRepoPermissionAny': 'repo:%s' % self.repo_name,
2098 'HasRepoPermissionAny': 'repo:%s' % self.repo_name,
2066 'HasRepoGroupPermissionAll': 'repo_group:%s' % self.repo_group_name,
2099 'HasRepoGroupPermissionAll': 'repo_group:%s' % self.repo_group_name,
2067 'HasRepoGroupPermissionAny': 'repo_group:%s' % self.repo_group_name,
2100 'HasRepoGroupPermissionAny': 'repo_group:%s' % self.repo_group_name,
2068 'HasUserGroupPermissionAll': 'user_group:%s' % self.user_group_name,
2101 'HasUserGroupPermissionAll': 'user_group:%s' % self.user_group_name,
2069 'HasUserGroupPermissionAny': 'user_group:%s' % self.user_group_name,
2102 'HasUserGroupPermissionAny': 'user_group:%s' % self.user_group_name,
2070 }.get(cls_name, '?:%s' % cls_name)
2103 }.get(cls_name, '?:%s' % cls_name)
2071
2104
2072 def check_permissions(self, user):
2105 def check_permissions(self, user):
2073 """Dummy function for overriding"""
2106 """Dummy function for overriding"""
2074 raise Exception('You have to write this function in child class')
2107 raise Exception('You have to write this function in child class')
2075
2108
2076
2109
2077 class HasPermissionAll(PermsFunction):
2110 class HasPermissionAll(PermsFunction):
2078 def check_permissions(self, user):
2111 def check_permissions(self, user):
2079 perms = user.permissions_with_scope({})
2112 perms = user.permissions_with_scope({})
2080 if self.required_perms.issubset(perms.get('global')):
2113 if self.required_perms.issubset(perms.get('global')):
2081 return True
2114 return True
2082 return False
2115 return False
2083
2116
2084
2117
2085 class HasPermissionAny(PermsFunction):
2118 class HasPermissionAny(PermsFunction):
2086 def check_permissions(self, user):
2119 def check_permissions(self, user):
2087 perms = user.permissions_with_scope({})
2120 perms = user.permissions_with_scope({})
2088 if self.required_perms.intersection(perms.get('global')):
2121 if self.required_perms.intersection(perms.get('global')):
2089 return True
2122 return True
2090 return False
2123 return False
2091
2124
2092
2125
2093 class HasRepoPermissionAll(PermsFunction):
2126 class HasRepoPermissionAll(PermsFunction):
2094 def __call__(self, repo_name=None, check_location='', user=None):
2127 def __call__(self, repo_name=None, check_location='', user=None):
2095 self.repo_name = repo_name
2128 self.repo_name = repo_name
2096 return super(HasRepoPermissionAll, self).__call__(check_location, user)
2129 return super(HasRepoPermissionAll, self).__call__(check_location, user)
2097
2130
2098 def _get_repo_name(self):
2131 def _get_repo_name(self):
2099 if not self.repo_name:
2132 if not self.repo_name:
2100 _request = self._get_request()
2133 _request = self._get_request()
2101 self.repo_name = get_repo_slug(_request)
2134 self.repo_name = get_repo_slug(_request)
2102 return self.repo_name
2135 return self.repo_name
2103
2136
2104 def check_permissions(self, user):
2137 def check_permissions(self, user):
2105 self.repo_name = self._get_repo_name()
2138 self.repo_name = self._get_repo_name()
2106 perms = user.permissions
2139 perms = user.permissions
2107 try:
2140 try:
2108 user_perms = {perms['repositories'][self.repo_name]}
2141 user_perms = {perms['repositories'][self.repo_name]}
2109 except KeyError:
2142 except KeyError:
2110 return False
2143 return False
2111 if self.required_perms.issubset(user_perms):
2144 if self.required_perms.issubset(user_perms):
2112 return True
2145 return True
2113 return False
2146 return False
2114
2147
2115
2148
2116 class HasRepoPermissionAny(PermsFunction):
2149 class HasRepoPermissionAny(PermsFunction):
2117 def __call__(self, repo_name=None, check_location='', user=None):
2150 def __call__(self, repo_name=None, check_location='', user=None):
2118 self.repo_name = repo_name
2151 self.repo_name = repo_name
2119 return super(HasRepoPermissionAny, self).__call__(check_location, user)
2152 return super(HasRepoPermissionAny, self).__call__(check_location, user)
2120
2153
2121 def _get_repo_name(self):
2154 def _get_repo_name(self):
2122 if not self.repo_name:
2155 if not self.repo_name:
2123 _request = self._get_request()
2156 _request = self._get_request()
2124 self.repo_name = get_repo_slug(_request)
2157 self.repo_name = get_repo_slug(_request)
2125 return self.repo_name
2158 return self.repo_name
2126
2159
2127 def check_permissions(self, user):
2160 def check_permissions(self, user):
2128 self.repo_name = self._get_repo_name()
2161 self.repo_name = self._get_repo_name()
2129 perms = user.permissions
2162 perms = user.permissions
2130 try:
2163 try:
2131 user_perms = {perms['repositories'][self.repo_name]}
2164 user_perms = {perms['repositories'][self.repo_name]}
2132 except KeyError:
2165 except KeyError:
2133 return False
2166 return False
2134 if self.required_perms.intersection(user_perms):
2167 if self.required_perms.intersection(user_perms):
2135 return True
2168 return True
2136 return False
2169 return False
2137
2170
2138
2171
2139 class HasRepoGroupPermissionAny(PermsFunction):
2172 class HasRepoGroupPermissionAny(PermsFunction):
2140 def __call__(self, group_name=None, check_location='', user=None):
2173 def __call__(self, group_name=None, check_location='', user=None):
2141 self.repo_group_name = group_name
2174 self.repo_group_name = group_name
2142 return super(HasRepoGroupPermissionAny, self).__call__(check_location, user)
2175 return super(HasRepoGroupPermissionAny, self).__call__(check_location, user)
2143
2176
2144 def check_permissions(self, user):
2177 def check_permissions(self, user):
2145 perms = user.permissions
2178 perms = user.permissions
2146 try:
2179 try:
2147 user_perms = {perms['repositories_groups'][self.repo_group_name]}
2180 user_perms = {perms['repositories_groups'][self.repo_group_name]}
2148 except KeyError:
2181 except KeyError:
2149 return False
2182 return False
2150 if self.required_perms.intersection(user_perms):
2183 if self.required_perms.intersection(user_perms):
2151 return True
2184 return True
2152 return False
2185 return False
2153
2186
2154
2187
2155 class HasRepoGroupPermissionAll(PermsFunction):
2188 class HasRepoGroupPermissionAll(PermsFunction):
2156 def __call__(self, group_name=None, check_location='', user=None):
2189 def __call__(self, group_name=None, check_location='', user=None):
2157 self.repo_group_name = group_name
2190 self.repo_group_name = group_name
2158 return super(HasRepoGroupPermissionAll, self).__call__(check_location, user)
2191 return super(HasRepoGroupPermissionAll, self).__call__(check_location, user)
2159
2192
2160 def check_permissions(self, user):
2193 def check_permissions(self, user):
2161 perms = user.permissions
2194 perms = user.permissions
2162 try:
2195 try:
2163 user_perms = {perms['repositories_groups'][self.repo_group_name]}
2196 user_perms = {perms['repositories_groups'][self.repo_group_name]}
2164 except KeyError:
2197 except KeyError:
2165 return False
2198 return False
2166 if self.required_perms.issubset(user_perms):
2199 if self.required_perms.issubset(user_perms):
2167 return True
2200 return True
2168 return False
2201 return False
2169
2202
2170
2203
2171 class HasUserGroupPermissionAny(PermsFunction):
2204 class HasUserGroupPermissionAny(PermsFunction):
2172 def __call__(self, user_group_name=None, check_location='', user=None):
2205 def __call__(self, user_group_name=None, check_location='', user=None):
2173 self.user_group_name = user_group_name
2206 self.user_group_name = user_group_name
2174 return super(HasUserGroupPermissionAny, self).__call__(check_location, user)
2207 return super(HasUserGroupPermissionAny, self).__call__(check_location, user)
2175
2208
2176 def check_permissions(self, user):
2209 def check_permissions(self, user):
2177 perms = user.permissions
2210 perms = user.permissions
2178 try:
2211 try:
2179 user_perms = {perms['user_groups'][self.user_group_name]}
2212 user_perms = {perms['user_groups'][self.user_group_name]}
2180 except KeyError:
2213 except KeyError:
2181 return False
2214 return False
2182 if self.required_perms.intersection(user_perms):
2215 if self.required_perms.intersection(user_perms):
2183 return True
2216 return True
2184 return False
2217 return False
2185
2218
2186
2219
2187 class HasUserGroupPermissionAll(PermsFunction):
2220 class HasUserGroupPermissionAll(PermsFunction):
2188 def __call__(self, user_group_name=None, check_location='', user=None):
2221 def __call__(self, user_group_name=None, check_location='', user=None):
2189 self.user_group_name = user_group_name
2222 self.user_group_name = user_group_name
2190 return super(HasUserGroupPermissionAll, self).__call__(check_location, user)
2223 return super(HasUserGroupPermissionAll, self).__call__(check_location, user)
2191
2224
2192 def check_permissions(self, user):
2225 def check_permissions(self, user):
2193 perms = user.permissions
2226 perms = user.permissions
2194 try:
2227 try:
2195 user_perms = {perms['user_groups'][self.user_group_name]}
2228 user_perms = {perms['user_groups'][self.user_group_name]}
2196 except KeyError:
2229 except KeyError:
2197 return False
2230 return False
2198 if self.required_perms.issubset(user_perms):
2231 if self.required_perms.issubset(user_perms):
2199 return True
2232 return True
2200 return False
2233 return False
2201
2234
2202
2235
2203 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
2236 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
2204 class HasPermissionAnyMiddleware(object):
2237 class HasPermissionAnyMiddleware(object):
2205 def __init__(self, *perms):
2238 def __init__(self, *perms):
2206 self.required_perms = set(perms)
2239 self.required_perms = set(perms)
2207
2240
2208 def __call__(self, auth_user, repo_name):
2241 def __call__(self, auth_user, repo_name):
2209 # repo_name MUST be unicode, since we handle keys in permission
2242 # repo_name MUST be unicode, since we handle keys in permission
2210 # dict by unicode
2243 # dict by unicode
2211 repo_name = safe_unicode(repo_name)
2244 repo_name = safe_unicode(repo_name)
2212 log.debug(
2245 log.debug(
2213 'Checking VCS protocol permissions %s for user:%s repo:`%s`',
2246 'Checking VCS protocol permissions %s for user:%s repo:`%s`',
2214 self.required_perms, auth_user, repo_name)
2247 self.required_perms, auth_user, repo_name)
2215
2248
2216 if self.check_permissions(auth_user, repo_name):
2249 if self.check_permissions(auth_user, repo_name):
2217 log.debug('Permission to repo:`%s` GRANTED for user:%s @ %s',
2250 log.debug('Permission to repo:`%s` GRANTED for user:%s @ %s',
2218 repo_name, auth_user, 'PermissionMiddleware')
2251 repo_name, auth_user, 'PermissionMiddleware')
2219 return True
2252 return True
2220
2253
2221 else:
2254 else:
2222 log.debug('Permission to repo:`%s` DENIED for user:%s @ %s',
2255 log.debug('Permission to repo:`%s` DENIED for user:%s @ %s',
2223 repo_name, auth_user, 'PermissionMiddleware')
2256 repo_name, auth_user, 'PermissionMiddleware')
2224 return False
2257 return False
2225
2258
2226 def check_permissions(self, user, repo_name):
2259 def check_permissions(self, user, repo_name):
2227 perms = user.permissions_with_scope({'repo_name': repo_name})
2260 perms = user.permissions_with_scope({'repo_name': repo_name})
2228
2261
2229 try:
2262 try:
2230 user_perms = {perms['repositories'][repo_name]}
2263 user_perms = {perms['repositories'][repo_name]}
2231 except Exception:
2264 except Exception:
2232 log.exception('Error while accessing user permissions')
2265 log.exception('Error while accessing user permissions')
2233 return False
2266 return False
2234
2267
2235 if self.required_perms.intersection(user_perms):
2268 if self.required_perms.intersection(user_perms):
2236 return True
2269 return True
2237 return False
2270 return False
2238
2271
2239
2272
2240 # SPECIAL VERSION TO HANDLE API AUTH
2273 # SPECIAL VERSION TO HANDLE API AUTH
2241 class _BaseApiPerm(object):
2274 class _BaseApiPerm(object):
2242 def __init__(self, *perms):
2275 def __init__(self, *perms):
2243 self.required_perms = set(perms)
2276 self.required_perms = set(perms)
2244
2277
2245 def __call__(self, check_location=None, user=None, repo_name=None,
2278 def __call__(self, check_location=None, user=None, repo_name=None,
2246 group_name=None, user_group_name=None):
2279 group_name=None, user_group_name=None):
2247 cls_name = self.__class__.__name__
2280 cls_name = self.__class__.__name__
2248 check_scope = 'global:%s' % (self.required_perms,)
2281 check_scope = 'global:%s' % (self.required_perms,)
2249 if repo_name:
2282 if repo_name:
2250 check_scope += ', repo_name:%s' % (repo_name,)
2283 check_scope += ', repo_name:%s' % (repo_name,)
2251
2284
2252 if group_name:
2285 if group_name:
2253 check_scope += ', repo_group_name:%s' % (group_name,)
2286 check_scope += ', repo_group_name:%s' % (group_name,)
2254
2287
2255 if user_group_name:
2288 if user_group_name:
2256 check_scope += ', user_group_name:%s' % (user_group_name,)
2289 check_scope += ', user_group_name:%s' % (user_group_name,)
2257
2290
2258 log.debug('checking cls:%s %s %s @ %s',
2291 log.debug('checking cls:%s %s %s @ %s',
2259 cls_name, self.required_perms, check_scope, check_location)
2292 cls_name, self.required_perms, check_scope, check_location)
2260 if not user:
2293 if not user:
2261 log.debug('Empty User passed into arguments')
2294 log.debug('Empty User passed into arguments')
2262 return False
2295 return False
2263
2296
2264 # process user
2297 # process user
2265 if not isinstance(user, AuthUser):
2298 if not isinstance(user, AuthUser):
2266 user = AuthUser(user.user_id)
2299 user = AuthUser(user.user_id)
2267 if not check_location:
2300 if not check_location:
2268 check_location = 'unspecified'
2301 check_location = 'unspecified'
2269 if self.check_permissions(user.permissions, repo_name, group_name,
2302 if self.check_permissions(user.permissions, repo_name, group_name,
2270 user_group_name):
2303 user_group_name):
2271 log.debug('Permission to repo:`%s` GRANTED for user:`%s` @ %s',
2304 log.debug('Permission to repo:`%s` GRANTED for user:`%s` @ %s',
2272 check_scope, user, check_location)
2305 check_scope, user, check_location)
2273 return True
2306 return True
2274
2307
2275 else:
2308 else:
2276 log.debug('Permission to repo:`%s` DENIED for user:`%s` @ %s',
2309 log.debug('Permission to repo:`%s` DENIED for user:`%s` @ %s',
2277 check_scope, user, check_location)
2310 check_scope, user, check_location)
2278 return False
2311 return False
2279
2312
2280 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2313 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2281 user_group_name=None):
2314 user_group_name=None):
2282 """
2315 """
2283 implement in child class should return True if permissions are ok,
2316 implement in child class should return True if permissions are ok,
2284 False otherwise
2317 False otherwise
2285
2318
2286 :param perm_defs: dict with permission definitions
2319 :param perm_defs: dict with permission definitions
2287 :param repo_name: repo name
2320 :param repo_name: repo name
2288 """
2321 """
2289 raise NotImplementedError()
2322 raise NotImplementedError()
2290
2323
2291
2324
2292 class HasPermissionAllApi(_BaseApiPerm):
2325 class HasPermissionAllApi(_BaseApiPerm):
2293 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2326 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2294 user_group_name=None):
2327 user_group_name=None):
2295 if self.required_perms.issubset(perm_defs.get('global')):
2328 if self.required_perms.issubset(perm_defs.get('global')):
2296 return True
2329 return True
2297 return False
2330 return False
2298
2331
2299
2332
2300 class HasPermissionAnyApi(_BaseApiPerm):
2333 class HasPermissionAnyApi(_BaseApiPerm):
2301 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2334 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2302 user_group_name=None):
2335 user_group_name=None):
2303 if self.required_perms.intersection(perm_defs.get('global')):
2336 if self.required_perms.intersection(perm_defs.get('global')):
2304 return True
2337 return True
2305 return False
2338 return False
2306
2339
2307
2340
2308 class HasRepoPermissionAllApi(_BaseApiPerm):
2341 class HasRepoPermissionAllApi(_BaseApiPerm):
2309 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2342 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2310 user_group_name=None):
2343 user_group_name=None):
2311 try:
2344 try:
2312 _user_perms = {perm_defs['repositories'][repo_name]}
2345 _user_perms = {perm_defs['repositories'][repo_name]}
2313 except KeyError:
2346 except KeyError:
2314 log.warning(traceback.format_exc())
2347 log.warning(traceback.format_exc())
2315 return False
2348 return False
2316 if self.required_perms.issubset(_user_perms):
2349 if self.required_perms.issubset(_user_perms):
2317 return True
2350 return True
2318 return False
2351 return False
2319
2352
2320
2353
2321 class HasRepoPermissionAnyApi(_BaseApiPerm):
2354 class HasRepoPermissionAnyApi(_BaseApiPerm):
2322 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2355 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2323 user_group_name=None):
2356 user_group_name=None):
2324 try:
2357 try:
2325 _user_perms = {perm_defs['repositories'][repo_name]}
2358 _user_perms = {perm_defs['repositories'][repo_name]}
2326 except KeyError:
2359 except KeyError:
2327 log.warning(traceback.format_exc())
2360 log.warning(traceback.format_exc())
2328 return False
2361 return False
2329 if self.required_perms.intersection(_user_perms):
2362 if self.required_perms.intersection(_user_perms):
2330 return True
2363 return True
2331 return False
2364 return False
2332
2365
2333
2366
2334 class HasRepoGroupPermissionAnyApi(_BaseApiPerm):
2367 class HasRepoGroupPermissionAnyApi(_BaseApiPerm):
2335 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2368 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2336 user_group_name=None):
2369 user_group_name=None):
2337 try:
2370 try:
2338 _user_perms = {perm_defs['repositories_groups'][group_name]}
2371 _user_perms = {perm_defs['repositories_groups'][group_name]}
2339 except KeyError:
2372 except KeyError:
2340 log.warning(traceback.format_exc())
2373 log.warning(traceback.format_exc())
2341 return False
2374 return False
2342 if self.required_perms.intersection(_user_perms):
2375 if self.required_perms.intersection(_user_perms):
2343 return True
2376 return True
2344 return False
2377 return False
2345
2378
2346
2379
2347 class HasRepoGroupPermissionAllApi(_BaseApiPerm):
2380 class HasRepoGroupPermissionAllApi(_BaseApiPerm):
2348 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2381 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2349 user_group_name=None):
2382 user_group_name=None):
2350 try:
2383 try:
2351 _user_perms = {perm_defs['repositories_groups'][group_name]}
2384 _user_perms = {perm_defs['repositories_groups'][group_name]}
2352 except KeyError:
2385 except KeyError:
2353 log.warning(traceback.format_exc())
2386 log.warning(traceback.format_exc())
2354 return False
2387 return False
2355 if self.required_perms.issubset(_user_perms):
2388 if self.required_perms.issubset(_user_perms):
2356 return True
2389 return True
2357 return False
2390 return False
2358
2391
2359
2392
2360 class HasUserGroupPermissionAnyApi(_BaseApiPerm):
2393 class HasUserGroupPermissionAnyApi(_BaseApiPerm):
2361 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2394 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2362 user_group_name=None):
2395 user_group_name=None):
2363 try:
2396 try:
2364 _user_perms = {perm_defs['user_groups'][user_group_name]}
2397 _user_perms = {perm_defs['user_groups'][user_group_name]}
2365 except KeyError:
2398 except KeyError:
2366 log.warning(traceback.format_exc())
2399 log.warning(traceback.format_exc())
2367 return False
2400 return False
2368 if self.required_perms.intersection(_user_perms):
2401 if self.required_perms.intersection(_user_perms):
2369 return True
2402 return True
2370 return False
2403 return False
2371
2404
2372
2405
2373 def check_ip_access(source_ip, allowed_ips=None):
2406 def check_ip_access(source_ip, allowed_ips=None):
2374 """
2407 """
2375 Checks if source_ip is a subnet of any of allowed_ips.
2408 Checks if source_ip is a subnet of any of allowed_ips.
2376
2409
2377 :param source_ip:
2410 :param source_ip:
2378 :param allowed_ips: list of allowed ips together with mask
2411 :param allowed_ips: list of allowed ips together with mask
2379 """
2412 """
2380 log.debug('checking if ip:%s is subnet of %s', source_ip, allowed_ips)
2413 log.debug('checking if ip:%s is subnet of %s', source_ip, allowed_ips)
2381 source_ip_address = ipaddress.ip_address(safe_unicode(source_ip))
2414 source_ip_address = ipaddress.ip_address(safe_unicode(source_ip))
2382 if isinstance(allowed_ips, (tuple, list, set)):
2415 if isinstance(allowed_ips, (tuple, list, set)):
2383 for ip in allowed_ips:
2416 for ip in allowed_ips:
2384 ip = safe_unicode(ip)
2417 ip = safe_unicode(ip)
2385 try:
2418 try:
2386 network_address = ipaddress.ip_network(ip, strict=False)
2419 network_address = ipaddress.ip_network(ip, strict=False)
2387 if source_ip_address in network_address:
2420 if source_ip_address in network_address:
2388 log.debug('IP %s is network %s', source_ip_address, network_address)
2421 log.debug('IP %s is network %s', source_ip_address, network_address)
2389 return True
2422 return True
2390 # for any case we cannot determine the IP, don't crash just
2423 # for any case we cannot determine the IP, don't crash just
2391 # skip it and log as error, we want to say forbidden still when
2424 # skip it and log as error, we want to say forbidden still when
2392 # sending bad IP
2425 # sending bad IP
2393 except Exception:
2426 except Exception:
2394 log.error(traceback.format_exc())
2427 log.error(traceback.format_exc())
2395 continue
2428 continue
2396 return False
2429 return False
2397
2430
2398
2431
2399 def get_cython_compat_decorator(wrapper, func):
2432 def get_cython_compat_decorator(wrapper, func):
2400 """
2433 """
2401 Creates a cython compatible decorator. The previously used
2434 Creates a cython compatible decorator. The previously used
2402 decorator.decorator() function seems to be incompatible with cython.
2435 decorator.decorator() function seems to be incompatible with cython.
2403
2436
2404 :param wrapper: __wrapper method of the decorator class
2437 :param wrapper: __wrapper method of the decorator class
2405 :param func: decorated function
2438 :param func: decorated function
2406 """
2439 """
2407 @wraps(func)
2440 @wraps(func)
2408 def local_wrapper(*args, **kwds):
2441 def local_wrapper(*args, **kwds):
2409 return wrapper(func, *args, **kwds)
2442 return wrapper(func, *args, **kwds)
2410 local_wrapper.__wrapped__ = func
2443 local_wrapper.__wrapped__ = func
2411 return local_wrapper
2444 return local_wrapper
2412
2445
2413
2446
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now