def change_password(user_id: ObjectId, user: dict): # check user permission when not updating current user if not user_id == ObjectId(user["_id"]): ensure_user_matches_role(user, Users.MANAGER_ROLE) request_json = request.get_json() # TODO: use json schema to validate password_old = request_json.get("old", None) password_new = request_json.get("new", None) if password_new is None or password_old is None: raise errors.BadRequest() user = Users().find_one({"_id": user_id}, {"password_hash": 1}) if user is None: raise errors.NotFound() valid = check_password_hash(user["password_hash"], password_old) if not valid: raise errors.Unauthorized() Users().update_one( {"_id": ObjectId(user_id)}, {"$set": {"password_hash": generate_password_hash(password_new)}}, ) return Response()
def change_password(user_id: ObjectId, user: dict): # check user permission when not updating current user if not user_id == ObjectId(user['_id']): if not user.get('scope', {}).get('users', {}).get('update', False): raise errors.NotEnoughPrivilege() request_json = request.get_json() # TODO: use json schema to validate password_old = request_json.get('old', None) password_new = request_json.get('new', None) if password_new is None or password_old is None: raise errors.BadRequest() user = Users().find_one({'_id': user_id}, {'password_hash': 1}) if user is None: raise errors.NotFound() valid = check_password_hash(user['password_hash'], password_old) if not valid: raise errors.Unauthorized() Users().update_one( {'_id': ObjectId(user_id)}, {'$set': { 'password_hash': generate_password_hash(password_new) }}) return Response()
def rabbitmq_user(intention: str): """ Handles RabbitMQ auth http backend request See also: https://github.com/rabbitmq/rabbitmq-auth-backend-http :param intention: the sub-path of the request :return Response: allow or deny the auth request """ username = request.form.get('username') if username is None: return Response("deny") if intention == 'user': password = request.form.get('password') if username == system_username and password == system_password: return Response("allow") else: user = Users().find_one({'username': username}, {'password_hash': 1, '_id': 0}) if user is not None and check_password_hash(user['password_hash'], password): return Response("allow") else: return Response("deny") elif intention == 'vhost' or intention == 'resource' or intention == 'topic': vhost = request.form.get('vhost') if username == system_username and vhost == 'zimfarm': return Response("allow") else: user = Users().find_one({'username': username}, {'_id': 0}) if user is not None and vhost == 'zimfarm': return Response("allow") else: return Response("deny") else: return Response("deny")
def authorize(): """ Authorize a user with username and password When success, return json object with access and refresh token """ # get username and password from request header if "application/x-www-form-urlencoded" in request.content_type: username = request.form.get("username") password = request.form.get("password") else: username = request.headers.get("username") password = request.headers.get("password") if username is None or password is None: raise BadRequest() # check user exists user = Users().find_one({"username": username}) if user is None: raise Unauthorized("Username incorrect") # check password is valid password_hash = user.pop("password_hash") is_valid = check_password_hash(password_hash, password) if not is_valid: raise Unauthorized("Password incorrect") # check that user is active if not user.get("active", False): raise Unauthorized("Account is disabled.") # generate token access_token = AccessToken.encode(user) refresh_token = uuid4() # store refresh token in database RefreshTokens().insert_one({ "token": refresh_token, "user_id": user["_id"], "expire_time": datetime.now() + timedelta(days=30), }) # send response response_json = { "access_token": access_token, "refresh_token": refresh_token } response = jsonify(response_json) response.headers["Cache-Control"] = "no-store" response.headers["Pragma"] = "no-cache" return response
def change_active_status(user_id: ObjectId, user: dict): request_json = request.get_json() new_status = request_json.get("active", None) if new_status is None: raise errors.BadRequest() user = Users().find_one({"_id": user_id}, {"active": 1}) if user is None: raise errors.NotFound() Users().update_one( {"_id": ObjectId(user_id)}, {"$set": {"active": bool(new_status)}} ) return jsonify({"_id": user_id})
def get_email_for(order_id, kind, formatted=True): def _fmt(name, email): return "{name} <{email}>".format(name=name, email=email) if kind not in ("client", "recipient", "operator", "error-manager"): return None, "en" if kind == "error-manager" and FAILED_ORDER_EMAIL: return _fmt("Cardshop Error Manager", FAILED_ORDER_EMAIL), "en" order = Orders.get_with_tasks(order_id, {"logs": 0}) if kind == "client": return ( _fmt(order["client"]["name"], order["client"]["email"]), order["client"]["language"], ) if kind == "recipient": return ( _fmt(order["recipient"]["name"], order["recipient"]["email"]), order["recipient"]["language"], ) if kind == "operator": worker = Users().by_username(order["tasks"]["download"]["worker"]) return worker["email"], "en" return None, "en"
def authorize(): """ Authorize a user with username and password When success, return json object with access and refresh token """ # get username and password from request header if 'application/x-www-form-urlencoded' in request.content_type: username = request.form.get('username') password = request.form.get('password') else: username = request.headers.get('username') password = request.headers.get('password') if username is None or password is None: raise BadRequest() # check user exists user = Users().find_one({'username': username}) if user is None: raise Unauthorized() # check password is valid password_hash = user.pop('password_hash') is_valid = check_password_hash(password_hash, password) if not is_valid: raise Unauthorized() # generate token access_token = AccessToken.encode(user) refresh_token = uuid4() # store refresh token in database RefreshTokens().insert_one({ 'token': refresh_token, 'user_id': user['_id'], 'expire_time': datetime.now() + timedelta(days=30) }) # send response response_json = { 'access_token': access_token, 'refresh_token': refresh_token } response = jsonify(response_json) response.headers['Cache-Control'] = 'no-store' response.headers['Pragma'] = 'no-cache' return response
def token(): """ Issue a new set of access and refresh token after validating an old refresh token Old refresh token can only be used once and hence is removed from database Unused but expired refresh token is also deleted from database """ # get old refresh token from request header old_token = request.headers.get("refresh-token") if old_token is None: raise BadRequest() # check token exists in database and get expire time and user id collection = RefreshTokens() old_token_document = collection.find_one({"token": UUID(old_token)}, { "expire_time": 1, "user_id": 1 }) if old_token_document is None: raise Unauthorized() # check token is not expired expire_time = old_token_document["expire_time"] if expire_time < datetime.now(): raise Unauthorized("token expired") # check user exists user_id = old_token_document["user_id"] user = Users().find_one({"_id": user_id}, {"password_hash": 0}) if user is None: raise Unauthorized() # generate token access_token = AccessToken.encode(user) refresh_token = uuid4() # store refresh token in database RefreshTokens().insert_one({ "token": refresh_token, "user_id": user["_id"], "expire_time": datetime.now() + timedelta(days=30), }) # delete old refresh token from database collection.delete_one({"token": UUID(old_token)}) collection.delete_many({"expire_time": {"$lte": datetime.now()}}) # send response response_json = { "access_token": access_token, "refresh_token": refresh_token } response = jsonify(response_json) response.headers["Cache-Control"] = "no-store" response.headers["Pragma"] = "no-cache" return response
def collection(user: dict): """ List or create users """ if request.method == "GET": # check user permission ensure_user_matches_role(user, Users.MANAGER_ROLE) # unpack url parameters skip = request.args.get("skip", default=0, type=int) limit = request.args.get("limit", default=20, type=int) skip = 0 if skip < 0 else skip limit = 20 if limit <= 0 else limit # get users from database cursor = Users().find({}, {"password_hash": 0}) users = [user for user in cursor] return jsonify({"meta": {"skip": skip, "limit": limit}, "items": users}) elif request.method == "POST": # check user permission ensure_user_matches_role(user, Users.MANAGER_ROLE) # validate request json try: request_json = request.get_json() validate(request_json, Users().schema) except ValidationError as error: raise errors.BadRequest(error.message) if Users().count({"username": request_json["username"]}): raise errors.BadRequest("Username is already taken.") if Users().count({"email": request_json["email"]}): raise errors.BadRequest("Email is already registered.") # generate password hash password = request_json.pop("password") request_json["password_hash"] = generate_password_hash(password) user_id = Users().insert_one(request_json).inserted_id return jsonify({"_id": user_id})
def send_worker_sos_email(ack_id): # client: image writing successful. ack = Acknowlegments.get(ack_id) context = {"ack": ack} subject = jinja_env.get_template("subject_worker_sos.txt").render(**context) content = jinja_env.get_template("operator_worker_sos.html").render(**context) send_email( to=Users().by_username(ack["username"])["email"], subject=subject, contents=content, )
def document(user_id: ObjectId, user: dict): if request.method == "GET": # check user permission when not querying current user if not user_id == ObjectId(user["_id"]): ensure_user_matches_role(user, Users.MANAGER_ROLE) user = Users().find_one({"_id": user_id}, {"password_hash": 0}) if user is None: raise errors.NotFound() return jsonify(user) elif request.method == "DELETE": # only manager can delete a user ensure_user_matches_role(user, Users.MANAGER_ROLE) deleted_count = Users().delete_one({"_id": user_id}).deleted_count if deleted_count == 0: raise errors.NotFound() return Response()
def token(): """ Issue a new set of access and refresh token after validating an old refresh token Old refresh token can only be used once and hence is removed from database Unused but expired refresh token is also deleted from database """ # get old refresh token from request header old_token = request.headers.get('refresh-token') if old_token is None: raise BadRequest() # check token exists in database and get expire time and user id collection = RefreshTokens() old_token_document = collection.find_one({'token': UUID(old_token)}, {'expire_time': 1, 'user_id': 1}) if old_token_document is None: raise Unauthorized() # check token is not expired expire_time = old_token_document['expire_time'] if expire_time < datetime.now(): raise Unauthorized('token expired') # check user exists user_id = old_token_document['user_id'] user = Users().find_one({'_id': user_id}, {'password_hash': 0}) if user is None: raise Unauthorized() # generate token access_token = AccessToken.encode(user) refresh_token = uuid4() # store refresh token in database RefreshTokens().insert_one({ 'token': refresh_token, 'user_id': user['_id'], 'expire_time': datetime.now() + timedelta(days=30) }) # delete old refresh token from database collection.delete_one({'token': UUID(old_token)}) collection.delete_many({'expire_time': {'$lte': datetime.now()}}) # send response response_json = { 'access_token': access_token, 'refresh_token': refresh_token } response = jsonify(response_json) response.headers['Cache-Control'] = 'no-store' response.headers['Pragma'] = 'no-cache' return response
def validate(): """ Validate an access token """ payload = AccessToken.decode(request.headers.get("access-token")) if payload is None: raise Unauthorized() user = Users().find_one({"username": payload["user"]["username"]}) if user is None: raise Unauthorized() return Response()
def validate(): """ Validate an access token """ payload = AccessToken.decode(request.headers.get('access-token')) if payload is None: raise Unauthorized() user = Users().find_one({'username': payload['user']['username']}) if user is None: raise Unauthorized() return Response()
def document(user_id: ObjectId, user: dict): if request.method == "GET": # check user permission when not querying current user if not user_id == ObjectId(user['_id']): if not user.get('scope', {}).get('users', {}).get('read', False): raise errors.NotEnoughPrivilege() user = Users().find_one({'_id': user_id}, {'password_hash': 0}) if user is None: raise errors.NotFound() return jsonify(user) elif request.method == "DELETE": # check user permission when not deleting current user if not user_id == ObjectId(user['_id']): if not user.get('scope', {}).get('users', {}).get('delete', False): raise errors.NotEnoughPrivilege() deleted_count = Users().delete_one({'_id': user_id}).deleted_count if deleted_count == 0: raise errors.NotFound() return Response()
def get_email_for(order_id, kind, formatted=True): def _fmt(name, email): return "{name} <{email}>".format(name=name, email=email) if kind not in ("client", "recipient", "operator"): return [] order = Orders.get_with_tasks(order_id, {"logs": 0}) if kind == "client": return _fmt(order["client"]["name"], order["client"]["email"]) if kind == "recipient": return _fmt(order["recipient"]["name"], order["recipient"]["email"]) if kind == "operator": worker = Users().by_username(order["tasks"]["download"]["worker"]) return worker["email"] return []
def collection(user: dict): """ List or create users """ if request.method == "GET": # check user permission if not user.get('scope', {}).get('users', {}).get('read', False): raise errors.NotEnoughPrivilege() # unpack url parameters skip = request.args.get('skip', default=0, type=int) limit = request.args.get('limit', default=20, type=int) skip = 0 if skip < 0 else skip limit = 20 if limit <= 0 else limit # get users from database cursor = Users().find({}, {'password_hash': 0}) users = [user for user in cursor] return jsonify({ 'meta': { 'skip': skip, 'limit': limit, }, 'items': users }) elif request.method == "POST": # check user permission if not user.get('scope', {}).get('users', {}).get('create', False): raise errors.NotEnoughPrivilege() # validate request json schema = { "type": "object", "properties": { "username": { "type": "string", "minLength": 1 }, "password": { "type": "string", "minLength": 6 }, "email": { "type": ["string", "null"] }, "scope": { "type": "object" } }, "required": ["username", "password"], "additionalProperties": False } try: request_json = request.get_json() validate(request_json, schema) except ValidationError as error: raise errors.BadRequest(error.message) # generate password hash password = request_json.pop('password') request_json['password_hash'] = generate_password_hash(password) user_id = Users().insert_one(request_json).inserted_id return jsonify({'_id': user_id})