Esempio n. 1
0
    def Authenticate(self, request, context):
        """
        Authenticates a classic password based login request.

        request.user can be any of id/username/email
        """
        logger.debug(f"Logging in with {request.user=}, password=*******")
        with session_scope() as session:
            user = get_user_by_field(session, request.user)
            if user:
                logger.debug(f"Found user")
                if not user.hashed_password:
                    logger.debug(f"User doesn't have a password!")
                    context.abort(grpc.StatusCode.FAILED_PRECONDITION, errors.NO_PASSWORD)
                if verify_password(user.hashed_password, request.password):
                    logger.debug(f"Right password")
                    # correct password
                    token, expiry = self._create_session(context, session, user, request.remember_device)
                    context.send_initial_metadata(
                        [
                            ("set-cookie", create_session_cookie(token, expiry)),
                        ]
                    )
                    return auth_pb2.AuthRes(jailed=user.is_jailed)
                else:
                    logger.debug(f"Wrong password")
                    # wrong password
                    context.abort(grpc.StatusCode.NOT_FOUND, errors.INVALID_USERNAME_OR_PASSWORD)
            else:  # user not found
                logger.debug(f"Didn't find user")
                # do about as much work as if the user was found, reduces timing based username enumeration attacks
                hash_password(request.password)
                context.abort(grpc.StatusCode.NOT_FOUND, errors.INVALID_USERNAME_OR_PASSWORD)
Esempio n. 2
0
    def Authenticate(self, request, context):
        """
        Authenticates a classic password based login request.

        request.user can be any of id/username/email
        """
        logging.debug(f"Logging in with {request.user=}, password=*******")
        with session_scope(self._Session) as session:
            user = get_user_by_field(session, request.user)
            if user:
                logging.debug(f"Found user")
                if not user.hashed_password:
                    logging.debug(f"User doesn't have a password!")
                    context.abort(grpc.StatusCode.FAILED_PRECONDITION, "User does not have a password")
                if verify_password(user.hashed_password, request.password):
                    logging.debug(f"Right password")
                    # correct password
                    token = self._create_session(session, user)
                    return auth_pb2.AuthRes(token=token)
                else:
                    logging.debug(f"Wrong password")
                    # wrong password
                    context.abort(grpc.StatusCode.UNAUTHENTICATED, "Invalid username or password")
            else: # user not found
                logging.debug(f"Didn't find user")
                # do about as much work as if the user was found, reduces timing based username enumeration attacks
                hash_password(request.password)
                context.abort(grpc.StatusCode.UNAUTHENTICATED, "Invalid username or password")
Esempio n. 3
0
def test_ChangePassword_normal_no_passwords(db, fast_passwords):
    # user has old password and called with empty body
    old_password = random_hex()
    user, token = generate_user(hashed_password=hash_password(old_password))

    with account_session(token) as account:
        with pytest.raises(grpc.RpcError) as e:
            account.ChangePassword(account_pb2.ChangePasswordReq())
        assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
        assert e.value.details() == errors.MISSING_BOTH_PASSWORDS

    with session_scope() as session:
        updated_user = session.query(User).filter(User.id == user.id).one()
        assert updated_user.hashed_password == hash_password(old_password)
Esempio n. 4
0
    def ChangePassword(self, request, context):
        """
        Changes the user's password. They have to confirm their old password just in case.

        If they didn't have an old password previously, then we don't check that.
        """
        with session_scope() as session:
            user = session.query(User).filter(User.id == context.user_id).one()

            if not request.HasField("old_password") and not request.HasField(
                    "new_password"):
                context.abort(grpc.StatusCode.INVALID_ARGUMENT,
                              errors.MISSING_BOTH_PASSWORDS)

            _check_password(user, "old_password", request, context)

            # password correct or no password

            if not request.HasField("new_password"):
                # the user wants to unset their password
                user.hashed_password = None
            else:
                _abort_if_terrible_password(request.new_password.value,
                                            context)
                user.hashed_password = hash_password(
                    request.new_password.value)

            session.commit()

            send_password_changed_email(user)

        return empty_pb2.Empty()
Esempio n. 5
0
def test_ChangeEmail_wrong_token(db, fast_passwords):
    password = random_hex()
    new_email = f"{random_hex()}@couchers.org.invalid"
    user, token = generate_user(db, hashed_password=hash_password(password))

    with account_session(db, token) as account:
        account.ChangeEmail(
            account_pb2.ChangeEmailReq(
                password=wrappers_pb2.StringValue(value=password),
                new_email=new_email,
            ))

    with session_scope(db) as session:
        user_updated = (session.query(User).filter(User.id == user.id).filter(
            User.new_email == new_email).filter(
                User.new_email_token_created <= func.now()).filter(
                    User.new_email_token_expiry >= func.now())).one()

        token = user_updated.new_email_token

    with auth_api_session(db) as auth_api:
        with pytest.raises(grpc.RpcError) as e:
            res = auth_api.CompleteChangeEmail(
                auth_pb2.CompleteChangeEmailReq(
                    change_email_token="wrongtoken", ))
        assert e.value.code() == grpc.StatusCode.UNAUTHENTICATED
        assert e.value.details() == errors.INVALID_TOKEN

    with session_scope(db) as session:
        user_updated2 = session.query(User).filter(User.id == user.id).one()
        assert user_updated2.email == user.email
Esempio n. 6
0
def test_ChangeEmail_sends_proper_emails_has_password(db, fast_passwords):
    password = random_hex()
    new_email = f"{random_hex()}@couchers.org.invalid"
    user, token = generate_user(hashed_password=hash_password(password))

    with account_session(token) as account:
        account.ChangeEmail(
            account_pb2.ChangeEmailReq(
                password=wrappers_pb2.StringValue(value=password),
                new_email=new_email,
            ))

    with session_scope() as session:
        jobs = (session.execute(
            select(BackgroundJob).where(
                BackgroundJob.job_type ==
                BackgroundJobType.send_email)).scalars().all())
        assert len(jobs) == 2
        payload_for_notification_email = jobs[0].payload
        payload_for_confirmation_email_new_address = jobs[1].payload
        unique_string_notification_email_as_bytes = b"You requested that your email on Couchers.org be changed to"
        unique_string_for_confirmation_email_new_email_address_as_bytes = (
            b"You requested that your email be changed to this email address on Couchers.org"
        )
        assert unique_string_notification_email_as_bytes in payload_for_notification_email
        assert (unique_string_for_confirmation_email_new_email_address_as_bytes
                in payload_for_confirmation_email_new_address)
Esempio n. 7
0
def test_ChangeEmail(db, fast_passwords):
    password = random_hex()
    new_email = f"{random_hex()}@couchers.org.invalid"
    user, token = generate_user(db, hashed_password=hash_password(password))

    with account_session(db, token) as account:
        account.ChangeEmail(
            account_pb2.ChangeEmailReq(
                password=wrappers_pb2.StringValue(value=password),
                new_email=new_email,
            ))

    with session_scope(db) as session:
        user_updated = (session.query(User).filter(User.id == user.id).filter(
            User.new_email == new_email).filter(
                User.new_email_token_created <= func.now()).filter(
                    User.new_email_token_expiry >= func.now())).one()

        token = user_updated.new_email_token

    with auth_api_session(db) as auth_api:
        res = auth_api.CompleteChangeEmail(
            auth_pb2.CompleteChangeEmailReq(change_email_token=token, ))

    with session_scope(db) as session:
        user_updated2 = session.query(User).filter(User.id == user.id).one()
        assert user_updated2.email == new_email
        assert user_updated2.new_email is None
        assert user_updated2.new_email_token is None

    # check there's no valid tokens left
    with session_scope(db) as session:
        assert (session.query(User).filter(
            User.new_email_token_created <= func.now()).filter(
                User.new_email_token_expiry >= func.now())).count() == 0
Esempio n. 8
0
def add_dummy_data(file_name):
    with session_scope(Session) as session:
        with open(file_name, "r") as file:
            users = json.loads(file.read())

        for user in users:
            new_user = User(
                username=user["username"],
                email=user["email"],
                hashed_password=hash_password(user["password"])
                if user["password"] else None,
                name=user["name"],
                city=user["city"],
                verification=user["verification"],
                community_standing=user["community_standing"],
                birthdate=date(year=user["birthdate"]["year"],
                               month=user["birthdate"]["month"],
                               day=user["birthdate"]["day"]),
                gender=user["gender"],
                languages="|".join(user["languages"]),
                occupation=user["occupation"],
                about_me=user["about_me"],
                about_place=user["about_place"],
                countries_visited="|".join(user["countries_visited"]),
                countries_lived="|".join(user["countries_lived"]),
            )
            session.add(new_user)
Esempio n. 9
0
def test_ChangePassword_remove_wrong_password(db, fast_passwords):
    old_password = random_hex()
    user, token = generate_user(db,
                                hashed_password=hash_password(old_password))

    with account_session(db, token) as account:
        with pytest.raises(grpc.RpcError) as e:
            account.ChangePassword(
                account_pb2.ChangePasswordReq(
                    old_password=wrappers_pb2.StringValue(
                        value="wrong password"), ))
        assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
        assert e.value.details() == errors.INVALID_USERNAME_OR_PASSWORD

    with session_scope(db) as session:
        updated_user = session.query(User).filter(User.id == user.id).one()
        assert updated_user.hashed_password == hash_password(old_password)
Esempio n. 10
0
def test_ChangePassword_regression(db, fast_passwords):
    # send_password_changed_email wasn't working
    # user has old password and is changing to new password
    old_password = random_hex()
    new_password = random_hex()
    user, token = generate_user(hashed_password=hash_password(old_password))

    with account_session(token) as account:
        account.ChangePassword(
            account_pb2.ChangePasswordReq(
                old_password=wrappers_pb2.StringValue(value=old_password),
                new_password=wrappers_pb2.StringValue(value=new_password),
            ))

    with session_scope() as session:
        updated_user = session.execute(
            select(User).where(User.id == user.id)).scalar_one()
        assert updated_user.hashed_password == hash_password(new_password)
Esempio n. 11
0
def test_ChangePassword_normal(db, fast_passwords):
    # user has old password and is changing to new password
    old_password = random_hex()
    new_password = random_hex()
    user, token = generate_user(hashed_password=hash_password(old_password))

    with account_session(token) as account:
        with patch("couchers.servicers.account.send_password_changed_email") as mock:
            account.ChangePassword(
                account_pb2.ChangePasswordReq(
                    old_password=wrappers_pb2.StringValue(value=old_password),
                    new_password=wrappers_pb2.StringValue(value=new_password),
                )
            )
        mock.assert_called_once()

    with session_scope() as session:
        updated_user = session.query(User).filter(User.id == user.id).one()
        assert updated_user.hashed_password == hash_password(new_password)
Esempio n. 12
0
def test_password_reset_invalid_token(db):
    password = random_hex()
    user, token = generate_user(hashed_password=hash_password(password))

    with auth_api_session() as (auth_api, metadata_interceptor):
        res = auth_api.ResetPassword(
            auth_pb2.ResetPasswordReq(user=user.username, ))

    with auth_api_session() as (auth_api, metadata_interceptor), pytest.raises(
            grpc.RpcError) as e:
        res = auth_api.CompletePasswordReset(
            auth_pb2.CompletePasswordResetReq(
                password_reset_token="wrongtoken"))
    assert e.value.code() == grpc.StatusCode.NOT_FOUND
    assert e.value.details() == errors.INVALID_TOKEN

    with session_scope() as session:
        user = session.execute(select(User)).scalar_one()
        assert user.hashed_password == hash_password(password)
Esempio n. 13
0
def test_ChangePassword_normal_no_password(db, fast_passwords):
    # user has old password and is changing to new password, but didn't supply old password
    old_password = random_hex()
    new_password = random_hex()
    user, token = generate_user(db,
                                hashed_password=hash_password(old_password))

    with account_session(db, token) as account:
        with pytest.raises(grpc.RpcError) as e:
            account.ChangePassword(
                account_pb2.ChangePasswordReq(
                    new_password=wrappers_pb2.StringValue(
                        value=new_password), ))
        assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
        assert e.value.details() == errors.MISSING_PASSWORD

    with session_scope(db) as session:
        updated_user = session.query(User).filter(User.id == user.id).one()
        assert updated_user.hashed_password == hash_password(old_password)
Esempio n. 14
0
def test_ChangePassword_normal_long_password(db, fast_passwords):
    # user has old password and is changing to new password, but used short password
    old_password = random_hex()
    new_password = random_hex(length=1000)
    user, token = generate_user(hashed_password=hash_password(old_password))

    with account_session(token) as account:
        with pytest.raises(grpc.RpcError) as e:
            account.ChangePassword(
                account_pb2.ChangePasswordReq(
                    old_password=wrappers_pb2.StringValue(value=old_password),
                    new_password=wrappers_pb2.StringValue(value=new_password),
                )
            )
        assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
        assert e.value.details() == errors.PASSWORD_TOO_LONG

    with session_scope() as session:
        updated_user = session.query(User).filter(User.id == user.id).one()
        assert updated_user.hashed_password == hash_password(old_password)
Esempio n. 15
0
def test_ChangePassword_normal_insecure_password(db, fast_passwords):
    # user has old password and is changing to new password, but used insecure password
    old_password = random_hex()
    new_password = "******"
    user, token = generate_user(hashed_password=hash_password(old_password))

    with account_session(token) as account:
        with pytest.raises(grpc.RpcError) as e:
            account.ChangePassword(
                account_pb2.ChangePasswordReq(
                    old_password=wrappers_pb2.StringValue(value=old_password),
                    new_password=wrappers_pb2.StringValue(value=new_password),
                ))
        assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
        assert e.value.details() == errors.INSECURE_PASSWORD

    with session_scope() as session:
        updated_user = session.execute(
            select(User).where(User.id == user.id)).scalar_one()
        assert updated_user.hashed_password == hash_password(old_password)
Esempio n. 16
0
def test_ChangeEmail_email_in_use(db, fast_passwords):
    password = random_hex()
    new_email = f"{random_hex()}@couchers.org.invalid"
    user, token = generate_user(db, hashed_password=hash_password(password))
    user2, token2 = generate_user(db, hashed_password=hash_password(password))

    with account_session(db, token) as account:
        with pytest.raises(grpc.RpcError) as e:
            account.ChangeEmail(
                account_pb2.ChangeEmailReq(
                    password=wrappers_pb2.StringValue(value=password),
                    new_email=user2.email,
                ))
        assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
        assert e.value.details() == errors.INVALID_EMAIL

    with session_scope(db) as session:
        assert (session.query(User).filter(
            User.new_email_token_created <= func.now()).filter(
                User.new_email_token_expiry >= func.now())).count() == 0
Esempio n. 17
0
def test_password_reset_invalid_token(db, fast_passwords):
    password = random_hex()
    user, token = generate_user(db, hashed_password=hash_password(password))

    with auth_api_session(db) as auth_api:
        res = auth_api.ResetPassword(
            auth_pb2.ResetPasswordReq(user=user.username, ))

    with session_scope(db) as session:
        token = session.query(PasswordResetToken).one_or_none().token

    with auth_api_session(db) as auth_api, pytest.raises(grpc.RpcError) as e:
        res = auth_api.CompletePasswordReset(
            auth_pb2.CompletePasswordResetReq(
                password_reset_token="wrongtoken"))
    assert e.value.code() == grpc.StatusCode.UNAUTHENTICATED
    assert e.value.details() == errors.INVALID_TOKEN

    with session_scope(db) as session:
        user = session.query(User).one()
        assert user.hashed_password == hash_password(password)
Esempio n. 18
0
def test_ChangeEmail_email_in_use(db, fast_passwords):
    password = random_hex()
    user, token = generate_user(hashed_password=hash_password(password))
    user2, token2 = generate_user(hashed_password=hash_password(password))

    with account_session(token) as account:
        with pytest.raises(grpc.RpcError) as e:
            account.ChangeEmail(
                account_pb2.ChangeEmailReq(
                    password=wrappers_pb2.StringValue(value=password),
                    new_email=user2.email,
                ))
        assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
        assert e.value.details() == errors.INVALID_EMAIL

    with session_scope() as session:
        assert (session.execute(
            select(func.count()).select_from(User).where(
                User.new_email_token_created <= func.now()).where(
                    User.new_email_token_expiry >= func.now()))
                ).scalar_one() == 0
Esempio n. 19
0
def test_successful_authenticate(db):
    user, _ = generate_user(hashed_password=hash_password("password"))

    # Authenticate with username
    with auth_api_session() as (auth_api, metadata_interceptor):
        reply = auth_api.Authenticate(
            auth_pb2.AuthReq(user=user.username, password="******"))
    assert not reply.jailed

    # Authenticate with email
    with auth_api_session() as (auth_api, metadata_interceptor):
        reply = auth_api.Authenticate(
            auth_pb2.AuthReq(user=user.email, password="******"))
    assert not reply.jailed
Esempio n. 20
0
def test_GetAccountInfo(db, fast_passwords):
    # without password
    user1, token1 = generate_user(hashed_password=None)

    with account_session(token1) as account:
        res = account.GetAccountInfo(empty_pb2.Empty())
        assert res.login_method == account_pb2.GetAccountInfoRes.LoginMethod.MAGIC_LINK
        assert not res.has_password

    # with password
    user1, token1 = generate_user(hashed_password=hash_password(random_hex()))

    with account_session(token1) as account:
        res = account.GetAccountInfo(empty_pb2.Empty())
        assert res.login_method == account_pb2.GetAccountInfoRes.LoginMethod.PASSWORD
        assert res.has_password
Esempio n. 21
0
def test_unsuccessful_authenticate(db):
    user, _ = generate_user(hashed_password=hash_password("password"))

    # Invalid password
    with auth_api_session() as (auth_api, metadata_interceptor):
        with pytest.raises(grpc.RpcError) as e:
            reply = auth_api.Authenticate(
                auth_pb2.AuthReq(user=user.username,
                                 password="******"))
        assert e.value.code() == grpc.StatusCode.NOT_FOUND
        assert e.value.details() == errors.INVALID_USERNAME_OR_PASSWORD

    # Invalid username
    with auth_api_session() as (auth_api, metadata_interceptor):
        with pytest.raises(grpc.RpcError) as e:
            reply = auth_api.Authenticate(
                auth_pb2.AuthReq(user="******", password="******"))
        assert e.value.code() == grpc.StatusCode.NOT_FOUND
        assert e.value.details() == errors.INVALID_USERNAME_OR_PASSWORD

    # Invalid email
    with auth_api_session() as (auth_api, metadata_interceptor):
        with pytest.raises(grpc.RpcError) as e:
            reply = auth_api.Authenticate(
                auth_pb2.AuthReq(user=f"{random_hex(12)}@couchers.org.invalid",
                                 password="******"))
        assert e.value.code() == grpc.StatusCode.NOT_FOUND
        assert e.value.details() == errors.INVALID_USERNAME_OR_PASSWORD

    # Invalid id
    with auth_api_session() as (auth_api, metadata_interceptor):
        with pytest.raises(grpc.RpcError) as e:
            reply = auth_api.Authenticate(
                auth_pb2.AuthReq(user="******", password="******"))
        assert e.value.code() == grpc.StatusCode.NOT_FOUND
        assert e.value.details() == errors.INVALID_USERNAME_OR_PASSWORD

    # No Password
    user_without_pass, _ = generate_user(hashed_password=None)

    with auth_api_session() as (auth_api, metadata_interceptor):
        with pytest.raises(grpc.RpcError) as e:
            reply = auth_api.Authenticate(
                auth_pb2.AuthReq(user=user_without_pass.username,
                                 password="******"))
        assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
        assert e.value.details() == errors.NO_PASSWORD
Esempio n. 22
0
def test_password_reset(db):
    user, token = generate_user(hashed_password=hash_password("mypassword"))

    with auth_api_session() as (auth_api, metadata_interceptor):
        res = auth_api.ResetPassword(
            auth_pb2.ResetPasswordReq(user=user.username, ))

    with session_scope() as session:
        token = session.execute(select(PasswordResetToken)).scalar_one().token

    with auth_api_session() as (auth_api, metadata_interceptor):
        res = auth_api.CompletePasswordReset(
            auth_pb2.CompletePasswordResetReq(password_reset_token=token))

    with session_scope() as session:
        user = session.execute(select(User)).scalar_one()
        assert not user.has_password
Esempio n. 23
0
def test_password_reset(db, fast_passwords):
    user, token = generate_user(hashed_password=hash_password("mypassword"))

    with auth_api_session() as (auth_api, metadata_interceptor):
        res = auth_api.ResetPassword(
            auth_pb2.ResetPasswordReq(user=user.username, ))

    with session_scope() as session:
        token = session.query(PasswordResetToken).one().token

    with auth_api_session() as (auth_api, metadata_interceptor):
        res = auth_api.CompletePasswordReset(
            auth_pb2.CompletePasswordResetReq(password_reset_token=token))

    with session_scope() as session:
        user = session.query(User).one()
        assert user.hashed_password is None
Esempio n. 24
0
def test_ChangeEmail_has_password(db, fast_passwords):
    password = random_hex()
    new_email = f"{random_hex()}@couchers.org.invalid"
    user, token = generate_user(hashed_password=hash_password(password))

    with account_session(token) as account:
        account.ChangeEmail(
            account_pb2.ChangeEmailReq(
                password=wrappers_pb2.StringValue(value=password),
                new_email=new_email,
            ))

    with session_scope() as session:
        user_updated = session.execute(
            select(User).where(User.id == user.id)).scalar_one()
        assert user_updated.email == user.email
        assert user_updated.new_email == new_email
        assert user_updated.old_email_token is None
        assert not user_updated.old_email_token_created
        assert not user_updated.old_email_token_expiry
        assert not user_updated.need_to_confirm_via_old_email
        assert user_updated.new_email_token is not None
        assert user_updated.new_email_token_created <= now()
        assert user_updated.new_email_token_expiry >= now()
        assert user_updated.need_to_confirm_via_new_email

        token = user_updated.new_email_token

    with auth_api_session() as (auth_api, metadata_interceptor):
        res = auth_api.ConfirmChangeEmail(
            auth_pb2.ConfirmChangeEmailReq(change_email_token=token, ))
        assert res.state == auth_pb2.EMAIL_CONFIRMATION_STATE_SUCCESS

    with session_scope() as session:
        user = session.execute(
            select(User).where(User.id == user.id)).scalar_one()
        assert user.email == new_email
        assert user.new_email is None
        assert user.old_email_token is None
        assert user.old_email_token_created is None
        assert user.old_email_token_expiry is None
        assert not user.need_to_confirm_via_old_email
        assert user.new_email_token is None
        assert user.new_email_token_created is None
        assert user.new_email_token_expiry is None
        assert not user.need_to_confirm_via_new_email
Esempio n. 25
0
def test_ChangePassword_add(db, fast_passwords):
    # user does not have an old password and is adding a new password
    new_password = random_hex()
    user, token = generate_user(db, hashed_password=None)

    with account_session(db, token) as account:
        with patch("couchers.servicers.account.send_password_changed_email"
                   ) as mock:
            account.ChangePassword(
                account_pb2.ChangePasswordReq(
                    new_password=wrappers_pb2.StringValue(
                        value=new_password), ))
        mock.assert_called_once()

    with session_scope(db) as session:
        updated_user = session.query(User).filter(User.id == user.id).one()
        assert updated_user.hashed_password == hash_password(new_password)
Esempio n. 26
0
def test_ChangePassword_remove(db, fast_passwords):
    old_password = random_hex()
    user, token = generate_user(hashed_password=hash_password(old_password))

    with account_session(token) as account:
        with patch("couchers.servicers.account.send_password_changed_email"
                   ) as mock:
            account.ChangePassword(
                account_pb2.ChangePasswordReq(
                    old_password=wrappers_pb2.StringValue(
                        value=old_password), ))
        mock.assert_called_once()

    with session_scope() as session:
        updated_user = session.execute(
            select(User).where(User.id == user.id)).scalar_one()
        assert not updated_user.has_password
Esempio n. 27
0
    def SetPassword(self, request, context):
        with session_scope() as session:
            user = session.execute(
                select(User).where(User.id == context.user_id)).scalar_one()

            # this is important so anybody can't just set your password through the jail API
            if user.has_password:
                context.abort(grpc.StatusCode.FAILED_PRECONDITION,
                              errors.ALREADY_HAS_PASSWORD)

            abort_on_invalid_password(request.new_password, context)

            user.hashed_password = hash_password(request.new_password)
            session.commit()

            send_password_changed_email(user)

            return self._get_jail_info(user)
Esempio n. 28
0
def test_GetAccountInfo(db, fast_passwords):
    # without password
    user1, token1 = generate_user(hashed_password=None, email="*****@*****.**")

    with account_session(token1) as account:
        res = account.GetAccountInfo(empty_pb2.Empty())
        assert res.login_method == account_pb2.GetAccountInfoRes.LoginMethod.MAGIC_LINK
        assert not res.has_password
        assert res.email == "*****@*****.**"

    # with password
    user1, token1 = generate_user(hashed_password=hash_password(random_hex()), email="*****@*****.**")

    with account_session(token1) as account:
        res = account.GetAccountInfo(empty_pb2.Empty())
        assert res.login_method == account_pb2.GetAccountInfoRes.LoginMethod.PASSWORD
        assert res.has_password
        assert res.email == "*****@*****.**"
Esempio n. 29
0
    def ChangePassword(self, request, context):
        """
        Changes the user's password. They have to confirm their old password just in case.

        If they didn't have an old password previously, then we don't check that.
        """
        with session_scope() as session:
            user = session.execute(
                select(User).where(User.id == context.user_id)).scalar_one()

            if not request.HasField("old_password") and not request.HasField(
                    "new_password"):
                context.abort(grpc.StatusCode.INVALID_ARGUMENT,
                              errors.MISSING_BOTH_PASSWORDS)

            _check_password(user, "old_password", request, context)

            # password correct or no password

            if not request.HasField("new_password"):
                # the user wants to unset their password
                user.hashed_password = None
            else:
                abort_on_invalid_password(request.new_password.value, context)
                user.hashed_password = hash_password(
                    request.new_password.value)

            session.commit()

            send_password_changed_email(user)

            notify(
                user_id=user.id,
                topic="password",
                key="",
                action="change",
                icon="wrench",
                title=f"Your password was changed",
                link=urls.account_settings_link(),
            )

        return empty_pb2.Empty()
Esempio n. 30
0
def test_ChangeEmail_wrong_email(db, fast_passwords):
    password = random_hex()
    new_email = f"{random_hex()}@couchers.org.invalid"
    user, token = generate_user(hashed_password=hash_password(password))

    with account_session(token) as account:
        with pytest.raises(grpc.RpcError) as e:
            account.ChangeEmail(
                account_pb2.ChangeEmailReq(
                    password=wrappers_pb2.StringValue(value="wrong password"),
                    new_email=new_email,
                ))
        assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
        assert e.value.details() == errors.INVALID_USERNAME_OR_PASSWORD

    with session_scope() as session:
        assert (session.execute(
            select(func.count()).select_from(User).where(
                User.new_email_token_created <= func.now()).where(
                    User.new_email_token_expiry >= func.now()))
                ).scalar_one() == 0