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 paginate_sqlalchemy
passlib passlib
Pillow Pillow
pyramid pyramid>=2
pyramid_beaker pyramid_beaker
pyramid_deform pyramid_deform
pyramid_exclog pyramid_exclog

View file

@ -39,7 +39,7 @@ from pyramid.authentication import SessionAuthenticationPolicy
from zope.sqlalchemy import register from zope.sqlalchemy import register
import tailbone.db 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.config import csrf_token_name, csrf_header_name
from tailbone.util import get_effective_theme, get_theme_template_path from tailbone.util import get_effective_theme, get_theme_template_path
from tailbone.providers import get_all_providers 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 config.registry['rattail_config'] = rattail_config
# configure user authorization / authentication # 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()) config.set_security_policy(TailboneSecurityPolicy())
else:
config.set_authorization_policy(TailboneAuthorizationPolicy())
config.set_authentication_policy(SessionAuthenticationPolicy())
# maybe require CSRF token protection # maybe require CSRF token protection
if configure_csrf: if configure_csrf:

View file

@ -30,9 +30,9 @@ import re
from rattail.util import prettify, NOTSET from rattail.util import prettify, NOTSET
from zope.interface import implementer from zope.interface import implementer
from pyramid.interfaces import IAuthorizationPolicy from pyramid.authentication import SessionAuthenticationHelper
from pyramid.security import remember, forget, Everyone, Authenticated from pyramid.request import RequestLocalCache
from pyramid.authentication import SessionAuthenticationPolicy from pyramid.security import remember, forget
from tailbone.db import Session from tailbone.db import Session
@ -90,73 +90,9 @@ def set_session_timeout(request, timeout):
request.session['_timeout'] = timeout or None 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: class TailboneSecurityPolicy:
def __init__(self, api_mode=False): def __init__(self, api_mode=False):
from pyramid.authentication import SessionAuthenticationHelper
from pyramid.request import RequestLocalCache
self.api_mode = api_mode self.api_mode = api_mode
self.session_helper = SessionAuthenticationHelper() self.session_helper = SessionAuthenticationHelper()
self.identity_cache = RequestLocalCache(self.load_identity) self.identity_cache = RequestLocalCache(self.load_identity)

View file

@ -30,7 +30,7 @@ from cornice.renderer import CorniceRenderer
from pyramid.config import Configurator from pyramid.config import Configurator
from tailbone import app from tailbone import app
from tailbone.auth import TailboneAuthenticationPolicy, TailboneAuthorizationPolicy from tailbone.auth import TailboneSecurityPolicy
from tailbone.providers import get_all_providers 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) pyramid_config = Configurator(settings=settings, root_factory=app.Root)
# configure user authorization / authentication # 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)) pyramid_config.set_security_policy(TailboneSecurityPolicy(api_mode=True))
else:
pyramid_config.set_authentication_policy(TailboneAuthenticationPolicy())
pyramid_config.set_authorization_policy(TailboneAuthorizationPolicy())
# always require CSRF token protection # always require CSRF token protection
pyramid_config.set_default_csrf_options(require_csrf=True, pyramid_config.set_default_csrf_options(require_csrf=True,