##// END OF EJS Templates
api: add consistent permissions_summary data for both user and user_groups that expose...
marcink -
r2437:31460ef8 default
parent child Browse files
Show More
@@ -1,560 +1,562 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2011-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import logging
22 22
23 23 from rhodecode.api import (
24 24 jsonrpc_method, JSONRPCError, JSONRPCForbidden, JSONRPCValidationError)
25 25 from rhodecode.api.utils import (
26 26 Optional, OAttr, has_superadmin_permission, get_user_or_error, store_update)
27 27 from rhodecode.lib import audit_logger
28 28 from rhodecode.lib.auth import AuthUser, PasswordGenerator
29 29 from rhodecode.lib.exceptions import DefaultUserException
30 30 from rhodecode.lib.utils2 import safe_int, str2bool
31 31 from rhodecode.model.db import Session, User, Repository
32 32 from rhodecode.model.user import UserModel
33 33 from rhodecode.model import validation_schema
34 34 from rhodecode.model.validation_schema.schemas import user_schema
35 35
36 36 log = logging.getLogger(__name__)
37 37
38 38
39 39 @jsonrpc_method()
40 40 def get_user(request, apiuser, userid=Optional(OAttr('apiuser'))):
41 41 """
42 42 Returns the information associated with a username or userid.
43 43
44 44 * If the ``userid`` is not set, this command returns the information
45 45 for the ``userid`` calling the method.
46 46
47 47 .. note::
48 48
49 49 Normal users may only run this command against their ``userid``. For
50 50 full privileges you must run this command using an |authtoken| with
51 51 admin rights.
52 52
53 53 :param apiuser: This is filled automatically from the |authtoken|.
54 54 :type apiuser: AuthUser
55 55 :param userid: Sets the userid for which data will be returned.
56 56 :type userid: Optional(str or int)
57 57
58 58 Example output:
59 59
60 60 .. code-block:: bash
61 61
62 62 {
63 63 "error": null,
64 64 "id": <id>,
65 65 "result": {
66 66 "active": true,
67 67 "admin": false,
68 68 "api_keys": [ list of keys ],
69 69 "auth_tokens": [ list of tokens with details ],
70 70 "email": "user@example.com",
71 71 "emails": [
72 72 "user@example.com"
73 73 ],
74 74 "extern_name": "rhodecode",
75 75 "extern_type": "rhodecode",
76 76 "firstname": "username",
77 77 "ip_addresses": [],
78 78 "language": null,
79 79 "last_login": "Timestamp",
80 80 "last_activity": "Timestamp",
81 81 "lastname": "surnae",
82 82 "permissions": {
83 83 "global": [
84 84 "hg.inherit_default_perms.true",
85 85 "usergroup.read",
86 86 "hg.repogroup.create.false",
87 87 "hg.create.none",
88 88 "hg.password_reset.enabled",
89 89 "hg.extern_activate.manual",
90 90 "hg.create.write_on_repogroup.false",
91 91 "hg.usergroup.create.false",
92 92 "group.none",
93 93 "repository.none",
94 94 "hg.register.none",
95 95 "hg.fork.repository"
96 96 ],
97 97 "repositories": { "username/example": "repository.write"},
98 98 "repositories_groups": { "user-group/repo": "group.none" },
99 99 "user_groups": { "user_group_name": "usergroup.read" }
100 100 },
101 101 "user_id": 32,
102 102 "username": "username"
103 103 }
104 104 }
105 105 """
106 106
107 107 if not has_superadmin_permission(apiuser):
108 108 # make sure normal user does not pass someone else userid,
109 109 # he is not allowed to do that
110 110 if not isinstance(userid, Optional) and userid != apiuser.user_id:
111 111 raise JSONRPCError('userid is not the same as your user')
112 112
113 113 userid = Optional.extract(userid, evaluate_locals=locals())
114 114 userid = getattr(userid, 'user_id', userid)
115 115
116 116 user = get_user_or_error(userid)
117 117 data = user.get_api_data(include_secrets=True)
118 data['permissions'] = AuthUser(user_id=user.user_id).permissions
118 permissions = AuthUser(user_id=user.user_id).permissions
119 data['permissions'] = permissions # TODO(marcink): should be deprecated
120 data['permissions_summary'] = permissions
119 121 return data
120 122
121 123
122 124 @jsonrpc_method()
123 125 def get_users(request, apiuser):
124 126 """
125 127 Lists all users in the |RCE| user database.
126 128
127 129 This command can only be run using an |authtoken| with admin rights to
128 130 the specified repository.
129 131
130 132 This command takes the following options:
131 133
132 134 :param apiuser: This is filled automatically from the |authtoken|.
133 135 :type apiuser: AuthUser
134 136
135 137 Example output:
136 138
137 139 .. code-block:: bash
138 140
139 141 id : <id_given_in_input>
140 142 result: [<user_object>, ...]
141 143 error: null
142 144 """
143 145
144 146 if not has_superadmin_permission(apiuser):
145 147 raise JSONRPCForbidden()
146 148
147 149 result = []
148 150 users_list = User.query().order_by(User.username) \
149 151 .filter(User.username != User.DEFAULT_USER) \
150 152 .all()
151 153 for user in users_list:
152 154 result.append(user.get_api_data(include_secrets=True))
153 155 return result
154 156
155 157
156 158 @jsonrpc_method()
157 159 def create_user(request, apiuser, username, email, password=Optional(''),
158 160 firstname=Optional(''), lastname=Optional(''),
159 161 active=Optional(True), admin=Optional(False),
160 162 extern_name=Optional('rhodecode'),
161 163 extern_type=Optional('rhodecode'),
162 164 force_password_change=Optional(False),
163 165 create_personal_repo_group=Optional(None)):
164 166 """
165 167 Creates a new user and returns the new user object.
166 168
167 169 This command can only be run using an |authtoken| with admin rights to
168 170 the specified repository.
169 171
170 172 This command takes the following options:
171 173
172 174 :param apiuser: This is filled automatically from the |authtoken|.
173 175 :type apiuser: AuthUser
174 176 :param username: Set the new username.
175 177 :type username: str or int
176 178 :param email: Set the user email address.
177 179 :type email: str
178 180 :param password: Set the new user password.
179 181 :type password: Optional(str)
180 182 :param firstname: Set the new user firstname.
181 183 :type firstname: Optional(str)
182 184 :param lastname: Set the new user surname.
183 185 :type lastname: Optional(str)
184 186 :param active: Set the user as active.
185 187 :type active: Optional(``True`` | ``False``)
186 188 :param admin: Give the new user admin rights.
187 189 :type admin: Optional(``True`` | ``False``)
188 190 :param extern_name: Set the authentication plugin name.
189 191 Using LDAP this is filled with LDAP UID.
190 192 :type extern_name: Optional(str)
191 193 :param extern_type: Set the new user authentication plugin.
192 194 :type extern_type: Optional(str)
193 195 :param force_password_change: Force the new user to change password
194 196 on next login.
195 197 :type force_password_change: Optional(``True`` | ``False``)
196 198 :param create_personal_repo_group: Create personal repo group for this user
197 199 :type create_personal_repo_group: Optional(``True`` | ``False``)
198 200
199 201 Example output:
200 202
201 203 .. code-block:: bash
202 204
203 205 id : <id_given_in_input>
204 206 result: {
205 207 "msg" : "created new user `<username>`",
206 208 "user": <user_obj>
207 209 }
208 210 error: null
209 211
210 212 Example error output:
211 213
212 214 .. code-block:: bash
213 215
214 216 id : <id_given_in_input>
215 217 result : null
216 218 error : {
217 219 "user `<username>` already exist"
218 220 or
219 221 "email `<email>` already exist"
220 222 or
221 223 "failed to create user `<username>`"
222 224 }
223 225
224 226 """
225 227 if not has_superadmin_permission(apiuser):
226 228 raise JSONRPCForbidden()
227 229
228 230 if UserModel().get_by_username(username):
229 231 raise JSONRPCError("user `%s` already exist" % (username,))
230 232
231 233 if UserModel().get_by_email(email, case_insensitive=True):
232 234 raise JSONRPCError("email `%s` already exist" % (email,))
233 235
234 236 # generate random password if we actually given the
235 237 # extern_name and it's not rhodecode
236 238 if (not isinstance(extern_name, Optional) and
237 239 Optional.extract(extern_name) != 'rhodecode'):
238 240 # generate temporary password if user is external
239 241 password = PasswordGenerator().gen_password(length=16)
240 242 create_repo_group = Optional.extract(create_personal_repo_group)
241 243 if isinstance(create_repo_group, basestring):
242 244 create_repo_group = str2bool(create_repo_group)
243 245
244 246 username = Optional.extract(username)
245 247 password = Optional.extract(password)
246 248 email = Optional.extract(email)
247 249 first_name = Optional.extract(firstname)
248 250 last_name = Optional.extract(lastname)
249 251 active = Optional.extract(active)
250 252 admin = Optional.extract(admin)
251 253 extern_type = Optional.extract(extern_type)
252 254 extern_name = Optional.extract(extern_name)
253 255
254 256 schema = user_schema.UserSchema().bind(
255 257 # user caller
256 258 user=apiuser)
257 259 try:
258 260 schema_data = schema.deserialize(dict(
259 261 username=username,
260 262 email=email,
261 263 password=password,
262 264 first_name=first_name,
263 265 last_name=last_name,
264 266 active=active,
265 267 admin=admin,
266 268 extern_type=extern_type,
267 269 extern_name=extern_name,
268 270 ))
269 271 except validation_schema.Invalid as err:
270 272 raise JSONRPCValidationError(colander_exc=err)
271 273
272 274 try:
273 275 user = UserModel().create_or_update(
274 276 username=schema_data['username'],
275 277 password=schema_data['password'],
276 278 email=schema_data['email'],
277 279 firstname=schema_data['first_name'],
278 280 lastname=schema_data['last_name'],
279 281 active=schema_data['active'],
280 282 admin=schema_data['admin'],
281 283 extern_type=schema_data['extern_type'],
282 284 extern_name=schema_data['extern_name'],
283 285 force_password_change=Optional.extract(force_password_change),
284 286 create_repo_group=create_repo_group
285 287 )
286 288 Session().flush()
287 289 creation_data = user.get_api_data()
288 290 audit_logger.store_api(
289 291 'user.create', action_data={'data': creation_data},
290 292 user=apiuser)
291 293
292 294 Session().commit()
293 295 return {
294 296 'msg': 'created new user `%s`' % username,
295 297 'user': user.get_api_data(include_secrets=True)
296 298 }
297 299 except Exception:
298 300 log.exception('Error occurred during creation of user')
299 301 raise JSONRPCError('failed to create user `%s`' % (username,))
300 302
301 303
302 304 @jsonrpc_method()
303 305 def update_user(request, apiuser, userid, username=Optional(None),
304 306 email=Optional(None), password=Optional(None),
305 307 firstname=Optional(None), lastname=Optional(None),
306 308 active=Optional(None), admin=Optional(None),
307 309 extern_type=Optional(None), extern_name=Optional(None), ):
308 310 """
309 311 Updates the details for the specified user, if that user exists.
310 312
311 313 This command can only be run using an |authtoken| with admin rights to
312 314 the specified repository.
313 315
314 316 This command takes the following options:
315 317
316 318 :param apiuser: This is filled automatically from |authtoken|.
317 319 :type apiuser: AuthUser
318 320 :param userid: Set the ``userid`` to update.
319 321 :type userid: str or int
320 322 :param username: Set the new username.
321 323 :type username: str or int
322 324 :param email: Set the new email.
323 325 :type email: str
324 326 :param password: Set the new password.
325 327 :type password: Optional(str)
326 328 :param firstname: Set the new first name.
327 329 :type firstname: Optional(str)
328 330 :param lastname: Set the new surname.
329 331 :type lastname: Optional(str)
330 332 :param active: Set the new user as active.
331 333 :type active: Optional(``True`` | ``False``)
332 334 :param admin: Give the user admin rights.
333 335 :type admin: Optional(``True`` | ``False``)
334 336 :param extern_name: Set the authentication plugin user name.
335 337 Using LDAP this is filled with LDAP UID.
336 338 :type extern_name: Optional(str)
337 339 :param extern_type: Set the authentication plugin type.
338 340 :type extern_type: Optional(str)
339 341
340 342
341 343 Example output:
342 344
343 345 .. code-block:: bash
344 346
345 347 id : <id_given_in_input>
346 348 result: {
347 349 "msg" : "updated user ID:<userid> <username>",
348 350 "user": <user_object>,
349 351 }
350 352 error: null
351 353
352 354 Example error output:
353 355
354 356 .. code-block:: bash
355 357
356 358 id : <id_given_in_input>
357 359 result : null
358 360 error : {
359 361 "failed to update user `<username>`"
360 362 }
361 363
362 364 """
363 365 if not has_superadmin_permission(apiuser):
364 366 raise JSONRPCForbidden()
365 367
366 368 user = get_user_or_error(userid)
367 369 old_data = user.get_api_data()
368 370 # only non optional arguments will be stored in updates
369 371 updates = {}
370 372
371 373 try:
372 374
373 375 store_update(updates, username, 'username')
374 376 store_update(updates, password, 'password')
375 377 store_update(updates, email, 'email')
376 378 store_update(updates, firstname, 'name')
377 379 store_update(updates, lastname, 'lastname')
378 380 store_update(updates, active, 'active')
379 381 store_update(updates, admin, 'admin')
380 382 store_update(updates, extern_name, 'extern_name')
381 383 store_update(updates, extern_type, 'extern_type')
382 384
383 385 user = UserModel().update_user(user, **updates)
384 386 audit_logger.store_api(
385 387 'user.edit', action_data={'old_data': old_data},
386 388 user=apiuser)
387 389 Session().commit()
388 390 return {
389 391 'msg': 'updated user ID:%s %s' % (user.user_id, user.username),
390 392 'user': user.get_api_data(include_secrets=True)
391 393 }
392 394 except DefaultUserException:
393 395 log.exception("Default user edit exception")
394 396 raise JSONRPCError('editing default user is forbidden')
395 397 except Exception:
396 398 log.exception("Error occurred during update of user")
397 399 raise JSONRPCError('failed to update user `%s`' % (userid,))
398 400
399 401
400 402 @jsonrpc_method()
401 403 def delete_user(request, apiuser, userid):
402 404 """
403 405 Deletes the specified user from the |RCE| user database.
404 406
405 407 This command can only be run using an |authtoken| with admin rights to
406 408 the specified repository.
407 409
408 410 .. important::
409 411
410 412 Ensure all open pull requests and open code review
411 413 requests to this user are close.
412 414
413 415 Also ensure all repositories, or repository groups owned by this
414 416 user are reassigned before deletion.
415 417
416 418 This command takes the following options:
417 419
418 420 :param apiuser: This is filled automatically from the |authtoken|.
419 421 :type apiuser: AuthUser
420 422 :param userid: Set the user to delete.
421 423 :type userid: str or int
422 424
423 425 Example output:
424 426
425 427 .. code-block:: bash
426 428
427 429 id : <id_given_in_input>
428 430 result: {
429 431 "msg" : "deleted user ID:<userid> <username>",
430 432 "user": null
431 433 }
432 434 error: null
433 435
434 436 Example error output:
435 437
436 438 .. code-block:: bash
437 439
438 440 id : <id_given_in_input>
439 441 result : null
440 442 error : {
441 443 "failed to delete user ID:<userid> <username>"
442 444 }
443 445
444 446 """
445 447 if not has_superadmin_permission(apiuser):
446 448 raise JSONRPCForbidden()
447 449
448 450 user = get_user_or_error(userid)
449 451 old_data = user.get_api_data()
450 452 try:
451 453 UserModel().delete(userid)
452 454 audit_logger.store_api(
453 455 'user.delete', action_data={'old_data': old_data},
454 456 user=apiuser)
455 457
456 458 Session().commit()
457 459 return {
458 460 'msg': 'deleted user ID:%s %s' % (user.user_id, user.username),
459 461 'user': None
460 462 }
461 463 except Exception:
462 464 log.exception("Error occurred during deleting of user")
463 465 raise JSONRPCError(
464 466 'failed to delete user ID:%s %s' % (user.user_id, user.username))
465 467
466 468
467 469 @jsonrpc_method()
468 470 def get_user_locks(request, apiuser, userid=Optional(OAttr('apiuser'))):
469 471 """
470 472 Displays all repositories locked by the specified user.
471 473
472 474 * If this command is run by a non-admin user, it returns
473 475 a list of |repos| locked by that user.
474 476
475 477 This command takes the following options:
476 478
477 479 :param apiuser: This is filled automatically from the |authtoken|.
478 480 :type apiuser: AuthUser
479 481 :param userid: Sets the userid whose list of locked |repos| will be
480 482 displayed.
481 483 :type userid: Optional(str or int)
482 484
483 485 Example output:
484 486
485 487 .. code-block:: bash
486 488
487 489 id : <id_given_in_input>
488 490 result : {
489 491 [repo_object, repo_object,...]
490 492 }
491 493 error : null
492 494 """
493 495
494 496 include_secrets = False
495 497 if not has_superadmin_permission(apiuser):
496 498 # make sure normal user does not pass someone else userid,
497 499 # he is not allowed to do that
498 500 if not isinstance(userid, Optional) and userid != apiuser.user_id:
499 501 raise JSONRPCError('userid is not the same as your user')
500 502 else:
501 503 include_secrets = True
502 504
503 505 userid = Optional.extract(userid, evaluate_locals=locals())
504 506 userid = getattr(userid, 'user_id', userid)
505 507 user = get_user_or_error(userid)
506 508
507 509 ret = []
508 510
509 511 # show all locks
510 512 for r in Repository.getAll():
511 513 _user_id, _time, _reason = r.locked
512 514 if _user_id and _time:
513 515 _api_data = r.get_api_data(include_secrets=include_secrets)
514 516 # if we use user filter just show the locks for this user
515 517 if safe_int(_user_id) == user.user_id:
516 518 ret.append(_api_data)
517 519
518 520 return ret
519 521
520 522
521 523 @jsonrpc_method()
522 524 def get_user_audit_logs(request, apiuser, userid=Optional(OAttr('apiuser'))):
523 525 """
524 526 Fetches all action logs made by the specified user.
525 527
526 528 This command takes the following options:
527 529
528 530 :param apiuser: This is filled automatically from the |authtoken|.
529 531 :type apiuser: AuthUser
530 532 :param userid: Sets the userid whose list of locked |repos| will be
531 533 displayed.
532 534 :type userid: Optional(str or int)
533 535
534 536 Example output:
535 537
536 538 .. code-block:: bash
537 539
538 540 id : <id_given_in_input>
539 541 result : {
540 542 [action, action,...]
541 543 }
542 544 error : null
543 545 """
544 546
545 547 if not has_superadmin_permission(apiuser):
546 548 # make sure normal user does not pass someone else userid,
547 549 # he is not allowed to do that
548 550 if not isinstance(userid, Optional) and userid != apiuser.user_id:
549 551 raise JSONRPCError('userid is not the same as your user')
550 552
551 553 userid = Optional.extract(userid, evaluate_locals=locals())
552 554 userid = getattr(userid, 'user_id', userid)
553 555 user = get_user_or_error(userid)
554 556
555 557 ret = []
556 558
557 559 # show all user actions
558 560 for entry in UserModel().get_user_log(user, filter_term=None):
559 561 ret.append(entry)
560 562 return ret
@@ -1,822 +1,823 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2011-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import logging
22 22
23 23 from rhodecode.api import (
24 24 jsonrpc_method, JSONRPCError, JSONRPCForbidden, JSONRPCValidationError)
25 25 from rhodecode.api.utils import (
26 26 Optional, OAttr, store_update, has_superadmin_permission, get_origin,
27 27 get_user_or_error, get_user_group_or_error, get_perm_or_error)
28 28 from rhodecode.lib import audit_logger
29 29 from rhodecode.lib.auth import HasUserGroupPermissionAnyApi, HasPermissionAnyApi
30 30 from rhodecode.lib.exceptions import UserGroupAssignedException
31 31 from rhodecode.model.db import Session
32 32 from rhodecode.model.scm import UserGroupList
33 33 from rhodecode.model.user_group import UserGroupModel
34 34 from rhodecode.model import validation_schema
35 35 from rhodecode.model.validation_schema.schemas import user_group_schema
36 36
37 37 log = logging.getLogger(__name__)
38 38
39 39
40 40 @jsonrpc_method()
41 41 def get_user_group(request, apiuser, usergroupid):
42 42 """
43 43 Returns the data of an existing user group.
44 44
45 45 This command can only be run using an |authtoken| with admin rights to
46 46 the specified repository.
47 47
48 48 :param apiuser: This is filled automatically from the |authtoken|.
49 49 :type apiuser: AuthUser
50 50 :param usergroupid: Set the user group from which to return data.
51 51 :type usergroupid: str or int
52 52
53 53 Example error output:
54 54
55 55 .. code-block:: bash
56 56
57 57 {
58 58 "error": null,
59 59 "id": <id>,
60 60 "result": {
61 61 "active": true,
62 62 "group_description": "group description",
63 63 "group_name": "group name",
64 64 "members": [
65 65 {
66 66 "name": "owner-name",
67 67 "origin": "owner",
68 68 "permission": "usergroup.admin",
69 69 "type": "user"
70 70 },
71 71 {
72 72 {
73 73 "name": "user name",
74 74 "origin": "permission",
75 75 "permission": "usergroup.admin",
76 76 "type": "user"
77 77 },
78 78 {
79 79 "name": "user group name",
80 80 "origin": "permission",
81 81 "permission": "usergroup.write",
82 82 "type": "user_group"
83 83 }
84 84 ],
85 85 "owner": "owner name",
86 86 "users": [],
87 87 "users_group_id": 2
88 88 }
89 89 }
90 90
91 91 """
92 92
93 93 user_group = get_user_group_or_error(usergroupid)
94 94 if not has_superadmin_permission(apiuser):
95 95 # check if we have at least read permission for this user group !
96 96 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
97 97 if not HasUserGroupPermissionAnyApi(*_perms)(
98 98 user=apiuser, user_group_name=user_group.users_group_name):
99 99 raise JSONRPCError('user group `%s` does not exist' % (
100 100 usergroupid,))
101 101
102 102 permissions = []
103 103 for _user in user_group.permissions():
104 104 user_data = {
105 105 'name': _user.username,
106 106 'permission': _user.permission,
107 107 'origin': get_origin(_user),
108 108 'type': "user",
109 109 }
110 110 permissions.append(user_data)
111 111
112 112 for _user_group in user_group.permission_user_groups():
113 113 user_group_data = {
114 114 'name': _user_group.users_group_name,
115 115 'permission': _user_group.permission,
116 116 'origin': get_origin(_user_group),
117 117 'type': "user_group",
118 118 }
119 119 permissions.append(user_group_data)
120 120
121 121 data = user_group.get_api_data()
122 122 data["permissions"] = permissions
123
123 data["Permissions_summary"] = UserGroupModel().get_perms_summary(
124 user_group.users_group_id)
124 125 return data
125 126
126 127
127 128 @jsonrpc_method()
128 129 def get_user_groups(request, apiuser):
129 130 """
130 131 Lists all the existing user groups within RhodeCode.
131 132
132 133 This command can only be run using an |authtoken| with admin rights to
133 134 the specified repository.
134 135
135 136 This command takes the following options:
136 137
137 138 :param apiuser: This is filled automatically from the |authtoken|.
138 139 :type apiuser: AuthUser
139 140
140 141 Example error output:
141 142
142 143 .. code-block:: bash
143 144
144 145 id : <id_given_in_input>
145 146 result : [<user_group_obj>,...]
146 147 error : null
147 148 """
148 149
149 150 include_secrets = has_superadmin_permission(apiuser)
150 151
151 152 result = []
152 153 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
153 154 extras = {'user': apiuser}
154 155 for user_group in UserGroupList(UserGroupModel().get_all(),
155 156 perm_set=_perms, extra_kwargs=extras):
156 157 result.append(
157 158 user_group.get_api_data(include_secrets=include_secrets))
158 159 return result
159 160
160 161
161 162 @jsonrpc_method()
162 163 def create_user_group(
163 164 request, apiuser, group_name, description=Optional(''),
164 165 owner=Optional(OAttr('apiuser')), active=Optional(True)):
165 166 """
166 167 Creates a new user group.
167 168
168 169 This command can only be run using an |authtoken| with admin rights to
169 170 the specified repository.
170 171
171 172 This command takes the following options:
172 173
173 174 :param apiuser: This is filled automatically from the |authtoken|.
174 175 :type apiuser: AuthUser
175 176 :param group_name: Set the name of the new user group.
176 177 :type group_name: str
177 178 :param description: Give a description of the new user group.
178 179 :type description: str
179 180 :param owner: Set the owner of the new user group.
180 181 If not set, the owner is the |authtoken| user.
181 182 :type owner: Optional(str or int)
182 183 :param active: Set this group as active.
183 184 :type active: Optional(``True`` | ``False``)
184 185
185 186 Example output:
186 187
187 188 .. code-block:: bash
188 189
189 190 id : <id_given_in_input>
190 191 result: {
191 192 "msg": "created new user group `<groupname>`",
192 193 "user_group": <user_group_object>
193 194 }
194 195 error: null
195 196
196 197 Example error output:
197 198
198 199 .. code-block:: bash
199 200
200 201 id : <id_given_in_input>
201 202 result : null
202 203 error : {
203 204 "user group `<group name>` already exist"
204 205 or
205 206 "failed to create group `<group name>`"
206 207 }
207 208
208 209 """
209 210
210 211 if not has_superadmin_permission(apiuser):
211 212 if not HasPermissionAnyApi('hg.usergroup.create.true')(user=apiuser):
212 213 raise JSONRPCForbidden()
213 214
214 215 if UserGroupModel().get_by_name(group_name):
215 216 raise JSONRPCError("user group `%s` already exist" % (group_name,))
216 217
217 218 if isinstance(owner, Optional):
218 219 owner = apiuser.user_id
219 220
220 221 owner = get_user_or_error(owner)
221 222 active = Optional.extract(active)
222 223 description = Optional.extract(description)
223 224
224 225 schema = user_group_schema.UserGroupSchema().bind(
225 226 # user caller
226 227 user=apiuser)
227 228 try:
228 229 schema_data = schema.deserialize(dict(
229 230 user_group_name=group_name,
230 231 user_group_description=description,
231 232 user_group_owner=owner.username,
232 233 user_group_active=active,
233 234 ))
234 235 except validation_schema.Invalid as err:
235 236 raise JSONRPCValidationError(colander_exc=err)
236 237
237 238 try:
238 239 user_group = UserGroupModel().create(
239 240 name=schema_data['user_group_name'],
240 241 description=schema_data['user_group_description'],
241 242 owner=owner,
242 243 active=schema_data['user_group_active'])
243 244 Session().flush()
244 245 creation_data = user_group.get_api_data()
245 246 audit_logger.store_api(
246 247 'user_group.create', action_data={'data': creation_data},
247 248 user=apiuser)
248 249 Session().commit()
249 250 return {
250 251 'msg': 'created new user group `%s`' % group_name,
251 252 'user_group': creation_data
252 253 }
253 254 except Exception:
254 255 log.exception("Error occurred during creation of user group")
255 256 raise JSONRPCError('failed to create group `%s`' % (group_name,))
256 257
257 258
258 259 @jsonrpc_method()
259 260 def update_user_group(request, apiuser, usergroupid, group_name=Optional(''),
260 261 description=Optional(''), owner=Optional(None),
261 262 active=Optional(True)):
262 263 """
263 264 Updates the specified `user group` with the details provided.
264 265
265 266 This command can only be run using an |authtoken| with admin rights to
266 267 the specified repository.
267 268
268 269 :param apiuser: This is filled automatically from the |authtoken|.
269 270 :type apiuser: AuthUser
270 271 :param usergroupid: Set the id of the `user group` to update.
271 272 :type usergroupid: str or int
272 273 :param group_name: Set the new name the `user group`
273 274 :type group_name: str
274 275 :param description: Give a description for the `user group`
275 276 :type description: str
276 277 :param owner: Set the owner of the `user group`.
277 278 :type owner: Optional(str or int)
278 279 :param active: Set the group as active.
279 280 :type active: Optional(``True`` | ``False``)
280 281
281 282 Example output:
282 283
283 284 .. code-block:: bash
284 285
285 286 id : <id_given_in_input>
286 287 result : {
287 288 "msg": 'updated user group ID:<user group id> <user group name>',
288 289 "user_group": <user_group_object>
289 290 }
290 291 error : null
291 292
292 293 Example error output:
293 294
294 295 .. code-block:: bash
295 296
296 297 id : <id_given_in_input>
297 298 result : null
298 299 error : {
299 300 "failed to update user group `<user group name>`"
300 301 }
301 302
302 303 """
303 304
304 305 user_group = get_user_group_or_error(usergroupid)
305 306 include_secrets = False
306 307 if not has_superadmin_permission(apiuser):
307 308 # check if we have admin permission for this user group !
308 309 _perms = ('usergroup.admin',)
309 310 if not HasUserGroupPermissionAnyApi(*_perms)(
310 311 user=apiuser, user_group_name=user_group.users_group_name):
311 312 raise JSONRPCError(
312 313 'user group `%s` does not exist' % (usergroupid,))
313 314 else:
314 315 include_secrets = True
315 316
316 317 if not isinstance(owner, Optional):
317 318 owner = get_user_or_error(owner)
318 319
319 320 old_data = user_group.get_api_data()
320 321 updates = {}
321 322 store_update(updates, group_name, 'users_group_name')
322 323 store_update(updates, description, 'user_group_description')
323 324 store_update(updates, owner, 'user')
324 325 store_update(updates, active, 'users_group_active')
325 326 try:
326 327 UserGroupModel().update(user_group, updates)
327 328 audit_logger.store_api(
328 329 'user_group.edit', action_data={'old_data': old_data},
329 330 user=apiuser)
330 331 Session().commit()
331 332 return {
332 333 'msg': 'updated user group ID:%s %s' % (
333 334 user_group.users_group_id, user_group.users_group_name),
334 335 'user_group': user_group.get_api_data(
335 336 include_secrets=include_secrets)
336 337 }
337 338 except Exception:
338 339 log.exception("Error occurred during update of user group")
339 340 raise JSONRPCError(
340 341 'failed to update user group `%s`' % (usergroupid,))
341 342
342 343
343 344 @jsonrpc_method()
344 345 def delete_user_group(request, apiuser, usergroupid):
345 346 """
346 347 Deletes the specified `user group`.
347 348
348 349 This command can only be run using an |authtoken| with admin rights to
349 350 the specified repository.
350 351
351 352 This command takes the following options:
352 353
353 354 :param apiuser: filled automatically from apikey
354 355 :type apiuser: AuthUser
355 356 :param usergroupid:
356 357 :type usergroupid: int
357 358
358 359 Example output:
359 360
360 361 .. code-block:: bash
361 362
362 363 id : <id_given_in_input>
363 364 result : {
364 365 "msg": "deleted user group ID:<user_group_id> <user_group_name>"
365 366 }
366 367 error : null
367 368
368 369 Example error output:
369 370
370 371 .. code-block:: bash
371 372
372 373 id : <id_given_in_input>
373 374 result : null
374 375 error : {
375 376 "failed to delete user group ID:<user_group_id> <user_group_name>"
376 377 or
377 378 "RepoGroup assigned to <repo_groups_list>"
378 379 }
379 380
380 381 """
381 382
382 383 user_group = get_user_group_or_error(usergroupid)
383 384 if not has_superadmin_permission(apiuser):
384 385 # check if we have admin permission for this user group !
385 386 _perms = ('usergroup.admin',)
386 387 if not HasUserGroupPermissionAnyApi(*_perms)(
387 388 user=apiuser, user_group_name=user_group.users_group_name):
388 389 raise JSONRPCError(
389 390 'user group `%s` does not exist' % (usergroupid,))
390 391
391 392 old_data = user_group.get_api_data()
392 393 try:
393 394 UserGroupModel().delete(user_group)
394 395 audit_logger.store_api(
395 396 'user_group.delete', action_data={'old_data': old_data},
396 397 user=apiuser)
397 398 Session().commit()
398 399 return {
399 400 'msg': 'deleted user group ID:%s %s' % (
400 401 user_group.users_group_id, user_group.users_group_name),
401 402 'user_group': None
402 403 }
403 404 except UserGroupAssignedException as e:
404 405 log.exception("UserGroupAssigned error")
405 406 raise JSONRPCError(str(e))
406 407 except Exception:
407 408 log.exception("Error occurred during deletion of user group")
408 409 raise JSONRPCError(
409 410 'failed to delete user group ID:%s %s' %(
410 411 user_group.users_group_id, user_group.users_group_name))
411 412
412 413
413 414 @jsonrpc_method()
414 415 def add_user_to_user_group(request, apiuser, usergroupid, userid):
415 416 """
416 417 Adds a user to a `user group`. If the user already exists in the group
417 418 this command will return false.
418 419
419 420 This command can only be run using an |authtoken| with admin rights to
420 421 the specified user group.
421 422
422 423 This command takes the following options:
423 424
424 425 :param apiuser: This is filled automatically from the |authtoken|.
425 426 :type apiuser: AuthUser
426 427 :param usergroupid: Set the name of the `user group` to which a
427 428 user will be added.
428 429 :type usergroupid: int
429 430 :param userid: Set the `user_id` of the user to add to the group.
430 431 :type userid: int
431 432
432 433 Example output:
433 434
434 435 .. code-block:: bash
435 436
436 437 id : <id_given_in_input>
437 438 result : {
438 439 "success": True|False # depends on if member is in group
439 440 "msg": "added member `<username>` to user group `<groupname>` |
440 441 User is already in that group"
441 442
442 443 }
443 444 error : null
444 445
445 446 Example error output:
446 447
447 448 .. code-block:: bash
448 449
449 450 id : <id_given_in_input>
450 451 result : null
451 452 error : {
452 453 "failed to add member to user group `<user_group_name>`"
453 454 }
454 455
455 456 """
456 457
457 458 user = get_user_or_error(userid)
458 459 user_group = get_user_group_or_error(usergroupid)
459 460 if not has_superadmin_permission(apiuser):
460 461 # check if we have admin permission for this user group !
461 462 _perms = ('usergroup.admin',)
462 463 if not HasUserGroupPermissionAnyApi(*_perms)(
463 464 user=apiuser, user_group_name=user_group.users_group_name):
464 465 raise JSONRPCError('user group `%s` does not exist' % (
465 466 usergroupid,))
466 467
467 468 old_values = user_group.get_api_data()
468 469 try:
469 470 ugm = UserGroupModel().add_user_to_group(user_group, user)
470 471 success = True if ugm is not True else False
471 472 msg = 'added member `%s` to user group `%s`' % (
472 473 user.username, user_group.users_group_name
473 474 )
474 475 msg = msg if success else 'User is already in that group'
475 476 if success:
476 477 user_data = user.get_api_data()
477 478 audit_logger.store_api(
478 479 'user_group.edit.member.add',
479 480 action_data={'user': user_data, 'old_data': old_values},
480 481 user=apiuser)
481 482
482 483 Session().commit()
483 484
484 485 return {
485 486 'success': success,
486 487 'msg': msg
487 488 }
488 489 except Exception:
489 490 log.exception("Error occurred during adding a member to user group")
490 491 raise JSONRPCError(
491 492 'failed to add member to user group `%s`' % (
492 493 user_group.users_group_name,
493 494 )
494 495 )
495 496
496 497
497 498 @jsonrpc_method()
498 499 def remove_user_from_user_group(request, apiuser, usergroupid, userid):
499 500 """
500 501 Removes a user from a user group.
501 502
502 503 * If the specified user is not in the group, this command will return
503 504 `false`.
504 505
505 506 This command can only be run using an |authtoken| with admin rights to
506 507 the specified user group.
507 508
508 509 :param apiuser: This is filled automatically from the |authtoken|.
509 510 :type apiuser: AuthUser
510 511 :param usergroupid: Sets the user group name.
511 512 :type usergroupid: str or int
512 513 :param userid: The user you wish to remove from |RCE|.
513 514 :type userid: str or int
514 515
515 516 Example output:
516 517
517 518 .. code-block:: bash
518 519
519 520 id : <id_given_in_input>
520 521 result: {
521 522 "success": True|False, # depends on if member is in group
522 523 "msg": "removed member <username> from user group <groupname> |
523 524 User wasn't in group"
524 525 }
525 526 error: null
526 527
527 528 """
528 529
529 530 user = get_user_or_error(userid)
530 531 user_group = get_user_group_or_error(usergroupid)
531 532 if not has_superadmin_permission(apiuser):
532 533 # check if we have admin permission for this user group !
533 534 _perms = ('usergroup.admin',)
534 535 if not HasUserGroupPermissionAnyApi(*_perms)(
535 536 user=apiuser, user_group_name=user_group.users_group_name):
536 537 raise JSONRPCError(
537 538 'user group `%s` does not exist' % (usergroupid,))
538 539
539 540 old_values = user_group.get_api_data()
540 541 try:
541 542 success = UserGroupModel().remove_user_from_group(user_group, user)
542 543 msg = 'removed member `%s` from user group `%s`' % (
543 544 user.username, user_group.users_group_name
544 545 )
545 546 msg = msg if success else "User wasn't in group"
546 547 if success:
547 548 user_data = user.get_api_data()
548 549 audit_logger.store_api(
549 550 'user_group.edit.member.delete',
550 551 action_data={'user': user_data, 'old_data': old_values},
551 552 user=apiuser)
552 553
553 554 Session().commit()
554 555 return {'success': success, 'msg': msg}
555 556 except Exception:
556 557 log.exception("Error occurred during removing an member from user group")
557 558 raise JSONRPCError(
558 559 'failed to remove member from user group `%s`' % (
559 560 user_group.users_group_name,
560 561 )
561 562 )
562 563
563 564
564 565 @jsonrpc_method()
565 566 def grant_user_permission_to_user_group(
566 567 request, apiuser, usergroupid, userid, perm):
567 568 """
568 569 Set permissions for a user in a user group.
569 570
570 571 :param apiuser: This is filled automatically from the |authtoken|.
571 572 :type apiuser: AuthUser
572 573 :param usergroupid: Set the user group to edit permissions on.
573 574 :type usergroupid: str or int
574 575 :param userid: Set the user from whom you wish to set permissions.
575 576 :type userid: str
576 577 :param perm: (usergroup.(none|read|write|admin))
577 578 :type perm: str
578 579
579 580 Example output:
580 581
581 582 .. code-block:: bash
582 583
583 584 id : <id_given_in_input>
584 585 result : {
585 586 "msg": "Granted perm: `<perm_name>` for user: `<username>` in user group: `<user_group_name>`",
586 587 "success": true
587 588 }
588 589 error : null
589 590 """
590 591
591 592 user_group = get_user_group_or_error(usergroupid)
592 593
593 594 if not has_superadmin_permission(apiuser):
594 595 # check if we have admin permission for this user group !
595 596 _perms = ('usergroup.admin',)
596 597 if not HasUserGroupPermissionAnyApi(*_perms)(
597 598 user=apiuser, user_group_name=user_group.users_group_name):
598 599 raise JSONRPCError(
599 600 'user group `%s` does not exist' % (usergroupid,))
600 601
601 602 user = get_user_or_error(userid)
602 603 perm = get_perm_or_error(perm, prefix='usergroup.')
603 604
604 605 try:
605 606 UserGroupModel().grant_user_permission(
606 607 user_group=user_group, user=user, perm=perm)
607 608 Session().commit()
608 609 return {
609 610 'msg':
610 611 'Granted perm: `%s` for user: `%s` in user group: `%s`' % (
611 612 perm.permission_name, user.username,
612 613 user_group.users_group_name
613 614 ),
614 615 'success': True
615 616 }
616 617 except Exception:
617 618 log.exception("Error occurred during editing permissions "
618 619 "for user in user group")
619 620 raise JSONRPCError(
620 621 'failed to edit permission for user: '
621 622 '`%s` in user group: `%s`' % (
622 623 userid, user_group.users_group_name))
623 624
624 625
625 626 @jsonrpc_method()
626 627 def revoke_user_permission_from_user_group(
627 628 request, apiuser, usergroupid, userid):
628 629 """
629 630 Revoke a users permissions in a user group.
630 631
631 632 :param apiuser: This is filled automatically from the |authtoken|.
632 633 :type apiuser: AuthUser
633 634 :param usergroupid: Set the user group from which to revoke the user
634 635 permissions.
635 636 :type: usergroupid: str or int
636 637 :param userid: Set the userid of the user whose permissions will be
637 638 revoked.
638 639 :type userid: str
639 640
640 641 Example output:
641 642
642 643 .. code-block:: bash
643 644
644 645 id : <id_given_in_input>
645 646 result : {
646 647 "msg": "Revoked perm for user: `<username>` in user group: `<user_group_name>`",
647 648 "success": true
648 649 }
649 650 error : null
650 651 """
651 652
652 653 user_group = get_user_group_or_error(usergroupid)
653 654
654 655 if not has_superadmin_permission(apiuser):
655 656 # check if we have admin permission for this user group !
656 657 _perms = ('usergroup.admin',)
657 658 if not HasUserGroupPermissionAnyApi(*_perms)(
658 659 user=apiuser, user_group_name=user_group.users_group_name):
659 660 raise JSONRPCError(
660 661 'user group `%s` does not exist' % (usergroupid,))
661 662
662 663 user = get_user_or_error(userid)
663 664
664 665 try:
665 666 UserGroupModel().revoke_user_permission(
666 667 user_group=user_group, user=user)
667 668 Session().commit()
668 669 return {
669 670 'msg': 'Revoked perm for user: `%s` in user group: `%s`' % (
670 671 user.username, user_group.users_group_name
671 672 ),
672 673 'success': True
673 674 }
674 675 except Exception:
675 676 log.exception("Error occurred during editing permissions "
676 677 "for user in user group")
677 678 raise JSONRPCError(
678 679 'failed to edit permission for user: `%s` in user group: `%s`'
679 680 % (userid, user_group.users_group_name))
680 681
681 682
682 683 @jsonrpc_method()
683 684 def grant_user_group_permission_to_user_group(
684 685 request, apiuser, usergroupid, sourceusergroupid, perm):
685 686 """
686 687 Give one user group permissions to another user group.
687 688
688 689 :param apiuser: This is filled automatically from the |authtoken|.
689 690 :type apiuser: AuthUser
690 691 :param usergroupid: Set the user group on which to edit permissions.
691 692 :type usergroupid: str or int
692 693 :param sourceusergroupid: Set the source user group to which
693 694 access/permissions will be granted.
694 695 :type sourceusergroupid: str or int
695 696 :param perm: (usergroup.(none|read|write|admin))
696 697 :type perm: str
697 698
698 699 Example output:
699 700
700 701 .. code-block:: bash
701 702
702 703 id : <id_given_in_input>
703 704 result : {
704 705 "msg": "Granted perm: `<perm_name>` for user group: `<source_user_group_name>` in user group: `<user_group_name>`",
705 706 "success": true
706 707 }
707 708 error : null
708 709 """
709 710
710 711 user_group = get_user_group_or_error(sourceusergroupid)
711 712 target_user_group = get_user_group_or_error(usergroupid)
712 713 perm = get_perm_or_error(perm, prefix='usergroup.')
713 714
714 715 if not has_superadmin_permission(apiuser):
715 716 # check if we have admin permission for this user group !
716 717 _perms = ('usergroup.admin',)
717 718 if not HasUserGroupPermissionAnyApi(*_perms)(
718 719 user=apiuser,
719 720 user_group_name=target_user_group.users_group_name):
720 721 raise JSONRPCError(
721 722 'to user group `%s` does not exist' % (usergroupid,))
722 723
723 724 # check if we have at least read permission for source user group !
724 725 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
725 726 if not HasUserGroupPermissionAnyApi(*_perms)(
726 727 user=apiuser, user_group_name=user_group.users_group_name):
727 728 raise JSONRPCError(
728 729 'user group `%s` does not exist' % (sourceusergroupid,))
729 730
730 731 try:
731 732 UserGroupModel().grant_user_group_permission(
732 733 target_user_group=target_user_group,
733 734 user_group=user_group, perm=perm)
734 735 Session().commit()
735 736
736 737 return {
737 738 'msg': 'Granted perm: `%s` for user group: `%s` '
738 739 'in user group: `%s`' % (
739 740 perm.permission_name, user_group.users_group_name,
740 741 target_user_group.users_group_name
741 742 ),
742 743 'success': True
743 744 }
744 745 except Exception:
745 746 log.exception("Error occurred during editing permissions "
746 747 "for user group in user group")
747 748 raise JSONRPCError(
748 749 'failed to edit permission for user group: `%s` in '
749 750 'user group: `%s`' % (
750 751 sourceusergroupid, target_user_group.users_group_name
751 752 )
752 753 )
753 754
754 755
755 756 @jsonrpc_method()
756 757 def revoke_user_group_permission_from_user_group(
757 758 request, apiuser, usergroupid, sourceusergroupid):
758 759 """
759 760 Revoke the permissions that one user group has to another.
760 761
761 762 :param apiuser: This is filled automatically from the |authtoken|.
762 763 :type apiuser: AuthUser
763 764 :param usergroupid: Set the user group on which to edit permissions.
764 765 :type usergroupid: str or int
765 766 :param sourceusergroupid: Set the user group from which permissions
766 767 are revoked.
767 768 :type sourceusergroupid: str or int
768 769
769 770 Example output:
770 771
771 772 .. code-block:: bash
772 773
773 774 id : <id_given_in_input>
774 775 result : {
775 776 "msg": "Revoked perm for user group: `<user_group_name>` in user group: `<target_user_group_name>`",
776 777 "success": true
777 778 }
778 779 error : null
779 780 """
780 781
781 782 user_group = get_user_group_or_error(sourceusergroupid)
782 783 target_user_group = get_user_group_or_error(usergroupid)
783 784
784 785 if not has_superadmin_permission(apiuser):
785 786 # check if we have admin permission for this user group !
786 787 _perms = ('usergroup.admin',)
787 788 if not HasUserGroupPermissionAnyApi(*_perms)(
788 789 user=apiuser,
789 790 user_group_name=target_user_group.users_group_name):
790 791 raise JSONRPCError(
791 792 'to user group `%s` does not exist' % (usergroupid,))
792 793
793 794 # check if we have at least read permission
794 795 # for the source user group !
795 796 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
796 797 if not HasUserGroupPermissionAnyApi(*_perms)(
797 798 user=apiuser, user_group_name=user_group.users_group_name):
798 799 raise JSONRPCError(
799 800 'user group `%s` does not exist' % (sourceusergroupid,))
800 801
801 802 try:
802 803 UserGroupModel().revoke_user_group_permission(
803 804 target_user_group=target_user_group, user_group=user_group)
804 805 Session().commit()
805 806
806 807 return {
807 808 'msg': 'Revoked perm for user group: '
808 809 '`%s` in user group: `%s`' % (
809 810 user_group.users_group_name,
810 811 target_user_group.users_group_name
811 812 ),
812 813 'success': True
813 814 }
814 815 except Exception:
815 816 log.exception("Error occurred during editing permissions "
816 817 "for user group in user group")
817 818 raise JSONRPCError(
818 819 'failed to edit permission for user group: '
819 820 '`%s` in user group: `%s`' % (
820 821 sourceusergroupid, target_user_group.users_group_name
821 822 )
822 823 )
@@ -1,546 +1,519 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import logging
22 22
23 23 import peppercorn
24 24 import formencode
25 25 import formencode.htmlfill
26 26 from pyramid.httpexceptions import HTTPFound
27 27 from pyramid.view import view_config
28 28 from pyramid.response import Response
29 29 from pyramid.renderers import render
30 30
31 31 from rhodecode.lib.exceptions import (
32 32 RepoGroupAssignmentError, UserGroupAssignedException)
33 33 from rhodecode.model.forms import (
34 34 UserGroupPermsForm, UserGroupForm, UserIndividualPermissionsForm,
35 35 UserPermissionsForm)
36 36 from rhodecode.model.permission import PermissionModel
37 37
38 38 from rhodecode.apps._base import UserGroupAppView
39 39 from rhodecode.lib.auth import (
40 40 LoginRequired, HasUserGroupPermissionAnyDecorator, CSRFRequired)
41 41 from rhodecode.lib import helpers as h, audit_logger
42 42 from rhodecode.lib.utils2 import str2bool
43 from rhodecode.model.db import (
44 joinedload, User, UserGroupRepoToPerm, UserGroupRepoGroupToPerm)
43 from rhodecode.model.db import User
45 44 from rhodecode.model.meta import Session
46 45 from rhodecode.model.user_group import UserGroupModel
47 46
48 47 log = logging.getLogger(__name__)
49 48
50 49
51 50 class UserGroupsView(UserGroupAppView):
52 51
53 52 def load_default_context(self):
54 53 c = self._get_local_tmpl_context()
55 54
56 55 PermissionModel().set_global_permission_choices(
57 56 c, gettext_translator=self.request.translate)
58 57
59
60 58 return c
61 59
62 def _get_perms_summary(self, user_group_id):
63 permissions = {
64 'repositories': {},
65 'repositories_groups': {},
66 }
67 ugroup_repo_perms = UserGroupRepoToPerm.query()\
68 .options(joinedload(UserGroupRepoToPerm.permission))\
69 .options(joinedload(UserGroupRepoToPerm.repository))\
70 .filter(UserGroupRepoToPerm.users_group_id == user_group_id)\
71 .all()
72
73 for gr in ugroup_repo_perms:
74 permissions['repositories'][gr.repository.repo_name] \
75 = gr.permission.permission_name
76
77 ugroup_group_perms = UserGroupRepoGroupToPerm.query()\
78 .options(joinedload(UserGroupRepoGroupToPerm.permission))\
79 .options(joinedload(UserGroupRepoGroupToPerm.group))\
80 .filter(UserGroupRepoGroupToPerm.users_group_id == user_group_id)\
81 .all()
82
83 for gr in ugroup_group_perms:
84 permissions['repositories_groups'][gr.group.group_name] \
85 = gr.permission.permission_name
86 return permissions
87
88 60 @LoginRequired()
89 61 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
90 62 @view_config(
91 63 route_name='user_group_members_data', request_method='GET',
92 64 renderer='json_ext', xhr=True)
93 65 def user_group_members(self):
94 66 """
95 67 Return members of given user group
96 68 """
97 69 self.load_default_context()
98 70 user_group = self.db_user_group
99 71 group_members_obj = sorted((x.user for x in user_group.members),
100 72 key=lambda u: u.username.lower())
101 73
102 74 group_members = [
103 75 {
104 76 'id': user.user_id,
105 77 'first_name': user.first_name,
106 78 'last_name': user.last_name,
107 79 'username': user.username,
108 80 'icon_link': h.gravatar_url(user.email, 30),
109 81 'value_display': h.person(user.email),
110 82 'value': user.username,
111 83 'value_type': 'user',
112 84 'active': user.active,
113 85 }
114 86 for user in group_members_obj
115 87 ]
116 88
117 89 return {
118 90 'members': group_members
119 91 }
120 92
121 93 @LoginRequired()
122 94 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
123 95 @view_config(
124 96 route_name='edit_user_group_perms_summary', request_method='GET',
125 97 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
126 98 def user_group_perms_summary(self):
127 99 c = self.load_default_context()
128 100 c.user_group = self.db_user_group
129 101 c.active = 'perms_summary'
130 c.permissions = self._get_perms_summary(c.user_group.users_group_id)
102 c.permissions = UserGroupModel().get_perms_summary(
103 c.user_group.users_group_id)
131 104 return self._get_template_context(c)
132 105
133 106 @LoginRequired()
134 107 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
135 108 @view_config(
136 109 route_name='edit_user_group_perms_summary_json', request_method='GET',
137 110 renderer='json_ext')
138 111 def user_group_perms_summary_json(self):
139 112 self.load_default_context()
140 113 user_group = self.db_user_group
141 return self._get_perms_summary(user_group.users_group_id)
114 return UserGroupModel().get_perms_summary(user_group.users_group_id)
142 115
143 116 def _revoke_perms_on_yourself(self, form_result):
144 117 _updates = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
145 118 form_result['perm_updates'])
146 119 _additions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
147 120 form_result['perm_additions'])
148 121 _deletions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
149 122 form_result['perm_deletions'])
150 123 admin_perm = 'usergroup.admin'
151 124 if _updates and _updates[0][1] != admin_perm or \
152 125 _additions and _additions[0][1] != admin_perm or \
153 126 _deletions and _deletions[0][1] != admin_perm:
154 127 return True
155 128 return False
156 129
157 130 @LoginRequired()
158 131 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
159 132 @CSRFRequired()
160 133 @view_config(
161 134 route_name='user_groups_update', request_method='POST',
162 135 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
163 136 def user_group_update(self):
164 137 _ = self.request.translate
165 138
166 139 user_group = self.db_user_group
167 140 user_group_id = user_group.users_group_id
168 141
169 142 c = self.load_default_context()
170 143 c.user_group = user_group
171 144 c.group_members_obj = [x.user for x in c.user_group.members]
172 145 c.group_members_obj.sort(key=lambda u: u.username.lower())
173 146 c.group_members = [(x.user_id, x.username) for x in c.group_members_obj]
174 147 c.active = 'settings'
175 148
176 149 users_group_form = UserGroupForm(
177 150 self.request.translate, edit=True,
178 151 old_data=c.user_group.get_dict(), allow_disabled=True)()
179 152
180 153 old_values = c.user_group.get_api_data()
181 154 user_group_name = self.request.POST.get('users_group_name')
182 155 try:
183 156 form_result = users_group_form.to_python(self.request.POST)
184 157 pstruct = peppercorn.parse(self.request.POST.items())
185 158 form_result['users_group_members'] = pstruct['user_group_members']
186 159
187 160 user_group, added_members, removed_members = \
188 161 UserGroupModel().update(c.user_group, form_result)
189 162 updated_user_group = form_result['users_group_name']
190 163
191 164 for user_id in added_members:
192 165 user = User.get(user_id)
193 166 user_data = user.get_api_data()
194 167 audit_logger.store_web(
195 168 'user_group.edit.member.add',
196 169 action_data={'user': user_data, 'old_data': old_values},
197 170 user=self._rhodecode_user)
198 171
199 172 for user_id in removed_members:
200 173 user = User.get(user_id)
201 174 user_data = user.get_api_data()
202 175 audit_logger.store_web(
203 176 'user_group.edit.member.delete',
204 177 action_data={'user': user_data, 'old_data': old_values},
205 178 user=self._rhodecode_user)
206 179
207 180 audit_logger.store_web(
208 181 'user_group.edit', action_data={'old_data': old_values},
209 182 user=self._rhodecode_user)
210 183
211 184 h.flash(_('Updated user group %s') % updated_user_group,
212 185 category='success')
213 186 Session().commit()
214 187 except formencode.Invalid as errors:
215 188 defaults = errors.value
216 189 e = errors.error_dict or {}
217 190
218 191 data = render(
219 192 'rhodecode:templates/admin/user_groups/user_group_edit.mako',
220 193 self._get_template_context(c), self.request)
221 194 html = formencode.htmlfill.render(
222 195 data,
223 196 defaults=defaults,
224 197 errors=e,
225 198 prefix_error=False,
226 199 encoding="UTF-8",
227 200 force_defaults=False
228 201 )
229 202 return Response(html)
230 203
231 204 except Exception:
232 205 log.exception("Exception during update of user group")
233 206 h.flash(_('Error occurred during update of user group %s')
234 207 % user_group_name, category='error')
235 208
236 209 raise HTTPFound(
237 210 h.route_path('edit_user_group', user_group_id=user_group_id))
238 211
239 212 @LoginRequired()
240 213 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
241 214 @CSRFRequired()
242 215 @view_config(
243 216 route_name='user_groups_delete', request_method='POST',
244 217 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
245 218 def user_group_delete(self):
246 219 _ = self.request.translate
247 220 user_group = self.db_user_group
248 221
249 222 self.load_default_context()
250 223 force = str2bool(self.request.POST.get('force'))
251 224
252 225 old_values = user_group.get_api_data()
253 226 try:
254 227 UserGroupModel().delete(user_group, force=force)
255 228 audit_logger.store_web(
256 229 'user.delete', action_data={'old_data': old_values},
257 230 user=self._rhodecode_user)
258 231 Session().commit()
259 232 h.flash(_('Successfully deleted user group'), category='success')
260 233 except UserGroupAssignedException as e:
261 234 h.flash(str(e), category='error')
262 235 except Exception:
263 236 log.exception("Exception during deletion of user group")
264 237 h.flash(_('An error occurred during deletion of user group'),
265 238 category='error')
266 239 raise HTTPFound(h.route_path('user_groups'))
267 240
268 241 @LoginRequired()
269 242 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
270 243 @view_config(
271 244 route_name='edit_user_group', request_method='GET',
272 245 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
273 246 def user_group_edit(self):
274 247 user_group = self.db_user_group
275 248
276 249 c = self.load_default_context()
277 250 c.user_group = user_group
278 251 c.group_members_obj = [x.user for x in c.user_group.members]
279 252 c.group_members_obj.sort(key=lambda u: u.username.lower())
280 253 c.group_members = [(x.user_id, x.username) for x in c.group_members_obj]
281 254
282 255 c.active = 'settings'
283 256
284 257 defaults = user_group.get_dict()
285 258 # fill owner
286 259 if user_group.user:
287 260 defaults.update({'user': user_group.user.username})
288 261 else:
289 262 replacement_user = User.get_first_super_admin().username
290 263 defaults.update({'user': replacement_user})
291 264
292 265 data = render(
293 266 'rhodecode:templates/admin/user_groups/user_group_edit.mako',
294 267 self._get_template_context(c), self.request)
295 268 html = formencode.htmlfill.render(
296 269 data,
297 270 defaults=defaults,
298 271 encoding="UTF-8",
299 272 force_defaults=False
300 273 )
301 274 return Response(html)
302 275
303 276 @LoginRequired()
304 277 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
305 278 @view_config(
306 279 route_name='edit_user_group_perms', request_method='GET',
307 280 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
308 281 def user_group_edit_perms(self):
309 282 user_group = self.db_user_group
310 283 c = self.load_default_context()
311 284 c.user_group = user_group
312 285 c.active = 'perms'
313 286
314 287 defaults = {}
315 288 # fill user group users
316 289 for p in c.user_group.user_user_group_to_perm:
317 290 defaults.update({'u_perm_%s' % p.user.user_id:
318 291 p.permission.permission_name})
319 292
320 293 for p in c.user_group.user_group_user_group_to_perm:
321 294 defaults.update({'g_perm_%s' % p.user_group.users_group_id:
322 295 p.permission.permission_name})
323 296
324 297 data = render(
325 298 'rhodecode:templates/admin/user_groups/user_group_edit.mako',
326 299 self._get_template_context(c), self.request)
327 300 html = formencode.htmlfill.render(
328 301 data,
329 302 defaults=defaults,
330 303 encoding="UTF-8",
331 304 force_defaults=False
332 305 )
333 306 return Response(html)
334 307
335 308 @LoginRequired()
336 309 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
337 310 @CSRFRequired()
338 311 @view_config(
339 312 route_name='edit_user_group_perms_update', request_method='POST',
340 313 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
341 314 def user_group_update_perms(self):
342 315 """
343 316 grant permission for given user group
344 317 """
345 318 _ = self.request.translate
346 319
347 320 user_group = self.db_user_group
348 321 user_group_id = user_group.users_group_id
349 322 c = self.load_default_context()
350 323 c.user_group = user_group
351 324 form = UserGroupPermsForm(self.request.translate)().to_python(self.request.POST)
352 325
353 326 if not self._rhodecode_user.is_admin:
354 327 if self._revoke_perms_on_yourself(form):
355 328 msg = _('Cannot change permission for yourself as admin')
356 329 h.flash(msg, category='warning')
357 330 raise HTTPFound(
358 331 h.route_path('edit_user_group_perms',
359 332 user_group_id=user_group_id))
360 333
361 334 try:
362 335 changes = UserGroupModel().update_permissions(
363 336 user_group_id,
364 337 form['perm_additions'], form['perm_updates'],
365 338 form['perm_deletions'])
366 339
367 340 except RepoGroupAssignmentError:
368 341 h.flash(_('Target group cannot be the same'), category='error')
369 342 raise HTTPFound(
370 343 h.route_path('edit_user_group_perms',
371 344 user_group_id=user_group_id))
372 345
373 346 action_data = {
374 347 'added': changes['added'],
375 348 'updated': changes['updated'],
376 349 'deleted': changes['deleted'],
377 350 }
378 351 audit_logger.store_web(
379 352 'user_group.edit.permissions', action_data=action_data,
380 353 user=self._rhodecode_user)
381 354
382 355 Session().commit()
383 356 h.flash(_('User Group permissions updated'), category='success')
384 357 raise HTTPFound(
385 358 h.route_path('edit_user_group_perms', user_group_id=user_group_id))
386 359
387 360 @LoginRequired()
388 361 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
389 362 @view_config(
390 363 route_name='edit_user_group_global_perms', request_method='GET',
391 364 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
392 365 def user_group_global_perms_edit(self):
393 366 user_group = self.db_user_group
394 367 c = self.load_default_context()
395 368 c.user_group = user_group
396 369 c.active = 'global_perms'
397 370
398 371 c.default_user = User.get_default_user()
399 372 defaults = c.user_group.get_dict()
400 373 defaults.update(c.default_user.get_default_perms(suffix='_inherited'))
401 374 defaults.update(c.user_group.get_default_perms())
402 375
403 376 data = render(
404 377 'rhodecode:templates/admin/user_groups/user_group_edit.mako',
405 378 self._get_template_context(c), self.request)
406 379 html = formencode.htmlfill.render(
407 380 data,
408 381 defaults=defaults,
409 382 encoding="UTF-8",
410 383 force_defaults=False
411 384 )
412 385 return Response(html)
413 386
414 387 @LoginRequired()
415 388 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
416 389 @CSRFRequired()
417 390 @view_config(
418 391 route_name='edit_user_group_global_perms_update', request_method='POST',
419 392 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
420 393 def user_group_global_perms_update(self):
421 394 _ = self.request.translate
422 395 user_group = self.db_user_group
423 396 user_group_id = self.db_user_group.users_group_id
424 397
425 398 c = self.load_default_context()
426 399 c.user_group = user_group
427 400 c.active = 'global_perms'
428 401
429 402 try:
430 403 # first stage that verifies the checkbox
431 404 _form = UserIndividualPermissionsForm(self.request.translate)
432 405 form_result = _form.to_python(dict(self.request.POST))
433 406 inherit_perms = form_result['inherit_default_permissions']
434 407 user_group.inherit_default_permissions = inherit_perms
435 408 Session().add(user_group)
436 409
437 410 if not inherit_perms:
438 411 # only update the individual ones if we un check the flag
439 412 _form = UserPermissionsForm(
440 413 self.request.translate,
441 414 [x[0] for x in c.repo_create_choices],
442 415 [x[0] for x in c.repo_create_on_write_choices],
443 416 [x[0] for x in c.repo_group_create_choices],
444 417 [x[0] for x in c.user_group_create_choices],
445 418 [x[0] for x in c.fork_choices],
446 419 [x[0] for x in c.inherit_default_permission_choices])()
447 420
448 421 form_result = _form.to_python(dict(self.request.POST))
449 422 form_result.update(
450 423 {'perm_user_group_id': user_group.users_group_id})
451 424
452 425 PermissionModel().update_user_group_permissions(form_result)
453 426
454 427 Session().commit()
455 428 h.flash(_('User Group global permissions updated successfully'),
456 429 category='success')
457 430
458 431 except formencode.Invalid as errors:
459 432 defaults = errors.value
460 433
461 434 data = render(
462 435 'rhodecode:templates/admin/user_groups/user_group_edit.mako',
463 436 self._get_template_context(c), self.request)
464 437 html = formencode.htmlfill.render(
465 438 data,
466 439 defaults=defaults,
467 440 errors=errors.error_dict or {},
468 441 prefix_error=False,
469 442 encoding="UTF-8",
470 443 force_defaults=False
471 444 )
472 445 return Response(html)
473 446 except Exception:
474 447 log.exception("Exception during permissions saving")
475 448 h.flash(_('An error occurred during permissions saving'),
476 449 category='error')
477 450
478 451 raise HTTPFound(
479 452 h.route_path('edit_user_group_global_perms',
480 453 user_group_id=user_group_id))
481 454
482 455 @LoginRequired()
483 456 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
484 457 @view_config(
485 458 route_name='edit_user_group_advanced', request_method='GET',
486 459 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
487 460 def user_group_edit_advanced(self):
488 461 user_group = self.db_user_group
489 462
490 463 c = self.load_default_context()
491 464 c.user_group = user_group
492 465 c.active = 'advanced'
493 466 c.group_members_obj = sorted(
494 467 (x.user for x in c.user_group.members),
495 468 key=lambda u: u.username.lower())
496 469
497 470 c.group_to_repos = sorted(
498 471 (x.repository for x in c.user_group.users_group_repo_to_perm),
499 472 key=lambda u: u.repo_name.lower())
500 473
501 474 c.group_to_repo_groups = sorted(
502 475 (x.group for x in c.user_group.users_group_repo_group_to_perm),
503 476 key=lambda u: u.group_name.lower())
504 477
505 478 c.group_to_review_rules = sorted(
506 479 (x.users_group for x in c.user_group.user_group_review_rules),
507 480 key=lambda u: u.users_group_name.lower())
508 481
509 482 return self._get_template_context(c)
510 483
511 484 @LoginRequired()
512 485 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
513 486 @CSRFRequired()
514 487 @view_config(
515 488 route_name='edit_user_group_advanced_sync', request_method='POST',
516 489 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
517 490 def user_group_edit_advanced_set_synchronization(self):
518 491 _ = self.request.translate
519 492 user_group = self.db_user_group
520 493 user_group_id = user_group.users_group_id
521 494
522 495 existing = user_group.group_data.get('extern_type')
523 496
524 497 if existing:
525 498 new_state = user_group.group_data
526 499 new_state['extern_type'] = None
527 500 else:
528 501 new_state = user_group.group_data
529 502 new_state['extern_type'] = 'manual'
530 503 new_state['extern_type_set_by'] = self._rhodecode_user.username
531 504
532 505 try:
533 506 user_group.group_data = new_state
534 507 Session().add(user_group)
535 508 Session().commit()
536 509
537 510 h.flash(_('User Group synchronization updated successfully'),
538 511 category='success')
539 512 except Exception:
540 513 log.exception("Exception during sync settings saving")
541 514 h.flash(_('An error occurred during synchronization update'),
542 515 category='error')
543 516
544 517 raise HTTPFound(
545 518 h.route_path('edit_user_group_advanced',
546 519 user_group_id=user_group_id))
@@ -1,647 +1,673 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2011-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import logging
22 22 import traceback
23 23
24 24 from rhodecode.lib.utils2 import safe_str, safe_unicode
25 25 from rhodecode.lib.exceptions import (
26 26 UserGroupAssignedException, RepoGroupAssignmentError)
27 27 from rhodecode.lib.utils2 import (
28 28 get_current_rhodecode_user, action_logger_generic)
29 29 from rhodecode.model import BaseModel
30 30 from rhodecode.model.scm import UserGroupList
31 31 from rhodecode.model.db import (
32 true, func, User, UserGroupMember, UserGroup,
32 joinedload, true, func, User, UserGroupMember, UserGroup,
33 33 UserGroupRepoToPerm, Permission, UserGroupToPerm, UserUserGroupToPerm,
34 34 UserGroupUserGroupToPerm, UserGroupRepoGroupToPerm)
35 35
36 36
37 37 log = logging.getLogger(__name__)
38 38
39 39
40 40 class UserGroupModel(BaseModel):
41 41
42 42 cls = UserGroup
43 43
44 44 def _get_user_group(self, user_group):
45 45 return self._get_instance(UserGroup, user_group,
46 46 callback=UserGroup.get_by_group_name)
47 47
48 48 def _create_default_perms(self, user_group):
49 49 # create default permission
50 50 default_perm = 'usergroup.read'
51 51 def_user = User.get_default_user()
52 52 for p in def_user.user_perms:
53 53 if p.permission.permission_name.startswith('usergroup.'):
54 54 default_perm = p.permission.permission_name
55 55 break
56 56
57 57 user_group_to_perm = UserUserGroupToPerm()
58 58 user_group_to_perm.permission = Permission.get_by_key(default_perm)
59 59
60 60 user_group_to_perm.user_group = user_group
61 61 user_group_to_perm.user_id = def_user.user_id
62 62 return user_group_to_perm
63 63
64 64 def update_permissions(
65 65 self, user_group, perm_additions=None, perm_updates=None,
66 66 perm_deletions=None, check_perms=True, cur_user=None):
67 67
68 68 from rhodecode.lib.auth import HasUserGroupPermissionAny
69 69 if not perm_additions:
70 70 perm_additions = []
71 71 if not perm_updates:
72 72 perm_updates = []
73 73 if not perm_deletions:
74 74 perm_deletions = []
75 75
76 76 req_perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin')
77 77
78 78 changes = {
79 79 'added': [],
80 80 'updated': [],
81 81 'deleted': []
82 82 }
83 83 # update permissions
84 84 for member_id, perm, member_type in perm_updates:
85 85 member_id = int(member_id)
86 86 if member_type == 'user':
87 87 member_name = User.get(member_id).username
88 88 # this updates existing one
89 89 self.grant_user_permission(
90 90 user_group=user_group, user=member_id, perm=perm
91 91 )
92 92 else:
93 93 # check if we have permissions to alter this usergroup
94 94 member_name = UserGroup.get(member_id).users_group_name
95 95 if not check_perms or HasUserGroupPermissionAny(
96 96 *req_perms)(member_name, user=cur_user):
97 97 self.grant_user_group_permission(
98 98 target_user_group=user_group, user_group=member_id, perm=perm)
99 99
100 100 changes['updated'].append({'type': member_type, 'id': member_id,
101 101 'name': member_name, 'new_perm': perm})
102 102
103 103 # set new permissions
104 104 for member_id, perm, member_type in perm_additions:
105 105 member_id = int(member_id)
106 106 if member_type == 'user':
107 107 member_name = User.get(member_id).username
108 108 self.grant_user_permission(
109 109 user_group=user_group, user=member_id, perm=perm)
110 110 else:
111 111 # check if we have permissions to alter this usergroup
112 112 member_name = UserGroup.get(member_id).users_group_name
113 113 if not check_perms or HasUserGroupPermissionAny(
114 114 *req_perms)(member_name, user=cur_user):
115 115 self.grant_user_group_permission(
116 116 target_user_group=user_group, user_group=member_id, perm=perm)
117 117
118 118 changes['added'].append({'type': member_type, 'id': member_id,
119 119 'name': member_name, 'new_perm': perm})
120 120
121 121 # delete permissions
122 122 for member_id, perm, member_type in perm_deletions:
123 123 member_id = int(member_id)
124 124 if member_type == 'user':
125 125 member_name = User.get(member_id).username
126 126 self.revoke_user_permission(user_group=user_group, user=member_id)
127 127 else:
128 128 # check if we have permissions to alter this usergroup
129 129 member_name = UserGroup.get(member_id).users_group_name
130 130 if not check_perms or HasUserGroupPermissionAny(
131 131 *req_perms)(member_name, user=cur_user):
132 132 self.revoke_user_group_permission(
133 133 target_user_group=user_group, user_group=member_id)
134 134
135 135 changes['deleted'].append({'type': member_type, 'id': member_id,
136 136 'name': member_name, 'new_perm': perm})
137 137 return changes
138 138
139 139 def get(self, user_group_id, cache=False):
140 140 return UserGroup.get(user_group_id)
141 141
142 142 def get_group(self, user_group):
143 143 return self._get_user_group(user_group)
144 144
145 145 def get_by_name(self, name, cache=False, case_insensitive=False):
146 146 return UserGroup.get_by_group_name(name, cache, case_insensitive)
147 147
148 148 def create(self, name, description, owner, active=True, group_data=None):
149 149 try:
150 150 new_user_group = UserGroup()
151 151 new_user_group.user = self._get_user(owner)
152 152 new_user_group.users_group_name = name
153 153 new_user_group.user_group_description = description
154 154 new_user_group.users_group_active = active
155 155 if group_data:
156 156 new_user_group.group_data = group_data
157 157 self.sa.add(new_user_group)
158 158 perm_obj = self._create_default_perms(new_user_group)
159 159 self.sa.add(perm_obj)
160 160
161 161 self.grant_user_permission(user_group=new_user_group,
162 162 user=owner, perm='usergroup.admin')
163 163
164 164 return new_user_group
165 165 except Exception:
166 166 log.error(traceback.format_exc())
167 167 raise
168 168
169 169 def _get_memberships_for_user_ids(self, user_group, user_id_list):
170 170 members = []
171 171 for user_id in user_id_list:
172 172 member = self._get_membership(user_group.users_group_id, user_id)
173 173 members.append(member)
174 174 return members
175 175
176 176 def _get_added_and_removed_user_ids(self, user_group, user_id_list):
177 177 current_members = user_group.members or []
178 178 current_members_ids = [m.user.user_id for m in current_members]
179 179
180 180 added_members = [
181 181 user_id for user_id in user_id_list
182 182 if user_id not in current_members_ids]
183 183 if user_id_list == []:
184 184 # all members were deleted
185 185 deleted_members = current_members_ids
186 186 else:
187 187 deleted_members = [
188 188 user_id for user_id in current_members_ids
189 189 if user_id not in user_id_list]
190 190
191 191 return added_members, deleted_members
192 192
193 193 def _set_users_as_members(self, user_group, user_ids):
194 194 user_group.members = []
195 195 self.sa.flush()
196 196 members = self._get_memberships_for_user_ids(
197 197 user_group, user_ids)
198 198 user_group.members = members
199 199 self.sa.add(user_group)
200 200
201 201 def _update_members_from_user_ids(self, user_group, user_ids):
202 202 added, removed = self._get_added_and_removed_user_ids(
203 203 user_group, user_ids)
204 204 self._set_users_as_members(user_group, user_ids)
205 205 self._log_user_changes('added to', user_group, added)
206 206 self._log_user_changes('removed from', user_group, removed)
207 207 return added, removed
208 208
209 209 def _clean_members_data(self, members_data):
210 210 if not members_data:
211 211 members_data = []
212 212
213 213 members = []
214 214 for user in members_data:
215 215 uid = int(user['member_user_id'])
216 216 if uid not in members and user['type'] in ['new', 'existing']:
217 217 members.append(uid)
218 218 return members
219 219
220 220 def update(self, user_group, form_data):
221 221 user_group = self._get_user_group(user_group)
222 222 if 'users_group_name' in form_data:
223 223 user_group.users_group_name = form_data['users_group_name']
224 224 if 'users_group_active' in form_data:
225 225 user_group.users_group_active = form_data['users_group_active']
226 226 if 'user_group_description' in form_data:
227 227 user_group.user_group_description = form_data[
228 228 'user_group_description']
229 229
230 230 # handle owner change
231 231 if 'user' in form_data:
232 232 owner = form_data['user']
233 233 if isinstance(owner, basestring):
234 234 owner = User.get_by_username(form_data['user'])
235 235
236 236 if not isinstance(owner, User):
237 237 raise ValueError(
238 238 'invalid owner for user group: %s' % form_data['user'])
239 239
240 240 user_group.user = owner
241 241
242 242 added_user_ids = []
243 243 removed_user_ids = []
244 244 if 'users_group_members' in form_data:
245 245 members_id_list = self._clean_members_data(
246 246 form_data['users_group_members'])
247 247 added_user_ids, removed_user_ids = \
248 248 self._update_members_from_user_ids(user_group, members_id_list)
249 249
250 250 self.sa.add(user_group)
251 251 return user_group, added_user_ids, removed_user_ids
252 252
253 253 def delete(self, user_group, force=False):
254 254 """
255 255 Deletes repository group, unless force flag is used
256 256 raises exception if there are members in that group, else deletes
257 257 group and users
258 258
259 259 :param user_group:
260 260 :param force:
261 261 """
262 262 user_group = self._get_user_group(user_group)
263 263 if not user_group:
264 264 return
265 265
266 266 try:
267 267 # check if this group is not assigned to repo
268 268 assigned_to_repo = [x.repository for x in UserGroupRepoToPerm.query()\
269 269 .filter(UserGroupRepoToPerm.users_group == user_group).all()]
270 270 # check if this group is not assigned to repo
271 271 assigned_to_repo_group = [x.group for x in UserGroupRepoGroupToPerm.query()\
272 272 .filter(UserGroupRepoGroupToPerm.users_group == user_group).all()]
273 273
274 274 if (assigned_to_repo or assigned_to_repo_group) and not force:
275 275 assigned = ','.join(map(safe_str,
276 276 assigned_to_repo+assigned_to_repo_group))
277 277
278 278 raise UserGroupAssignedException(
279 279 'UserGroup assigned to %s' % (assigned,))
280 280 self.sa.delete(user_group)
281 281 except Exception:
282 282 log.error(traceback.format_exc())
283 283 raise
284 284
285 285 def _log_user_changes(self, action, user_group, user_or_users):
286 286 users = user_or_users
287 287 if not isinstance(users, (list, tuple)):
288 288 users = [users]
289 289
290 290 group_name = user_group.users_group_name
291 291
292 292 for user_or_user_id in users:
293 293 user = self._get_user(user_or_user_id)
294 294 log_text = 'User {user} {action} {group}'.format(
295 295 action=action, user=user.username, group=group_name)
296 296 action_logger_generic(log_text)
297 297
298 298 def _find_user_in_group(self, user, user_group):
299 299 user_group_member = None
300 300 for m in user_group.members:
301 301 if m.user_id == user.user_id:
302 302 # Found this user's membership row
303 303 user_group_member = m
304 304 break
305 305
306 306 return user_group_member
307 307
308 308 def _get_membership(self, user_group_id, user_id):
309 309 user_group_member = UserGroupMember(user_group_id, user_id)
310 310 return user_group_member
311 311
312 312 def add_user_to_group(self, user_group, user):
313 313 user_group = self._get_user_group(user_group)
314 314 user = self._get_user(user)
315 315 user_member = self._find_user_in_group(user, user_group)
316 316 if user_member:
317 317 # user already in the group, skip
318 318 return True
319 319
320 320 member = self._get_membership(
321 321 user_group.users_group_id, user.user_id)
322 322 user_group.members.append(member)
323 323
324 324 try:
325 325 self.sa.add(member)
326 326 except Exception:
327 327 # what could go wrong here?
328 328 log.error(traceback.format_exc())
329 329 raise
330 330
331 331 self._log_user_changes('added to', user_group, user)
332 332 return member
333 333
334 334 def remove_user_from_group(self, user_group, user):
335 335 user_group = self._get_user_group(user_group)
336 336 user = self._get_user(user)
337 337 user_group_member = self._find_user_in_group(user, user_group)
338 338
339 339 if not user_group_member:
340 340 # User isn't in that group
341 341 return False
342 342
343 343 try:
344 344 self.sa.delete(user_group_member)
345 345 except Exception:
346 346 log.error(traceback.format_exc())
347 347 raise
348 348
349 349 self._log_user_changes('removed from', user_group, user)
350 350 return True
351 351
352 352 def has_perm(self, user_group, perm):
353 353 user_group = self._get_user_group(user_group)
354 354 perm = self._get_perm(perm)
355 355
356 356 return UserGroupToPerm.query()\
357 357 .filter(UserGroupToPerm.users_group == user_group)\
358 358 .filter(UserGroupToPerm.permission == perm).scalar() is not None
359 359
360 360 def grant_perm(self, user_group, perm):
361 361 user_group = self._get_user_group(user_group)
362 362 perm = self._get_perm(perm)
363 363
364 364 # if this permission is already granted skip it
365 365 _perm = UserGroupToPerm.query()\
366 366 .filter(UserGroupToPerm.users_group == user_group)\
367 367 .filter(UserGroupToPerm.permission == perm)\
368 368 .scalar()
369 369 if _perm:
370 370 return
371 371
372 372 new = UserGroupToPerm()
373 373 new.users_group = user_group
374 374 new.permission = perm
375 375 self.sa.add(new)
376 376 return new
377 377
378 378 def revoke_perm(self, user_group, perm):
379 379 user_group = self._get_user_group(user_group)
380 380 perm = self._get_perm(perm)
381 381
382 382 obj = UserGroupToPerm.query()\
383 383 .filter(UserGroupToPerm.users_group == user_group)\
384 384 .filter(UserGroupToPerm.permission == perm).scalar()
385 385 if obj:
386 386 self.sa.delete(obj)
387 387
388 388 def grant_user_permission(self, user_group, user, perm):
389 389 """
390 390 Grant permission for user on given user group, or update
391 391 existing one if found
392 392
393 393 :param user_group: Instance of UserGroup, users_group_id,
394 394 or users_group_name
395 395 :param user: Instance of User, user_id or username
396 396 :param perm: Instance of Permission, or permission_name
397 397 """
398 398
399 399 user_group = self._get_user_group(user_group)
400 400 user = self._get_user(user)
401 401 permission = self._get_perm(perm)
402 402
403 403 # check if we have that permission already
404 404 obj = self.sa.query(UserUserGroupToPerm)\
405 405 .filter(UserUserGroupToPerm.user == user)\
406 406 .filter(UserUserGroupToPerm.user_group == user_group)\
407 407 .scalar()
408 408 if obj is None:
409 409 # create new !
410 410 obj = UserUserGroupToPerm()
411 411 obj.user_group = user_group
412 412 obj.user = user
413 413 obj.permission = permission
414 414 self.sa.add(obj)
415 415 log.debug('Granted perm %s to %s on %s', perm, user, user_group)
416 416 action_logger_generic(
417 417 'granted permission: {} to user: {} on usergroup: {}'.format(
418 418 perm, user, user_group), namespace='security.usergroup')
419 419
420 420 return obj
421 421
422 422 def revoke_user_permission(self, user_group, user):
423 423 """
424 424 Revoke permission for user on given user group
425 425
426 426 :param user_group: Instance of UserGroup, users_group_id,
427 427 or users_group name
428 428 :param user: Instance of User, user_id or username
429 429 """
430 430
431 431 user_group = self._get_user_group(user_group)
432 432 user = self._get_user(user)
433 433
434 434 obj = self.sa.query(UserUserGroupToPerm)\
435 435 .filter(UserUserGroupToPerm.user == user)\
436 436 .filter(UserUserGroupToPerm.user_group == user_group)\
437 437 .scalar()
438 438 if obj:
439 439 self.sa.delete(obj)
440 440 log.debug('Revoked perm on %s on %s', user_group, user)
441 441 action_logger_generic(
442 442 'revoked permission from user: {} on usergroup: {}'.format(
443 443 user, user_group), namespace='security.usergroup')
444 444
445 445 def grant_user_group_permission(self, target_user_group, user_group, perm):
446 446 """
447 447 Grant user group permission for given target_user_group
448 448
449 449 :param target_user_group:
450 450 :param user_group:
451 451 :param perm:
452 452 """
453 453 target_user_group = self._get_user_group(target_user_group)
454 454 user_group = self._get_user_group(user_group)
455 455 permission = self._get_perm(perm)
456 456 # forbid assigning same user group to itself
457 457 if target_user_group == user_group:
458 458 raise RepoGroupAssignmentError('target repo:%s cannot be '
459 459 'assigned to itself' % target_user_group)
460 460
461 461 # check if we have that permission already
462 462 obj = self.sa.query(UserGroupUserGroupToPerm)\
463 463 .filter(UserGroupUserGroupToPerm.target_user_group == target_user_group)\
464 464 .filter(UserGroupUserGroupToPerm.user_group == user_group)\
465 465 .scalar()
466 466 if obj is None:
467 467 # create new !
468 468 obj = UserGroupUserGroupToPerm()
469 469 obj.user_group = user_group
470 470 obj.target_user_group = target_user_group
471 471 obj.permission = permission
472 472 self.sa.add(obj)
473 473 log.debug(
474 474 'Granted perm %s to %s on %s', perm, target_user_group, user_group)
475 475 action_logger_generic(
476 476 'granted permission: {} to usergroup: {} on usergroup: {}'.format(
477 477 perm, user_group, target_user_group),
478 478 namespace='security.usergroup')
479 479
480 480 return obj
481 481
482 482 def revoke_user_group_permission(self, target_user_group, user_group):
483 483 """
484 484 Revoke user group permission for given target_user_group
485 485
486 486 :param target_user_group:
487 487 :param user_group:
488 488 """
489 489 target_user_group = self._get_user_group(target_user_group)
490 490 user_group = self._get_user_group(user_group)
491 491
492 492 obj = self.sa.query(UserGroupUserGroupToPerm)\
493 493 .filter(UserGroupUserGroupToPerm.target_user_group == target_user_group)\
494 494 .filter(UserGroupUserGroupToPerm.user_group == user_group)\
495 495 .scalar()
496 496 if obj:
497 497 self.sa.delete(obj)
498 498 log.debug(
499 499 'Revoked perm on %s on %s', target_user_group, user_group)
500 500 action_logger_generic(
501 501 'revoked permission from usergroup: {} on usergroup: {}'.format(
502 502 user_group, target_user_group),
503 503 namespace='security.repogroup')
504 504
505 def get_perms_summary(self, user_group_id):
506 permissions = {
507 'repositories': {},
508 'repositories_groups': {},
509 }
510 ugroup_repo_perms = UserGroupRepoToPerm.query()\
511 .options(joinedload(UserGroupRepoToPerm.permission))\
512 .options(joinedload(UserGroupRepoToPerm.repository))\
513 .filter(UserGroupRepoToPerm.users_group_id == user_group_id)\
514 .all()
515
516 for gr in ugroup_repo_perms:
517 permissions['repositories'][gr.repository.repo_name] \
518 = gr.permission.permission_name
519
520 ugroup_group_perms = UserGroupRepoGroupToPerm.query()\
521 .options(joinedload(UserGroupRepoGroupToPerm.permission))\
522 .options(joinedload(UserGroupRepoGroupToPerm.group))\
523 .filter(UserGroupRepoGroupToPerm.users_group_id == user_group_id)\
524 .all()
525
526 for gr in ugroup_group_perms:
527 permissions['repositories_groups'][gr.group.group_name] \
528 = gr.permission.permission_name
529 return permissions
530
505 531 def enforce_groups(self, user, groups, extern_type=None):
506 532 user = self._get_user(user)
507 533 current_groups = user.group_member
508 534
509 535 # find the external created groups, i.e automatically created
510 536 log.debug('Enforcing user group set `%s` on user %s', groups, user)
511 537 # calculate from what groups user should be removed
512 538 # external_groups that are not in groups
513 539 for gr in [x.users_group for x in current_groups]:
514 540 managed = gr.group_data.get('extern_type')
515 541 if managed:
516 542 if gr.users_group_name not in groups:
517 543 log.debug('Removing user %s from user group %s. '
518 544 'Group sync managed by: %s', user, gr, managed)
519 545 self.remove_user_from_group(gr, user)
520 546 else:
521 547 log.debug('Skipping removal from group %s since it is '
522 548 'not set to be automatically synchronized' % gr)
523 549
524 550 # now we calculate in which groups user should be == groups params
525 551 owner = User.get_first_super_admin().username
526 552 for gr in set(groups):
527 553 existing_group = UserGroup.get_by_group_name(gr)
528 554 if not existing_group:
529 555 desc = 'Automatically created from plugin:%s' % extern_type
530 556 # we use first admin account to set the owner of the group
531 557 existing_group = UserGroupModel().create(
532 558 gr, desc, owner, group_data={'extern_type': extern_type})
533 559
534 560 # we can only add users to groups which have set sync flag via
535 561 # extern_type attribute.
536 562 # This is either set and created via plugins, or manually
537 563 managed = existing_group.group_data.get('extern_type')
538 564 if managed:
539 565 log.debug('Adding user %s to user group %s', user, gr)
540 566 UserGroupModel().add_user_to_group(existing_group, user)
541 567 else:
542 568 log.debug('Skipping addition to group %s since it is '
543 569 'not set to be automatically synchronized' % gr)
544 570
545 571 def change_groups(self, user, groups):
546 572 """
547 573 This method changes user group assignment
548 574 :param user: User
549 575 :param groups: array of UserGroupModel
550 576 """
551 577 user = self._get_user(user)
552 578 log.debug('Changing user(%s) assignment to groups(%s)', user, groups)
553 579 current_groups = user.group_member
554 580 current_groups = [x.users_group for x in current_groups]
555 581
556 582 # calculate from what groups user should be removed/add
557 583 groups = set(groups)
558 584 current_groups = set(current_groups)
559 585
560 586 groups_to_remove = current_groups - groups
561 587 groups_to_add = groups - current_groups
562 588
563 589 removed_from_groups = []
564 590 added_to_groups = []
565 591 for gr in groups_to_remove:
566 592 log.debug('Removing user %s from user group %s',
567 593 user.username, gr.users_group_name)
568 594 removed_from_groups.append(gr.users_group_id)
569 595 self.remove_user_from_group(gr.users_group_name, user.username)
570 596 for gr in groups_to_add:
571 597 log.debug('Adding user %s to user group %s',
572 598 user.username, gr.users_group_name)
573 599 added_to_groups.append(gr.users_group_id)
574 600 UserGroupModel().add_user_to_group(
575 601 gr.users_group_name, user.username)
576 602
577 603 return added_to_groups, removed_from_groups
578 604
579 605 def _serialize_user_group(self, user_group):
580 606 import rhodecode.lib.helpers as h
581 607 return {
582 608 'id': user_group.users_group_id,
583 609 # TODO: marcink figure out a way to generate the url for the
584 610 # icon
585 611 'icon_link': '',
586 612 'value_display': 'Group: %s (%d members)' % (
587 613 user_group.users_group_name, len(user_group.members),),
588 614 'value': user_group.users_group_name,
589 615 'description': user_group.user_group_description,
590 616 'owner': user_group.user.username,
591 617
592 618 'owner_icon': h.gravatar_url(user_group.user.email, 30),
593 619 'value_display_owner': h.person(user_group.user.email),
594 620
595 621 'value_type': 'user_group',
596 622 'active': user_group.users_group_active,
597 623 }
598 624
599 625 def get_user_groups(self, name_contains=None, limit=20, only_active=True,
600 626 expand_groups=False):
601 627 query = self.sa.query(UserGroup)
602 628 if only_active:
603 629 query = query.filter(UserGroup.users_group_active == true())
604 630
605 631 if name_contains:
606 632 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
607 633 query = query.filter(
608 634 UserGroup.users_group_name.ilike(ilike_expression))\
609 635 .order_by(func.length(UserGroup.users_group_name))\
610 636 .order_by(UserGroup.users_group_name)
611 637
612 638 query = query.limit(limit)
613 639 user_groups = query.all()
614 640 perm_set = ['usergroup.read', 'usergroup.write', 'usergroup.admin']
615 641 user_groups = UserGroupList(user_groups, perm_set=perm_set)
616 642
617 643 # store same serialize method to extract data from User
618 644 from rhodecode.model.user import UserModel
619 645 serialize_user = UserModel()._serialize_user
620 646
621 647 _groups = []
622 648 for group in user_groups:
623 649 entry = self._serialize_user_group(group)
624 650 if expand_groups:
625 651 expanded_members = []
626 652 for member in group.members:
627 653 expanded_members.append(serialize_user(member.user))
628 654 entry['members'] = expanded_members
629 655 _groups.append(entry)
630 656 return _groups
631 657
632 658 @staticmethod
633 659 def get_user_groups_as_dict(user_group):
634 660 import rhodecode.lib.helpers as h
635 661
636 662 data = {
637 663 'users_group_id': user_group.users_group_id,
638 664 'group_name': user_group.users_group_name,
639 665 'group_description': user_group.user_group_description,
640 666 'active': user_group.users_group_active,
641 667 "owner": user_group.user.username,
642 668 'owner_icon': h.gravatar_url(user_group.user.email, 30),
643 669 "owner_data": {
644 670 'owner': user_group.user.username,
645 671 'owner_icon': h.gravatar_url(user_group.user.email, 30)}
646 672 }
647 673 return data
General Comments 0
You need to be logged in to leave comments. Login now