Example #1
0
def set_user_account(username, **kwargs):
    """
    Save the user account information.

    Variables:
    username    => Name of the user to get the account info

    Arguments:
    None

    Data Block:
    {
     "name": "Test user",        # Name of the user
     "is_active": true,          # Is the user active?
     "classification": "",            # Max classification for user
     "uname": "usertest",        # Username
     "type": ['user'],           # List of all types the user is member of
     "avatar": null,             # Avatar of the user
     "groups": ["TEST"]          # Groups the user is member of
    }

    Result example:
    {
     "success": true             # Saving the user info succeded
    }
    """
    try:
        data = request.json
        new_pass = data.pop('new_pass', None)

        old_user = STORAGE.user.get(username, as_obj=False)
        if not old_user:
            return make_api_response({"success": False}, "User %s does not exists" % username, 404)

        if not data['name']:
            return make_api_response({"success": False}, "Full name of the user cannot be empty", 400)

        data['apikeys'] = old_user.get('apikeys', [])
        data['otp_sk'] = old_user.get('otp_sk', None)
        data['security_tokens'] = old_user.get('security_tokens', {}) or {}

        if new_pass:
            password_requirements = config.auth.internal.password_requirements.as_primitives()
            if not check_password_requirements(new_pass, **password_requirements):
                error_msg = get_password_requirement_message(**password_requirements)
                return make_api_response({"success": False}, error_msg, 469)
            data['password'] = get_password_hash(new_pass)
            data.pop('new_pass_confirm', None)
        else:
            data['password'] = old_user.get('password', "__NO_PASSWORD__") or "__NO_PASSWORD__"

        # Apply dynamic classification
        data['classification'] = get_dynamic_classification(data['classification'], data['email'])

        ret_val = save_user_account(username, data, kwargs['user'])

        if ret_val and \
                not old_user['is_active'] \
                and data['is_active'] \
                and config.ui.tos_lockout \
                and config.ui.tos_lockout_notify:
            try:
                email = data['email'] or ""
                for adr in config.ui.tos_lockout_notify:
                    send_activated_email(adr, username, email, kwargs['user']['uname'])
                if email:
                    send_activated_email(email, username, email, kwargs['user']['uname'])
            except Exception as e:
                # We can't send confirmation email, Rollback user change and mark this a failure
                STORAGE.user.save(username, old_user)
                LOGGER.error(f"An error occured while sending confirmation emails: {str(e)}")
                return make_api_response({"success": False}, "The system was unable to send confirmation emails. "
                                                             "Retry again later...", 404)

        return make_api_response({"success": ret_val})
    except AccessDeniedException as e:
        return make_api_response({"success": False}, str(e), 403)
    except InvalidDataException as e:
        return make_api_response({"success": False}, str(e), 400)
Example #2
0
def signup(**_):
    """
    Signup a new user into the system

    Variables:
    None

    Arguments:
    None

    Data Block:
    {
     "user": <UID>,
     "password": <DESIRED_PASSWORD>,
     "password_confirm": <DESIRED_PASSWORD_CONFIRMATION>,
     "email": <EMAIL_ADDRESS>
    }

    Result example:
    {
     "success": true
    }
    """
    if not config.auth.internal.signup.enabled:
        return make_api_response({"success": False},
                                 "Signup process has been disabled", 403)

    data = request.json
    if not data:
        data = request.values

    uname = data.get('user', None)
    password = data.get('password', None)
    password_confirm = data.get('password_confirm', None)
    email = data.get('email', None)

    if not uname or not password or not password_confirm or not email:
        return make_api_response(
            {"success": False},
            "Not enough information to proceed with user creation", 400)

    if STORAGE.user.get(uname) or len(uname) < 3:
        return make_api_response(
            {"success": False},
            "There is already a user registered with this name", 460)
    else:
        for c in uname:
            if not 97 <= ord(c) <= 122 and not ord(c) == 45:
                return make_api_response(
                    {"success": False},
                    "Invalid username. [Lowercase letters and dashes "
                    "only with at least 3 letters]", 460)

    if password_confirm != password:
        return make_api_response("", "Passwords do not match", 469)

    password_requirements = config.auth.internal.password_requirements.as_primitives(
    )
    if not check_password_requirements(password, **password_requirements):
        error_msg = get_password_requirement_message(**password_requirements)
        return make_api_response({"success": False}, error_msg, 469)

    if STORAGE.user.search(f"email:{email.lower()}").get('total', 0) != 0:
        return make_api_response(
            {"success": False},
            "There is already a user registered with this email address", 466)

    # Normalize email address
    email = email.lower()
    email_valid = False
    for r in config.auth.internal.signup.valid_email_patterns:
        matcher = re.compile(r)
        if matcher.findall(email):
            email_valid = True
            break

    if not email_valid:
        extra = ""
        if config.ui.email:
            extra = f". Contact {config.ui.email} for more information."
        return make_api_response({"success": False},
                                 f"Invalid email address{extra}", 466)

    password = get_password_hash(password)
    key = hashlib.sha256(
        get_random_password(length=512).encode('utf-8')).hexdigest()
    try:
        send_signup_email(email, key)
        get_signup_queue(key).add({
            "uname": uname,
            "password": password,
            "email": email,
            "groups": ['USERS'],
            "name": uname
        })
    except Exception:
        return make_api_response(
            {"success": False},
            "The system failed to send signup confirmation link.", 400)

    return make_api_response({"success": True})
Example #3
0
def add_user_account(username, **_):
    """
    Add a user to the system

    Variables:
    username    => Name of the user to add

    Arguments:
    None

    Data Block:
    {
     "name": "Test user",        # Name of the user
     "is_active": true,          # Is the user active?
     "classification": "",       # Max classification for user
     "uname": "usertest",        # Username
     "type": ['user'],           # List of all types the user is member of
     "avatar": null,             # Avatar of the user
     "groups": ["TEST"]          # Groups the user is member of
    }

    Result example:
    {
     "success": true             # Saving the user info succeded
    }
    """

    data = request.json

    if "{" in username or "}" in username:
        return make_api_response({"success": False}, "You can't use '{}' in the username", 412)

    if not STORAGE.user.get(username):
        new_pass = data.pop('new_pass', None)
        if new_pass:
            password_requirements = config.auth.internal.password_requirements.as_primitives()
            if not check_password_requirements(new_pass, **password_requirements):
                error_msg = get_password_requirement_message(**password_requirements)
                return make_api_response({"success": False}, error_msg, 469)
            data['password'] = get_password_hash(new_pass)
        else:
            data['password'] = data.get('password', "__NO_PASSWORD__") or "__NO_PASSWORD__"

        # Data's username as to match the API call username
        data['uname'] = username
        if not data['name']:
            data['name'] = data['uname']

        # Add add dynamic classification group
        data['classification'] = get_dynamic_classification(data['classification'], data['email'])

        # Clear non user account data
        avatar = data.pop('avatar', None)

        if avatar is not None:
            STORAGE.user_avatar.save(username, avatar)

        try:
            return make_api_response({"success": STORAGE.user.save(username, User(data))})
        except ValueError as e:
            return make_api_response({"success": False}, str(e), 400)

    else:
        return make_api_response({"success": False}, "The username you are trying to add already exists.", 400)
Example #4
0
def reset_pwd(**_):
    """
    Reset the password for the specified reset ID

    Variables:
    None

    Arguments:
    None

    Data Block:
    {
     "reset_id": <RESET_HASH>,
     "password": <PASSWORD TO RESET TO>,
     "password_confirm": <CONFIRMATION OF PASSWORD TO RESET TO>
    }

    Result example:
    {
     "success": true
    }
    """
    if not config.auth.internal.signup.enabled:
        return make_api_response({"success": False},
                                 "Signup process has been disabled", 403)

    data = request.json
    if not data:
        data = request.values

    reset_id = data.get('reset_id', None)
    password = data.get('password', None)
    password_confirm = data.get('password_confirm', None)

    if reset_id and password and password_confirm:
        if password != password_confirm:
            return make_api_response({"success": False},
                                     err="Password mismatch",
                                     status_code=469)

        password_requirements = config.auth.internal.password_requirements.as_primitives(
        )
        if not check_password_requirements(password, **password_requirements):
            error_msg = get_password_requirement_message(
                **password_requirements)
            return make_api_response({"success": False}, error_msg, 469)

        try:
            reset_queue = get_reset_queue(reset_id)
            members = reset_queue.members()
            reset_queue.delete()
            if members:
                email = members[0]
                res = STORAGE.user.search(f"email:{email}")
                if res.get('total', 0) == 1:
                    user = STORAGE.user.get(res['items'][0].uname)
                    user.password = get_password_hash(password)
                    STORAGE.user.save(user.uname, user)
                    return make_api_response({"success": True})

        except Exception:
            pass

    return make_api_response({"success": False},
                             err="Invalid parameters passed",
                             status_code=400)