Require pyramid 2.x; remove 1.x-style auth policies
This commit is contained in:
parent
e17ef2edd8
commit
efe477d0db
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue