Invoke the auth handler to cache user permissions etc.
various changes for sake of "synced" roles feature
This commit is contained in:
parent
80589cde2f
commit
22aa55c24b
|
@ -2,7 +2,7 @@
|
|||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2020 Lance Edgar
|
||||
# Copyright © 2010-2021 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
|
@ -93,9 +93,6 @@ def set_session_timeout(request, timeout):
|
|||
class TailboneAuthorizationPolicy(object):
|
||||
|
||||
def permits(self, context, principals, permission):
|
||||
from rattail.db import model
|
||||
from rattail.db.auth import has_permission
|
||||
|
||||
for userid in principals:
|
||||
if userid not in (Everyone, Authenticated):
|
||||
if context.request.user and context.request.user.uuid == userid:
|
||||
|
@ -103,11 +100,15 @@ class TailboneAuthorizationPolicy(object):
|
|||
else:
|
||||
# this is pretty rare, but can happen in dev after
|
||||
# re-creating the database, which means new user uuids.
|
||||
config = context.request.rattail_config
|
||||
model = config.get_model()
|
||||
app = config.get_app()
|
||||
auth = app.get_auth_handler()
|
||||
# TODO: the odds of this query returning a user in that
|
||||
# case, are probably nil, and we should just skip this bit?
|
||||
user = Session.query(model.User).get(userid)
|
||||
if user:
|
||||
if has_permission(Session(), user, permission):
|
||||
if auth.has_permission(Session(), user, permission):
|
||||
return True
|
||||
if Everyone in principals:
|
||||
return has_permission(Session(), None, permission)
|
||||
|
|
|
@ -32,7 +32,6 @@ import datetime
|
|||
|
||||
import rattail
|
||||
from rattail.db import model
|
||||
from rattail.db.auth import cache_permissions
|
||||
|
||||
import colander
|
||||
import deform
|
||||
|
@ -69,6 +68,7 @@ def new_request(event):
|
|||
"""
|
||||
request = event.request
|
||||
rattail_config = request.registry.settings.get('rattail_config')
|
||||
# TODO: why would this ever be null?
|
||||
if rattail_config:
|
||||
request.rattail_config = rattail_config
|
||||
|
||||
|
@ -86,7 +86,17 @@ def new_request(event):
|
|||
request.is_admin = bool(request.user) and request.user.is_admin()
|
||||
request.is_root = request.is_admin and request.session.get('is_root', False)
|
||||
|
||||
request.tailbone_cached_permissions = cache_permissions(Session(), request.user)
|
||||
if rattail_config:
|
||||
app = rattail_config.get_app()
|
||||
auth = app.get_auth_handler()
|
||||
request.tailbone_cached_permissions = auth.cache_permissions(
|
||||
Session(), request.user)
|
||||
else:
|
||||
# TODO: not sure why this would really work, or even be
|
||||
# needed, if there was no rattail config?
|
||||
from rattail.db.auth import cache_permissions
|
||||
request.tailbone_cached_permissions = cache_permissions(
|
||||
Session(), request.user)
|
||||
|
||||
|
||||
def before_render(event):
|
||||
|
|
|
@ -52,10 +52,13 @@ class RoleView(PrincipalMasterView):
|
|||
"""
|
||||
model_class = model.Role
|
||||
has_versions = True
|
||||
touchable = True
|
||||
|
||||
grid_columns = [
|
||||
'name',
|
||||
'session_timeout',
|
||||
'sync_me',
|
||||
'node_type',
|
||||
'notes',
|
||||
]
|
||||
|
||||
|
@ -63,6 +66,8 @@ class RoleView(PrincipalMasterView):
|
|||
'name',
|
||||
'session_timeout',
|
||||
'notes',
|
||||
'sync_me',
|
||||
'node_type',
|
||||
'users',
|
||||
'permissions',
|
||||
]
|
||||
|
@ -93,6 +98,11 @@ class RoleView(PrincipalMasterView):
|
|||
We must prevent edit for certain built-in roles etc., depending on
|
||||
current user's permissions.
|
||||
"""
|
||||
# role with node type specified, can only be edited from a
|
||||
# node of the same type
|
||||
if role.node_type and role.node_type != self.rattail_config.node_type():
|
||||
return False
|
||||
|
||||
# only "root" can edit Administrator
|
||||
if role is administrator_role(self.Session()):
|
||||
return self.request.is_root
|
||||
|
@ -116,6 +126,11 @@ class RoleView(PrincipalMasterView):
|
|||
"""
|
||||
We must prevent deletion for all built-in roles.
|
||||
"""
|
||||
# role with node type specified, can only be edited from a
|
||||
# node of the same type
|
||||
if role.node_type and role.node_type != self.rattail_config.node_type():
|
||||
return False
|
||||
|
||||
if role is administrator_role(self.Session()):
|
||||
return False
|
||||
if role is authenticated_role(self.Session()):
|
||||
|
@ -147,6 +162,27 @@ class RoleView(PrincipalMasterView):
|
|||
# name
|
||||
f.set_validator('name', self.unique_name)
|
||||
|
||||
# session_timeout
|
||||
f.set_renderer('session_timeout', self.render_session_timeout)
|
||||
if self.editing and role is guest_role(self.Session()):
|
||||
f.set_readonly('session_timeout')
|
||||
|
||||
# sync_me, node_type
|
||||
if not self.creating:
|
||||
include = True
|
||||
if role is administrator_role(self.Session()):
|
||||
include = False
|
||||
elif role is authenticated_role(self.Session()):
|
||||
include = False
|
||||
elif role is guest_role(self.Session()):
|
||||
include = False
|
||||
if not include:
|
||||
f.remove('sync_me', 'node_type')
|
||||
else:
|
||||
if not self.has_perm('edit_node_sync'):
|
||||
f.set_readonly('sync_me')
|
||||
f.set_readonly('node_type')
|
||||
|
||||
# notes
|
||||
f.set_type('notes', 'text_wrapped')
|
||||
|
||||
|
@ -173,11 +209,6 @@ class RoleView(PrincipalMasterView):
|
|||
elif self.deleting:
|
||||
f.remove_field('permissions')
|
||||
|
||||
# session_timeout
|
||||
f.set_renderer('session_timeout', self.render_session_timeout)
|
||||
if self.editing and role is guest_role(self.Session()):
|
||||
f.set_readonly('session_timeout')
|
||||
|
||||
def render_users(self, role, field):
|
||||
|
||||
if role is guest_role(self.Session()):
|
||||
|
@ -417,6 +448,7 @@ class RoleView(PrincipalMasterView):
|
|||
route_prefix = cls.get_route_prefix()
|
||||
url_prefix = cls.get_url_prefix()
|
||||
permission_prefix = cls.get_permission_prefix()
|
||||
model_title = cls.get_model_title()
|
||||
|
||||
# extra permissions for editing built-in roles etc.
|
||||
config.add_tailbone_permission(permission_prefix, '{}.edit_authenticated'.format(permission_prefix),
|
||||
|
@ -425,6 +457,9 @@ class RoleView(PrincipalMasterView):
|
|||
"Edit the \"Guest\" Role")
|
||||
config.add_tailbone_permission(permission_prefix, '{}.edit_my'.format(permission_prefix),
|
||||
"Edit Role(s) to which current user belongs")
|
||||
config.add_tailbone_permission(permission_prefix,
|
||||
'{}.edit_node_sync'.format(permission_prefix),
|
||||
"Edit the Node Type and Sync flags for a {}".format(model_title))
|
||||
|
||||
# download permissions matrix
|
||||
config.add_tailbone_permission(permission_prefix, '{}.download_permissions_matrix'.format(permission_prefix),
|
||||
|
|
|
@ -320,6 +320,14 @@ class UserView(PrincipalMasterView):
|
|||
if self.request.is_root or uuid != admin.uuid:
|
||||
user._roles.append(model.UserRole(role_uuid=uuid))
|
||||
|
||||
# also record a change to the role, for datasync.
|
||||
# this is done "just in case" the role is to be
|
||||
# synced to all nodes
|
||||
if self.Session().rattail_record_changes:
|
||||
self.Session.add(model.Change(class_name='Role',
|
||||
instance_uuid=uuid,
|
||||
deleted=False))
|
||||
|
||||
# remove any roles which were *not* specified, although must take care
|
||||
# not to remove admin role, unless acting as root
|
||||
for uuid in old_roles:
|
||||
|
@ -328,6 +336,14 @@ class UserView(PrincipalMasterView):
|
|||
role = self.Session.query(model.Role).get(uuid)
|
||||
user.roles.remove(role)
|
||||
|
||||
# also record a change to the role, for datasync.
|
||||
# this is done "just in case" the role is to be
|
||||
# synced to all nodes
|
||||
if self.Session().rattail_record_changes:
|
||||
self.Session.add(model.Change(class_name='Role',
|
||||
instance_uuid=uuid,
|
||||
deleted=False))
|
||||
|
||||
def render_person(self, user, field):
|
||||
person = user.person
|
||||
if not person:
|
||||
|
|
Loading…
Reference in a new issue