##// END OF EJS Templates
api: added audit logs for user-group related calls....
marcink -
r2686:7f25a959 default
parent child Browse files
Show More
@@ -1,858 +1,895 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2011-2018 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 "permissions": [
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 "permissions_summary": {
86 86 "repositories": {
87 87 "aa-root-level-repo-1": "repository.admin"
88 88 },
89 89 "repositories_groups": {}
90 90 },
91 91 "owner": "owner name",
92 92 "users": [],
93 93 "users_group_id": 2
94 94 }
95 95 }
96 96
97 97 """
98 98
99 99 user_group = get_user_group_or_error(usergroupid)
100 100 if not has_superadmin_permission(apiuser):
101 101 # check if we have at least read permission for this user group !
102 102 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
103 103 if not HasUserGroupPermissionAnyApi(*_perms)(
104 104 user=apiuser, user_group_name=user_group.users_group_name):
105 105 raise JSONRPCError('user group `%s` does not exist' % (
106 106 usergroupid,))
107 107
108 108 permissions = []
109 109 for _user in user_group.permissions():
110 110 user_data = {
111 111 'name': _user.username,
112 112 'permission': _user.permission,
113 113 'origin': get_origin(_user),
114 114 'type': "user",
115 115 }
116 116 permissions.append(user_data)
117 117
118 118 for _user_group in user_group.permission_user_groups():
119 119 user_group_data = {
120 120 'name': _user_group.users_group_name,
121 121 'permission': _user_group.permission,
122 122 'origin': get_origin(_user_group),
123 123 'type': "user_group",
124 124 }
125 125 permissions.append(user_group_data)
126 126
127 127 data = user_group.get_api_data()
128 128 data["permissions"] = permissions
129 129 data["permissions_summary"] = UserGroupModel().get_perms_summary(
130 130 user_group.users_group_id)
131 131 return data
132 132
133 133
134 134 @jsonrpc_method()
135 135 def get_user_groups(request, apiuser):
136 136 """
137 137 Lists all the existing user groups within RhodeCode.
138 138
139 139 This command can only be run using an |authtoken| with admin rights to
140 140 the specified repository.
141 141
142 142 This command takes the following options:
143 143
144 144 :param apiuser: This is filled automatically from the |authtoken|.
145 145 :type apiuser: AuthUser
146 146
147 147 Example error output:
148 148
149 149 .. code-block:: bash
150 150
151 151 id : <id_given_in_input>
152 152 result : [<user_group_obj>,...]
153 153 error : null
154 154 """
155 155
156 156 include_secrets = has_superadmin_permission(apiuser)
157 157
158 158 result = []
159 159 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
160 160 extras = {'user': apiuser}
161 161 for user_group in UserGroupList(UserGroupModel().get_all(),
162 162 perm_set=_perms, extra_kwargs=extras):
163 163 result.append(
164 164 user_group.get_api_data(include_secrets=include_secrets))
165 165 return result
166 166
167 167
168 168 @jsonrpc_method()
169 169 def create_user_group(
170 170 request, apiuser, group_name, description=Optional(''),
171 171 owner=Optional(OAttr('apiuser')), active=Optional(True),
172 172 sync=Optional(None)):
173 173 """
174 174 Creates a new user group.
175 175
176 176 This command can only be run using an |authtoken| with admin rights to
177 177 the specified repository.
178 178
179 179 This command takes the following options:
180 180
181 181 :param apiuser: This is filled automatically from the |authtoken|.
182 182 :type apiuser: AuthUser
183 183 :param group_name: Set the name of the new user group.
184 184 :type group_name: str
185 185 :param description: Give a description of the new user group.
186 186 :type description: str
187 187 :param owner: Set the owner of the new user group.
188 188 If not set, the owner is the |authtoken| user.
189 189 :type owner: Optional(str or int)
190 190 :param active: Set this group as active.
191 191 :type active: Optional(``True`` | ``False``)
192 192 :param sync: Set enabled or disabled the automatically sync from
193 193 external authentication types like ldap.
194 194 :type sync: Optional(``True`` | ``False``)
195 195
196 196 Example output:
197 197
198 198 .. code-block:: bash
199 199
200 200 id : <id_given_in_input>
201 201 result: {
202 202 "msg": "created new user group `<groupname>`",
203 203 "user_group": <user_group_object>
204 204 }
205 205 error: null
206 206
207 207 Example error output:
208 208
209 209 .. code-block:: bash
210 210
211 211 id : <id_given_in_input>
212 212 result : null
213 213 error : {
214 214 "user group `<group name>` already exist"
215 215 or
216 216 "failed to create group `<group name>`"
217 217 }
218 218
219 219 """
220 220
221 221 if not has_superadmin_permission(apiuser):
222 222 if not HasPermissionAnyApi('hg.usergroup.create.true')(user=apiuser):
223 223 raise JSONRPCForbidden()
224 224
225 225 if UserGroupModel().get_by_name(group_name):
226 226 raise JSONRPCError("user group `%s` already exist" % (group_name,))
227 227
228 228 if isinstance(owner, Optional):
229 229 owner = apiuser.user_id
230 230
231 231 owner = get_user_or_error(owner)
232 232 active = Optional.extract(active)
233 233 description = Optional.extract(description)
234 234 sync = Optional.extract(sync)
235 235
236 236 # set the sync option based on group_data
237 237 group_data = None
238 238 if sync:
239 239 group_data = {
240 240 'extern_type': 'manual_api',
241 241 'extern_type_set_by': apiuser.username
242 242 }
243 243
244 244 schema = user_group_schema.UserGroupSchema().bind(
245 245 # user caller
246 246 user=apiuser)
247 247 try:
248 248 schema_data = schema.deserialize(dict(
249 249 user_group_name=group_name,
250 250 user_group_description=description,
251 251 user_group_owner=owner.username,
252 252 user_group_active=active,
253 253 ))
254 254 except validation_schema.Invalid as err:
255 255 raise JSONRPCValidationError(colander_exc=err)
256 256
257 257 try:
258 258 user_group = UserGroupModel().create(
259 259 name=schema_data['user_group_name'],
260 260 description=schema_data['user_group_description'],
261 261 owner=owner,
262 262 active=schema_data['user_group_active'], group_data=group_data)
263 263 Session().flush()
264 264 creation_data = user_group.get_api_data()
265 265 audit_logger.store_api(
266 266 'user_group.create', action_data={'data': creation_data},
267 267 user=apiuser)
268 268 Session().commit()
269 269 return {
270 270 'msg': 'created new user group `%s`' % group_name,
271 271 'user_group': creation_data
272 272 }
273 273 except Exception:
274 274 log.exception("Error occurred during creation of user group")
275 275 raise JSONRPCError('failed to create group `%s`' % (group_name,))
276 276
277 277
278 278 @jsonrpc_method()
279 279 def update_user_group(request, apiuser, usergroupid, group_name=Optional(''),
280 280 description=Optional(''), owner=Optional(None),
281 281 active=Optional(True), sync=Optional(None)):
282 282 """
283 283 Updates the specified `user group` with the details provided.
284 284
285 285 This command can only be run using an |authtoken| with admin rights to
286 286 the specified repository.
287 287
288 288 :param apiuser: This is filled automatically from the |authtoken|.
289 289 :type apiuser: AuthUser
290 290 :param usergroupid: Set the id of the `user group` to update.
291 291 :type usergroupid: str or int
292 292 :param group_name: Set the new name the `user group`
293 293 :type group_name: str
294 294 :param description: Give a description for the `user group`
295 295 :type description: str
296 296 :param owner: Set the owner of the `user group`.
297 297 :type owner: Optional(str or int)
298 298 :param active: Set the group as active.
299 299 :type active: Optional(``True`` | ``False``)
300 300 :param sync: Set enabled or disabled the automatically sync from
301 301 external authentication types like ldap.
302 302 :type sync: Optional(``True`` | ``False``)
303 303
304 304 Example output:
305 305
306 306 .. code-block:: bash
307 307
308 308 id : <id_given_in_input>
309 309 result : {
310 310 "msg": 'updated user group ID:<user group id> <user group name>',
311 311 "user_group": <user_group_object>
312 312 }
313 313 error : null
314 314
315 315 Example error output:
316 316
317 317 .. code-block:: bash
318 318
319 319 id : <id_given_in_input>
320 320 result : null
321 321 error : {
322 322 "failed to update user group `<user group name>`"
323 323 }
324 324
325 325 """
326 326
327 327 user_group = get_user_group_or_error(usergroupid)
328 328 include_secrets = False
329 329 if not has_superadmin_permission(apiuser):
330 330 # check if we have admin permission for this user group !
331 331 _perms = ('usergroup.admin',)
332 332 if not HasUserGroupPermissionAnyApi(*_perms)(
333 333 user=apiuser, user_group_name=user_group.users_group_name):
334 334 raise JSONRPCError(
335 335 'user group `%s` does not exist' % (usergroupid,))
336 336 else:
337 337 include_secrets = True
338 338
339 339 if not isinstance(owner, Optional):
340 340 owner = get_user_or_error(owner)
341 341
342 342 old_data = user_group.get_api_data()
343 343 updates = {}
344 344 store_update(updates, group_name, 'users_group_name')
345 345 store_update(updates, description, 'user_group_description')
346 346 store_update(updates, owner, 'user')
347 347 store_update(updates, active, 'users_group_active')
348 348
349 349 sync = Optional.extract(sync)
350 350 group_data = None
351 351 if sync is True:
352 352 group_data = {
353 353 'extern_type': 'manual_api',
354 354 'extern_type_set_by': apiuser.username
355 355 }
356 356 if sync is False:
357 357 group_data = user_group.group_data
358 358 if group_data and "extern_type" in group_data:
359 359 del group_data["extern_type"]
360 360
361 361 try:
362 362 UserGroupModel().update(user_group, updates, group_data=group_data)
363 363 audit_logger.store_api(
364 364 'user_group.edit', action_data={'old_data': old_data},
365 365 user=apiuser)
366 366 Session().commit()
367 367 return {
368 368 'msg': 'updated user group ID:%s %s' % (
369 369 user_group.users_group_id, user_group.users_group_name),
370 370 'user_group': user_group.get_api_data(
371 371 include_secrets=include_secrets)
372 372 }
373 373 except Exception:
374 374 log.exception("Error occurred during update of user group")
375 375 raise JSONRPCError(
376 376 'failed to update user group `%s`' % (usergroupid,))
377 377
378 378
379 379 @jsonrpc_method()
380 380 def delete_user_group(request, apiuser, usergroupid):
381 381 """
382 382 Deletes the specified `user group`.
383 383
384 384 This command can only be run using an |authtoken| with admin rights to
385 385 the specified repository.
386 386
387 387 This command takes the following options:
388 388
389 389 :param apiuser: filled automatically from apikey
390 390 :type apiuser: AuthUser
391 391 :param usergroupid:
392 392 :type usergroupid: int
393 393
394 394 Example output:
395 395
396 396 .. code-block:: bash
397 397
398 398 id : <id_given_in_input>
399 399 result : {
400 400 "msg": "deleted user group ID:<user_group_id> <user_group_name>"
401 401 }
402 402 error : null
403 403
404 404 Example error output:
405 405
406 406 .. code-block:: bash
407 407
408 408 id : <id_given_in_input>
409 409 result : null
410 410 error : {
411 411 "failed to delete user group ID:<user_group_id> <user_group_name>"
412 412 or
413 413 "RepoGroup assigned to <repo_groups_list>"
414 414 }
415 415
416 416 """
417 417
418 418 user_group = get_user_group_or_error(usergroupid)
419 419 if not has_superadmin_permission(apiuser):
420 420 # check if we have admin permission for this user group !
421 421 _perms = ('usergroup.admin',)
422 422 if not HasUserGroupPermissionAnyApi(*_perms)(
423 423 user=apiuser, user_group_name=user_group.users_group_name):
424 424 raise JSONRPCError(
425 425 'user group `%s` does not exist' % (usergroupid,))
426 426
427 427 old_data = user_group.get_api_data()
428 428 try:
429 429 UserGroupModel().delete(user_group)
430 430 audit_logger.store_api(
431 431 'user_group.delete', action_data={'old_data': old_data},
432 432 user=apiuser)
433 433 Session().commit()
434 434 return {
435 435 'msg': 'deleted user group ID:%s %s' % (
436 436 user_group.users_group_id, user_group.users_group_name),
437 437 'user_group': None
438 438 }
439 439 except UserGroupAssignedException as e:
440 440 log.exception("UserGroupAssigned error")
441 441 raise JSONRPCError(str(e))
442 442 except Exception:
443 443 log.exception("Error occurred during deletion of user group")
444 444 raise JSONRPCError(
445 445 'failed to delete user group ID:%s %s' %(
446 446 user_group.users_group_id, user_group.users_group_name))
447 447
448 448
449 449 @jsonrpc_method()
450 450 def add_user_to_user_group(request, apiuser, usergroupid, userid):
451 451 """
452 452 Adds a user to a `user group`. If the user already exists in the group
453 453 this command will return false.
454 454
455 455 This command can only be run using an |authtoken| with admin rights to
456 456 the specified user group.
457 457
458 458 This command takes the following options:
459 459
460 460 :param apiuser: This is filled automatically from the |authtoken|.
461 461 :type apiuser: AuthUser
462 462 :param usergroupid: Set the name of the `user group` to which a
463 463 user will be added.
464 464 :type usergroupid: int
465 465 :param userid: Set the `user_id` of the user to add to the group.
466 466 :type userid: int
467 467
468 468 Example output:
469 469
470 470 .. code-block:: bash
471 471
472 472 id : <id_given_in_input>
473 473 result : {
474 474 "success": True|False # depends on if member is in group
475 475 "msg": "added member `<username>` to user group `<groupname>` |
476 476 User is already in that group"
477 477
478 478 }
479 479 error : null
480 480
481 481 Example error output:
482 482
483 483 .. code-block:: bash
484 484
485 485 id : <id_given_in_input>
486 486 result : null
487 487 error : {
488 488 "failed to add member to user group `<user_group_name>`"
489 489 }
490 490
491 491 """
492 492
493 493 user = get_user_or_error(userid)
494 494 user_group = get_user_group_or_error(usergroupid)
495 495 if not has_superadmin_permission(apiuser):
496 496 # check if we have admin permission for this user group !
497 497 _perms = ('usergroup.admin',)
498 498 if not HasUserGroupPermissionAnyApi(*_perms)(
499 499 user=apiuser, user_group_name=user_group.users_group_name):
500 500 raise JSONRPCError('user group `%s` does not exist' % (
501 501 usergroupid,))
502 502
503 503 old_values = user_group.get_api_data()
504 504 try:
505 505 ugm = UserGroupModel().add_user_to_group(user_group, user)
506 506 success = True if ugm is not True else False
507 507 msg = 'added member `%s` to user group `%s`' % (
508 508 user.username, user_group.users_group_name
509 509 )
510 510 msg = msg if success else 'User is already in that group'
511 511 if success:
512 512 user_data = user.get_api_data()
513 513 audit_logger.store_api(
514 514 'user_group.edit.member.add',
515 515 action_data={'user': user_data, 'old_data': old_values},
516 516 user=apiuser)
517 517
518 518 Session().commit()
519 519
520 520 return {
521 521 'success': success,
522 522 'msg': msg
523 523 }
524 524 except Exception:
525 525 log.exception("Error occurred during adding a member to user group")
526 526 raise JSONRPCError(
527 527 'failed to add member to user group `%s`' % (
528 528 user_group.users_group_name,
529 529 )
530 530 )
531 531
532 532
533 533 @jsonrpc_method()
534 534 def remove_user_from_user_group(request, apiuser, usergroupid, userid):
535 535 """
536 536 Removes a user from a user group.
537 537
538 538 * If the specified user is not in the group, this command will return
539 539 `false`.
540 540
541 541 This command can only be run using an |authtoken| with admin rights to
542 542 the specified user group.
543 543
544 544 :param apiuser: This is filled automatically from the |authtoken|.
545 545 :type apiuser: AuthUser
546 546 :param usergroupid: Sets the user group name.
547 547 :type usergroupid: str or int
548 548 :param userid: The user you wish to remove from |RCE|.
549 549 :type userid: str or int
550 550
551 551 Example output:
552 552
553 553 .. code-block:: bash
554 554
555 555 id : <id_given_in_input>
556 556 result: {
557 557 "success": True|False, # depends on if member is in group
558 558 "msg": "removed member <username> from user group <groupname> |
559 559 User wasn't in group"
560 560 }
561 561 error: null
562 562
563 563 """
564 564
565 565 user = get_user_or_error(userid)
566 566 user_group = get_user_group_or_error(usergroupid)
567 567 if not has_superadmin_permission(apiuser):
568 568 # check if we have admin permission for this user group !
569 569 _perms = ('usergroup.admin',)
570 570 if not HasUserGroupPermissionAnyApi(*_perms)(
571 571 user=apiuser, user_group_name=user_group.users_group_name):
572 572 raise JSONRPCError(
573 573 'user group `%s` does not exist' % (usergroupid,))
574 574
575 575 old_values = user_group.get_api_data()
576 576 try:
577 577 success = UserGroupModel().remove_user_from_group(user_group, user)
578 578 msg = 'removed member `%s` from user group `%s`' % (
579 579 user.username, user_group.users_group_name
580 580 )
581 581 msg = msg if success else "User wasn't in group"
582 582 if success:
583 583 user_data = user.get_api_data()
584 584 audit_logger.store_api(
585 585 'user_group.edit.member.delete',
586 586 action_data={'user': user_data, 'old_data': old_values},
587 587 user=apiuser)
588 588
589 589 Session().commit()
590 590 return {'success': success, 'msg': msg}
591 591 except Exception:
592 592 log.exception("Error occurred during removing an member from user group")
593 593 raise JSONRPCError(
594 594 'failed to remove member from user group `%s`' % (
595 595 user_group.users_group_name,
596 596 )
597 597 )
598 598
599 599
600 600 @jsonrpc_method()
601 601 def grant_user_permission_to_user_group(
602 602 request, apiuser, usergroupid, userid, perm):
603 603 """
604 604 Set permissions for a user in a user group.
605 605
606 606 :param apiuser: This is filled automatically from the |authtoken|.
607 607 :type apiuser: AuthUser
608 608 :param usergroupid: Set the user group to edit permissions on.
609 609 :type usergroupid: str or int
610 610 :param userid: Set the user from whom you wish to set permissions.
611 611 :type userid: str
612 612 :param perm: (usergroup.(none|read|write|admin))
613 613 :type perm: str
614 614
615 615 Example output:
616 616
617 617 .. code-block:: bash
618 618
619 619 id : <id_given_in_input>
620 620 result : {
621 621 "msg": "Granted perm: `<perm_name>` for user: `<username>` in user group: `<user_group_name>`",
622 622 "success": true
623 623 }
624 624 error : null
625 625 """
626 626
627 627 user_group = get_user_group_or_error(usergroupid)
628 628
629 629 if not has_superadmin_permission(apiuser):
630 630 # check if we have admin permission for this user group !
631 631 _perms = ('usergroup.admin',)
632 632 if not HasUserGroupPermissionAnyApi(*_perms)(
633 633 user=apiuser, user_group_name=user_group.users_group_name):
634 634 raise JSONRPCError(
635 635 'user group `%s` does not exist' % (usergroupid,))
636 636
637 637 user = get_user_or_error(userid)
638 638 perm = get_perm_or_error(perm, prefix='usergroup.')
639 639
640 640 try:
641 UserGroupModel().grant_user_permission(
641 changes = UserGroupModel().grant_user_permission(
642 642 user_group=user_group, user=user, perm=perm)
643
644 action_data = {
645 'added': changes['added'],
646 'updated': changes['updated'],
647 'deleted': changes['deleted'],
648 }
649 audit_logger.store_api(
650 'user_group.edit.permissions', action_data=action_data,
651 user=apiuser)
652
643 653 Session().commit()
644 654 return {
645 655 'msg':
646 656 'Granted perm: `%s` for user: `%s` in user group: `%s`' % (
647 657 perm.permission_name, user.username,
648 658 user_group.users_group_name
649 659 ),
650 660 'success': True
651 661 }
652 662 except Exception:
653 663 log.exception("Error occurred during editing permissions "
654 664 "for user in user group")
655 665 raise JSONRPCError(
656 666 'failed to edit permission for user: '
657 667 '`%s` in user group: `%s`' % (
658 668 userid, user_group.users_group_name))
659 669
660 670
661 671 @jsonrpc_method()
662 672 def revoke_user_permission_from_user_group(
663 673 request, apiuser, usergroupid, userid):
664 674 """
665 675 Revoke a users permissions in a user group.
666 676
667 677 :param apiuser: This is filled automatically from the |authtoken|.
668 678 :type apiuser: AuthUser
669 679 :param usergroupid: Set the user group from which to revoke the user
670 680 permissions.
671 681 :type: usergroupid: str or int
672 682 :param userid: Set the userid of the user whose permissions will be
673 683 revoked.
674 684 :type userid: str
675 685
676 686 Example output:
677 687
678 688 .. code-block:: bash
679 689
680 690 id : <id_given_in_input>
681 691 result : {
682 692 "msg": "Revoked perm for user: `<username>` in user group: `<user_group_name>`",
683 693 "success": true
684 694 }
685 695 error : null
686 696 """
687 697
688 698 user_group = get_user_group_or_error(usergroupid)
689 699
690 700 if not has_superadmin_permission(apiuser):
691 701 # check if we have admin permission for this user group !
692 702 _perms = ('usergroup.admin',)
693 703 if not HasUserGroupPermissionAnyApi(*_perms)(
694 704 user=apiuser, user_group_name=user_group.users_group_name):
695 705 raise JSONRPCError(
696 706 'user group `%s` does not exist' % (usergroupid,))
697 707
698 708 user = get_user_or_error(userid)
699 709
700 710 try:
701 UserGroupModel().revoke_user_permission(
711 changes = UserGroupModel().revoke_user_permission(
702 712 user_group=user_group, user=user)
713 action_data = {
714 'added': changes['added'],
715 'updated': changes['updated'],
716 'deleted': changes['deleted'],
717 }
718 audit_logger.store_api(
719 'user_group.edit.permissions', action_data=action_data,
720 user=apiuser)
721
703 722 Session().commit()
704 723 return {
705 724 'msg': 'Revoked perm for user: `%s` in user group: `%s`' % (
706 725 user.username, user_group.users_group_name
707 726 ),
708 727 'success': True
709 728 }
710 729 except Exception:
711 730 log.exception("Error occurred during editing permissions "
712 731 "for user in user group")
713 732 raise JSONRPCError(
714 733 'failed to edit permission for user: `%s` in user group: `%s`'
715 734 % (userid, user_group.users_group_name))
716 735
717 736
718 737 @jsonrpc_method()
719 738 def grant_user_group_permission_to_user_group(
720 739 request, apiuser, usergroupid, sourceusergroupid, perm):
721 740 """
722 741 Give one user group permissions to another user group.
723 742
724 743 :param apiuser: This is filled automatically from the |authtoken|.
725 744 :type apiuser: AuthUser
726 745 :param usergroupid: Set the user group on which to edit permissions.
727 746 :type usergroupid: str or int
728 747 :param sourceusergroupid: Set the source user group to which
729 748 access/permissions will be granted.
730 749 :type sourceusergroupid: str or int
731 750 :param perm: (usergroup.(none|read|write|admin))
732 751 :type perm: str
733 752
734 753 Example output:
735 754
736 755 .. code-block:: bash
737 756
738 757 id : <id_given_in_input>
739 758 result : {
740 759 "msg": "Granted perm: `<perm_name>` for user group: `<source_user_group_name>` in user group: `<user_group_name>`",
741 760 "success": true
742 761 }
743 762 error : null
744 763 """
745 764
746 765 user_group = get_user_group_or_error(sourceusergroupid)
747 766 target_user_group = get_user_group_or_error(usergroupid)
748 767 perm = get_perm_or_error(perm, prefix='usergroup.')
749 768
750 769 if not has_superadmin_permission(apiuser):
751 770 # check if we have admin permission for this user group !
752 771 _perms = ('usergroup.admin',)
753 772 if not HasUserGroupPermissionAnyApi(*_perms)(
754 773 user=apiuser,
755 774 user_group_name=target_user_group.users_group_name):
756 775 raise JSONRPCError(
757 776 'to user group `%s` does not exist' % (usergroupid,))
758 777
759 778 # check if we have at least read permission for source user group !
760 779 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
761 780 if not HasUserGroupPermissionAnyApi(*_perms)(
762 781 user=apiuser, user_group_name=user_group.users_group_name):
763 782 raise JSONRPCError(
764 783 'user group `%s` does not exist' % (sourceusergroupid,))
765 784
766 785 try:
767 UserGroupModel().grant_user_group_permission(
786 changes = UserGroupModel().grant_user_group_permission(
768 787 target_user_group=target_user_group,
769 788 user_group=user_group, perm=perm)
789
790 action_data = {
791 'added': changes['added'],
792 'updated': changes['updated'],
793 'deleted': changes['deleted'],
794 }
795 audit_logger.store_api(
796 'user_group.edit.permissions', action_data=action_data,
797 user=apiuser)
798
770 799 Session().commit()
771
772 800 return {
773 801 'msg': 'Granted perm: `%s` for user group: `%s` '
774 802 'in user group: `%s`' % (
775 803 perm.permission_name, user_group.users_group_name,
776 804 target_user_group.users_group_name
777 805 ),
778 806 'success': True
779 807 }
780 808 except Exception:
781 809 log.exception("Error occurred during editing permissions "
782 810 "for user group in user group")
783 811 raise JSONRPCError(
784 812 'failed to edit permission for user group: `%s` in '
785 813 'user group: `%s`' % (
786 814 sourceusergroupid, target_user_group.users_group_name
787 815 )
788 816 )
789 817
790 818
791 819 @jsonrpc_method()
792 820 def revoke_user_group_permission_from_user_group(
793 821 request, apiuser, usergroupid, sourceusergroupid):
794 822 """
795 823 Revoke the permissions that one user group has to another.
796 824
797 825 :param apiuser: This is filled automatically from the |authtoken|.
798 826 :type apiuser: AuthUser
799 827 :param usergroupid: Set the user group on which to edit permissions.
800 828 :type usergroupid: str or int
801 829 :param sourceusergroupid: Set the user group from which permissions
802 830 are revoked.
803 831 :type sourceusergroupid: str or int
804 832
805 833 Example output:
806 834
807 835 .. code-block:: bash
808 836
809 837 id : <id_given_in_input>
810 838 result : {
811 839 "msg": "Revoked perm for user group: `<user_group_name>` in user group: `<target_user_group_name>`",
812 840 "success": true
813 841 }
814 842 error : null
815 843 """
816 844
817 845 user_group = get_user_group_or_error(sourceusergroupid)
818 846 target_user_group = get_user_group_or_error(usergroupid)
819 847
820 848 if not has_superadmin_permission(apiuser):
821 849 # check if we have admin permission for this user group !
822 850 _perms = ('usergroup.admin',)
823 851 if not HasUserGroupPermissionAnyApi(*_perms)(
824 852 user=apiuser,
825 853 user_group_name=target_user_group.users_group_name):
826 854 raise JSONRPCError(
827 855 'to user group `%s` does not exist' % (usergroupid,))
828 856
829 857 # check if we have at least read permission
830 858 # for the source user group !
831 859 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
832 860 if not HasUserGroupPermissionAnyApi(*_perms)(
833 861 user=apiuser, user_group_name=user_group.users_group_name):
834 862 raise JSONRPCError(
835 863 'user group `%s` does not exist' % (sourceusergroupid,))
836 864
837 865 try:
838 UserGroupModel().revoke_user_group_permission(
866 changes = UserGroupModel().revoke_user_group_permission(
839 867 target_user_group=target_user_group, user_group=user_group)
868 action_data = {
869 'added': changes['added'],
870 'updated': changes['updated'],
871 'deleted': changes['deleted'],
872 }
873 audit_logger.store_api(
874 'user_group.edit.permissions', action_data=action_data,
875 user=apiuser)
876
840 877 Session().commit()
841 878
842 879 return {
843 880 'msg': 'Revoked perm for user group: '
844 881 '`%s` in user group: `%s`' % (
845 882 user_group.users_group_name,
846 883 target_user_group.users_group_name
847 884 ),
848 885 'success': True
849 886 }
850 887 except Exception:
851 888 log.exception("Error occurred during editing permissions "
852 889 "for user group in user group")
853 890 raise JSONRPCError(
854 891 'failed to edit permission for user group: '
855 892 '`%s` in user group: `%s`' % (
856 893 sourceusergroupid, target_user_group.users_group_name
857 894 )
858 895 )
@@ -1,678 +1,745 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2011-2018 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 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 change_obj = user_group.get_api_data()
83 84 # update permissions
84 85 for member_id, perm, member_type in perm_updates:
85 86 member_id = int(member_id)
86 87 if member_type == 'user':
87 88 member_name = User.get(member_id).username
88 89 # this updates existing one
89 90 self.grant_user_permission(
90 91 user_group=user_group, user=member_id, perm=perm
91 92 )
92 93 else:
93 94 # check if we have permissions to alter this usergroup
94 95 member_name = UserGroup.get(member_id).users_group_name
95 96 if not check_perms or HasUserGroupPermissionAny(
96 97 *req_perms)(member_name, user=cur_user):
97 98 self.grant_user_group_permission(
98 99 target_user_group=user_group, user_group=member_id, perm=perm)
99 100
100 changes['updated'].append({'type': member_type, 'id': member_id,
101 changes['updated'].append({
102 'change_obj': change_obj,
103 'type': member_type, 'id': member_id,
101 104 'name': member_name, 'new_perm': perm})
102 105
103 106 # set new permissions
104 107 for member_id, perm, member_type in perm_additions:
105 108 member_id = int(member_id)
106 109 if member_type == 'user':
107 110 member_name = User.get(member_id).username
108 111 self.grant_user_permission(
109 112 user_group=user_group, user=member_id, perm=perm)
110 113 else:
111 114 # check if we have permissions to alter this usergroup
112 115 member_name = UserGroup.get(member_id).users_group_name
113 116 if not check_perms or HasUserGroupPermissionAny(
114 117 *req_perms)(member_name, user=cur_user):
115 118 self.grant_user_group_permission(
116 119 target_user_group=user_group, user_group=member_id, perm=perm)
117 120
118 changes['added'].append({'type': member_type, 'id': member_id,
121 changes['added'].append({
122 'change_obj': change_obj,
123 'type': member_type, 'id': member_id,
119 124 'name': member_name, 'new_perm': perm})
120 125
121 126 # delete permissions
122 127 for member_id, perm, member_type in perm_deletions:
123 128 member_id = int(member_id)
124 129 if member_type == 'user':
125 130 member_name = User.get(member_id).username
126 131 self.revoke_user_permission(user_group=user_group, user=member_id)
127 132 else:
128 133 # check if we have permissions to alter this usergroup
129 134 member_name = UserGroup.get(member_id).users_group_name
130 135 if not check_perms or HasUserGroupPermissionAny(
131 136 *req_perms)(member_name, user=cur_user):
132 137 self.revoke_user_group_permission(
133 138 target_user_group=user_group, user_group=member_id)
134 139
135 changes['deleted'].append({'type': member_type, 'id': member_id,
140 changes['deleted'].append({
141 'change_obj': change_obj,
142 'type': member_type, 'id': member_id,
136 143 'name': member_name, 'new_perm': perm})
144
137 145 return changes
138 146
139 147 def get(self, user_group_id, cache=False):
140 148 return UserGroup.get(user_group_id)
141 149
142 150 def get_group(self, user_group):
143 151 return self._get_user_group(user_group)
144 152
145 153 def get_by_name(self, name, cache=False, case_insensitive=False):
146 154 return UserGroup.get_by_group_name(name, cache, case_insensitive)
147 155
148 156 def create(self, name, description, owner, active=True, group_data=None):
149 157 try:
150 158 new_user_group = UserGroup()
151 159 new_user_group.user = self._get_user(owner)
152 160 new_user_group.users_group_name = name
153 161 new_user_group.user_group_description = description
154 162 new_user_group.users_group_active = active
155 163 if group_data:
156 164 new_user_group.group_data = group_data
157 165 self.sa.add(new_user_group)
158 166 perm_obj = self._create_default_perms(new_user_group)
159 167 self.sa.add(perm_obj)
160 168
161 169 self.grant_user_permission(user_group=new_user_group,
162 170 user=owner, perm='usergroup.admin')
163 171
164 172 return new_user_group
165 173 except Exception:
166 174 log.error(traceback.format_exc())
167 175 raise
168 176
169 177 def _get_memberships_for_user_ids(self, user_group, user_id_list):
170 178 members = []
171 179 for user_id in user_id_list:
172 180 member = self._get_membership(user_group.users_group_id, user_id)
173 181 members.append(member)
174 182 return members
175 183
176 184 def _get_added_and_removed_user_ids(self, user_group, user_id_list):
177 185 current_members = user_group.members or []
178 186 current_members_ids = [m.user.user_id for m in current_members]
179 187
180 188 added_members = [
181 189 user_id for user_id in user_id_list
182 190 if user_id not in current_members_ids]
183 191 if user_id_list == []:
184 192 # all members were deleted
185 193 deleted_members = current_members_ids
186 194 else:
187 195 deleted_members = [
188 196 user_id for user_id in current_members_ids
189 197 if user_id not in user_id_list]
190 198
191 199 return added_members, deleted_members
192 200
193 201 def _set_users_as_members(self, user_group, user_ids):
194 202 user_group.members = []
195 203 self.sa.flush()
196 204 members = self._get_memberships_for_user_ids(
197 205 user_group, user_ids)
198 206 user_group.members = members
199 207 self.sa.add(user_group)
200 208
201 209 def _update_members_from_user_ids(self, user_group, user_ids):
202 210 added, removed = self._get_added_and_removed_user_ids(
203 211 user_group, user_ids)
204 212 self._set_users_as_members(user_group, user_ids)
205 213 self._log_user_changes('added to', user_group, added)
206 214 self._log_user_changes('removed from', user_group, removed)
207 215 return added, removed
208 216
209 217 def _clean_members_data(self, members_data):
210 218 if not members_data:
211 219 members_data = []
212 220
213 221 members = []
214 222 for user in members_data:
215 223 uid = int(user['member_user_id'])
216 224 if uid not in members and user['type'] in ['new', 'existing']:
217 225 members.append(uid)
218 226 return members
219 227
220 228 def update(self, user_group, form_data, group_data=None):
221 229 user_group = self._get_user_group(user_group)
222 230 if 'users_group_name' in form_data:
223 231 user_group.users_group_name = form_data['users_group_name']
224 232 if 'users_group_active' in form_data:
225 233 user_group.users_group_active = form_data['users_group_active']
226 234 if 'user_group_description' in form_data:
227 235 user_group.user_group_description = form_data[
228 236 'user_group_description']
229 237
230 238 # handle owner change
231 239 if 'user' in form_data:
232 240 owner = form_data['user']
233 241 if isinstance(owner, basestring):
234 242 owner = User.get_by_username(form_data['user'])
235 243
236 244 if not isinstance(owner, User):
237 245 raise ValueError(
238 246 'invalid owner for user group: %s' % form_data['user'])
239 247
240 248 user_group.user = owner
241 249
242 250 added_user_ids = []
243 251 removed_user_ids = []
244 252 if 'users_group_members' in form_data:
245 253 members_id_list = self._clean_members_data(
246 254 form_data['users_group_members'])
247 255 added_user_ids, removed_user_ids = \
248 256 self._update_members_from_user_ids(user_group, members_id_list)
249 257
250 258 if group_data:
251 259 new_group_data = {}
252 260 new_group_data.update(group_data)
253 261 user_group.group_data = new_group_data
254 262
255 263 self.sa.add(user_group)
256 264 return user_group, added_user_ids, removed_user_ids
257 265
258 266 def delete(self, user_group, force=False):
259 267 """
260 268 Deletes repository group, unless force flag is used
261 269 raises exception if there are members in that group, else deletes
262 270 group and users
263 271
264 272 :param user_group:
265 273 :param force:
266 274 """
267 275 user_group = self._get_user_group(user_group)
268 276 if not user_group:
269 277 return
270 278
271 279 try:
272 280 # check if this group is not assigned to repo
273 281 assigned_to_repo = [x.repository for x in UserGroupRepoToPerm.query()\
274 282 .filter(UserGroupRepoToPerm.users_group == user_group).all()]
275 283 # check if this group is not assigned to repo
276 284 assigned_to_repo_group = [x.group for x in UserGroupRepoGroupToPerm.query()\
277 285 .filter(UserGroupRepoGroupToPerm.users_group == user_group).all()]
278 286
279 287 if (assigned_to_repo or assigned_to_repo_group) and not force:
280 288 assigned = ','.join(map(safe_str,
281 289 assigned_to_repo+assigned_to_repo_group))
282 290
283 291 raise UserGroupAssignedException(
284 292 'UserGroup assigned to %s' % (assigned,))
285 293 self.sa.delete(user_group)
286 294 except Exception:
287 295 log.error(traceback.format_exc())
288 296 raise
289 297
290 298 def _log_user_changes(self, action, user_group, user_or_users):
291 299 users = user_or_users
292 300 if not isinstance(users, (list, tuple)):
293 301 users = [users]
294 302
295 303 group_name = user_group.users_group_name
296 304
297 305 for user_or_user_id in users:
298 306 user = self._get_user(user_or_user_id)
299 307 log_text = 'User {user} {action} {group}'.format(
300 308 action=action, user=user.username, group=group_name)
301 309 action_logger_generic(log_text)
302 310
303 311 def _find_user_in_group(self, user, user_group):
304 312 user_group_member = None
305 313 for m in user_group.members:
306 314 if m.user_id == user.user_id:
307 315 # Found this user's membership row
308 316 user_group_member = m
309 317 break
310 318
311 319 return user_group_member
312 320
313 321 def _get_membership(self, user_group_id, user_id):
314 322 user_group_member = UserGroupMember(user_group_id, user_id)
315 323 return user_group_member
316 324
317 325 def add_user_to_group(self, user_group, user):
318 326 user_group = self._get_user_group(user_group)
319 327 user = self._get_user(user)
320 328 user_member = self._find_user_in_group(user, user_group)
321 329 if user_member:
322 330 # user already in the group, skip
323 331 return True
324 332
325 333 member = self._get_membership(
326 334 user_group.users_group_id, user.user_id)
327 335 user_group.members.append(member)
328 336
329 337 try:
330 338 self.sa.add(member)
331 339 except Exception:
332 340 # what could go wrong here?
333 341 log.error(traceback.format_exc())
334 342 raise
335 343
336 344 self._log_user_changes('added to', user_group, user)
337 345 return member
338 346
339 347 def remove_user_from_group(self, user_group, user):
340 348 user_group = self._get_user_group(user_group)
341 349 user = self._get_user(user)
342 350 user_group_member = self._find_user_in_group(user, user_group)
343 351
344 352 if not user_group_member:
345 353 # User isn't in that group
346 354 return False
347 355
348 356 try:
349 357 self.sa.delete(user_group_member)
350 358 except Exception:
351 359 log.error(traceback.format_exc())
352 360 raise
353 361
354 362 self._log_user_changes('removed from', user_group, user)
355 363 return True
356 364
357 365 def has_perm(self, user_group, perm):
358 366 user_group = self._get_user_group(user_group)
359 367 perm = self._get_perm(perm)
360 368
361 369 return UserGroupToPerm.query()\
362 370 .filter(UserGroupToPerm.users_group == user_group)\
363 371 .filter(UserGroupToPerm.permission == perm).scalar() is not None
364 372
365 373 def grant_perm(self, user_group, perm):
366 374 user_group = self._get_user_group(user_group)
367 375 perm = self._get_perm(perm)
368 376
369 377 # if this permission is already granted skip it
370 378 _perm = UserGroupToPerm.query()\
371 379 .filter(UserGroupToPerm.users_group == user_group)\
372 380 .filter(UserGroupToPerm.permission == perm)\
373 381 .scalar()
374 382 if _perm:
375 383 return
376 384
377 385 new = UserGroupToPerm()
378 386 new.users_group = user_group
379 387 new.permission = perm
380 388 self.sa.add(new)
381 389 return new
382 390
383 391 def revoke_perm(self, user_group, perm):
384 392 user_group = self._get_user_group(user_group)
385 393 perm = self._get_perm(perm)
386 394
387 395 obj = UserGroupToPerm.query()\
388 396 .filter(UserGroupToPerm.users_group == user_group)\
389 397 .filter(UserGroupToPerm.permission == perm).scalar()
390 398 if obj:
391 399 self.sa.delete(obj)
392 400
393 401 def grant_user_permission(self, user_group, user, perm):
394 402 """
395 403 Grant permission for user on given user group, or update
396 404 existing one if found
397 405
398 406 :param user_group: Instance of UserGroup, users_group_id,
399 407 or users_group_name
400 408 :param user: Instance of User, user_id or username
401 409 :param perm: Instance of Permission, or permission_name
402 410 """
411 changes = {
412 'added': [],
413 'updated': [],
414 'deleted': []
415 }
403 416
404 417 user_group = self._get_user_group(user_group)
405 418 user = self._get_user(user)
406 419 permission = self._get_perm(perm)
420 perm_name = permission.permission_name
421 member_id = user.user_id
422 member_name = user.username
407 423
408 424 # check if we have that permission already
409 425 obj = self.sa.query(UserUserGroupToPerm)\
410 426 .filter(UserUserGroupToPerm.user == user)\
411 427 .filter(UserUserGroupToPerm.user_group == user_group)\
412 428 .scalar()
413 429 if obj is None:
414 430 # create new !
415 431 obj = UserUserGroupToPerm()
416 432 obj.user_group = user_group
417 433 obj.user = user
418 434 obj.permission = permission
419 435 self.sa.add(obj)
420 436 log.debug('Granted perm %s to %s on %s', perm, user, user_group)
421 437 action_logger_generic(
422 438 'granted permission: {} to user: {} on usergroup: {}'.format(
423 439 perm, user, user_group), namespace='security.usergroup')
424 440
425 return obj
441 changes['added'].append({
442 'change_obj': user_group.get_api_data(),
443 'type': 'user', 'id': member_id,
444 'name': member_name, 'new_perm': perm_name})
445
446 return changes
426 447
427 448 def revoke_user_permission(self, user_group, user):
428 449 """
429 450 Revoke permission for user on given user group
430 451
431 452 :param user_group: Instance of UserGroup, users_group_id,
432 453 or users_group name
433 454 :param user: Instance of User, user_id or username
434 455 """
456 changes = {
457 'added': [],
458 'updated': [],
459 'deleted': []
460 }
435 461
436 462 user_group = self._get_user_group(user_group)
437 463 user = self._get_user(user)
464 perm_name = 'usergroup.none'
465 member_id = user.user_id
466 member_name = user.username
438 467
439 468 obj = self.sa.query(UserUserGroupToPerm)\
440 469 .filter(UserUserGroupToPerm.user == user)\
441 470 .filter(UserUserGroupToPerm.user_group == user_group)\
442 471 .scalar()
443 472 if obj:
444 473 self.sa.delete(obj)
445 474 log.debug('Revoked perm on %s on %s', user_group, user)
446 475 action_logger_generic(
447 476 'revoked permission from user: {} on usergroup: {}'.format(
448 477 user, user_group), namespace='security.usergroup')
449 478
479 changes['deleted'].append({
480 'change_obj': user_group.get_api_data(),
481 'type': 'user', 'id': member_id,
482 'name': member_name, 'new_perm': perm_name})
483
484 return changes
485
450 486 def grant_user_group_permission(self, target_user_group, user_group, perm):
451 487 """
452 488 Grant user group permission for given target_user_group
453 489
454 490 :param target_user_group:
455 491 :param user_group:
456 492 :param perm:
457 493 """
494 changes = {
495 'added': [],
496 'updated': [],
497 'deleted': []
498 }
499
458 500 target_user_group = self._get_user_group(target_user_group)
459 501 user_group = self._get_user_group(user_group)
460 502 permission = self._get_perm(perm)
503 perm_name = permission.permission_name
504 member_id = user_group.users_group_id
505 member_name = user_group.users_group_name
506
461 507 # forbid assigning same user group to itself
462 508 if target_user_group == user_group:
463 509 raise RepoGroupAssignmentError('target repo:%s cannot be '
464 510 'assigned to itself' % target_user_group)
465 511
466 512 # check if we have that permission already
467 513 obj = self.sa.query(UserGroupUserGroupToPerm)\
468 514 .filter(UserGroupUserGroupToPerm.target_user_group == target_user_group)\
469 515 .filter(UserGroupUserGroupToPerm.user_group == user_group)\
470 516 .scalar()
471 517 if obj is None:
472 518 # create new !
473 519 obj = UserGroupUserGroupToPerm()
474 520 obj.user_group = user_group
475 521 obj.target_user_group = target_user_group
476 522 obj.permission = permission
477 523 self.sa.add(obj)
478 524 log.debug(
479 525 'Granted perm %s to %s on %s', perm, target_user_group, user_group)
480 526 action_logger_generic(
481 527 'granted permission: {} to usergroup: {} on usergroup: {}'.format(
482 528 perm, user_group, target_user_group),
483 529 namespace='security.usergroup')
484 530
485 return obj
531 changes['added'].append({
532 'change_obj': target_user_group.get_api_data(),
533 'type': 'user_group', 'id': member_id,
534 'name': member_name, 'new_perm': perm_name})
535
536 return changes
486 537
487 538 def revoke_user_group_permission(self, target_user_group, user_group):
488 539 """
489 540 Revoke user group permission for given target_user_group
490 541
491 542 :param target_user_group:
492 543 :param user_group:
493 544 """
545 changes = {
546 'added': [],
547 'updated': [],
548 'deleted': []
549 }
550
494 551 target_user_group = self._get_user_group(target_user_group)
495 552 user_group = self._get_user_group(user_group)
553 perm_name = 'usergroup.none'
554 member_id = user_group.users_group_id
555 member_name = user_group.users_group_name
496 556
497 557 obj = self.sa.query(UserGroupUserGroupToPerm)\
498 558 .filter(UserGroupUserGroupToPerm.target_user_group == target_user_group)\
499 559 .filter(UserGroupUserGroupToPerm.user_group == user_group)\
500 560 .scalar()
501 561 if obj:
502 562 self.sa.delete(obj)
503 563 log.debug(
504 564 'Revoked perm on %s on %s', target_user_group, user_group)
505 565 action_logger_generic(
506 566 'revoked permission from usergroup: {} on usergroup: {}'.format(
507 567 user_group, target_user_group),
508 568 namespace='security.repogroup')
509 569
570 changes['deleted'].append({
571 'change_obj': target_user_group.get_api_data(),
572 'type': 'user_group', 'id': member_id,
573 'name': member_name, 'new_perm': perm_name})
574
575 return changes
576
510 577 def get_perms_summary(self, user_group_id):
511 578 permissions = {
512 579 'repositories': {},
513 580 'repositories_groups': {},
514 581 }
515 582 ugroup_repo_perms = UserGroupRepoToPerm.query()\
516 583 .options(joinedload(UserGroupRepoToPerm.permission))\
517 584 .options(joinedload(UserGroupRepoToPerm.repository))\
518 585 .filter(UserGroupRepoToPerm.users_group_id == user_group_id)\
519 586 .all()
520 587
521 588 for gr in ugroup_repo_perms:
522 589 permissions['repositories'][gr.repository.repo_name] \
523 590 = gr.permission.permission_name
524 591
525 592 ugroup_group_perms = UserGroupRepoGroupToPerm.query()\
526 593 .options(joinedload(UserGroupRepoGroupToPerm.permission))\
527 594 .options(joinedload(UserGroupRepoGroupToPerm.group))\
528 595 .filter(UserGroupRepoGroupToPerm.users_group_id == user_group_id)\
529 596 .all()
530 597
531 598 for gr in ugroup_group_perms:
532 599 permissions['repositories_groups'][gr.group.group_name] \
533 600 = gr.permission.permission_name
534 601 return permissions
535 602
536 603 def enforce_groups(self, user, groups, extern_type=None):
537 604 user = self._get_user(user)
538 605 current_groups = user.group_member
539 606
540 607 # find the external created groups, i.e automatically created
541 608 log.debug('Enforcing user group set `%s` on user %s', groups, user)
542 609 # calculate from what groups user should be removed
543 610 # external_groups that are not in groups
544 611 for gr in [x.users_group for x in current_groups]:
545 612 managed = gr.group_data.get('extern_type')
546 613 if managed:
547 614 if gr.users_group_name not in groups:
548 615 log.debug('Removing user %s from user group %s. '
549 616 'Group sync managed by: %s', user, gr, managed)
550 617 self.remove_user_from_group(gr, user)
551 618 else:
552 619 log.debug('Skipping removal from group %s since it is '
553 620 'not set to be automatically synchronized' % gr)
554 621
555 622 # now we calculate in which groups user should be == groups params
556 623 owner = User.get_first_super_admin().username
557 624 for gr in set(groups):
558 625 existing_group = UserGroup.get_by_group_name(gr)
559 626 if not existing_group:
560 627 desc = 'Automatically created from plugin:%s' % extern_type
561 628 # we use first admin account to set the owner of the group
562 629 existing_group = UserGroupModel().create(
563 630 gr, desc, owner, group_data={'extern_type': extern_type})
564 631
565 632 # we can only add users to groups which have set sync flag via
566 633 # extern_type attribute.
567 634 # This is either set and created via plugins, or manually
568 635 managed = existing_group.group_data.get('extern_type')
569 636 if managed:
570 637 log.debug('Adding user %s to user group %s', user, gr)
571 638 UserGroupModel().add_user_to_group(existing_group, user)
572 639 else:
573 640 log.debug('Skipping addition to group %s since it is '
574 641 'not set to be automatically synchronized' % gr)
575 642
576 643 def change_groups(self, user, groups):
577 644 """
578 645 This method changes user group assignment
579 646 :param user: User
580 647 :param groups: array of UserGroupModel
581 648 """
582 649 user = self._get_user(user)
583 650 log.debug('Changing user(%s) assignment to groups(%s)', user, groups)
584 651 current_groups = user.group_member
585 652 current_groups = [x.users_group for x in current_groups]
586 653
587 654 # calculate from what groups user should be removed/add
588 655 groups = set(groups)
589 656 current_groups = set(current_groups)
590 657
591 658 groups_to_remove = current_groups - groups
592 659 groups_to_add = groups - current_groups
593 660
594 661 removed_from_groups = []
595 662 added_to_groups = []
596 663 for gr in groups_to_remove:
597 664 log.debug('Removing user %s from user group %s',
598 665 user.username, gr.users_group_name)
599 666 removed_from_groups.append(gr.users_group_id)
600 667 self.remove_user_from_group(gr.users_group_name, user.username)
601 668 for gr in groups_to_add:
602 669 log.debug('Adding user %s to user group %s',
603 670 user.username, gr.users_group_name)
604 671 added_to_groups.append(gr.users_group_id)
605 672 UserGroupModel().add_user_to_group(
606 673 gr.users_group_name, user.username)
607 674
608 675 return added_to_groups, removed_from_groups
609 676
610 677 def _serialize_user_group(self, user_group):
611 678 import rhodecode.lib.helpers as h
612 679 return {
613 680 'id': user_group.users_group_id,
614 681 # TODO: marcink figure out a way to generate the url for the
615 682 # icon
616 683 'icon_link': '',
617 684 'value_display': 'Group: %s (%d members)' % (
618 685 user_group.users_group_name, len(user_group.members),),
619 686 'value': user_group.users_group_name,
620 687 'description': user_group.user_group_description,
621 688 'owner': user_group.user.username,
622 689
623 690 'owner_icon': h.gravatar_url(user_group.user.email, 30),
624 691 'value_display_owner': h.person(user_group.user.email),
625 692
626 693 'value_type': 'user_group',
627 694 'active': user_group.users_group_active,
628 695 }
629 696
630 697 def get_user_groups(self, name_contains=None, limit=20, only_active=True,
631 698 expand_groups=False):
632 699 query = self.sa.query(UserGroup)
633 700 if only_active:
634 701 query = query.filter(UserGroup.users_group_active == true())
635 702
636 703 if name_contains:
637 704 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
638 705 query = query.filter(
639 706 UserGroup.users_group_name.ilike(ilike_expression))\
640 707 .order_by(func.length(UserGroup.users_group_name))\
641 708 .order_by(UserGroup.users_group_name)
642 709
643 710 query = query.limit(limit)
644 711 user_groups = query.all()
645 712 perm_set = ['usergroup.read', 'usergroup.write', 'usergroup.admin']
646 713 user_groups = UserGroupList(user_groups, perm_set=perm_set)
647 714
648 715 # store same serialize method to extract data from User
649 716 from rhodecode.model.user import UserModel
650 717 serialize_user = UserModel()._serialize_user
651 718
652 719 _groups = []
653 720 for group in user_groups:
654 721 entry = self._serialize_user_group(group)
655 722 if expand_groups:
656 723 expanded_members = []
657 724 for member in group.members:
658 725 expanded_members.append(serialize_user(member.user))
659 726 entry['members'] = expanded_members
660 727 _groups.append(entry)
661 728 return _groups
662 729
663 730 @staticmethod
664 731 def get_user_groups_as_dict(user_group):
665 732 import rhodecode.lib.helpers as h
666 733
667 734 data = {
668 735 'users_group_id': user_group.users_group_id,
669 736 'group_name': user_group.users_group_name,
670 737 'group_description': user_group.user_group_description,
671 738 'active': user_group.users_group_active,
672 739 "owner": user_group.user.username,
673 740 'owner_icon': h.gravatar_url(user_group.user.email, 30),
674 741 "owner_data": {
675 742 'owner': user_group.user.username,
676 743 'owner_icon': h.gravatar_url(user_group.user.email, 30)}
677 744 }
678 745 return data
General Comments 0
You need to be logged in to leave comments. Login now