def patch(self) -> (str, int): """ API that allows a user change their password in the users table Parameters can be passed using a PATCH request that contains a JSON with the following fields: :param email: users email address :param password_old: users current password :param password_new: users new password that they want to replace password_old :type email: string :type password_old: string :type password_new: string :return: A message that indicates whether a user's password has been updated. If they have not, the message indicates why not. :rtype: JSON """ args = self.parser.parse_args() current_user = Users.find_by_email(args['email']) #t if current_user and Users.verify_hash( args['password_old'].encode("utf8"), current_user.password.encode("utf8")): current_user.password = Users.generate_hash( args["password_new"].encode("utf8") ).decode( "utf8" ) # decode necessary so that string (and not binary) is stored in the DB current_user.commit() return {"message": "Password has been updated"}, 200 else: return {"message": "Incorrect credentials. Please Try again"}, 403
def dummy_user(): """ A fixture that creates and saves a user to the database that is to be used for testing purposes """ user = Users("User", "*****@*****.**", Users.generate_hash("wfnbqk".encode("utf8")).decode("utf8"), True, True) user.save() user.commit() return user
def get_dummy_user(self) -> Users: """ Creates a dummy user to be used in the unit tests for Users :return: a user """ new_user = Users("fullname", '*****@*****.**', Users.generate_hash('top_secret'.encode("utf-8")), True, True) new_user.save() new_user.commit() return new_user
def setUp(self): """ Create testing client version of flask app """ self.test_app = create_app(DATABASE_NAME='test_analytics', TESTING=True) self.testing_client = self.test_app.test_client() self.testing_client_context = self.test_app.app_context() self.testing_client_context.push() self.dummy_user = Users( "Joey", "*****@*****.**", Users.generate_hash("1234".encode("utf8")).decode("utf8"), True, True) self.dummy_user.save() self.dummy_user.commit()
def post(self) -> (str, int): """ POST request that allows user to change their credentials in the Users table. A valid access JWT is required where the admin claim has to be True Parameters can be passed using a POST request that contains a JSON with the following fields: :required: :param email: users current email address :type email: str :optional: :param fullname: users to be fullname :param password: users to be password :param admin: users to be admin status :param activated: users to be activated status :type fullname: str :type password: str :type admin: bool :type activated: bool :return: A message indicating success or failure and the corresponding response code """ if not get_jwt_claims()['admin']: abort(HTTPStatus.FORBIDDEN.value, error="administration privileges required") args = self.post_reqparser.parse_args() current_user = Users.find_by_email(args["email"]) if current_user: if "fullname" in args: current_user.fullname = args["fullname"] if "activated" in args: current_user.activated = bool(args["activated"]) if "admin" in args: current_user.admin = bool(args["admin"]) if "password" in args: current_user.password = Users.generate_hash( args["password"].encode("utf8")).decode("utf8") try: current_user.commit() except Exception as e: logging.error(e) return {"message": "failed saving details to database"}, 500 return {"message": "success"}, 200 else: return {"message": "error: could not find user"}, 403
def dummy_user(): """ Create and save regular user to the database for duration of test and delete it afterwards """ user = Users("Dummy", "*****@*****.**", Users.generate_hash("1234".encode("utf8")).decode("utf8"), True, True) try: user.save() user.commit() except Exception as e: pass yield user db.session.delete(user) db.session.commit()
def admin_user(): """ Create and save admin user to the database for duration of test and delete it afterwards """ user = Users("Admin", "*****@*****.**", Users.generate_hash("wfnbqk".encode("utf8")).decode("utf8"), True, True) try: user.save() user.commit() except Exception as e: pass yield user db.session.delete(user) db.session.commit()
def post(self) -> (dict, int): """ API resource class which creates a new user and adds it to the database Parameters can be passed using a POST request that contains a JSON with the following fields: :required: valid access JWT where the admin claim has to be true :param email: users email address :param fullname: users fullname :param admin: whether the user will be an admin user or not :param password: users password :type email: str :type fullname: str :type admin: str :type password: str :return: A message indicating a successful or unsuccessful addition of user to the database """ args = self.post_reqparser.parse_args() # User needs admin rights to continue if not get_jwt_claims()['admin']: abort(HTTPStatus.FORBIDDEN.value, error="administration privileges required") # Check email address supplied is actually an email address args["email"].lower() # if not Users.email_regex_checker(args["email"]): # abort(HTTPStatus.BAD_REQUEST.value, error="{} is not a valid email".format(args["email"])) # Is the user email already registered if self._does_user_exsist(args["email"]): abort(HTTPStatus.BAD_REQUEST.value, error='User email exists. email address must be unique') # Create new user database entry in users table try: hashed_password = Users.generate_hash( args["password"].encode("utf-8")).decode("utf-8") new_user = Users(args["fullname"], args["email"], hashed_password, bool(args["admin"]), False) new_user.save() new_user.commit() except Exception as e: abort(HTTPStatus.BAD_REQUEST.value, error=e, admin=get_jwt_claims()['admin']) return ({ "user": "******".format(args["email"]) }), 201
def generate_access_token(self) -> {str, str}: """ Generate admin access JWT. :return: a HTTP authorization header containing a admin access token """ admin_user = Users("Admin user", "*****@*****.**", Users.generate_hash(b"1234").decode("utf8"), True, True) admin_user.save() admin_user.commit() response_login = self.testing_client.post('/login', data=dict( email="*****@*****.**", password="******", remember=True)) response_login_json = response_login.get_json() admin_user.delete() admin_user.commit() return {'Authorization': 'Bearer {}'.format( response_login_json["access_token"])}
def post(self) -> (dict, int): """ API resource class which changes a users password and saves changes to the database Parameters can be passed using a POST request that contains a JSON with the following fields: :required: valid access JWT where the admin claim may be either true or false :param email: users email address :param password: the new password which the user wants to store in the database :param verify_password: a repitition of the the 'password' param :type email: str :type password: str :type verify_password: str :return: A message indicating a successful or unsuccessful change """ args = self.post_reqparser.parse_args() user = None # User must be an admin if not get_jwt_claims()['admin']: abort(HTTPStatus.FORBIDDEN.value, error="administration privileges required") # get user instance using email address if args["email"]: user = Users.find_by_email(args["email"]) if not user: abort(HTTPStatus.BAD_REQUEST.value, error="User not found") if args["password"] == args["verify_password"]: user.password = Users.generate_hash( args["password"].encode("utf-8")).decode("utf-8") try: user.save() user.commit() except exc.SQLAlchemyError as e: logging.critical(e) abort(HTTPStatus.BAD_REQUEST.value, error="User password not changed") return {"user": "******".format(args["email"])}, 201
def test_user_email_duplication() -> NoReturn: """ test that duplication of a user email is not possible """ json_data = { "email": "*****@*****.**", "fullname": "fullname", "admin": True, "password": "******" } new_user = Users("fullname", '*****@*****.**', Users.generate_hash('top_secret'.encode("utf-8")), True, True) new_user.save() new_user.commit() response = dependencies.client.post('/admin/create_new_user', json=json_data, headers=dependencies.auth_header, follow_redirects=True) assert response.status_code == 400 new_user.delete() new_user.commit()
def post(self) -> (str, int): """ POST requests, activate user's account and change their password Parameters can be passed using a POST request that contains a JSON of the following fields: :param fullname: users fullname :param email: users email address :param password: users password that was sent when they were added on the admin page :type fullname: string :type email: string :type password: string :return: A message that indicates whether a user has been registered. If they have not, the message indicates why not """ args = self.parser.parse_args() current_user = Users.find_by_email(args['email']) #t if not current_user: return { 'message': 'User {} is not authorised to access Sharing Cities Dashboard'. format(args['email']) }, 403 if not Users.verify_hash(args['password'].encode("utf8"), current_user.password.encode("utf8")): return { 'message': 'The password entered does not correspond to the password sent to {}. Please try again' .format(args['email']) }, 403 current_user.activated = True current_user.password = Users.generate_hash( args["password_new"].encode("utf8")).decode("utf8") current_user.commit() return { 'message': '{}\'s account has been registered. Redirect to login'.format( args['email']) }, 201
def generate_access_token(self) -> dict: """ Remove the entries that were persisted in the simulate_importer method :return: a HTTP authorization header containing a admin access token """ admin_user = Users("Admin user", "*****@*****.**", Users.generate_hash(b"1234").decode("utf8"), True, True) admin_user.save() admin_user.commit() response_login = self.testing_client.post('/login', data=dict( email="*****@*****.**", password="******", remember=True)) response_login_json = response_login.get_json() admin_user.delete() admin_user.commit() return { 'Authorization': 'Bearer {}'.format(response_login_json["access_token"]) }
def post(self): args = self.post_reqparser.parse_args() user = None #User must be an admin if not get_jwt_claims()['admin']: abort(HTTPStatus.FORBIDDEN.value, error="administration privileges required") #get user instance using email if args["email"]: user = Users.find_by_email(args["email"]) if not user: abort(HTTPStatus.BAD_REQUEST.value, error="User not found") if args["password"] == args["verify_password"]: user.password = Users.generate_hash(args["password"].encode("utf-8")) try: user.save() user.commit() except exc.SQLAlchemyError: abort(HTTPStatus.BAD_REQUEST.value, error="User password not changed") return {"user": "******".format(args["email"])}, 201
def post(self) -> (str, int): """ POST request endpoint. Set user password to a system generated password and send password to user's email """ args = self.parser.parse_args() current_user = Users.find_by_email(args["email"]) if current_user: system_password = self.generate_random_password( self.system_password_length) if self.send_forgot_password_email(current_user.fullname, current_user.email, system_password): current_user.password = Users.generate_hash( system_password.encode("utf8")).decode("utf8") current_user.commit() return {"message": "success"}, 200 else: return {"message": "could not send email"}, 500 else: return {"message": "cannot find user"}, 403