Exemple #1
0
    def generate_sample_user(self, confirmed: bool = True) \
            -> Tuple[User, str, str]:
        """
        Generates a random user for use in tests
        :param confirmed: Whether or not the user should be confirmed
        :return: The User object, the password and the confirmation key
        """
        if self.user_cred_count >= \
                len(_TestFramework.GENERATED_USER_CREDENTIALS):
            password = generate_random(20)
            password_hash = generate_hash(password)
            confirm_key = generate_random(20)
            confirmation_hash = generate_hash(confirm_key)
            _TestFramework.GENERATED_USER_CREDENTIALS.append(
                (password, password_hash, confirm_key, confirmation_hash))
        else:
            password, password_hash, confirm_key, confirmation_hash = \
                _TestFramework.GENERATED_USER_CREDENTIALS[self.user_cred_count]
        self.user_cred_count += 1

        user = User(username=generate_random(12),
                    password_hash=password_hash,
                    email=generate_random(8) + "@example.com",
                    confirmed=confirmed,
                    confirmation_hash=confirmation_hash)
        self.db.session.add(user)
        self.db.session.commit()
        return user, password, confirm_key
    def register() -> Union[Response, str]:
        """
        Page that allows a new user to register
        :return: The response
        """
        if request.method == "POST":
            username = request.form["username"]
            email = request.form["email"]
            password = request.form["password"]
            password_repeat = request.form["password-repeat"]
            recaptcha_result = verify_recaptcha(
                request.remote_addr,
                request.form.get("g-recaptcha-response", ""),
                Config.RECAPTCHA_SECRET_KEY)

            all_users = User.query.all()
            usernames = [user.username for user in all_users]
            emails = [user.email for user in all_users]

            _min, _max = Config.MIN_USERNAME_LENGTH, Config.MAX_USERNAME_LENGTH

            if len(username) < _min or len(username) > _max:
                flash(Config.STRINGS["username_length"].format(_min, _max),
                      "danger")
            elif password != password_repeat:
                flash(Config.STRINGS["passwords_do_not_match"], "danger")
            elif username in usernames:
                flash(Config.STRINGS["username_already_exists"], "danger")
            elif email in emails:
                flash(Config.STRINGS["email_already_in_use"], "danger")
            elif not recaptcha_result:
                flash(Config.STRINGS["recaptcha_incorrect"], "danger")
            else:
                confirmation_key = generate_random(32)
                confirmation_hash = generate_hash(confirmation_key)
                user = User(username=username,
                            email=email,
                            password_hash=generate_hash(password),
                            confirmation_hash=confirmation_hash)
                db.session.add(user)
                db.session.commit()
                email_msg = render_template(
                    "email/registration.html",
                    domain_name=Config.DOMAIN_NAME,
                    host_url=Config.base_url(),
                    target_url=os.path.join(Config.base_url(), "confirm"),
                    username=username,
                    user_id=user.id,
                    confirm_key=confirmation_key,
                    **Config.TEMPLATE_EXTRAS["registration_email"]())
                send_email(email, Config.STRINGS["registration_email_title"],
                           email_msg, Config.SMTP_HOST, Config.SMTP_ADDRESS,
                           Config.SMTP_PASSWORD, Config.SMTP_PORT)
                app.logger.info("User {} registered.".format(user.username))
                flash(Config.STRINGS["registration_successful"], "info")
                return redirect(url_for("static.index"))
            return redirect(url_for("user_management.register"))
        else:
            return render_template("user_management/register.html",
                                   **Config.TEMPLATE_EXTRAS["register"]())
Exemple #3
0
    def test_salt(self):
        """
        Tests that password hashes are salted
        :return: None
        """
        password = generate_random(30)
        hash_one = generate_hash(password)
        hash_two = generate_hash(password)

        self.assertNotEqual(hash_one, hash_two)

        self.assertTrue(verify_password(password, hash_one))
        self.assertTrue(verify_password(password, hash_two))
Exemple #4
0
 def test_hashing_strings(self):
     """
     Tests that password hashing and verifying works with string as well
     :return: None
     """
     password = str(generate_random(30))
     _hash = generate_hash(password)
     self.assertTrue(verify_password(password, _hash))
Exemple #5
0
    def test_hashing(self):
        """
        Tests that passwords can be hashed successfully
        :return: None
        """
        password_one = generate_random(30)
        password_two = generate_random(20)

        hash_one = generate_hash(password_one)
        hash_two = generate_hash(password_two)

        self.assertEqual(len(hash_one), len(hash_two))
        self.assertNotEqual(hash_one, hash_two)

        self.assertTrue(verify_password(password_one, hash_one))
        self.assertTrue(verify_password(password_two, hash_two))
        self.assertFalse(verify_password(password_one, hash_two))
        self.assertFalse(verify_password(password_two, hash_one))
Exemple #6
0
    def forgot() -> Union[Response, str]:
        """
        Allows a user to reset their password
        :return: The response
        """
        if request.method == "POST":
            email = request.form["email"]
            recaptcha_result = verify_recaptcha(
                request.remote_addr,
                request.form.get("g-recaptcha-response", ""),
                Config.RECAPTCHA_SECRET_KEY)
            user: User = User.query.filter_by(email=email).first()

            if not recaptcha_result:
                flash(Config.STRINGS["recaptcha_incorrect"], "danger")
                return redirect(url_for("user_management.forgot"))
            else:
                if user is None:
                    # Fail silently to ensure that a potential attacker can't
                    # use the response to figure out information
                    # on registered users
                    pass
                else:
                    new_pass = generate_random(20)
                    user.password_hash = generate_hash(new_pass)
                    db.session.commit()

                    email_msg = render_template(
                        "email/forgot_password.html",
                        domain_name=Config.DOMAIN_NAME,
                        host_url=Config.base_url(),
                        target_url=os.path.join(Config.base_url(), "login"),
                        password=new_pass,
                        username=user.username,
                        **Config.TEMPLATE_EXTRAS["forgot_email"]())
                    try:
                        send_email(
                            email,
                            Config.STRINGS["password_reset_email_title"],
                            email_msg, Config.SMTP_HOST, Config.SMTP_ADDRESS,
                            Config.SMTP_PASSWORD, Config.SMTP_PORT)
                    except SMTPAuthenticationError:  # pragma: no cover
                        app.logger.error("SMTP Authentication failed")
                        flash("SMTP AUTHENTICATION FAILED", "info")
                flash(Config.STRINGS["password_was_reset"], "success")
                return redirect(url_for("static.index"))

        else:
            return render_template("user_management/forgot.html",
                                   **Config.TEMPLATE_EXTRAS["forgot"]())
Exemple #7
0
    def api_key() -> Dict[str, Any]:
        """
        Allows users to request a new API key or revoke an existing API key
        :return: The JSON response
        """
        data = request.get_json()
        assert data is not None
        if request.method == "POST":
            username = data["username"]
            password = data["password"]
            user = User.query.filter_by(username=username).first()

            if user is None:
                raise ApiException("user does not exist", 401)
            elif not user.confirmed:
                raise ApiException("user is not confirmed", 401)
            elif not user.verify_password(password):
                raise ApiException("password is incorrect", 401)
            else:
                key = generate_random(32)
                hashed = generate_hash(key)
                _api_key = ApiKey(user=user, key_hash=hashed)
                db.session.add(_api_key)
                db.session.commit()

                return {
                    "api_key":
                    "{}:{}".format(_api_key.id, key),
                    "expiration":
                    (int(_api_key.creation_time) + Config.MAX_API_KEY_AGE),
                    "user":
                    user.__json__(False)
                }

        else:  # request.method == "DELETE"
            key = data["api_key"]
            _api_key = ApiKey.query.get(key.split(":", 1)[0])

            if _api_key is None:
                raise ApiException("api key does not exist", 401)
            elif not _api_key.verify_key(key):
                raise ApiException("api key not valid", 401)
            else:
                db.session.delete(_api_key)
                db.session.commit()
                return {}
Exemple #8
0
    def change_password() -> Union[Response, str]:
        """
        Allows the user to change their password
        :return: The response
        """
        old_password = request.form["old_password"]
        new_password = request.form["new_password"]
        password_repeat = request.form["password_repeat"]
        user: User = current_user

        if new_password != password_repeat:
            flash(Config.STRINGS["passwords_do_not_match"], "danger")
        elif not user.verify_password(old_password):
            flash(Config.STRINGS["invalid_password"], "danger")
        else:
            user.password_hash = generate_hash(new_password)
            db.session.commit()
            flash(Config.STRINGS["password_changed"], "success")
        return redirect(url_for("user_management.profile"))
Exemple #9
0
    def generate_api_key(self, user: User) \
            -> Tuple[ApiKey, str, Dict[str, str]]:
        """
        Generates an API key and base64 encoded headers for requests
        :param user: The user for which to create the key
        :return: The API key object, the actual API key, the headers
        """
        if self.api_cred_count >= \
                len(_TestFramework.GENERATED_API_KEY_CREDENTIALS):
            key = generate_random(20)
            hashed = generate_hash(key)
            _TestFramework.GENERATED_API_KEY_CREDENTIALS.append((key, hashed))
        else:
            key, hashed = _TestFramework.GENERATED_API_KEY_CREDENTIALS[
                self.api_cred_count]
        self.api_cred_count += 1

        api_key_obj = ApiKey(user=user, key_hash=hashed)
        self.db.session.add(api_key_obj)
        self.db.session.commit()
        api_key = "{}:{}".format(api_key_obj.id, key)

        return api_key_obj, api_key, self.generate_api_key_headers(api_key)