Source code for iceprod.rest.handlers.auth

import logging
import json

import pymongo.errors
import tornado.web

from ..base_handler import APIBase
from ..auth import authorization
from iceprod.roles_groups import ROLES, GROUP_PRIORITIES

logger = logging.getLogger('rest.auth')


[docs] def setup(handler_cfg): """ Setup method for Config REST API. Args: handler_cfg (dict): args to pass to the route Returns: dict: routes, database, indexes """ return { 'routes': [ ('/roles', MultiRoleHandler, handler_cfg), ('/groups', MultiGroupHandler, handler_cfg), ('/users', MultiUserHandler, handler_cfg), (r'/users/(?P<username>[^\/\?\#]+)', UserHandler, handler_cfg), (r'/users/(?P<username>[^\/\?\#]+)/priority', UserPriorityHandler, handler_cfg), ('/auths', AuthHandler, handler_cfg), ], 'database': 'auth', 'indexes': { 'users': { 'username_index': {'keys': 'username', 'unique': True}, }, 'attr_auths': { 'dataset_id_index': {'keys': 'dataset_id', 'unique': False}, } } }
[docs] class MultiRoleHandler(APIBase): """ Handle multi-role requests. """
[docs] @authorization(roles=['admin']) async def get(self): """ Get a list of roles. Returns: dict: {'results': list of roles} """ self.write({'results': list(ROLES)})
[docs] class MultiGroupHandler(APIBase): """ Handle multi-group requests. """
[docs] @authorization(roles=['admin', 'system']) async def get(self): """ Get a list of groups. Returns: dict: {'results': list of groups} """ ret = [] for name, priority in GROUP_PRIORITIES.items(): ret.append({ 'name': name, 'priority': priority, }) self.write({'results': ret})
[docs] class MultiUserHandler(APIBase): """ Handle multi-user requests. """
[docs] @authorization(roles=['admin', 'system']) async def get(self): """ Get a list of users. Returns: dict: {'results': list of users} """ ret = await self.db.users.find(projection={'_id': False}).to_list(length=10000) self.write({'results': ret}) self.finish()
[docs] class UserHandler(APIBase): """ Handle individual user requests. """
[docs] @authorization(roles=['admin', 'system']) async def get(self, username): """ Get a user. Args: username (str): the user to get Returns: dict: user info """ ret = await self.db.users.find_one({'username': username}, projection={'_id':False}) if not ret: self.send_error(404, reason="User not found") else: self.write(ret) self.finish()
[docs] @authorization(roles=['admin']) async def put(self, username): """ Add a User. Args: username (str): the user to delete Returns: dict: empty dict """ try: await self.add_user(username) except pymongo.errors.DuplicateKeyError: raise tornado.web.HTTPError(409, reason='duplicate username') self.write({}) self.finish()
[docs] @authorization(roles=['admin']) async def delete(self, username): """ Delete a user. Args: username (str): the user to delete Returns: dict: empty dict """ await self.db.users.delete_one({'username': username}) self.write({}) self.finish()
[docs] class UserPriorityHandler(APIBase): """ Handle individual user requests. """
[docs] @authorization(roles=['admin']) async def put(self, username): """ Add a User. Args: username (str): the user to modify Body Args: priority (float): the new priority Returns: dict: empty dict """ data = json.loads(self.request.body) if 'priority' not in data: raise tornado.web.HTTPError(400, reason='missing priority in body') try: priority = float(data['priority']) if not 0 <= priority <= 1: raise ValueError() except Exception: raise tornado.web.HTTPError(400, reason='bad priority: should be between 0 and 1') ret = await self.db.users.update_one({'username': username}, {'$set': {'priority': priority}}) if ret.matched_count < 1: raise tornado.web.HTTPError(400, reason='bad username') self.write({}) self.finish()
[docs] class AuthHandler(APIBase): """ Handle authorization requests. """
[docs] @authorization(roles=['admin', 'system']) async def post(self): """ Do a remote auth lookup. Raises a 403 on auth failure. Body Args: name (str): name of attr value (str): value of attr role (str): the role to check (read | write) username (str): username groups (list): groups for user Returns: dict: {result: ok} """ data = json.loads(self.request.body) # validate first req_fields = { 'name': str, 'value': str, 'role': str, 'username': str, 'groups': list, } for k in req_fields: if k not in data: raise tornado.web.HTTPError(400, reason='missing key: '+k) if not isinstance(data[k], req_fields[k]): r = 'key "{}" should be of type {}'.format(k, req_fields[k].__name__) raise tornado.web.HTTPError(400, reason=r) # check auth self.current_user = data['username'] self.auth_groups = data['groups'] await self.check_attr_auth(data['name'], data['value'], data['role']) self.write({})