Page MenuHome

auth.py
No OneTemporary

File Metadata

Created
Fri, Nov 22, 11:57 AM
import enum
import flask
import attr
import bson
from pillar import attrs_extra
# Having any of these methods on a project means you can use Attract.
# Prerequisite: the project is set up for Attract and has a Manager assigned to it.
PROJECT_METHODS_TO_USE_ATTRACT = {'PUT'}
class Actions(enum.Enum):
VIEW = 'view'
USE = 'use'
# Required capability for a given action.
req_cap = {
Actions.VIEW: 'attract-view',
Actions.USE: 'attract-use',
}
@attr.s
class Auth(object):
"""Handles authorization for Attract."""
_log = attrs_extra.log('%s.Auth' % __name__)
Actions = Actions # this allows using current_attract.auth.Actions
def current_user_is_attract_user(self) -> bool:
"""Returns True iff the current user has Attract User role."""
from pillar.auth import current_user
return current_user.has_cap('attract-use')
def user_is_attract_user(self, user_id: bson.ObjectId) -> bool:
"""Returns True iff the user has Attract User role."""
from pillar import current_app
from pillar.auth import UserClass
assert isinstance(user_id, bson.ObjectId)
# TODO: move role checking code to Pillar.
users_coll = current_app.db('users')
db_user = users_coll.find_one({'_id': user_id}, {'roles': 1})
if not db_user:
self._log.debug('user_is_attract_user: User %s not found', user_id)
return False
user = UserClass.construct('', db_user)
return user.has_cap('attract-use')
def current_user_may(self, action: Actions, project_id: bson.ObjectId = None) -> bool:
"""Returns True iff the user is authorised to use/view Attract on the current project.
Requires that determine_user_rights() was called before.
"""
try:
attract_rights = flask.g.attract_rights
except AttributeError:
if not project_id:
self._log.error('current_user_may() called without previous call '
'to current_user_rights()')
return False
self.determine_user_rights(project_id)
attract_rights = flask.g.attract_rights
return action in attract_rights
def determine_user_rights(self, project_id: bson.ObjectId):
"""Updates g.attract_rights to reflect the current user's usage rights.
g.attract_rights is a frozenset that contains zero or more Actions.
"""
from pillar.auth import current_user
from pillar.api.projects.utils import user_rights_in_project
if current_user.is_anonymous:
self._log.debug('Anonymous user never has access to Attract.')
flask.g.attract_rights = frozenset()
return
rights = set()
for action in Actions:
cap = req_cap[action]
if current_user.has_cap(cap):
rights.add(action)
# TODO Sybren: possibly split this up into a manager-fetching func + authorisation func.
# TODO: possibly store the user rights on the current project in the current_user object?
allowed_on_proj = user_rights_in_project(project_id)
if not allowed_on_proj.intersection(PROJECT_METHODS_TO_USE_ATTRACT):
rights.discard(Actions.USE)
flask.g.attract_rights = frozenset(rights)

Event Timeline