示例#1
0
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()
示例#2
0
文件: users.py 项目: akuendig/zimfarm
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()
示例#3
0
文件: auth.py 项目: akuendig/zimfarm
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")
示例#4
0
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
示例#5
0
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})
示例#6
0
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"
示例#7
0
文件: auth.py 项目: akuendig/zimfarm
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
示例#8
0
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
示例#9
0
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})
示例#10
0
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,
    )
示例#11
0
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()
示例#12
0
文件: auth.py 项目: akuendig/zimfarm
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
示例#13
0
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()
示例#14
0
文件: auth.py 项目: akuendig/zimfarm
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()
示例#15
0
文件: users.py 项目: akuendig/zimfarm
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()
示例#16
0
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 []
示例#17
0
文件: users.py 项目: akuendig/zimfarm
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})