Exemplo n.º 1
0
def register():
    USERS_TABLE, IDENTIFIER_FIELD, PASSWORD_FIELD, ROLE_FIELD, ACTIVE_FIELD = get_login_settings(
    )

    # Ensure that the user has sent the required fields
    form = request.json if request.is_json else request.form
    form = filter_fields_db(form, USERS_TABLE)

    username = form.get(IDENTIFIER_FIELD, None)
    password = form.get(PASSWORD_FIELD, None)

    if not username or not password:
        raise HTTPError(
            400,
            f"Both '{IDENTIFIER_FIELD}' and '{PASSWORD_FIELD}' are required")

    logger.debug(f"Register request with data {form}")

    # Ensure that the identifier is unique
    login_q = get_login_query(USERS_TABLE, IDENTIFIER_FIELD, username)
    other_users = dal.api_safe_query(login_q)

    if other_users:
        logger.debug(f"The identifier {username} already exists")
        raise HTTPError(
            400,
            f"There already exists another user with that {IDENTIFIER_FIELD}")

    # Create the user object, replacing the password with the hashed one
    user = dict(form)
    user[PASSWORD_FIELD] = generate_password_hash(password)

    # Assign a default role to the user, if specified in the settings
    if settings.DEFAULT_ROLE_REGISTER:
        user[ROLE_FIELD] = settings.DEFAULT_ROLE_REGISTER

    # Assign a default active status, if the activity check is on and none has
    # been provided
    if ACTIVE_FIELD and ACTIVE_FIELD not in user:
        user[ACTIVE_FIELD] = settings.DEFAULT_ACTIVE_STATUS

    # Try to insert it in the DB
    # Since the /register endpoint must adapt to any possible table,
    # we assume that the user knows what they're doing and submits the
    # appropriate fields. Otherwise, the DB will just complain.
    register_q = get_register_user_query(USERS_TABLE, user)
    dal.api_safe_update(register_q)

    # Fetch the newly created user from the DB (some fields may have been)
    # automatically generated, like its ID
    # It should now exist
    user = dal.api_safe_query(login_q)[0]

    # If we've reached here the register is successful, generate a session token
    # and return it with the logged user's info
    logger.debug("Register OK")
    token = create_token(user)
    del user[PASSWORD_FIELD]
    res = {"sessionToken": token, "user": user}
    return jsonify(res), 200
Exemplo n.º 2
0
def check_session(allowed_roles):
    token = request.headers.get("Token", default=None)
    if not token:
        raise HTTPError(401, "Unauthorized")

    try:
        user_data = check_token(token)
        u_data = settings.USER_AUTH_DATA['table']
        primary = get_primary_key(u_data)
        res = user_data[primary]

        # Check if the user's role is allowed to access this endpoint
        role_col_name = settings.USER_AUTH_DATA.get("role", None)

        if role_col_name:  # Only check the role if we know the role column
            # Find the role of the user from the user data
            user_role = next((v for k, v in user_data.items()
                              if k.lower() == role_col_name.lower()), None)

            logger.debug(
                f"Allowed roles are {allowed_roles} and the user role is {user_role}"
            )

            if user_role not in allowed_roles and "*" not in allowed_roles:
                raise HTTPError(401, "Unauthorized")

        return res
    except TokenError as exc:
        raise HTTPError(401, str(exc))
Exemplo n.º 3
0
def login():
    USERS_TABLE, IDENTIFIER_FIELD, PASSWORD_FIELD, ROLE_FIELD, ACTIVE_FIELD = get_login_settings(
    )
    # Ensure that the user has sent the required fields
    form = request.json if request.is_json else request.form
    form = filter_fields_db(form, USERS_TABLE)

    username = form.get(IDENTIFIER_FIELD, None)
    password = form.get(PASSWORD_FIELD, None)

    if not username or not password:
        raise HTTPError(
            400,
            f"Both '{IDENTIFIER_FIELD}' and '{PASSWORD_FIELD}' are required")

    logger.debug(
        f"Login request from user {username} with password {password}")

    # Look if there is an user with such username
    q = get_login_query(USERS_TABLE, IDENTIFIER_FIELD, username)
    users = dal.api_safe_query(q)

    if not users:
        logger.debug(f"The identifier {username} was not found")
        raise HTTPError(400, "User not found")

    # The identifier field should be unique (/register also takes care of that)
    # so we can just extract the first one
    user = users[0]

    # Check if the user's password matches the provided one
    if PASSWORD_FIELD not in user:
        raise HTTPError(500, f"The user has no attribute '{PASSWORD_FIELD}'")

    password_ok = (settings.ALLOW_CLEAR_PASSWORDS and user[PASSWORD_FIELD] == password) \
                    or check_password_hash(user[PASSWORD_FIELD], password)
    if not password_ok:
        logger.debug(f"Incorrect password")
        raise HTTPError(400, "The password is not correct")

    # If a column has been specified for the "is active" field, and the check
    # is enabled in the settings, check that the user has not been deactivated
    if ACTIVE_FIELD is not None and settings.CHECK_USER_IS_ACTIVE:
        if not user[ACTIVE_FIELD]:
            logger.debug("The user is deactivated, login denied")
            raise HTTPError(401, "This user has been deactivated")

    # If we've reached here the login is successful, generate a session token
    # and return it with the logged user's info
    logger.debug("Login OK")
    token = create_token(user)
    del user[PASSWORD_FIELD]
    res = {"sessionToken": token, "user": user}
    return jsonify(res), 200
Exemplo n.º 4
0
 def wrapper(*args, **kwargs):
     try:
         return func(*args, **kwargs)
     except DatabaseError as dberr:
         # Grab the error message from the exception
         m = regex_error_str.match(str(dberr))
         msg = m.group(1) if m else str(dberr)
         code = 400
         raise HTTPError(code, msg)
Exemplo n.º 5
0
    def handle_generic_error(exc):
        # Pass through our own HTTP error exception
        if isinstance(exc, HTTPError):
            return exc

        # Create a similar JSON response for Werkzeug's exceptions
        if isinstance(exc, HTTPException):
            code = exc.code
            res = jsonify({"message": exc.description, "code": code})
            return res, code

        # We're facing an uncontrolled server exception
        logger.exception(exc)

        exc_type = type(exc).__name__
        msg = str(exc)
        err = HTTPError(500, msg, exc_type)
        return handle_HTTPError(err)
Exemplo n.º 6
0
def add(email, password, departmentId, bossId, firstName, lastName, salary):
    if not firstName or not lastName:
        raise HTTPError(400, "The first and last name are required.")
Exemplo n.º 7
0
    def route_handler(*args, **kwargs):
        # If this endpoint requires authentication, check that the
        # user has provided a session token and that it is valid
        if auth_required:
            userId = check_session(allowed_roles)

        # Collect all url pattern params
        request_url_params_dict = kwargs

        # If endpoint requires the logged userId it adds the pair (loggedId, loggedUserId)
        if logged_user:
            if not auth_required:
                userId = check_session(allowed_roles)
            if userId != None:
                request_url_params_dict["loggedId"] = userId
        else:
            request_url_params_dict["loggedId"] = None

        # Convert the silence-style placeholders in the SQL query to proper MySQL placeholders
        query_string = silence_to_mysql(sql)

        # Default outputs
        res = None
        status = 200

        # SELECT/GET operations
        if sql_op == SQL.SELECT:
            # The URL params have been checked to be enough to fill all SQL params
            url_pattern_params = tuple(request_url_params_dict[param]
                                       for param in sql_params)
            res = dal.api_safe_query(query_string, url_pattern_params)

            # Filter these results according to the URL query string, if there is one
            # Possible TO-DO: do this by directly editing the SQL query for extra efficiency
            res = filter_query_results(res, request.args)

            # In our teaching context, it is safe to assume that if the URL ends
            # with a parameter and we have no results, we should return a 404 code
            if RE_QUERY_PARAM.match(route) and not res:
                raise HTTPError(404, "Not found")

        else:  # POST/PUT/DELETE operations
            #Construct a dict for all params expected in the request body, setting them to None if they have not been provided
            form = request.json if request.is_json else request.form
            body_params = {
                param: form.get(param, None)
                for param in request_body_params
            }

            # We have checked that sql_params is a subset of url_params U body_params,
            # construct a joint param object and use it to fill the SQL placeholders
            for param in url_params:
                body_params[param] = request_url_params_dict[param]

            if logged_user and auth_required:
                body_params["loggedId"] = userId
            param_tuple = tuple(body_params[param] for param in sql_params)

            param_tuple = tuple(body_params[param] for param in sql_params)

            # Run the execute query
            res = dal.api_safe_update(query_string, param_tuple)

        return jsonify(res), status