"""Helper functions to validate request.""" from collections import namedtuple from functools import wraps from flask import request from oto import response from oto import status as response_code from oto.adaptors.flask import flaskify from owsrequest import flask_request from conflict_manager.constants import auth as auth_const from conflict_manager.constants import error from conflict_manager.constants import header as header_const from conflict_manager.constants import query_parameters as query_const Account = namedtuple('Account', ['type', 'id']) def account_required(function): """Use to decorate handler function to verify account was specified.""" @wraps(function) def wrapper(*args, **kwargs): res = _get_account_info() if not res: return flaskify(res) res = _validate_authorization_info( res.message[query_const.ACCOUNT_TYPE], res.message[query_const.ACCOUNT_ID]) if not res: return flaskify(res) return function(*args, **kwargs) return wrapper def get_account(): """Get account_id and account_type from request object. Please make sure the handler is using the `account_required` decorator before getting the account data. Returns: dict: with account_id and account_type """ account_id = ( request.headers.get(header_const.GRASS_ACCOUNT_ID) or request.args.get(query_const.ACCOUNT_ID)) account_type = ( request.headers.get(header_const.GRASS_ACCOUNT_TYPE) or request.args.get(query_const.ACCOUNT_TYPE)) return Account(type=account_type, id=account_id) def _get_account_info(): """Get account info from headers or query params.""" account_type, account_id = flask_request.get_grass_headers(request) alt_account_type = request.args.get(query_const.ACCOUNT_TYPE) alt_account_id = request.args.get(query_const.ACCOUNT_ID) # If no account data from headers, check query parameters if not account_type and not account_id: account_type = alt_account_type account_id = alt_account_id elif alt_account_type or alt_account_id: return response.create_error_response( code=error.ERROR_CODE_BAD_REQUEST, message='Account data cannot be passed in both the request ' 'headers and via query parameters') return response.Response({ query_const.ACCOUNT_TYPE: account_type, query_const.ACCOUNT_ID: account_id }) def _validate_authorization_info(account_type, account_id): """Check whether auth info is present either in headers or params. Args: account_id (str): Account id account_type(dict): Account type Returns: response.Response: validation result, error with description if failed """ if not account_id and not account_type: error_response = response.create_error_response( status=response_code.FORBIDDEN, code=error.ERROR_CODE_AUTHORIZATION, message=error.AUTHORIZATION_MSG) return error_response if any([not account_id, not account_type]): error_response = response.create_error_response( code=error.ERROR_CODE_AUTHORIZATION, message=error.INCOMPLETE_GRASS_HEADERS_MSG) return error_response is_valid_account_id_response = _validate_account_id(account_id) if not is_valid_account_id_response: return is_valid_account_id_response if account_type not in auth_const.ALLOWED_ACCOUNT_TYPES: error_response = response.create_error_response( status=response_code.FORBIDDEN, code=error.ERROR_CODE_AUTHORIZATION, message=error.INVALID_GRASS_ACCOUNT_TYPE_MSG) return error_response return response.Response() def _validate_account_id(account_id): """Check whether given account_id is valid. Args: account_id (str): what received in headers/request params Returns: response.Response """ try: account_id = int(account_id) if account_id < 0: raise ValueError except ValueError: error_response = response.create_error_response( code=error.ERROR_CODE_AUTHORIZATION, message=error.INVALID_GRASS_ACCOUNT_ID_MSG) return error_response return response.Response() def validate_user_id(user_id): """Check whether given user_id is valid. Args: user_id (str): what received in headers/request params Returns: response.Response """ try: user_id = int(user_id.split(':')[-1]) if user_id < 0: raise ValueError except ValueError: error_response = response.create_error_response( code=error.ERROR_CODE_BAD_REQUEST, message=error.INVALID_GRASS_USER_ID_MSG) return error_response return response.Response() def get_user_id(): """Get orchard user id from header. Returns: str: orchard user id """ return request.headers.get(header_const.GRASS_HEADER_USER_ID)