diff --git a/tailbone/api/auth.py b/tailbone/api/auth.py index 16e48e82..80f8fac0 100644 --- a/tailbone/api/auth.py +++ b/tailbone/api/auth.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2020 Lance Edgar +# Copyright © 2010-2021 Lance Edgar # # This file is part of Rattail. # @@ -26,7 +26,7 @@ Tailbone Web API - Auth Views 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 @@ -82,15 +82,20 @@ class AuthenticationView(APIView): if error: return {'error': error} + app = self.get_rattail_app() + auth = app.get_auth_handler() + login_user(self.request, user) return { 'ok': True, '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): - 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): """ @@ -156,7 +161,7 @@ class AuthenticationView(APIView): data = self.request.json_body # 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"} # okay then, set new password diff --git a/tailbone/auth.py b/tailbone/auth.py index deda1ab7..88fbab0b 100644 --- a/tailbone/auth.py +++ b/tailbone/auth.py @@ -93,6 +93,11 @@ def set_session_timeout(request, timeout): class TailboneAuthorizationPolicy(object): 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: if userid not in (Everyone, Authenticated): if context.request.user and context.request.user.uuid == userid: @@ -100,10 +105,6 @@ 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) @@ -111,7 +112,7 @@ class TailboneAuthorizationPolicy(object): if auth.has_permission(Session(), user, permission): return True if Everyone in principals: - return has_permission(Session(), None, permission) + return auth.has_permission(Session(), None, permission) return False def principals_allowed_by_permission(self, context, permission): diff --git a/tailbone/subscribers.py b/tailbone/subscribers.py index 5468df7f..6fbced82 100644 --- a/tailbone/subscribers.py +++ b/tailbone/subscribers.py @@ -91,12 +91,13 @@ def new_request(event): 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) + # TODO: until we know otherwise, let's assume this is not needed + # 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): diff --git a/tailbone/views/auth.py b/tailbone/views/auth.py index d071ace7..efe2794d 100644 --- a/tailbone/views/auth.py +++ b/tailbone/views/auth.py @@ -50,9 +50,12 @@ class UserLogin(colander.MappingSchema): @colander.deferred def current_password_correct(node, kw): + request = kw['request'] + app = request.rattail_config.get_app() + auth = app.get_auth_handler() user = kw['user'] 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") return validate @@ -175,7 +178,7 @@ class AuthenticationView(View): return self.redirect(self.request.get_referrer()) 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) if form.validate(newstyle=True): set_user_password(self.request.user, form.validated['new_password']) diff --git a/tailbone/views/principal.py b/tailbone/views/principal.py index b3d032ab..3fc5ce6b 100644 --- a/tailbone/views/principal.py +++ b/tailbone/views/principal.py @@ -28,7 +28,6 @@ from __future__ import unicode_literals, absolute_import import copy -from rattail.db.auth import has_permission from rattail.core import Object from rattail.util import OrderedDict @@ -144,6 +143,9 @@ class PermissionsRenderer(Object): return self.render() def render(self): + app = self.request.rattail_config.get_app() + auth = app.get_handler() + principal = self.principal html = '' 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'] rendered = False for key in sorted(perms, key=lambda p: perms[p]['label'].lower()): - checked = has_permission(Session(), principal, key, - include_guest=self.include_guest, - include_authenticated=self.include_authenticated) + checked = auth.has_permission(Session(), principal, key, + include_guest=self.include_guest, + include_authenticated=self.include_authenticated) if checked: label = perms[key]['label'] span = HTML.tag('span', c="[X]" if checked else "[ ]") diff --git a/tailbone/views/roles.py b/tailbone/views/roles.py index ded1f5cf..2ce48f0d 100644 --- a/tailbone/views/roles.py +++ b/tailbone/views/roles.py @@ -33,8 +33,7 @@ from sqlalchemy import orm from openpyxl.styles import Font, PatternFill from rattail.db import model -from rattail.db.auth import (has_permission, grant_permission, revoke_permission, - administrator_role, guest_role, authenticated_role) +from rattail.db.auth import administrator_role, guest_role, authenticated_role from rattail.excel import ExcelWriter import colander @@ -158,6 +157,8 @@ class RoleView(PrincipalMasterView): super(RoleView, self).configure_form(f) role = f.model_instance use_buefy = self.get_use_buefy() + app = self.get_rattail_app() + auth = app.get_auth_handler() # name f.set_validator('name', self.unique_name) @@ -194,7 +195,8 @@ class RoleView(PrincipalMasterView): # 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_widget('permissions', PermissionsWidget( permissions=self.tailbone_permissions, @@ -203,7 +205,9 @@ class RoleView(PrincipalMasterView): granted = [] for groupkey in self.tailbone_permissions: 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) f.set_default('permissions', granted) elif self.deleting: @@ -309,13 +313,16 @@ class RoleView(PrincipalMasterView): permissions, but rather each "available" permission (depends on current user) will be examined individually, and updated as needed. """ + app = self.get_rattail_app() + auth = app.get_auth_handler() + available = self.tailbone_permissions for gkey, group in six.iteritems(available): for pkey, perm in six.iteritems(group['perms']): if pkey in permissions: - grant_permission(role, pkey) + auth.grant_permission(role, pkey) else: - revoke_permission(role, pkey) + auth.revoke_permission(role, pkey) def template_kwargs_view(self, **kwargs): role = kwargs['instance'] @@ -364,13 +371,16 @@ class RoleView(PrincipalMasterView): return self.redirect(self.request.get_referrer(default=self.request.route_url('roles'))) 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? all_roles = session.query(model.Role)\ .order_by(model.Role.name)\ .options(orm.joinedload(model.Role._permissions)) 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) return roles @@ -379,6 +389,9 @@ class RoleView(PrincipalMasterView): View which renders the complete role / permissions matrix data into an Excel spreadsheet, and returns that file. """ + app = self.get_rattail_app() + auth = app.get_auth_handler() + roles = self.Session.query(model.Role)\ .order_by(model.Role.name)\ .all() @@ -427,7 +440,8 @@ class RoleView(PrincipalMasterView): # and show an 'X' for any role which has this perm 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") writing_row += 1 diff --git a/tailbone/views/users.py b/tailbone/views/users.py index b0f6a5de..7b8312bd 100644 --- a/tailbone/views/users.py +++ b/tailbone/views/users.py @@ -32,7 +32,8 @@ import six from sqlalchemy import orm 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 from deform import widget as dfwidget @@ -239,7 +240,8 @@ class UserView(PrincipalMasterView): if self.viewing: permissions = self.request.registry.settings.get('tailbone_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_authenticated=True)) @@ -389,6 +391,9 @@ class UserView(PrincipalMasterView): ] 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? all_users = session.query(model.User)\ .filter(model.User.active == True)\ @@ -398,7 +403,7 @@ class UserView(PrincipalMasterView): .joinedload(model.Role._permissions)) users = [] for user in all_users: - if has_permission(session, user, permission): + if auth.has_permission(session, user, permission): users.append(user) return users