# -*- coding: utf-8 -*- ################################################################################ # # Rattail -- Retail Software Framework # Copyright © 2010-2017 Lance Edgar # # This file is part of Rattail. # # Rattail is free software: you can redistribute it and/or modify it under the # terms of the GNU Affero General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) # any later version. # # Rattail is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for # more details. # # You should have received a copy of the GNU Affero General Public License # along with Rattail. If not, see . # ################################################################################ """ Authentication & Authorization """ from __future__ import unicode_literals, absolute_import import logging from rattail.db import model from rattail.db.auth import has_permission from rattail.util import prettify, NOTSET from zope.interface import implementer from pyramid.interfaces import IAuthorizationPolicy from pyramid.security import remember, Everyone, Authenticated from tailbone.db import Session log = logging.getLogger(__name__) def login_user(request, user, type_='default', timeout=NOTSET): """ Perform the steps necessary to login the given user. Note that this returns a ``headers`` dict which you should pass to the redirect. """ headers = remember(request, user.uuid) if timeout is NOTSET: timeout = get_session_timeout_for_user(request.rattail_config, user, type_) or None log.debug("setting session timeout for '{}' to {}".format(user.username, timeout)) set_session_timeout(request, timeout) return headers def get_session_timeout_for_user(config, user, type_='default'): """ Must return a value to be used to set the session timeout for the given user. By default this will return ``None`` if the user has the "forever session" permission, otherwise will try to read a default value from config: .. code-block:: ini [tailbone] # set session timeout to 10 minutes: session.timeout.default = 600 # or, set to 0 to disable: #session.timeout.default = 0 """ if not has_permission(Session(), user, 'general.forever_session'): timeout = config.getint('tailbone', 'session.timeout.{}'.format(type_)) # TODO: remove this hack after no longer needed if timeout is None and type_ == 'default': timeout = config.getint('tailbone', 'session.default_timeout') return timeout if timeout is not None else 300 # 5 minutes def set_session_timeout(request, timeout): """ Set the server-side session timeout to the given value. """ request.session['_timeout'] = timeout or None @implementer(IAuthorizationPolicy) class TailboneAuthorizationPolicy(object): def permits(self, context, principals, permission): 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: assert False # should no longer happen..right? user = Session.query(model.User).get(userid) if user: if has_permission(Session(), user, permission): return True if Everyone in principals: return has_permission(Session(), None, permission) return False def principals_allowed_by_permission(self, context, permission): raise NotImplementedError def add_permission_group(config, key, label=None, overwrite=True): """ Add a permission group to the app configuration. """ def action(): perms = config.get_settings().get('tailbone_permissions', {}) if key not in perms or overwrite: group = perms.setdefault(key, {'key': key}) group['label'] = label or prettify(key) config.add_settings({'tailbone_permissions': perms}) config.action(None, action) def add_permission(config, groupkey, key, label=None): """ Add a permission to the app configuration. """ def action(): perms = config.get_settings().get('tailbone_permissions', {}) group = perms.setdefault(groupkey, {'key': groupkey}) group.setdefault('label', prettify(groupkey)) perm = group.setdefault('perms', {}).setdefault(key, {'key': key}) perm['label'] = label or prettify(key) config.add_settings({'tailbone_permissions': perms}) config.action(None, action)