Refactor to leverage all existing methods of auth handler

instead of importing and calling functions from core rattail
This commit is contained in:
Lance Edgar 2021-10-14 21:42:16 -04:00
parent 53fc1508f3
commit 232a02b944
7 changed files with 64 additions and 33 deletions

View file

@ -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.
# #
@ -26,7 +26,7 @@ Tailbone Web API - Auth Views
from __future__ import unicode_literals, absolute_import from __future__ import unicode_literals, absolute_import
from rattail.db.auth import authenticate_user, set_user_password, cache_permissions from rattail.db.auth import set_user_password
from cornice import Service from cornice import Service
@ -82,15 +82,20 @@ class AuthenticationView(APIView):
if error: if error:
return {'error': error} return {'error': error}
app = self.get_rattail_app()
auth = app.get_auth_handler()
login_user(self.request, user) login_user(self.request, user)
return { return {
'ok': True, 'ok': True,
'user': self.get_user_info(user), 'user': self.get_user_info(user),
'permissions': list(cache_permissions(Session(), user)), 'permissions': list(auth.cache_permissions(Session(), user)),
} }
def authenticate_user(self, username, password): def authenticate_user(self, username, password):
return authenticate_user(Session(), username, password) app = self.get_rattail_app()
auth = app.get_auth_handler()
return auth.authenticate_user(Session(), username, password)
def why_cant_user_login(self, user): def why_cant_user_login(self, user):
""" """
@ -156,7 +161,7 @@ class AuthenticationView(APIView):
data = self.request.json_body data = self.request.json_body
# first make sure "current" password is accurate # first make sure "current" password is accurate
if not authenticate_user(Session(), self.request.user, data['current_password']): if not self.authenticate_user(self.request.user, data['current_password']):
return {'error': "The current/old password you provided is incorrect"} return {'error': "The current/old password you provided is incorrect"}
# okay then, set new password # okay then, set new password

View file

@ -93,6 +93,11 @@ def set_session_timeout(request, timeout):
class TailboneAuthorizationPolicy(object): class TailboneAuthorizationPolicy(object):
def permits(self, context, principals, permission): def permits(self, context, principals, permission):
config = context.request.rattail_config
model = config.get_model()
app = config.get_app()
auth = app.get_auth_handler()
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:
@ -100,10 +105,6 @@ 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)
@ -111,7 +112,7 @@ class TailboneAuthorizationPolicy(object):
if auth.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 auth.has_permission(Session(), None, permission)
return False return False
def principals_allowed_by_permission(self, context, permission): def principals_allowed_by_permission(self, context, permission):

View file

@ -91,12 +91,13 @@ def new_request(event):
auth = app.get_auth_handler() auth = app.get_auth_handler()
request.tailbone_cached_permissions = auth.cache_permissions( request.tailbone_cached_permissions = auth.cache_permissions(
Session(), request.user) Session(), request.user)
else: # TODO: until we know otherwise, let's assume this is not needed
# TODO: not sure why this would really work, or even be # else:
# needed, if there was no rattail config? # # TODO: not sure why this would really work, or even be
from rattail.db.auth import cache_permissions # # needed, if there was no rattail config?
request.tailbone_cached_permissions = cache_permissions( # from rattail.db.auth import cache_permissions
Session(), request.user) # request.tailbone_cached_permissions = cache_permissions(
# Session(), request.user)
def before_render(event): def before_render(event):

View file

@ -50,9 +50,12 @@ class UserLogin(colander.MappingSchema):
@colander.deferred @colander.deferred
def current_password_correct(node, kw): def current_password_correct(node, kw):
request = kw['request']
app = request.rattail_config.get_app()
auth = app.get_auth_handler()
user = kw['user'] user = kw['user']
def validate(node, value): def validate(node, value):
if not authenticate_user(Session(), user.username, value): if not auth.authenticate_user(Session(), user.username, value):
raise colander.Invalid(node, "The password is incorrect") raise colander.Invalid(node, "The password is incorrect")
return validate return validate
@ -175,7 +178,7 @@ class AuthenticationView(View):
return self.redirect(self.request.get_referrer()) return self.redirect(self.request.get_referrer())
use_buefy = self.get_use_buefy() use_buefy = self.get_use_buefy()
schema = ChangePassword().bind(user=self.request.user) schema = ChangePassword().bind(user=self.request.user, request=self.request)
form = forms.Form(schema=schema, request=self.request, use_buefy=use_buefy) form = forms.Form(schema=schema, request=self.request, use_buefy=use_buefy)
if form.validate(newstyle=True): if form.validate(newstyle=True):
set_user_password(self.request.user, form.validated['new_password']) set_user_password(self.request.user, form.validated['new_password'])

View file

@ -28,7 +28,6 @@ from __future__ import unicode_literals, absolute_import
import copy import copy
from rattail.db.auth import has_permission
from rattail.core import Object from rattail.core import Object
from rattail.util import OrderedDict from rattail.util import OrderedDict
@ -144,6 +143,9 @@ class PermissionsRenderer(Object):
return self.render() return self.render()
def render(self): def render(self):
app = self.request.rattail_config.get_app()
auth = app.get_handler()
principal = self.principal principal = self.principal
html = '' html = ''
for groupkey in sorted(self.permissions, key=lambda k: self.permissions[k]['label'].lower()): for groupkey in sorted(self.permissions, key=lambda k: self.permissions[k]['label'].lower()):
@ -151,9 +153,9 @@ class PermissionsRenderer(Object):
perms = self.permissions[groupkey]['perms'] perms = self.permissions[groupkey]['perms']
rendered = False rendered = False
for key in sorted(perms, key=lambda p: perms[p]['label'].lower()): for key in sorted(perms, key=lambda p: perms[p]['label'].lower()):
checked = has_permission(Session(), principal, key, checked = auth.has_permission(Session(), principal, key,
include_guest=self.include_guest, include_guest=self.include_guest,
include_authenticated=self.include_authenticated) include_authenticated=self.include_authenticated)
if checked: if checked:
label = perms[key]['label'] label = perms[key]['label']
span = HTML.tag('span', c="[X]" if checked else "[ ]") span = HTML.tag('span', c="[X]" if checked else "[ ]")

View file

@ -33,8 +33,7 @@ from sqlalchemy import orm
from openpyxl.styles import Font, PatternFill from openpyxl.styles import Font, PatternFill
from rattail.db import model from rattail.db import model
from rattail.db.auth import (has_permission, grant_permission, revoke_permission, from rattail.db.auth import administrator_role, guest_role, authenticated_role
administrator_role, guest_role, authenticated_role)
from rattail.excel import ExcelWriter from rattail.excel import ExcelWriter
import colander import colander
@ -158,6 +157,8 @@ class RoleView(PrincipalMasterView):
super(RoleView, self).configure_form(f) super(RoleView, self).configure_form(f)
role = f.model_instance role = f.model_instance
use_buefy = self.get_use_buefy() use_buefy = self.get_use_buefy()
app = self.get_rattail_app()
auth = app.get_auth_handler()
# name # name
f.set_validator('name', self.unique_name) f.set_validator('name', self.unique_name)
@ -194,7 +195,8 @@ class RoleView(PrincipalMasterView):
# permissions # permissions
self.tailbone_permissions = self.get_available_permissions() self.tailbone_permissions = self.get_available_permissions()
f.set_renderer('permissions', PermissionsRenderer(permissions=self.tailbone_permissions)) f.set_renderer('permissions', PermissionsRenderer(request=self.request,
permissions=self.tailbone_permissions))
f.set_node('permissions', colander.Set()) f.set_node('permissions', colander.Set())
f.set_widget('permissions', PermissionsWidget( f.set_widget('permissions', PermissionsWidget(
permissions=self.tailbone_permissions, permissions=self.tailbone_permissions,
@ -203,7 +205,9 @@ class RoleView(PrincipalMasterView):
granted = [] granted = []
for groupkey in self.tailbone_permissions: for groupkey in self.tailbone_permissions:
for key in self.tailbone_permissions[groupkey]['perms']: for key in self.tailbone_permissions[groupkey]['perms']:
if has_permission(self.Session(), role, key, include_guest=False, include_authenticated=False): if auth.has_permission(self.Session(), role, key,
include_guest=False,
include_authenticated=False):
granted.append(key) granted.append(key)
f.set_default('permissions', granted) f.set_default('permissions', granted)
elif self.deleting: elif self.deleting:
@ -309,13 +313,16 @@ class RoleView(PrincipalMasterView):
permissions, but rather each "available" permission (depends on current permissions, but rather each "available" permission (depends on current
user) will be examined individually, and updated as needed. user) will be examined individually, and updated as needed.
""" """
app = self.get_rattail_app()
auth = app.get_auth_handler()
available = self.tailbone_permissions available = self.tailbone_permissions
for gkey, group in six.iteritems(available): for gkey, group in six.iteritems(available):
for pkey, perm in six.iteritems(group['perms']): for pkey, perm in six.iteritems(group['perms']):
if pkey in permissions: if pkey in permissions:
grant_permission(role, pkey) auth.grant_permission(role, pkey)
else: else:
revoke_permission(role, pkey) auth.revoke_permission(role, pkey)
def template_kwargs_view(self, **kwargs): def template_kwargs_view(self, **kwargs):
role = kwargs['instance'] role = kwargs['instance']
@ -364,13 +371,16 @@ class RoleView(PrincipalMasterView):
return self.redirect(self.request.get_referrer(default=self.request.route_url('roles'))) return self.redirect(self.request.get_referrer(default=self.request.route_url('roles')))
def find_principals_with_permission(self, session, permission): def find_principals_with_permission(self, session, permission):
app = self.get_rattail_app()
auth = app.get_auth_handler()
# TODO: this should search Permission table instead, and work backward to Role? # TODO: this should search Permission table instead, and work backward to Role?
all_roles = session.query(model.Role)\ all_roles = session.query(model.Role)\
.order_by(model.Role.name)\ .order_by(model.Role.name)\
.options(orm.joinedload(model.Role._permissions)) .options(orm.joinedload(model.Role._permissions))
roles = [] roles = []
for role in all_roles: for role in all_roles:
if has_permission(session, role, permission, include_guest=False): if auth.has_permission(session, role, permission, include_guest=False):
roles.append(role) roles.append(role)
return roles return roles
@ -379,6 +389,9 @@ class RoleView(PrincipalMasterView):
View which renders the complete role / permissions matrix data into an View which renders the complete role / permissions matrix data into an
Excel spreadsheet, and returns that file. Excel spreadsheet, and returns that file.
""" """
app = self.get_rattail_app()
auth = app.get_auth_handler()
roles = self.Session.query(model.Role)\ roles = self.Session.query(model.Role)\
.order_by(model.Role.name)\ .order_by(model.Role.name)\
.all() .all()
@ -427,7 +440,8 @@ class RoleView(PrincipalMasterView):
# and show an 'X' for any role which has this perm # and show an 'X' for any role which has this perm
for col, role in enumerate(roles, 2): for col, role in enumerate(roles, 2):
if has_permission(self.Session(), role, key, include_guest=False): if auth.has_permission(self.Session(), role, key,
include_guest=False):
sheet.cell(row=writing_row, column=col, value="X") sheet.cell(row=writing_row, column=col, value="X")
writing_row += 1 writing_row += 1

View file

@ -32,7 +32,8 @@ import six
from sqlalchemy import orm from sqlalchemy import orm
from rattail.db import model from rattail.db import model
from rattail.db.auth import administrator_role, guest_role, authenticated_role, set_user_password, has_permission from rattail.db.auth import (administrator_role, guest_role,
authenticated_role, set_user_password)
import colander import colander
from deform import widget as dfwidget from deform import widget as dfwidget
@ -239,7 +240,8 @@ class UserView(PrincipalMasterView):
if self.viewing: if self.viewing:
permissions = self.request.registry.settings.get('tailbone_permissions', {}) permissions = self.request.registry.settings.get('tailbone_permissions', {})
f.append('permissions') f.append('permissions')
f.set_renderer('permissions', PermissionsRenderer(permissions=permissions, f.set_renderer('permissions', PermissionsRenderer(request=self.request,
permissions=permissions,
include_guest=True, include_guest=True,
include_authenticated=True)) include_authenticated=True))
@ -389,6 +391,9 @@ class UserView(PrincipalMasterView):
] ]
def find_principals_with_permission(self, session, permission): def find_principals_with_permission(self, session, permission):
app = self.get_rattail_app()
auth = app.get_auth_handler()
# TODO: this should search Permission table instead, and work backward to User? # TODO: this should search Permission table instead, and work backward to User?
all_users = session.query(model.User)\ all_users = session.query(model.User)\
.filter(model.User.active == True)\ .filter(model.User.active == True)\
@ -398,7 +403,7 @@ class UserView(PrincipalMasterView):
.joinedload(model.Role._permissions)) .joinedload(model.Role._permissions))
users = [] users = []
for user in all_users: for user in all_users:
if has_permission(session, user, permission): if auth.has_permission(session, user, permission):
users.append(user) users.append(user)
return users return users