def resetPassword(self,system_email,session): """ Remove old password and email user a token to set a new password. Request should have key "email" arguments: system_email -- (string) email used to send messages session -- (Session) object from flask """ requestDict = RequestDictionary(self.request) if(not (requestDict.exists("email"))): # Don't have the keys we need in request exc = ResponseException("Reset password route requires key 'email'",StatusCode.CLIENT_ERROR) return JsonResponse.error(exc,exc.status) # Get user object try: user = self.interfaces.userDb.getUserByEmail(requestDict.getValue("email")) except Exception as e: exc = ResponseException("Unknown Error",StatusCode.CLIENT_ERROR,ValueError) return JsonResponse.error(exc,exc.status) email = requestDict.getValue("email") LoginSession.logout(session) self.sendResetPasswordEmail(user, system_email, email) # Return success message return JsonResponse.create(StatusCode.OK,{"message":"Password reset"})
def decorated_function(*args, **kwargs): errorMessage = "Login Required" if LoginSession.isLogin(session): userDb = UserHandler() try: user = userDb.getUserByUID(session["name"]) validUser = True for permission in permissionList: if (not userDb.hasPermission(user, permission)): validUser = False finally: InterfaceHolder.closeOne(userDb) if (validUser): return f(*args, **kwargs) errorMessage = "Wrong User Type" elif "check_email_token" in permissionList: if (LoginSession.isRegistering(session)): return f(*args, **kwargs) else: errorMessage = "unauthorized" elif "check_password_token" in permissionList: if (LoginSession.isResetingPassword(session)): return f(*args, **kwargs) else: errorMessage = "unauthorized" returnResponse = flask.Response() returnResponse.headers["Content-Type"] = "application/json" returnResponse.status_code = 401 # Error code responseDict = {} responseDict["message"] = errorMessage returnResponse.set_data(json.dumps(responseDict)) return returnResponse
def checkPasswordToken(self,session): """ Checks the password token if its valid arguments: session -- (Session) object from flask return the reponse object with a error code and a message """ request_fields = RequestDictionary.derive(self.request) try: if 'token' not in request_fields: raise ResponseException( "Request body must include token", StatusCode.CLIENT_ERROR) except ResponseException as exc: return JsonResponse.error(exc, exc.status) token = request_fields['token'] # Save token to be deleted after reset session["token"] = token success, message, errorCode = sesEmail.check_token(token, "password_reset") if success: #mark session that password can be filled out LoginSession.reset_password(session) return JsonResponse.create(StatusCode.OK,{"email":message,"errorCode":errorCode,"message":"success"}) else: #failure but alert UI of issue return JsonResponse.create(StatusCode.OK,{"errorCode":errorCode,"message":message})
def reset_password(self,system_email,session): """ Remove old password and email user a token to set a new password. Request should have key "email" arguments: system_email -- (string) email used to send messages session -- (Session) object from flask """ sess = GlobalDB.db().session request_dict = RequestDictionary.derive(self.request) try: if 'email' not in request_dict: # Don't have the keys we need in request raise ResponseException( "Reset password route requires key 'email'", StatusCode.CLIENT_ERROR ) user = sess.query(User).filter( func.lower(User.email) == func.lower(request_dict['email']) ).one() except Exception as exc: return JsonResponse.error(exc, StatusCode.CLIENT_ERROR) email = request_dict['email'] LoginSession.logout(session) self.send_reset_password_email(user, system_email, email) # Return success message return JsonResponse.create(StatusCode.OK,{"message":"Password reset"})
def checkPasswordToken(self, session): """ Checks the password token if its valid arguments: session -- (Session) object from flask return the reponse object with a error code and a message """ requestFields = RequestDictionary(self.request) if (not requestFields.exists("token")): exc = ResponseException("Request body must include token", StatusCode.CLIENT_ERROR) return JsonResponse.error(exc, exc.status) token = requestFields.getValue("token") success, message, errorCode = sesEmail.checkToken( token, self.interfaces.userDb, "password_reset") if (success): #mark session that password can be filled out LoginSession.resetPassword(session) return JsonResponse.create(StatusCode.OK, { "email": message, "errorCode": errorCode, "message": "success" }) else: #failure but alert UI of issue return JsonResponse.create(StatusCode.OK, { "errorCode": errorCode, "message": message })
def decorated_function(*args, **kwargs): errorMessage = "Login Required" if LoginSession.isLogin(session): userDb = UserHandler() try: user = userDb.getUserByUID(session["name"]) validUser = True for permission in permissionList: if not userDb.hasPermission(user, permission): validUser = False finally: InterfaceHolder.closeOne(userDb) if validUser: return f(*args, **kwargs) errorMessage = "Wrong User Type" elif "check_email_token" in permissionList: if LoginSession.isRegistering(session): return f(*args, **kwargs) else: errorMessage = "unauthorized" elif "check_password_token" in permissionList: if LoginSession.isResetingPassword(session): return f(*args, **kwargs) else: errorMessage = "unauthorized" returnResponse = flask.Response() returnResponse.headers["Content-Type"] = "application/json" returnResponse.status_code = 401 # Error code responseDict = {} responseDict["message"] = errorMessage returnResponse.set_data(json.dumps(responseDict)) return returnResponse
def checkEmailConfirmationToken(self,session): """ Creates user record and email arguments: session -- (Session) object from flask return the reponse object with a error code and a message """ requestFields = RequestDictionary(self.request) if(not requestFields.exists("token")): exc = ResponseException("Request body must include token", StatusCode.CLIENT_ERROR) return JsonResponse.error(exc,exc.status) token = requestFields.getValue("token") success,message,errorCode = sesEmail.checkToken(token,self.interfaces.userDb,"validate_email") if(success): #mark session that email can be filled out LoginSession.register(session) #remove token so it cant be used again # The following line is commented out for issues with registration email links bouncing users back # to the original email input page instead of the registration page #self.interfaces.userDb.deleteToken(token) #set the status only if current status is awaiting confirmation user = self.interfaces.userDb.getUserByEmail(message) if self.interfaces.userDb.checkStatus(user,"awaiting_confirmation"): self.interfaces.userDb.changeStatus(user,"email_confirmed") return JsonResponse.create(StatusCode.OK,{"email":message,"errorCode":errorCode,"message":"success"}) else: #failure but alert UI of issue return JsonResponse.create(StatusCode.OK,{"errorCode":errorCode,"message":message})
def resetPassword(self, system_email, session): """ Remove old password and email user a token to set a new password. Request should have key "email" arguments: system_email -- (string) email used to send messages session -- (Session) object from flask """ requestDict = RequestDictionary(self.request) if (not (requestDict.exists("email"))): # Don't have the keys we need in request exc = ResponseException( "Reset password route requires key 'email'", StatusCode.CLIENT_ERROR) return JsonResponse.error(exc, exc.status) # Get user object try: user = self.interfaces.userDb.getUserByEmail( requestDict.getValue("email")) except Exception as e: exc = ResponseException("Unknown Error", StatusCode.CLIENT_ERROR, ValueError) return JsonResponse.error(exc, exc.status) email = requestDict.getValue("email") LoginSession.logout(session) self.sendResetPasswordEmail(user, system_email, email) # Return success message return JsonResponse.create(StatusCode.OK, {"message": "Password reset"})
def checkPasswordToken(self,session): """ Checks the password token if its valid arguments: session -- (Session) object from flask return the reponse object with a error code and a message """ requestFields = RequestDictionary(self.request) if(not requestFields.exists("token")): exc = ResponseException("Request body must include token", StatusCode.CLIENT_ERROR) return JsonResponse.error(exc,exc.status) token = requestFields.getValue("token") success,message,errorCode = sesEmail.checkToken(token,self.interfaces.userDb,"password_reset") if(success): #mark session that password can be filled out LoginSession.resetPassword(session) return JsonResponse.create(StatusCode.OK,{"email":message,"errorCode":errorCode,"message":"success"}) else: #failure but alert UI of issue return JsonResponse.create(StatusCode.OK,{"errorCode":errorCode,"message":message})
def resetPassword(self,system_email,session): """ Remove old password and email user a token to set a new password. Request should have key "email" arguments: system_email -- (string) email used to send messages session -- (Session) object from flask """ requestDict = RequestDictionary(self.request) if(not (requestDict.exists("email"))): # Don't have the keys we need in request exc = ResponseException("Reset password route requires key 'email'",StatusCode.CLIENT_ERROR) return JsonResponse.error(exc,exc.status) # Get user object try: user = self.interfaces.userDb.getUserByEmail(requestDict.getValue("email")) except Exception as e: exc = ResponseException("Unknown Error",StatusCode.CLIENT_ERROR,ValueError) return JsonResponse.error(exc,exc.status) LoginSession.logout(session) self.interfaces.userDb.session.commit() email = requestDict.getValue("email") # Send email with token emailToken = sesEmail.createToken(email,self.interfaces.userDb,"password_reset") link= "".join([ AccountHandler.FRONT_END,'#/forgotpassword/',emailToken]) emailTemplate = { '[URL]':link} newEmail = sesEmail(user.email, system_email,templateType="reset_password",parameters=emailTemplate,database=self.interfaces.userDb) newEmail.send() # Return success message return JsonResponse.create(StatusCode.OK,{"message":"Password reset"})
def login(self,session): """ Logs a user in if their password matches arguments: session -- (Session) object from flask return the reponse object """ try: safeDictionary = RequestDictionary(self.request) username = safeDictionary.getValue('username') password = safeDictionary.getValue('password') try: user = self.interfaces.userDb.getUserByEmail(username) except Exception as e: raise ValueError("user name and or password invalid") if(not self.interfaces.userDb.checkStatus(user,"approved")): raise ValueError("user name and or password invalid") # Only check if user is active after they've logged in for the first time if user.last_login_date is not None and not self.isUserActive(user): raise ValueError("Your account has expired. Please contact an administrator.") try: if(self.interfaces.userDb.checkPassword(user,password,self.bcrypt)): # We have a valid login LoginSession.login(session,user.user_id) permissionList = [] for permission in self.interfaces.userDb.getPermssionList(): if(self.interfaces.userDb.hasPermission(user, permission.name)): permissionList.append(permission.permission_type_id) self.interfaces.userDb.updateLastLogin(user) return JsonResponse.create(StatusCode.OK,{"message":"Login successful","user_id": int(user.user_id),"name":user.name,"title":user.title ,"agency":user.agency, "permissions" : permissionList}) else : raise ValueError("user name and or password invalid") except Exception as e: LoginSession.logout(session) raise ValueError("user name and or password invalid") except (TypeError, KeyError, NotImplementedError) as e: # Return a 400 with appropriate message return JsonResponse.error(e,StatusCode.CLIENT_ERROR) except ValueError as e: # Return a 401 for login denied return JsonResponse.error(e,StatusCode.LOGIN_REQUIRED) except Exception as e: # Return 500 return JsonResponse.error(e,StatusCode.INTERNAL_ERROR) return self.response
def decorated_function(*args, **kwargs): try: sess = GlobalDB.db().session error_message = "Login Required" if permission == "check_email_token": if LoginSession.isRegistering(session): return f(*args, **kwargs) else: error_message = "unauthorized" elif permission == "check_password_token": if LoginSession.isResetingPassword(session): return f(*args, **kwargs) else: error_message = "unauthorized" elif LoginSession.isLogin(session): user = sess.query(User).filter( User.user_id == session["name"]).one() valid_user = True if permission is not None: perm_hierarchy = { d['name']: d['order'] for d in PERMISSION_MAP.values() } # if the users permission is not higher than the one specified, check their permission # if user's perm order is < than what's passed in, it means they have higher permissions if perm_hierarchy[PERMISSION_TYPE_DICT_ID[ user.permission_type_id]] > perm_hierarchy[ permission]: if not user.permission_type_id == PERMISSION_TYPE_DICT[ permission]: valid_user = False if valid_user: return f(*args, **kwargs) error_message = "You are not authorized to perform the requested task. Please contact your administrator." # No user logged in return_response = flask.Response() return_response.headers["Content-Type"] = "application/json" return_response.status_code = 401 # Error code response_dict = {} response_dict["message"] = error_message return_response.set_data(json.dumps(response_dict)) return return_response except ResponseException as e: return JsonResponse.error(e, e.status) except InvalidUsage: raise except Exception as e: exc = ResponseException(str(e), StatusCode.INTERNAL_ERROR, type(e)) return JsonResponse.error(exc, exc.status)
def create_session_and_response(self, session, user): """Create a session.""" LoginSession.login(session, user.user_id) sess = GlobalDB.db().session updateLastLogin(user) agency_name = sess.query(CGAC.agency_name).\ filter(CGAC.cgac_code == user.cgac_code).\ one_or_none() return JsonResponse.create(StatusCode.OK, {"message": "Login successful", "user_id": int(user.user_id), "name": user.name, "title": user.title, "agency_name": agency_name, "cgac_code": user.cgac_code, "permission": user.permission_type_id})
def logout(session): """ This function removes the session from the session table if currently logged in, and then returns a success message Args: session: the Session object Returns: a JsonResponse that the logout was successful """ # Call session handler LoginSession.logout(session) return JsonResponse.create(StatusCode.OK, {"message": "Logout successful"})
def create_session_and_response(session, user): """ Create a session. Args: session: Session object from flask user: Users object Returns: JsonResponse containing the JSON for the user """ LoginSession.login(session, user.user_id) data = json_for_user(user, session['sid']) data['message'] = 'Login successful' return JsonResponse.create(StatusCode.OK, data)
def login(self, session): """ Logs a user in if their password matches arguments: session -- (Session) object from flask return the response object """ try: sess = GlobalDB.db().session safe_dictionary = RequestDictionary(self.request) username = safe_dictionary.get_value('username') password = safe_dictionary.get_value('password') try: user = sess.query(User).filter( func.lower(User.email) == func.lower(username)).one() except Exception: raise ValueError("Invalid username and/or password") try: if check_correct_password(user, password, self.bcrypt): # We have a valid login return self.create_session_and_response(session, user) else: raise ValueError("Invalid username and/or password") except ValueError as ve: LoginSession.logout(session) raise ve except Exception as e: LoginSession.logout(session) raise e except (TypeError, KeyError, NotImplementedError) as e: # Return a 400 with appropriate message return JsonResponse.error(e, StatusCode.CLIENT_ERROR) except ValueError as e: # Return a 401 for login denied return JsonResponse.error(e, StatusCode.LOGIN_REQUIRED) except Exception as e: # Return 500 return JsonResponse.error(e, StatusCode.INTERNAL_ERROR)
def logout(self,session): """ This function removes the session from the session table if currently logged in, and then returns a success message arguments: session -- (Session) object from flask return the reponse object """ # Call session handler LoginSession.logout(session) return JsonResponse.create(StatusCode.OK,{"message":"Logout successful"})
def login(self, session): """ Logs a user in if their password matches arguments: session -- (Session) object from flask return the response object """ try: sess = GlobalDB.db().session safe_dictionary = RequestDictionary(self.request) username = safe_dictionary.get_value('username') password = safe_dictionary.get_value('password') try: user = sess.query(User).filter(func.lower(User.email) == func.lower(username)).one() except Exception: raise ValueError("Invalid username and/or password") try: if check_correct_password(user, password, self.bcrypt): # We have a valid login return self.create_session_and_response(session, user) else: raise ValueError("Invalid username and/or password") except ValueError as ve: LoginSession.logout(session) raise ve except Exception as e: LoginSession.logout(session) raise e except (TypeError, KeyError, NotImplementedError) as e: # Return a 400 with appropriate message return JsonResponse.error(e, StatusCode.CLIENT_ERROR) except ValueError as e: # Return a 401 for login denied return JsonResponse.error(e, StatusCode.LOGIN_REQUIRED) except Exception as e: # Return 500 return JsonResponse.error(e, StatusCode.INTERNAL_ERROR)
def finalize(self): """ Set upload job in job tracker database to finished, allowing dependent jobs to be started Flask request should include key "upload_id", which holds the job_id for the file_upload job Returns: A flask response object, if successful just contains key "success" with value True, otherwise value is False """ responseDict = {} try: inputDictionary = RequestDictionary(self.request) jobId = inputDictionary.getValue("upload_id") # Compare user ID with user who submitted job, if no match return 400 job = self.jobManager.getJobById(jobId) submission = self.jobManager.getSubmissionForJob(job) if(submission.user_id != LoginSession.getName(session)): # This user cannot finalize this job raise ResponseException("Cannot finalize a job created by a different user", StatusCode.CLIENT_ERROR) # Change job status to finished if(self.jobManager.checkUploadType(jobId)): self.jobManager.changeToFinished(jobId) responseDict["success"] = True return JsonResponse.create(StatusCode.OK,responseDict) else: raise ResponseException("Wrong job type for finalize route",StatusCode.CLIENT_ERROR) except ( ValueError , TypeError ) as e: return JsonResponse.error(e,StatusCode.CLIENT_ERROR) except ResponseException as e: return JsonResponse.error(e,e.status) except Exception as e: # Unexpected exception, this is a 500 server error return JsonResponse.error(e,StatusCode.INTERNAL_ERROR)
def run_instance_function(accountManager, accountFunction, getSystemEmail=False, getSession=False, getUser=False, getCredentials=False): """ Standard error handling around each route """ interfaces = InterfaceHolder() try: accountManager.addInterfaces(interfaces) if (getSystemEmail and getSession): return accountFunction(RouteUtils.SYSTEM_EMAIL, session) elif (getSystemEmail): return accountFunction(RouteUtils.SYSTEM_EMAIL) elif (getSession): return accountFunction(session) elif (getUser): if (getCredentials): return accountFunction(LoginSession.getName(session), RouteUtils.CREATE_CREDENTIALS) else: # Currently no functions with user but not credentials flag raise ValueError( "Invalid combination of flags to run_instance_function" ) else: return accountFunction() except ResponseException as e: return JsonResponse.error(e, e.status) except Exception as e: exc = ResponseException(str(e), StatusCode.INTERNAL_ERROR, type(e)) return JsonResponse.error(exc, exc.status) finally: interfaces.close()
def run_instance_function( accountManager, accountFunction, getSystemEmail=False, getSession=False, getUser=False, getCredentials=False ): """ Standard error handling around each route """ interfaces = InterfaceHolder() try: accountManager.addInterfaces(interfaces) if getSystemEmail and getSession: return accountFunction(RouteUtils.SYSTEM_EMAIL, session) elif getSystemEmail: return accountFunction(RouteUtils.SYSTEM_EMAIL) elif getSession: return accountFunction(session) elif getUser: if getCredentials: return accountFunction(LoginSession.getName(session), RouteUtils.CREATE_CREDENTIALS) else: # Currently no functions with user but not credentials flag raise ValueError("Invalid combination of flags to run_instance_function") else: return accountFunction() except ResponseException as e: return JsonResponse.error(e, e.status) except Exception as e: exc = ResponseException(str(e), StatusCode.INTERNAL_ERROR, type(e)) return JsonResponse.error(exc, exc.status) finally: interfaces.close()
def login(self, session): """ Logs a user in if their password matches using local data Args: session: the Session object from flask Returns: A JsonResponse containing the user information or details on which error occurred, such as whether a type was wrong, something wasn't implemented, invalid keys were provided, login was denied, or a different, unexpected error occurred. """ try: sess = GlobalDB.db().session safe_dictionary = RequestDictionary(self.request) username = safe_dictionary.get_value('username') password = safe_dictionary.get_value('password') try: user = sess.query(User).filter( func.lower(User.email) == func.lower(username)).one() except Exception: raise ValueError("Invalid username and/or password") try: if check_correct_password(user, password, self.bcrypt): # We have a valid login return self.create_session_and_response(session, user) else: raise ValueError("Invalid username and/or password") except ValueError as ve: LoginSession.logout(session) raise ve except Exception as e: LoginSession.logout(session) raise e # Catch any specifically raised errors or any other errors that may have happened and return them cleanly except (TypeError, KeyError, NotImplementedError) as e: # Return a 400 with appropriate message return JsonResponse.error(e, StatusCode.CLIENT_ERROR) except ValueError as e: # Return a 401 for login denied return JsonResponse.error(e, StatusCode.LOGIN_REQUIRED) except Exception as e: # Return 500 return JsonResponse.error(e, StatusCode.INTERNAL_ERROR)
def listSubmissionsByCurrentUser(self): """ List all submission IDs associated with the current user ID """ userId = LoginSession.getName(flaskSession) submissions = self.interfaces.jobDb.getSubmissionsByUserId(userId) submissionIdList = [] for submission in submissions: submissionIdList.append(submission.submission_id) return JsonResponse.create(StatusCode.OK,{"submission_id_list": submissionIdList})
def login(self, session): """ Logs a user in if their password matches using local data Args: session: the Session object from flask Returns: A JsonResponse containing the user information or details on which error occurred, such as whether a type was wrong, something wasn't implemented, invalid keys were provided, login was denied, or a different, unexpected error occurred. """ try: sess = GlobalDB.db().session safe_dictionary = RequestDictionary(self.request) username = safe_dictionary.get_value('username') password = safe_dictionary.get_value('password') try: user = sess.query(User).filter(func.lower(User.email) == func.lower(username)).one() except Exception: raise ValueError("Invalid username and/or password") try: if check_correct_password(user, password, self.bcrypt): # We have a valid login return self.create_session_and_response(session, user) else: raise ValueError("Invalid username and/or password") except ValueError as ve: LoginSession.logout(session) raise ve except Exception as e: LoginSession.logout(session) raise e # Catch any specifically raised errors or any other errors that may have happened and return them cleanly except (TypeError, KeyError, NotImplementedError) as e: # Return a 400 with appropriate message return JsonResponse.error(e, StatusCode.CLIENT_ERROR) except ValueError as e: # Return a 401 for login denied return JsonResponse.error(e, StatusCode.LOGIN_REQUIRED) except Exception as e: # Return 500 return JsonResponse.error(e, StatusCode.INTERNAL_ERROR)
def checkSubmissionPermission(self,submission): """ Check if current user has permisson to access submission and return user object. """ userId = LoginSession.getName(session) user = self.interfaces.userDb.getUserByUID(userId) # Check that user has permission to see this submission, user must either own the submission or be an admin if(submission.user_id != userId and not self.interfaces.userDb.hasPermission(user,"website_admin")): raise ResponseException("User does not have permission to view that submission",StatusCode.CLIENT_ERROR) return user
def check_email_confirmation_token(self,session): """ Creates user record and email arguments: session -- (Session) object from flask return the response object with a error code and a message """ sess = GlobalDB.db().session request_fields = RequestDictionary.derive(self.request) try: if 'token' not in request_fields: raise ResponseException( "Request body must include token", StatusCode.CLIENT_ERROR ) except ResponseException as exc: return JsonResponse.error(exc, exc.status) token = request_fields['token'] session["token"] = token success, message, errorCode = sesEmail.check_token(token, "validate_email") if success: #mark session that email can be filled out LoginSession.register(session) #remove token so it cant be used again # The following lines are commented out for issues with registration email links bouncing users back # to the original email input page instead of the registration page # oldToken = sess.query(EmailToken).filter(EmailToken.token == session["token"]).one() # sess.delete(oldToken) # sess.commit() #set the status only if current status is awaiting confirmation user = sess.query(User).filter(func.lower(User.email) == func.lower(message)).one() if user.user_status_id == USER_STATUS_DICT["awaiting_confirmation"]: user.user_status_id = USER_STATUS_DICT["email_confirmed"] sess.commit() return JsonResponse.create(StatusCode.OK,{"email":message,"errorCode":errorCode,"message":"success"}) else: #failure but alert UI of issue return JsonResponse.create(StatusCode.OK,{"errorCode":errorCode,"message":message})
def checkEmailConfirmationToken(self, session): """ Creates user record and email arguments: session -- (Session) object from flask return the reponse object with a error code and a message """ requestFields = RequestDictionary(self.request) if (not requestFields.exists("token")): exc = ResponseException("Request body must include token", StatusCode.CLIENT_ERROR) return JsonResponse.error(exc, exc.status) token = requestFields.getValue("token") session["token"] = token success, message, errorCode = sesEmail.checkToken( token, self.interfaces.userDb, "validate_email") if (success): #mark session that email can be filled out LoginSession.register(session) #remove token so it cant be used again # The following line is commented out for issues with registration email links bouncing users back # to the original email input page instead of the registration page #self.interfaces.userDb.deleteToken(token) #set the status only if current status is awaiting confirmation user = self.interfaces.userDb.getUserByEmail(message) if self.interfaces.userDb.checkStatus(user, "awaiting_confirmation"): self.interfaces.userDb.changeStatus(user, "email_confirmed") return JsonResponse.create(StatusCode.OK, { "email": message, "errorCode": errorCode, "message": "success" }) else: #failure but alert UI of issue return JsonResponse.create(StatusCode.OK, { "errorCode": errorCode, "message": message })
def submit_files(): fileManager = FileHandler(request, isLocal=IS_LOCAL, serverPath=SERVER_PATH) return RouteUtils.run_instance_function(fileManager, fileManager.submit, LoginSession.getName(session), RouteUtils.CREATE_CREDENTIALS)
def resetPassword(self, system_email, session): """ Remove old password and email user a token to set a new password. Request should have key "email" arguments: system_email -- (string) email used to send messages session -- (Session) object from flask """ requestDict = RequestDictionary(self.request) if (not (requestDict.exists("email"))): # Don't have the keys we need in request exc = ResponseException( "Reset password route requires key 'email'", StatusCode.CLIENT_ERROR) return JsonResponse.error(exc, exc.status) # Get user object try: user = self.interfaces.userDb.getUserByEmail( requestDict.getValue("email")) except Exception as e: exc = ResponseException("Unknown Error", StatusCode.CLIENT_ERROR, ValueError) return JsonResponse.error(exc, exc.status) LoginSession.logout(session) self.interfaces.userDb.session.commit() email = requestDict.getValue("email") # Send email with token emailToken = sesEmail.createToken(email, self.interfaces.userDb, "password_reset") link = "".join( [AccountHandler.FRONT_END, '#/forgotpassword/', emailToken]) emailTemplate = {'[URL]': link} newEmail = sesEmail(user.email, system_email, templateType="reset_password", parameters=emailTemplate, database=self.interfaces.userDb) newEmail.send() # Return success message return JsonResponse.create(StatusCode.OK, {"message": "Password reset"})
def startGenerationJob(self, submission_id, file_type): """ Initiates a file generation job Args: submission_id: ID of submission to start job for file_type: Type of file to be generated Returns: Tuple of boolean indicating successful start, and error response if False """ jobDb = self.interfaces.jobDb file_type_name = self.fileTypeMap[file_type] if file_type in ["D1", "D2"]: # Populate start and end dates, these should be provided in MM/DD/YYYY format, using calendar year (not fiscal year) requestDict = RequestDictionary(self.request) start_date = requestDict.getValue("start") end_date = requestDict.getValue("end") if not (StringCleaner.isDate(start_date) and StringCleaner.isDate(end_date)): exc = ResponseException("Start or end date cannot be parsed into a date", StatusCode.CLIENT_ERROR) return False, JsonResponse.error(exc, exc.status, start = "", end = "", file_type = file_type, status = "failed") elif file_type not in ["E","F"]: exc = ResponseException("File type must be either D1, D2, E or F", StatusCode.CLIENT_ERROR) return False, JsonResponse.error(exc, exc.status, file_type = file_type, status = "failed") cgac_code = self.jobManager.getSubmissionById(submission_id).cgac_code # Generate and upload file to S3 user_id = LoginSession.getName(session) timestamped_name = s3UrlHandler.getTimestampedFilename(CONFIG_BROKER["".join([str(file_type_name),"_file_name"])]) if self.isLocal: upload_file_name = "".join([CONFIG_BROKER['broker_files'], timestamped_name]) else: upload_file_name = "".join([str(user_id), "/", timestamped_name]) job = jobDb.getJobBySubmissionFileTypeAndJobType(submission_id, file_type_name, "file_upload") job.filename = upload_file_name job.original_filename = timestamped_name job.job_status_id = jobDb.getJobStatusId("running") jobDb.session.commit() if file_type in ["D1", "D2"]: CloudLogger.log("DEBUG: Adding job info for job id of " + str(job.job_id), log_type="debug", file_name=self.debug_file_name) return self.addJobInfoForDFile(upload_file_name, timestamped_name, submission_id, file_type, file_type_name, start_date, end_date, cgac_code, job) elif file_type == 'E': generate_e_file.delay( submission_id, job.job_id, InterfaceHolder, timestamped_name, upload_file_name, self.isLocal) elif file_type == 'F': generate_f_file.delay( submission_id, job.job_id, InterfaceHolder, timestamped_name, upload_file_name, self.isLocal) return True, None
def listSubmissionsByCurrentUser(self): """ List all submission IDs associated with the current user ID """ userId = LoginSession.getName(flaskSession) submissions = self.interfaces.jobDb.getSubmissionsByUserId(userId) submissionIdList = [] for submission in submissions: submissionIdList.append(submission.submission_id) return JsonResponse.create(StatusCode.OK, {"submission_id_list": submissionIdList})
def decorated_function(*args, **kwargs): try: errorMessage = "Login Required" if "check_email_token" in permissionList: if(LoginSession.isRegistering(session)) : return f(*args, **kwargs) else : errorMessage = "unauthorized" elif "check_password_token" in permissionList : if(LoginSession.isResetingPassword(session)) : return f(*args, **kwargs) else : errorMessage = "unauthorized" elif LoginSession.isLogin(session): userDb = UserHandler() try: user = userDb.getUserByUID(session["name"]) validUser = True for permission in permissionList : if(not userDb.hasPermission(user, permission)) : validUser = False else: validUser = True break finally: userDb.close() if(validUser) : return f(*args, **kwargs) errorMessage = "Wrong User Type" returnResponse = flask.Response() returnResponse.headers["Content-Type"] = "application/json" returnResponse.status_code = 401 # Error code responseDict = {} responseDict["message"] = errorMessage returnResponse.set_data(json.dumps(responseDict)) return returnResponse except ResponseException as e: return JsonResponse.error(e,e.status) except Exception as e: exc = ResponseException(str(e),StatusCode.INTERNAL_ERROR,type(e)) return JsonResponse.error(exc,exc.status)
def create_session_and_response(self, session, user): # Create session LoginSession.login(session, user.user_id) permissionList = [] for permission in self.interfaces.userDb.getPermissionList(): if (self.interfaces.userDb.hasPermission(user, permission.name)): permissionList.append(permission.permission_type_id) self.interfaces.userDb.updateLastLogin(user) agency_name = self.interfaces.validationDb.getAgencyName( user.cgac_code) return JsonResponse.create( StatusCode.OK, { "message": "Login successful", "user_id": int(user.user_id), "name": user.name, "title": user.title, "agency_name": agency_name, "cgac_code": user.cgac_code, "permissions": permissionList })
def listAgencies(self): """ Retrieves a list of all agency names and their cgac codes. If there is a user logged in, it will check if that user is part of the 'SYS' agency. If so, 'SYS' will be added to the agency_list. """ agencies = self.validationManager.getAllAgencies() agency_list = [] for agency in agencies: agency_list.append({ "agency_name": agency.agency_name, "cgac_code": agency.cgac_code }) if LoginSession.isLogin(session): user_id = LoginSession.getName(session) user = self.userManager.getUserByUID(user_id) if user.cgac_code.lower() == "sys": agency_list.append({"agency_name": "SYS", "cgac_code": "SYS"}) return JsonResponse.create(StatusCode.OK, {"cgac_agency_list": agency_list})
def checkSubmissionPermission(self,submission): """ Check if current user has permisson to access submission and return user object. Args: submission - Submission model object """ userId = LoginSession.getName(session) user = self.interfaces.userDb.getUserByUID(userId) # Check that user has permission to see this submission, user must be within the agency of the submission if(submission.cgac_code != user.cgac_code and submission.user_id != user.user_id): raise ResponseException("User does not have permission to view that submission",StatusCode.CLIENT_ERROR) return user
def list_agencies(self): """ Retrieves a list of all agency names and their cgac codes. If there is a user logged in, it will check if that user is part of the 'SYS' agency. If so, 'SYS' will be added to the agency_list. """ sess = GlobalDB.db().session agencies = sess.query(CGAC).all() agency_list = [] for agency in agencies: agency_list.append({ "agency_name": agency.agency_name, "cgac_code": agency.cgac_code }) if LoginSession.isLogin(session): user = sess.query(User).filter( User.user_id == LoginSession.getName(session)).one() if user.cgac_code.lower() == "sys": agency_list.append({"agency_name": "SYS", "cgac_code": "SYS"}) return JsonResponse.create(StatusCode.OK, {"cgac_agency_list": agency_list})
def list_user_emails(self): """ List user names and emails """ sess = GlobalDB.db().session user = sess.query(User).filter(User.user_id == LoginSession.getName(flaskSession)).one() try: users = sess.query(User).filter(User.cgac_code == user.cgac_code, User.user_status_id == USER_STATUS_DICT["approved"], User.is_active == True).all() except ValueError as exc: # Client provided a bad status return JsonResponse.error(exc, StatusCode.CLIENT_ERROR) user_info = [] for user in users: this_info = {"id":user.user_id, "name": user.name, "email": user.email} user_info.append(this_info) return JsonResponse.create(StatusCode.OK, {"users": user_info})
def listUsers(self): """ List all users ordered by status. Associated request body must have key 'filter_by' """ requestDict = RequestDictionary(self.request, optionalRequest=True) user_status = requestDict.getValue("status") if requestDict.exists( "status") else "all" user = self.interfaces.userDb.getUserByUID( LoginSession.getName(flaskSession)) isAgencyAdmin = self.userManager.hasPermission( user, "agency_admin") and not self.userManager.hasPermission( user, "website_admin") try: if isAgencyAdmin: users = self.interfaces.userDb.getUsers( cgac_code=user.cgac_code, status=user_status) else: users = self.interfaces.userDb.getUsers(status=user_status) except ValueError as e: # Client provided a bad status exc = ResponseException(str(e), StatusCode.CLIENT_ERROR, ValueError) return JsonResponse.error(exc, exc.status) userInfo = [] for user in users: agency_name = self.interfaces.validationDb.getAgencyName( user.cgac_code) thisInfo = { "name": user.name, "title": user.title, "agency_name": agency_name, "cgac_code": user.cgac_code, "email": user.email, "id": user.user_id, "is_active": user.is_active, "permissions": ",".join(self.interfaces.userDb.getUserPermissions(user)), "status": user.user_status.name } userInfo.append(thisInfo) return JsonResponse.create(StatusCode.OK, {"users": userInfo})
def checkSubmissionPermission(self,submission): """ Check if current user has permisson to access submission and return user object. Args: submission - Submission model object """ userId = LoginSession.getName(session) user = self.interfaces.userDb.getUserByUID(userId) # Check that user has permission to see this submission, user must be within the agency of the submission, or be # the original user, or be in the 'SYS' agency submissionCgac = StringCleaner.cleanString(submission.cgac_code) userCgac = StringCleaner.cleanString(user.cgac_code) if(submissionCgac != userCgac and submission.user_id != user.user_id and userCgac != "sys"): raise ResponseException("User does not have permission to view that submission", StatusCode.PERMISSION_DENIED) return user
def listSubmissionsByCurrentUserAgency(self): """ List all submission IDs associated with the current user's agency """ userId = LoginSession.getName(flaskSession) user = self.interfaces.userDb.getUserByUID(userId) submissions = self.interfaces.jobDb.getSubmissionsByUserAgency(user) submissionDetails = [] for submission in submissions: jobIds = self.interfaces.jobDb.getJobsBySubmission( submission.submission_id) total_size = 0 for jobId in jobIds: file_size = self.interfaces.jobDb.getFileSize(jobId) total_size += file_size if file_size is not None else 0 status = self.interfaces.jobDb.getSubmissionStatus( submission.submission_id, self.interfaces) error_count = self.interfaces.errorDb.sumNumberOfErrorsForJobList( jobIds, self.interfaces.validationDb) if submission.user_id is None: submission_user_name = "No user" else: submission_user_name = self.interfaces.userDb.getUserByUID( submission.user_id).name submissionDetails.append({ "submission_id": submission.submission_id, "last_modified": submission.updated_at.strftime('%m/%d/%Y'), "size": total_size, "status": status, "errors": error_count, "reporting_start_date": str(submission.reporting_start_date), "reporting_end_date": str(submission.reporting_end_date), "user": { "user_id": submission.user_id, "name": submission_user_name } }) return JsonResponse.create(StatusCode.OK, {"submissions": submissionDetails})
def listSubmissionsByCurrentUser(self): """ List all submission IDs associated with the current user ID """ userId = LoginSession.getName(flaskSession) user = self.interfaces.userDb.getUserByUID(userId) submissions = self.interfaces.jobDb.getSubmissionsByUserId(userId) submissionDetails = [] for submission in submissions: jobIds = self.interfaces.jobDb.getJobsBySubmission(submission.submission_id) total_size = 0 for jobId in jobIds: file_size = self.interfaces.jobDb.getFileSize(jobId) total_size += file_size if file_size is not None else 0 status = self.interfaces.jobDb.getSubmissionStatus(submission.submission_id) error_count = self.interfaces.errorDb.sumNumberOfErrorsForJobList(jobIds) submissionDetails.append( {"submission_id": submission.submission_id, "last_modified": submission.updated_at.strftime('%m/%d/%Y'), "size": total_size, "status": status, "errors": error_count, "reporting_start_date": str(submission.reporting_start_date), "reporting_end_date": str(submission.reporting_end_date), "user": {"user_id": str(userId), "name": user.name}}) return JsonResponse.create(StatusCode.OK, {"submissions": submissionDetails})
def listUsers(self): """ List all users ordered by status. Associated request body must have key 'filter_by' """ user = self.interfaces.userDb.getUserByUID(LoginSession.getName(flaskSession)) isAgencyAdmin = True if self.interfaces.userDb.hasPermission(user, "agency_admin") else False try: if isAgencyAdmin: users = self.interfaces.userDb.getUsers(cgac_code=user.cgac_code) else: users = self.interfaces.userDb.getUsers() except ValueError as e: # Client provided a bad status exc = ResponseException(str(e),StatusCode.CLIENT_ERROR,ValueError) return JsonResponse.error(exc,exc.status) userInfo = [] for user in users: agency_name = self.interfaces.validationDb.getAgencyName(user.cgac_code) thisInfo = {"name":user.name, "title":user.title, "agency_name":agency_name, "cgac_code":user.cgac_code, "email":user.email, "id":user.user_id, "is_active":user.is_active, "permissions": ",".join(self.interfaces.userDb.getUserPermissions(user)), "status": user.user_status.name} userInfo.append(thisInfo) return JsonResponse.create(StatusCode.OK,{"users":userInfo})
def sessionCheck(): session["session_check"] = True return JsonResponse.create(StatusCode.OK,{"status":str(LoginSession.isLogin(session))})
def login(self,session): """ Logs a user in if their password matches arguments: session -- (Session) object from flask return the reponse object """ try: safeDictionary = RequestDictionary(self.request) username = safeDictionary.getValue('username') password = safeDictionary.getValue('password') try: user = self.interfaces.userDb.getUserByEmail(username) except Exception as e: raise ValueError("Invalid username and/or password") if(not self.interfaces.userDb.checkStatus(user,"approved")): raise ValueError("Invalid username and/or password") # Only check if user is active after they've logged in for the first time if user.last_login_date is not None and self.isAccountExpired(user): raise ValueError("Your account has expired. Please contact an administrator.") # for whatever reason, your account is not active, therefore it's locked if not self.isUserActive(user): raise ValueError("Your account has been locked. Please contact an administrator.") try: if(self.interfaces.userDb.checkPassword(user,password,self.bcrypt)): # We have a valid login # Reset incorrect password attempt count to 0 self.resetPasswordCount(user) LoginSession.login(session,user.user_id) permissionList = [] for permission in self.interfaces.userDb.getPermissionList(): if(self.interfaces.userDb.hasPermission(user, permission.name)): permissionList.append(permission.permission_type_id) self.interfaces.userDb.updateLastLogin(user) agency_name = self.interfaces.validationDb.getAgencyName(user.cgac_code) return JsonResponse.create(StatusCode.OK,{"message":"Login successful","user_id": int(user.user_id), "name":user.name,"title":user.title,"agency_name":agency_name, "cgac_code":user.cgac_code, "permissions" : permissionList}) else : # increase incorrect password attempt count by 1 # if this is the 3rd incorrect attempt, lock account self.incrementPasswordCount(user) if user.incorrect_password_attempts == 3: raise ValueError("Your account has been locked due to too many failed login attempts. Please contact an administrator.") raise ValueError("Invalid username and/or password") except ValueError as ve: LoginSession.logout(session) raise ve except Exception as e: LoginSession.logout(session) raise ValueError("Invalid username and/or password") except (TypeError, KeyError, NotImplementedError) as e: # Return a 400 with appropriate message return JsonResponse.error(e,StatusCode.CLIENT_ERROR) except ValueError as e: # Return a 401 for login denied return JsonResponse.error(e,StatusCode.LOGIN_REQUIRED) except Exception as e: # Return 500 return JsonResponse.error(e,StatusCode.INTERNAL_ERROR) return self.response
def create_session_and_response(session, user): """Create a session.""" LoginSession.login(session, user.user_id) data = json_for_user(user) data['message'] = 'Login successful' return JsonResponse.create(StatusCode.OK, data)
def register(self,system_email,session): """ Save user's information into user database. Associated request body should have keys 'email', 'name', 'agency', and 'title' arguments: system_email -- (string) email used to send messages session -- (Session) object from flask Returns message that registration is successful or error message that fields are not valid """ def ThreadedFunction (from_email="",username="",title="",agency="",userEmail="" ,link="") : """ This inner function sends emails in a new thread as there could be lots of admins from_email -- (string) the from email address username -- (string) the name of the user title -- (string) the title of the user agency -- (string) the agency of the user userEmail -- (string) the email of the user link -- (string) the broker email link """ threadedDatabase = UserHandler() try: for user in threadedDatabase.getUsersByType("website_admin") : emailTemplate = {'[REG_NAME]': username, '[REG_TITLE]':title, '[REG_AGENCY]':agency,'[REG_EMAIL]' : userEmail,'[URL]':link} newEmail = sesEmail(user.email, system_email,templateType="account_creation",parameters=emailTemplate,database=threadedDatabase) newEmail.send() finally: InterfaceHolder.closeOne(threadedDatabase) requestFields = RequestDictionary(self.request) if(not (requestFields.exists("email") and requestFields.exists("name") and requestFields.exists("agency") and requestFields.exists("title") and requestFields.exists("password"))): # Missing a required field, return 400 exc = ResponseException("Request body must include email, name, agency, title, and password", StatusCode.CLIENT_ERROR) return JsonResponse.error(exc,exc.status) if(not self.checkPassword(requestFields.getValue("password"))): exc = ResponseException("Invalid Password", StatusCode.CLIENT_ERROR) return JsonResponse.error(exc,exc.status) # Find user that matches specified email user = self.interfaces.userDb.getUserByEmail(requestFields.getValue("email")) # Check that user's status is before submission of registration if not (self.interfaces.userDb.checkStatus(user,"awaiting_confirmation") or self.interfaces.userDb.checkStatus(user,"email_confirmed")): # Do not allow duplicate registrations exc = ResponseException("User already registered",StatusCode.CLIENT_ERROR) return JsonResponse.error(exc,exc.status) # Add user info to database self.interfaces.userDb.addUserInfo(user,requestFields.getValue("name"),requestFields.getValue("agency"),requestFields.getValue("title")) self.interfaces.userDb.setPassword(user,requestFields.getValue("password"),self.bcrypt) userLink= "".join([AccountHandler.FRONT_END, '#/login?redirect=/admin']) # Send email to approver list emailThread = Thread(target=ThreadedFunction, kwargs=dict(from_email=system_email,username=user.name,title=user.title,agency=user.agency,userEmail=user.email,link=userLink)) emailThread.start() #email user link= AccountHandler.FRONT_END emailTemplate = {'[EMAIL]' : system_email} newEmail = sesEmail(user.email, system_email,templateType="account_creation_user",parameters=emailTemplate,database=self.interfaces.userDb) newEmail.send() LoginSession.logout(session) # Mark user as awaiting approval self.interfaces.userDb.changeStatus(user,"awaiting_approval") return JsonResponse.create(StatusCode.OK,{"message":"Registration successful"})