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
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2020 Lance Edgar
|
# Copyright © 2010-2021 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -93,9 +93,6 @@ def set_session_timeout(request, timeout):
|
||||||
class TailboneAuthorizationPolicy(object):
|
class TailboneAuthorizationPolicy(object):
|
||||||
|
|
||||||
def permits(self, context, principals, permission):
|
def permits(self, context, principals, permission):
|
||||||
from rattail.db import model
|
|
||||||
from rattail.db.auth import has_permission
|
|
||||||
|
|
||||||
for userid in principals:
|
for userid in principals:
|
||||||
if userid not in (Everyone, Authenticated):
|
if userid not in (Everyone, Authenticated):
|
||||||
if context.request.user and context.request.user.uuid == userid:
|
if context.request.user and context.request.user.uuid == userid:
|
||||||
|
@ -103,11 +100,15 @@ class TailboneAuthorizationPolicy(object):
|
||||||
else:
|
else:
|
||||||
# this is pretty rare, but can happen in dev after
|
# this is pretty rare, but can happen in dev after
|
||||||
# re-creating the database, which means new user uuids.
|
# 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
|
# TODO: the odds of this query returning a user in that
|
||||||
# case, are probably nil, and we should just skip this bit?
|
# case, are probably nil, and we should just skip this bit?
|
||||||
user = Session.query(model.User).get(userid)
|
user = Session.query(model.User).get(userid)
|
||||||
if user:
|
if user:
|
||||||
if has_permission(Session(), user, permission):
|
if auth.has_permission(Session(), user, permission):
|
||||||
return True
|
return True
|
||||||
if Everyone in principals:
|
if Everyone in principals:
|
||||||
return has_permission(Session(), None, permission)
|
return has_permission(Session(), None, permission)
|
||||||
|
|
|
@ -32,7 +32,6 @@ import datetime
|
||||||
|
|
||||||
import rattail
|
import rattail
|
||||||
from rattail.db import model
|
from rattail.db import model
|
||||||
from rattail.db.auth import cache_permissions
|
|
||||||
|
|
||||||
import colander
|
import colander
|
||||||
import deform
|
import deform
|
||||||
|
@ -69,6 +68,7 @@ def new_request(event):
|
||||||
"""
|
"""
|
||||||
request = event.request
|
request = event.request
|
||||||
rattail_config = request.registry.settings.get('rattail_config')
|
rattail_config = request.registry.settings.get('rattail_config')
|
||||||
|
# TODO: why would this ever be null?
|
||||||
if rattail_config:
|
if rattail_config:
|
||||||
request.rattail_config = 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_admin = bool(request.user) and request.user.is_admin()
|
||||||
request.is_root = request.is_admin and request.session.get('is_root', False)
|
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):
|
def before_render(event):
|
||||||
|
|
|
@ -52,10 +52,13 @@ class RoleView(PrincipalMasterView):
|
||||||
"""
|
"""
|
||||||
model_class = model.Role
|
model_class = model.Role
|
||||||
has_versions = True
|
has_versions = True
|
||||||
|
touchable = True
|
||||||
|
|
||||||
grid_columns = [
|
grid_columns = [
|
||||||
'name',
|
'name',
|
||||||
'session_timeout',
|
'session_timeout',
|
||||||
|
'sync_me',
|
||||||
|
'node_type',
|
||||||
'notes',
|
'notes',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -63,6 +66,8 @@ class RoleView(PrincipalMasterView):
|
||||||
'name',
|
'name',
|
||||||
'session_timeout',
|
'session_timeout',
|
||||||
'notes',
|
'notes',
|
||||||
|
'sync_me',
|
||||||
|
'node_type',
|
||||||
'users',
|
'users',
|
||||||
'permissions',
|
'permissions',
|
||||||
]
|
]
|
||||||
|
@ -93,6 +98,11 @@ class RoleView(PrincipalMasterView):
|
||||||
We must prevent edit for certain built-in roles etc., depending on
|
We must prevent edit for certain built-in roles etc., depending on
|
||||||
current user's permissions.
|
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
|
# only "root" can edit Administrator
|
||||||
if role is administrator_role(self.Session()):
|
if role is administrator_role(self.Session()):
|
||||||
return self.request.is_root
|
return self.request.is_root
|
||||||
|
@ -116,6 +126,11 @@ class RoleView(PrincipalMasterView):
|
||||||
"""
|
"""
|
||||||
We must prevent deletion for all built-in roles.
|
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()):
|
if role is administrator_role(self.Session()):
|
||||||
return False
|
return False
|
||||||
if role is authenticated_role(self.Session()):
|
if role is authenticated_role(self.Session()):
|
||||||
|
@ -147,6 +162,27 @@ class RoleView(PrincipalMasterView):
|
||||||
# name
|
# name
|
||||||
f.set_validator('name', self.unique_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
|
# notes
|
||||||
f.set_type('notes', 'text_wrapped')
|
f.set_type('notes', 'text_wrapped')
|
||||||
|
|
||||||
|
@ -173,11 +209,6 @@ class RoleView(PrincipalMasterView):
|
||||||
elif self.deleting:
|
elif self.deleting:
|
||||||
f.remove_field('permissions')
|
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):
|
def render_users(self, role, field):
|
||||||
|
|
||||||
if role is guest_role(self.Session()):
|
if role is guest_role(self.Session()):
|
||||||
|
@ -417,6 +448,7 @@ class RoleView(PrincipalMasterView):
|
||||||
route_prefix = cls.get_route_prefix()
|
route_prefix = cls.get_route_prefix()
|
||||||
url_prefix = cls.get_url_prefix()
|
url_prefix = cls.get_url_prefix()
|
||||||
permission_prefix = cls.get_permission_prefix()
|
permission_prefix = cls.get_permission_prefix()
|
||||||
|
model_title = cls.get_model_title()
|
||||||
|
|
||||||
# extra permissions for editing built-in roles etc.
|
# extra permissions for editing built-in roles etc.
|
||||||
config.add_tailbone_permission(permission_prefix, '{}.edit_authenticated'.format(permission_prefix),
|
config.add_tailbone_permission(permission_prefix, '{}.edit_authenticated'.format(permission_prefix),
|
||||||
|
@ -425,6 +457,9 @@ class RoleView(PrincipalMasterView):
|
||||||
"Edit the \"Guest\" Role")
|
"Edit the \"Guest\" Role")
|
||||||
config.add_tailbone_permission(permission_prefix, '{}.edit_my'.format(permission_prefix),
|
config.add_tailbone_permission(permission_prefix, '{}.edit_my'.format(permission_prefix),
|
||||||
"Edit Role(s) to which current user belongs")
|
"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
|
# download permissions matrix
|
||||||
config.add_tailbone_permission(permission_prefix, '{}.download_permissions_matrix'.format(permission_prefix),
|
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:
|
if self.request.is_root or uuid != admin.uuid:
|
||||||
user._roles.append(model.UserRole(role_uuid=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
|
# remove any roles which were *not* specified, although must take care
|
||||||
# not to remove admin role, unless acting as root
|
# not to remove admin role, unless acting as root
|
||||||
for uuid in old_roles:
|
for uuid in old_roles:
|
||||||
|
@ -328,6 +336,14 @@ class UserView(PrincipalMasterView):
|
||||||
role = self.Session.query(model.Role).get(uuid)
|
role = self.Session.query(model.Role).get(uuid)
|
||||||
user.roles.remove(role)
|
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):
|
def render_person(self, user, field):
|
||||||
person = user.person
|
person = user.person
|
||||||
if not person:
|
if not person:
|
||||||
|
|
Loading…
Reference in a new issue