def base(*args, **kwargs): if 'user' in kwargs: if kwargs['user'].get('authenticated', False): return func(*args, **kwargs) else: abort(403, "Invalid pre-authenticated user") return self.test_readonly("API") logged_in_uname = self.get_logged_in_user() impersonator = None # Impersonate authorization = request.environ.get("HTTP_AUTHORIZATION", None) if authorization: # noinspection PyBroadException try: bearer_token = authorization.split(" ")[-1] headers = jwt.get_unverified_header(bearer_token) decoded = jwt.decode( bearer_token, hashlib.sha256(f"{SECRET_KEY}_{headers['token_id']}". encode()).hexdigest(), algorithms=[headers.get('alg', "HS256")]) except Exception: abort(400, "Malformed bearer token") return target_user = STORAGE.user.get(headers['user'], as_obj=False) if target_user: target_token = target_user.get('apps', {}).get( headers['token_id'], {}) if target_token == decoded and target_token[ 'client_id'] == logged_in_uname: impersonator = logged_in_uname logged_in_uname = headers['user'] LOGGER.info( f"{impersonator} is impersonating {logged_in_uname} for query: {request.path}" ) if not set(self.required_priv).intersection( set(SCOPES[decoded["scope"]])): abort( 403, "The method you've used to login does not give you access to this API" ) return else: abort(403, "Invalid bearer token") return else: abort(404, "User not found") return user = login(logged_in_uname) # Terms of Service if request.path not in ["/api/v4/help/tos/", "/api/v4/user/whoami/", f"/api/v4/user/tos/{logged_in_uname}/", "/api/v4/auth/logout/"] \ and not user.get('agrees_with_tos', False) and config.ui.tos is not None: abort( 403, "Agree to Terms of Service before you can make any API calls" ) return self.test_require_type(user, "API") ############################################# # Special username api query validation # # If an API call requests a username, the username as to match # the logged in user or the user has to be ADMIN # # API that needs this special validation need to make sure their # variable name for the username is as an optional parameter # inside 'username_key'. Default: 'username' if self.username_key in kwargs: if kwargs[self.username_key] != user['uname'] \ and not kwargs[self.username_key] == "__global__" \ and not kwargs[self.username_key] == "__workflow__" \ and not kwargs[self.username_key].lower() == "__current__" \ and 'admin' not in user['type']: return make_api_response( {}, "Your username does not match requested username", 403) self.audit_if_required(args, kwargs, logged_in_uname, user, func, impersonator=impersonator) # Save user credential in user kwarg for future reference kwargs['user'] = user if config.core.metrics.apm_server.server_url is not None: elasticapm.set_user_context(username=user.get('name', None), email=user.get('email', None), user_id=user.get('uname', None)) # Check current user quota quota_user = user['uname'] flsk_session['quota_user'] = quota_user flsk_session['quota_set'] = True quota = user.get('api_quota', 10) if not QUOTA_TRACKER.begin(quota_user, quota): if config.ui.enforce_quota: LOGGER.info( f"User {quota_user} was prevented from using the api due to exceeded quota." ) return make_api_response( "", f"You've exceeded your maximum quota of {quota}", 503) else: LOGGER.debug( f"Quota of {quota} exceeded for user {quota_user}.") else: LOGGER.debug( f"{quota_user}'s quota is under or equal its limit of {quota}" ) return func(*args, **kwargs)
def base(*args, **kwargs): if 'user' in kwargs: if kwargs['user'].get('authenticated', False): return func(*args, **kwargs) else: abort(403, "Invalid pre-authenticated user") return self.test_readonly("API") logged_in_uname = self.get_logged_in_user() user = login(logged_in_uname) # Terms of Service if request.path not in ["/api/v4/help/tos/", "/api/v4/user/whoami/", f"/api/v4/user/tos/{logged_in_uname}/", "/api/v4/auth/logout/"] \ and not user.get('agrees_with_tos', False) and config.ui.tos is not None: abort( 403, "Agree to Terms of Service before you can make any API calls" ) return self.test_require_type(user, "API") ############################################# # Special username api query validation # # If an API call requests a username, the username as to match # the logged in user or the user has to be ADMIN # # API that needs this special validation need to make sure their # variable name for the username is as an optional parameter # inside 'username_key'. Default: 'username' if self.username_key in kwargs: if kwargs[self.username_key] != user['uname'] \ and not kwargs[self.username_key] == "__global__" \ and not kwargs[self.username_key] == "__workflow__" \ and not kwargs[self.username_key].lower() == "__current__" \ and 'admin' not in user['type']: return make_api_response( {}, "Your username does not match requested username", 403) self.audit_if_required(args, kwargs, logged_in_uname, user, func) # Save user credential in user kwarg for future reference kwargs['user'] = user if config.core.metrics.apm_server.server_url is not None: elasticapm.set_user_context(username=user.get('name', None), email=user.get('email', None), user_id=user.get('uname', None)) # Check current user quota quota_user = user['uname'] flsk_session['quota_user'] = quota_user flsk_session['quota_set'] = True quota = user.get('api_quota', 10) if not QUOTA_TRACKER.begin(quota_user, quota): if config.ui.enforce_quota: LOGGER.info( f"User {quota_user} was prevented from using the api due to exceeded quota." ) return make_api_response( "", f"You've exceeded your maximum quota of {quota}", 503) else: LOGGER.debug( f"Quota of {quota} exceeded for user {quota_user}.") else: LOGGER.debug( f"{quota_user}'s quota is under or equal its limit of {quota}" ) return func(*args, **kwargs)