Require pyramid 2.x; remove 1.x-style auth policies

This commit is contained in:
Lance Edgar 2024-06-03 23:13:25 -05:00
parent e17ef2edd8
commit efe477d0db
4 changed files with 8 additions and 86 deletions

View file

@ -56,7 +56,7 @@ install_requires =
paginate_sqlalchemy
passlib
Pillow
pyramid
pyramid>=2
pyramid_beaker
pyramid_deform
pyramid_exclog

View file

@ -39,7 +39,7 @@ from pyramid.authentication import SessionAuthenticationPolicy
from zope.sqlalchemy import register
import tailbone.db
from tailbone.auth import TailboneAuthorizationPolicy
from tailbone.auth import TailboneSecurityPolicy
from tailbone.config import csrf_token_name, csrf_header_name
from tailbone.util import get_effective_theme, get_theme_template_path
from tailbone.providers import get_all_providers
@ -136,14 +136,7 @@ def make_pyramid_config(settings, configure_csrf=True):
config.registry['rattail_config'] = rattail_config
# configure user authorization / authentication
# TODO: security policy should become the default, for pyramid 2.x
if rattail_config.getbool('tailbone', 'pyramid.use_security_policy',
usedb=False, default=False):
from tailbone.auth import TailboneSecurityPolicy
config.set_security_policy(TailboneSecurityPolicy())
else:
config.set_authorization_policy(TailboneAuthorizationPolicy())
config.set_authentication_policy(SessionAuthenticationPolicy())
config.set_security_policy(TailboneSecurityPolicy())
# maybe require CSRF token protection
if configure_csrf:

View file

@ -30,9 +30,9 @@ import re
from rattail.util import prettify, NOTSET
from zope.interface import implementer
from pyramid.interfaces import IAuthorizationPolicy
from pyramid.security import remember, forget, Everyone, Authenticated
from pyramid.authentication import SessionAuthenticationPolicy
from pyramid.authentication import SessionAuthenticationHelper
from pyramid.request import RequestLocalCache
from pyramid.security import remember, forget
from tailbone.db import Session
@ -90,73 +90,9 @@ def set_session_timeout(request, timeout):
request.session['_timeout'] = timeout or None
class TailboneAuthenticationPolicy(SessionAuthenticationPolicy):
"""
Custom authentication policy for Tailbone.
This is mostly Pyramid's built-in session-based policy, but adds
logic to accept Rattail User API Tokens in lieu of current user
being identified via the session.
Note that the traditional Tailbone web app does *not* use this
policy, only the Tailbone web API uses it by default.
"""
def unauthenticated_userid(self, request):
# figure out userid from header token if present
credentials = request.headers.get('Authorization')
if credentials:
match = re.match(r'^Bearer (\S+)$', credentials)
if match:
token = match.group(1)
rattail_config = request.registry.settings.get('rattail_config')
app = rattail_config.get_app()
auth = app.get_auth_handler()
user = auth.authenticate_user_token(Session(), token)
if user:
return user.uuid
# otherwise do normal session-based logic
return super().unauthenticated_userid(request)
@implementer(IAuthorizationPolicy)
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:
return context.request.has_perm(permission)
else:
# this is pretty rare, but can happen in dev after
# re-creating the database, which means new user uuids.
# TODO: the odds of this query returning a user in that
# case, are probably nil, and we should just skip this bit?
user = Session.get(model.User, userid)
if user:
if auth.has_permission(Session(), user, permission):
return True
if Everyone in principals:
return auth.has_permission(Session(), None, permission)
return False
def principals_allowed_by_permission(self, context, permission):
raise NotImplementedError
class TailboneSecurityPolicy:
def __init__(self, api_mode=False):
from pyramid.authentication import SessionAuthenticationHelper
from pyramid.request import RequestLocalCache
self.api_mode = api_mode
self.session_helper = SessionAuthenticationHelper()
self.identity_cache = RequestLocalCache(self.load_identity)

View file

@ -30,7 +30,7 @@ from cornice.renderer import CorniceRenderer
from pyramid.config import Configurator
from tailbone import app
from tailbone.auth import TailboneAuthenticationPolicy, TailboneAuthorizationPolicy
from tailbone.auth import TailboneSecurityPolicy
from tailbone.providers import get_all_providers
@ -50,14 +50,7 @@ def make_pyramid_config(settings):
pyramid_config = Configurator(settings=settings, root_factory=app.Root)
# configure user authorization / authentication
# TODO: security policy should become the default, for pyramid 2.x
if rattail_config.getbool('tailbone', 'pyramid.use_security_policy',
usedb=False, default=False):
from tailbone.auth import TailboneSecurityPolicy
pyramid_config.set_security_policy(TailboneSecurityPolicy(api_mode=True))
else:
pyramid_config.set_authentication_policy(TailboneAuthenticationPolicy())
pyramid_config.set_authorization_policy(TailboneAuthorizationPolicy())
pyramid_config.set_security_policy(TailboneSecurityPolicy(api_mode=True))
# always require CSRF token protection
pyramid_config.set_default_csrf_options(require_csrf=True,