def get(self, login=None): """get users""" user_profile = get_user(request=self.request) # return all users if login is None: # security checks if user_profile['role'] != constant.ROLE_ADMIN: raise HTTP_403("access refused") success, details = usersmanager.get_users() # return one user else: login = fix_encoding_uri_param(login) # security checks if user_profile['role'] != constant.ROLE_ADMIN: if user_profile["login"] != login: raise HTTP_403("access refused") #if login not in success, details = usersmanager.get_user(login=login) if success != constant.OK: raise HTTP_500(details) return {"cmd": self.request.path, "users": details}
def before(self): if self.request.method == 'OPTIONS': return user = None token = self._parse_auth_header() if token: try: payload = jwt_auth.decode_token(token, self.audience) user_id = payload.get('id') user = rpc_call('get_vk_user', user_id) if not user: raise HTTP_403("Access denied") except jwt_auth.DecodeError as e: self.logger.warning(e) raise HTTP_401("Unable to parse authentication token") except jwt_auth.ExpiredSignatureError: if 'guest' not in self.audience: raise HTTP_401("Expired token") except jwt_auth.InvalidAudienceError: raise HTTP_403("Incorrect claims") except Exception as e: self.logger.exception(e) raise HTTP_500("Unable to parse authentication token") elif 'guest' not in self.audience: raise HTTP_403("Access denied") self.user = user or {}
def post(self, file_path): """upload file""" user_profile = _get_user(request=self.request) if user_profile['monitor']: raise HTTP_403("Access refused") try: projectId = self.request.args.get("workspace", 1) file_path = fix_encoding_uri_param(file_path) fileContent = self.request.data.get("file-content") if fileContent is None: raise EmptyValue("Please specify a file content") except EmptyValue as e: raise HTTP_400("%s" % e) except Exception as e: raise HTTP_400("Invalid request provided (%s ?)" % e) _check_project_permissions( user_login=user_profile['login'], project_id=projectId) try: filePath = os.path.normpath(file_path) p = pathlib.Path(filePath) fileExt = p.suffix[1:] fileName = p.stem filePath = filePath.rsplit("%s%s" %(p.stem, p.suffix))[0] except Exception as e: raise HTTP_403('Invalid file name: %s' % e) success, _, _, _, _, _, _, _, _ = RepoTests.instance().uploadFile(pathFile=filePath, nameFile=fileName, extFile=fileExt, contentFile=fileContent, login=user_profile['login'], project=projectId, overwriteFile=True, createFolders=True, lockMode=False, binaryMode=True) if success != Context.instance().CODE_OK: raise HTTP_500("Unable to upload file") return {"cmd": self.request.path, "message": "success"}
def patch(self, login): """update user""" user_profile = get_user(request=self.request) login = fix_encoding_uri_param(login) if user_profile['role'] != constant.ROLE_ADMIN: if user_profile["login"] != login: raise HTTP_403("access denied") cur_pwd = self.request.data.get("current-password") if cur_pwd is None: raise HTTP_400("Current password is expected") new_pwd = self.request.data.get("new-password") if new_pwd is None: raise HTTP_400("New password is expected") if not len(new_pwd): raise HTTP_400("password name cannot be empty") success, details = usersmanager.update_pwd(login=login, new_pwd=new_pwd, cur_pwd=cur_pwd) if success != constant.OK: raise HTTP_500(details) return {"cmd": self.request.path, "message": "password successfully updated"}
def post(self): """add user""" user_profile = get_user(request=self.request) # checking level access to this ressource if not user_profile['role'] == constant.ROLE_ADMIN: raise HTTP_403("access refused") # checking query request login = self.request.data.get("login") if login is None: raise HTTP_400("login is expected") if not len(login): raise HTTP_400("login name cannot be empty") password = self.request.data.get("password") if password is None: raise HTTP_400("password is expected") if not len(password): raise HTTP_400("password name cannot be empty") role = self.request.data.get("role") if role not in constant.ROLE_LIST: raise HTTP_400("bad role provided") success, details = usersmanager.add_user(role=role, login=login, password=password) if success != constant.OK: raise HTTP_500(details) return {"cmd": self.request.path, "message": "user successfully added"}
def get(self): code = self.request.args.get('code') # final stage if code: return self._final_stage(code) elif self.request.args.get('error'): self.logger.info('Error response from VK: %s', self.request.args) raise HTTP_403( self.request.args.get('error_description'), self.request.args.get('error_reason', self.request.args.get('error'))) # first stage client_id = config.get('vk', 'client_id') return { 'auth_url': 'https://oauth.vk.com/authorize?display=page&v=5.92' '&scope=wall,photos,video,pages,docs,groups,offline' '&redirect_uri=https://api.vk.com/blank.html' '&response_type=code&revoke=1' f'&client_id={client_id}' }
def delete(self, login): """delete user""" user_profile = get_user(request=self.request) if user_profile['role'] != constant.ROLE_ADMIN: raise HTTP_403("access refused") login = fix_encoding_uri_param(login) if user_profile["login"] == login: raise HTTP_403("deletion not authorized") success, details = usersmanager.delete_user(login=login) if success != constant.OK: raise HTTP_500(details) return {"cmd": self.request.path, "message": "user successfully removed"}
def wrapped(*args, **kwargs): remote_ip = args[0].request.environ['REMOTE_ADDR'] #remote_ip = args[0].request.environ['gunicorn.socket'].getpeername() #if remote_ip[0] not in config.allowed_hosts: logger.info(f'Remote ip: {remote_ip}') if remote_ip not in config.allowed_hosts: raise HTTP_403('Forbidden.') return f(*args, **kwargs)
def delete(self, login): """delete user""" user_profile = get_user(request=self.request) login = fix_encoding_uri_param(login) if user_profile['role'] != constant.ROLE_ADMIN: raise HTTP_403("access refused") success, details = usersmanager.reset_pwd(login=login) if success != constant.OK: raise HTTP_500(details) return {"cmd": self.request.path, "message": "password successfully reseted"}
def delete(self, name): """Delete a workpsace, only for administrator""" user_profile = get_user(request=self.request) name = fix_encoding_uri_param(name) # checking level access to this ressource if user_profile['role'] != constant.ROLE_ADMIN: raise HTTP_403("access refused") success, details = workspacesmanager.del_workspace(name=name) if success != constant.OK: raise HTTP_500(details) return {"cmd": self.request.path, "message": "project successfully removed"}
def _check_project_permissions(user_login, project_id): """ Look up project """ try: project_id = int(project_id) except BaseException: raise HTTP_400( "Invalid workspace id (Id=%s) provided in request, int expected" % str(project_id)) # get the project id according to the name and checking permissions project_authorized = ProjectsManager.instance().checkProjectsAuthorization(user=user_login, projectId=project_id) if not project_authorized: raise HTTP_403('Permission denied to this workspace')
def post(self): """Add a new project, only for administrator""" user_profile = get_user(request=self.request) # checking level access to this ressource if user_profile['role'] != constant.ROLE_ADMIN: raise HTTP_403("access refused") # checking request name = self.request.data.get("name") if name is None: raise HTTP_400("workspace name is mandatory") if not len(name): raise HTTP_400("workspace name cannot be empty") success, details = workspacesmanager.add_workspace(name=name) if success != constant.OK: raise HTTP_500(details) return {"cmd": self.request.path, "message": "workspace successfully added", "project-id": details}
def patch(self, login): """update user""" user_profile = get_user(request=self.request) # checking level access to this ressource if user_profile['role'] != constant.ROLE_ADMIN: raise HTTP_403("access refused") # checking query request login = fix_encoding_uri_param(login) role = self.request.data.get("role") if role not in constant.ROLE_LIST: raise HTTP_400("bad role provided") success, details = usersmanager.update_role(login=login, role=role) if success != constant.OK: raise HTTP_500(details) return {"cmd": self.request.path, "message": "role successfully updated"}
def delete(self, file_path): """delete file""" user_profile = _get_user(request=self.request) if user_profile['monitor']: raise HTTP_403("Access refused") try: projectId = self.request.args.get("workspace", 1) file_path = fix_encoding_uri_param(file_path) except Exception as e: raise HTTP_400("Invalid request provided (%s ?)" % e) # avoid directory traversal filePath = os.path.normpath("/" + file_path) success = RepoTests.instance().delFile(pathFile=filePath, project=projectId, supportSnapshot=False) if success != Context.instance().CODE_OK: raise HTTP_500("Unable to delete file") return {"cmd": self.request.path, "message": "success"}
def wrapped(*args, **kwargs): if not is_logged_in(args[0].request): raise HTTP_401("You must be logged in to do this.") if not is_admin(args[0].request): raise HTTP_403("You must be an admin to do this.") return f(*args, **kwargs)
def post(self): """create job""" user_profile = _get_user(request=self.request) projectId = self.request.args.get("workspace", 1) try: yamlFile = self.request.data.get("yaml-file") if yamlFile is None: raise EmptyValue("Please specify a yaml file") yamlContent = self.request.data.get("yaml-content", "") scheduleId = self.request.data.get("schedule-id", 0) _scheduleAt = self.request.data.get("schedule-at") _scheduleRepeat = self.request.data.get("schedule-repeat", 0) _debugEnabled = self.request.data.get("debug-enabled") _fromTime = self.request.data.get("from-time") _toTime = self.request.data.get("to-time") _testInputs = self.request.data.get("file-parameters") projectId = int(projectId) scheduleId = int(scheduleId) except EmptyValue as e: raise HTTP_400("%s" % e) except Exception as e: raise HTTP_400("Invalid request provided (%s ?)" % e) # checking input if _testInputs is not None: if not isinstance(_testInputs, list): raise HTTP_400( "Invalid parameters provided in request, list expected") for inp in _testInputs: if not isinstance(inp, dict): raise HTTP_400( "Invalid parameters provided in request, list of dict expected") if not ("name" in inp and "type" in inp and "value" in inp): raise HTTP_400( "Invalid parameters provided in request") # run a test not save; change the project id to the default if projectId == 0: projectId = ProjectsManager.instance().getDefaultProjectForUser( user=user_profile['login']) _check_project_permissions( user_login=user_profile['login'], project_id=projectId) try: if yamlFile.startswith("//"): yamlFile = yamlFile[1:] yamlFile = os.path.normpath(yamlFile) p = pathlib.Path(yamlFile) fileExtension = p.suffix[1:] fileName = p.stem filePath = yamlFile.rsplit("%s%s" %(p.stem, p.suffix))[0] except Exception as e: raise HTTP_403('Invalid yaml file: %s' % e) if len(yamlContent): try: res = yaml.safe_load(yamlContent) except Exception as e: raise HTTP_403('Invalid yaml content: %s' % e) else: try: file_path = "%s/%s/%s/%s.%s" % (RepoTests.instance().testsPath, projectId, filePath, fileName, fileExtension) # read the file with open(file_path, "r") as f: doc_yaml = f.read() res = yaml.safe_load(doc_yaml) except Exception as e: raise HTTP_403('Invalid yaml file: %s' % e) try: # just for backward compatibility if "testplan" in res: testextension = "tpx" testfile = res["testplan"] elif "testglobal" in res: testextension = "tgx" testfile = res["testglobal"] elif "testsuite" in res: testextension = "tsx" elif "testunit" in res: testextension = "tux" # end of backward compatibility elif "python" in res: testextension = "tsx" elif "actions" in res: testextension = "tpx" testfile = res["actions"] else: raise Exception("invalid yaml format") # add default props if missing if "properties" not in res: res["properties"] = {} # add default descriptions if missing if "descriptions" not in res["properties"]: res["properties"]["descriptions"] = {} if "author" not in res["properties"]["descriptions"]: res["properties"]["descriptions"]["author"] = "undefined" if "name" not in res["properties"]["descriptions"]: res["properties"]["descriptions"]["name"] = "undefined" if "requirement" not in res["properties"]["descriptions"]: res["properties"]["descriptions"]["requirement"] = "undefined" if "summary" not in res["properties"]["descriptions"]: res["properties"]["descriptions"]["summary"] = "undefined" # add parameters if missing if "parameters" not in res["properties"]: res["properties"]["parameters"] = [] # add default scope in main parameters for p in res["properties"]["parameters"]: if "scope" not in p: p["scope"] = "local" if "value" not in p: p["value"] = "" if "type" not in p: if p["value"] is None: p["type"] = "none" p["value"] = "" elif isinstance(p["value"], bool): p["type"] = "bool" p["value"] = "%s" % p["value"] elif isinstance(p["value"], int): p["type"] = "int" p["value"] = "%s" % p["value"] elif isinstance(p["value"], list) or isinstance(p["value"], dict): p["type"] = "json" p["value"] = json.dumps(p["value"]) else: p["type"] = "text" testprops = {} testprops["inputs-parameters"] = {} testprops["inputs-parameters"]["parameter"] = res["properties"]["parameters"] testprops["descriptions"] = {} testprops["descriptions"]["description"] = [] for k,v in res["properties"]["descriptions"].items(): s = { 'key': k, 'value': v } testprops["descriptions"]["description"].append(s) if testextension in ["tpx", "tgx"]: doc = TestPlan.DataModel() testplan = {} testplan['testplan'] = { 'testfile': [] } i = 1 for tp in testfile: # add parameters if missing if "parameters" not in tp: tp["parameters"] = [] # add default scope in main parameters for p in tp["parameters"]: if "scope" not in p: p["scope"] = "local" if "value" not in p: p["value"] = "" if "type" not in p: if p["value"] is None: p["type"] = "none" p["value"] = "" elif isinstance(p["value"], bool): p["type"] = "bool" p["value"] = "%s" % p["value"] elif isinstance(p["value"], int): p["type"] = "int" p["value"] = "%s" % p["value"] elif isinstance(p["value"], list) or isinstance(p["value"], dict): p["type"] = "json" p["value"] = json.dumps(p["value"]) else: p["type"] = "text" if "id" not in tp: tp["id"] = "%s" % i if isinstance(tp["id"], int): tp["id"] = str(tp["id"]) if "parent" not in tp: tp["parent"] = "0" if isinstance(tp["parent"], int): tp["parent"] = str(tp["parent"]) if "parent-condition" not in tp: tp["parent-condition"] = "0" else: if tp["parent-condition"] == "success": tp["parent-condition"] = "0" else: tp["parent-condition"] = "1" tp["parent-condition"] = str(tp["parent-condition"]) if "description" in tp: tp["alias"] = tp["description"] i+=1 tf_descr = [ {"key": "author", "value": "undefined"}, {"key": "summary", "value": "undefined"}, {"key": "name", "value": "undefined"}, {"key": "requirement", "value": "undefined"}] tf_prop = {"properties": {"descriptions": { "description": tf_descr}, "inputs-parameters": {} }} tf_prop["properties"]["inputs-parameters"]["parameter"] = tp["parameters"] tp.update(tf_prop) testplan['testplan']['testfile'].append(tp) doc.testplan = testplan tests = doc.getSorted() if testextension == "tpx": success, error_msg = RepoTests.instance().addtf2tp(data_=tests) if success != Context.instance().CODE_OK: raise HTTP_500( 'Unable to prepare test plan: %s' % error_msg) else: success, error_msg, tests = RepoTests.instance().addtf2tg(data_=tests) if success != Context.instance().CODE_OK: raise HTTP_500( 'Unable to prepare test global: %s' % error_msg) testData = {'test-properties': testprops, 'test-extension': testextension} if testextension == "tsx": if "python" in res: testData['test-definition'] = res["python"] else: testData['test-definition'] = res["testsuite"] testData['test-execution'] = "" elif testextension == "tux": testData['test-definition'] = res["testunit"] else: testData['test-execution'] = tests except Exception as e: raise HTTP_500('Unable to decode yaml: %s' % e) # now we can create the task debugEnabled = False fromTime = (0, 0, 0, 0, 0, 0) toTime = (0, 0, 0, 0, 0, 0) message = "success" scheduleAt = (0, 0, 0, 0, 0, 0) if _debugEnabled is not None: debugEnabled = _debugEnabled if _fromTime is not None: fromTime = _fromTime if _toTime is not None: toTime = _toTime if _scheduleAt is not None: scheduleAt = _scheduleAt # personalize test description ? if _testInputs is not None: for newInp in _testInputs: if "scope" not in newInp: newInp["scope"] = "local" for origInp in testData["test-properties"]['inputs-parameters']['parameter']: if "scope" not in origInp: origInp["scope"] = "local" # if the param exist on the original test than overwrite # them if newInp["name"] == origInp["name"]: origInp["value"] = newInp["value"] origInp["type"] = newInp["type"] origInp["scope"] = newInp["scope"] if not filePath.endswith(fileName): if len(filePath): _testPath = "%s/%s" % (filePath, fileName) else: _testPath = fileName _testPath = os.path.normpath(_testPath) else: _testPath = filePath task = TaskManager.instance().registerTask( testData=testData, testName=fileName, testPath=_testPath, testUserId=user_profile['id'], testUser=user_profile['login'], testId=0, testBackground=True, runAt=scheduleAt, runType=scheduleId, runNb=_scheduleRepeat, withoutProbes=False, debugActivated=debugEnabled, withoutNotif=False, noKeepTr=False, testProjectId=projectId, runFrom=fromTime, runTo=toTime, stepByStep=False, breakpoint=False, channelId=False ) if task.lastError is not None: raise HTTP_500('ERROR: %s' % task.lastError) message = "success" if task.isRecursive(): message = "recursive" if task.isPostponed(): message = "postponed" if task.isSuccessive(): message = "successive" return {"cmd": self.request.path, "message": message, "job-id": task.getId(), "execution-id": task.getTestID()}
def _final_stage(self, code): client_id = config.get('vk', 'client_id') client_secret = config.get('vk', 'client_secret') vksession = Session() try: resp = vksession.get( 'https://oauth.vk.com/access_token?' 'redirect_uri=https://api.vk.com/blank.html' f'&client_id={client_id}&client_secret={client_secret}&code={code}' ) resp.raise_for_status() auth = resp.json() if not auth.get('access_token'): raise VKException(auth) resp = vksession.get('https://api.vk.com/method/users.get', params={ 'v': '5.92', 'user_ids': auth['user_id'], 'fields': 'photo_100', 'access_token': auth['access_token'] }) resp.raise_for_status() user = resp.json() if user.get('error'): raise VKException(user) user = user.get('response', {}) user = { 'id': user[0]['id'], 'fullname':\ (user[0].get('first_name', '') + ' ' + user[0].get('last_name', '')).strip(), 'photo': user[0].get('photo_100'), 'access_token': auth['access_token'] } if user else {} rpc_call('set_vk_user', user) token = jwt_auth.create_token({ 'id': auth['user_id'], 'aud': 'authorized' }) self.logger.info('Issued JWT: %s', token) return { 'token': 'Bearer ' + token.decode("utf-8"), 'tgauth': user.get('id') and rpc_call('is_tg_authorized', user['id']) } except exceptions.HTTPError as e: self.logger.info('Error authorizing user on VK: %s', e) if e.response.status_code == 401: raise HTTP_403('Error authorizing user on VK') raise HTTPError(e.response.status_code, e.response.text) except VKException as e: self.logger.warning('Error authorizing user on VK: %s', e) raise HTTP_403(e.message, e.code) except Exception as e: self.logger.exception('Error authorizing user on VK: %s', e) finally: vksession.close() raise HTTP_500('Internal error')