permissions: handle more cases for invalidating permission caches

- invalidate user permissions on chaning the global permissions
- invalidate all users in case of creating new object with "copy permissions" flag
- invalidate all users permissions in case of repo/repo group renames
- invalidate all user permissions in forked repo with copy flag
This commit is contained in:
Marcin Kuzminski 2019-01-14 20:19:25 +01:00
parent 13baf5061a
commit 3268256a7a
7 changed files with 117 additions and 46 deletions

View file

@ -159,6 +159,7 @@ class AdminRepoGroupsView(BaseAppView, DataGridAppView):
try:
owner = self._rhodecode_user
form_result = repo_group_form.to_python(dict(self.request.POST))
copy_permissions = form_result.get('group_copy_permissions')
repo_group = RepoGroupModel().create(
group_name=form_result['group_name_full'],
group_description=form_result['group_description'],
@ -201,7 +202,14 @@ class AdminRepoGroupsView(BaseAppView, DataGridAppView):
% repo_group_name, category='error')
raise HTTPFound(h.route_path('home'))
events.trigger(events.UserPermissionsChange([self._rhodecode_user.user_id]))
affected_user_ids = [self._rhodecode_user.user_id]
if copy_permissions:
user_group_perms = repo_group.permissions(expand_from_user_groups=True)
copy_perms = [perm['user_id'] for perm in user_group_perms]
# also include those newly created by copy
affected_user_ids.extend(copy_perms)
events.trigger(events.UserPermissionsChange(affected_user_ids))
raise HTTPFound(
h.route_path('repo_group_home',
repo_group_name=form_result['group_name_full']))

View file

@ -146,14 +146,14 @@ class AdminReposView(BaseAppView, DataGridAppView):
form_result = {}
self._load_form_data(c)
task_id = None
try:
# CanWriteToGroup validators checks permissions of this POST
form = RepoForm(
self.request.translate, repo_groups=c.repo_groups_choices,
landing_revs=c.landing_revs_choices)()
form_result = form.to_python(dict(self.request.POST))
copy_permissions = form_result.get('repo_copy_permissions')
# create is done sometimes async on celery, db transaction
# management is handled there.
task = RepoModel().create(form_result, self._rhodecode_user.user_id)
@ -176,9 +176,19 @@ class AdminReposView(BaseAppView, DataGridAppView):
h.flash(msg, category='error')
raise HTTPFound(h.route_path('home'))
events.trigger(events.UserPermissionsChange([self._rhodecode_user.user_id]))
repo_name = form_result.get('repo_name_full')
affected_user_ids = [self._rhodecode_user.user_id]
if copy_permissions:
repository = Repository.get_by_repo_name(repo_name)
# also include those newly created by copy
user_group_perms = repository.permissions(expand_from_user_groups=True)
copy_perms = [perm['user_id'] for perm in user_group_perms]
# also include those newly created by copy
affected_user_ids.extend(copy_perms)
events.trigger(events.UserPermissionsChange(affected_user_ids))
raise HTTPFound(
h.route_path('repo_creating',
repo_name=form_result['repo_name_full'],
h.route_path('repo_creating', repo_name=repo_name,
_query=dict(task_id=task_id)))

View file

@ -28,6 +28,7 @@ from pyramid.view import view_config
from pyramid.renderers import render
from pyramid.response import Response
from rhodecode import events
from rhodecode.apps._base import BaseAppView, DataGridAppView, UserAppView
from rhodecode.apps.ssh_support import SshKeyFileChangeEvent
from rhodecode.authentication.plugins import auth_rhodecode
@ -573,6 +574,7 @@ class UsersView(UserAppView):
# audit_log.store_web('user.edit.permissions')
Session().commit()
h.flash(_('User global permissions updated successfully'),
category='success')
@ -593,6 +595,9 @@ class UsersView(UserAppView):
log.exception("Exception during permissions saving")
h.flash(_('An error occurred during permissions saving'),
category='error')
affected_user_ids = [user_id]
events.trigger(events.UserPermissionsChange(affected_user_ids))
raise HTTPFound(h.route_path('user_edit_global_perms', user_id=user_id))
@LoginRequired()

View file

@ -180,10 +180,14 @@ class RepoGroupSettingsView(RepoGroupAppView):
name_changed = old_repo_group_name != new_repo_group_name
if name_changed:
current_perms = self.db_repo_group.permissions(expand_from_user_groups=True)
affected_user_ids = [perm['user_id'] for perm in current_perms]
# NOTE(marcink): also add owner maybe it has changed
owner = User.get_by_username(schema_data['repo_group_owner'])
owner_id = owner.user_id if owner else self._rhodecode_user.user_id
events.trigger(events.UserPermissionsChange([
self._rhodecode_user.user_id, owner_id]))
affected_user_ids.extend([self._rhodecode_user.user_id, owner_id])
events.trigger(events.UserPermissionsChange(affected_user_ids))
raise HTTPFound(
h.route_path('edit_repo_group', repo_group_name=new_repo_group_name))

View file

@ -224,6 +224,7 @@ class RepoForksView(RepoAppView, DataGridAppView):
task_id = None
try:
form_result = _form.to_python(post_data)
copy_permissions = form_result.get('copy_permissions')
# create fork is done sometimes async on celery, db transaction
# management is handled there.
task = RepoModel().create_fork(
@ -246,18 +247,24 @@ class RepoForksView(RepoAppView, DataGridAppView):
return Response(html)
except Exception:
log.exception(
u'Exception while trying to fork the repository %s',
self.db_repo_name)
msg = (
_('An error occurred during repository forking %s') % (
self.db_repo_name, ))
u'Exception while trying to fork the repository %s', self.db_repo_name)
msg = _('An error occurred during repository forking %s') % (self.db_repo_name, )
h.flash(msg, category='error')
raise HTTPFound(h.route_path('home'))
repo_name = form_result.get('repo_name_full', self.db_repo_name)
events.trigger(events.UserPermissionsChange([self._rhodecode_user.user_id]))
affected_user_ids = [self._rhodecode_user.user_id]
if copy_permissions:
repository = Repository.get_by_repo_name(repo_name)
# also include those newly created by copy
user_group_perms = repository.permissions(expand_from_user_groups=True)
copy_perms = [perm['user_id'] for perm in user_group_perms]
# also include those newly created by copy
affected_user_ids.extend(copy_perms)
events.trigger(events.UserPermissionsChange(affected_user_ids))
raise HTTPFound(
h.route_path('repo_creating',
repo_name=repo_name,
h.route_path('repo_creating', repo_name=repo_name,
_query=dict(task_id=task_id)))

View file

@ -168,8 +168,8 @@ class RepoSettingsView(RepoAppView):
Session().commit()
h.flash(_('Repository `{}` updated successfully').format(
old_repo_name), category='success')
h.flash(_('Repository `{}` updated successfully').format(old_repo_name),
category='success')
except Exception:
log.exception("Exception during update of repository")
h.flash(_('Error occurred during update of repository {}').format(
@ -177,10 +177,14 @@ class RepoSettingsView(RepoAppView):
name_changed = old_repo_name != new_repo_name
if name_changed:
current_perms = self.db_repo.permissions(expand_from_user_groups=True)
affected_user_ids = [perm['user_id'] for perm in current_perms]
# NOTE(marcink): also add owner maybe it has changed
owner = User.get_by_username(schema_data['repo_owner'])
owner_id = owner.user_id if owner else self._rhodecode_user.user_id
events.trigger(events.UserPermissionsChange([
self._rhodecode_user.user_id, owner_id]))
affected_user_ids.extend([self._rhodecode_user.user_id, owner_id])
events.trigger(events.UserPermissionsChange(affected_user_ids))
raise HTTPFound(
h.route_path('edit_repo', repo_name=new_repo_name))

View file

@ -959,12 +959,14 @@ class User(Base, BaseModel):
return user
@classmethod
def get_all_super_admins(cls):
def get_all_super_admins(cls, only_active=False):
"""
Returns all admin accounts sorted by username
"""
return User.query().filter(User.admin == true())\
.order_by(User.username.asc()).all()
qry = User.query().filter(User.admin == true()).order_by(User.username.asc())
if only_active:
qry = qry.filter(User.active == true())
return qry.all()
@classmethod
def get_default_user(cls, cache=False, refresh=False):
@ -1390,7 +1392,8 @@ class UserGroup(Base, BaseModel):
FromCache("sql_cache_short", "get_users_group_%s" % user_group_id))
return user_group.get(user_group_id)
def permissions(self, with_admins=True, with_owner=True):
def permissions(self, with_admins=True, with_owner=True,
expand_from_user_groups=False):
"""
Permissions for user groups
"""
@ -1441,19 +1444,29 @@ class UserGroup(Base, BaseModel):
# each group
perm_rows = sorted(perm_rows, key=display_user_sort)
return super_admin_rows + owner_row + perm_rows
user_groups_rows = []
if expand_from_user_groups:
for ug in self.permission_user_groups(with_members=True):
for user_data in ug.members:
user_groups_rows.append(user_data)
def permission_user_groups(self):
q = UserGroupUserGroupToPerm.query().filter(UserGroupUserGroupToPerm.target_user_group == self)
return super_admin_rows + owner_row + perm_rows + user_groups_rows
def permission_user_groups(self, with_members=False):
q = UserGroupUserGroupToPerm.query()\
.filter(UserGroupUserGroupToPerm.target_user_group == self)
q = q.options(joinedload(UserGroupUserGroupToPerm.user_group),
joinedload(UserGroupUserGroupToPerm.target_user_group),
joinedload(UserGroupUserGroupToPerm.permission),)
perm_rows = []
for _user_group in q.all():
usr = AttributeDict(_user_group.user_group.get_dict())
usr.permission = _user_group.permission.permission_name
perm_rows.append(usr)
entry = AttributeDict(_user_group.user_group.get_dict())
entry.permission = _user_group.permission.permission_name
if with_members:
entry.members = [x.user.get_dict()
for x in _user_group.users_group.members]
perm_rows.append(entry)
perm_rows = sorted(perm_rows, key=display_user_group_sort)
return perm_rows
@ -1928,7 +1941,8 @@ class Repository(Base, BaseModel):
from rhodecode.lib.utils import make_db_config
return make_db_config(clear_session=False, repo=self)
def permissions(self, with_admins=True, with_owner=True):
def permissions(self, with_admins=True, with_owner=True,
expand_from_user_groups=False):
"""
Permissions for repositories
"""
@ -1986,20 +2000,29 @@ class Repository(Base, BaseModel):
# each group
perm_rows = sorted(perm_rows, key=display_user_sort)
return super_admin_rows + owner_row + perm_rows
user_groups_rows = []
if expand_from_user_groups:
for ug in self.permission_user_groups(with_members=True):
for user_data in ug.members:
user_groups_rows.append(user_data)
def permission_user_groups(self):
q = UserGroupRepoToPerm.query().filter(
UserGroupRepoToPerm.repository == self)
return super_admin_rows + owner_row + perm_rows + user_groups_rows
def permission_user_groups(self, with_members=True):
q = UserGroupRepoToPerm.query()\
.filter(UserGroupRepoToPerm.repository == self)
q = q.options(joinedload(UserGroupRepoToPerm.repository),
joinedload(UserGroupRepoToPerm.users_group),
joinedload(UserGroupRepoToPerm.permission),)
perm_rows = []
for _user_group in q.all():
usr = AttributeDict(_user_group.users_group.get_dict())
usr.permission = _user_group.permission.permission_name
perm_rows.append(usr)
entry = AttributeDict(_user_group.users_group.get_dict())
entry.permission = _user_group.permission.permission_name
if with_members:
entry.members = [x.user.get_dict()
for x in _user_group.users_group.members]
perm_rows.append(entry)
perm_rows = sorted(perm_rows, key=display_user_group_sort)
return perm_rows
@ -2641,7 +2664,8 @@ class RepoGroup(Base, BaseModel):
self.parent_group else [])
return RepoGroup.url_sep().join(path_prefix + [group_name])
def permissions(self, with_admins=True, with_owner=True):
def permissions(self, with_admins=True, with_owner=True,
expand_from_user_groups=False):
"""
Permissions for repository groups
"""
@ -2692,20 +2716,29 @@ class RepoGroup(Base, BaseModel):
# each group
perm_rows = sorted(perm_rows, key=display_user_sort)
return super_admin_rows + owner_row + perm_rows
user_groups_rows = []
if expand_from_user_groups:
for ug in self.permission_user_groups(with_members=True):
for user_data in ug.members:
user_groups_rows.append(user_data)
def permission_user_groups(self):
q = UserGroupRepoGroupToPerm.query().filter(
UserGroupRepoGroupToPerm.group == self)
return super_admin_rows + owner_row + perm_rows + user_groups_rows
def permission_user_groups(self, with_members=False):
q = UserGroupRepoGroupToPerm.query()\
.filter(UserGroupRepoGroupToPerm.group == self)
q = q.options(joinedload(UserGroupRepoGroupToPerm.group),
joinedload(UserGroupRepoGroupToPerm.users_group),
joinedload(UserGroupRepoGroupToPerm.permission),)
perm_rows = []
for _user_group in q.all():
usr = AttributeDict(_user_group.users_group.get_dict())
usr.permission = _user_group.permission.permission_name
perm_rows.append(usr)
entry = AttributeDict(_user_group.users_group.get_dict())
entry.permission = _user_group.permission.permission_name
if with_members:
entry.members = [x.user.get_dict()
for x in _user_group.users_group.members]
perm_rows.append(entry)
perm_rows = sorted(perm_rows, key=display_user_group_sort)
return perm_rows