From 7c95211649f51122202a872a95951aee24c44e8b Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Fri, 8 Mar 2024 08:44:27 -0800 Subject: [PATCH] fix login.gov to use user uuid instead of email (notify-admin-1277) --- app/dao/users_dao.py | 26 ++++++++++++++++++++++ app/models.py | 1 + app/user/rest.py | 11 +++++++++ migrations/versions/0411_add_login_uuid.py | 20 +++++++++++++++++ tests/app/dao/test_users_dao.py | 7 ++++++ 5 files changed, 65 insertions(+) create mode 100644 migrations/versions/0411_add_login_uuid.py diff --git a/app/dao/users_dao.py b/app/dao/users_dao.py index 7828c5c23..8180e6f11 100644 --- a/app/dao/users_dao.py +++ b/app/dao/users_dao.py @@ -25,6 +25,32 @@ def create_secret_code(length=6): return "{:0{length}d}".format(random_number, length=length) +def get_login_gov_user(login_uuid, email_address): + """ + We want to check to see if the user is registered with login.gov + If we can find the login.gov uuid in our user table, then they are. + + Also, because we originally keyed off email address we might have a few + older users who registered with login.gov but we don't know what their + login.gov uuids are. Eventually the code that checks by email address + should be removed. + """ + + print(User.query.filter_by(login_uuid=login_uuid).first()) + user = User.query.filter_by(login_uuid=login_uuid).first() + if user: + if user.email_address != email_address: + save_user_attribute(user, {"email_address": email_address}) + return user + # Remove this 1 July 2025, all users should have login.gov uuids by now + user = User.query.filter_by(email_address=email_address).first() + if user: + save_user_attribute(user, {"login_uuid": login_uuid}) + return user + + return None + + def save_user_attribute(usr, update_dict=None): db.session.query(User).filter_by(id=usr.id).update(update_dict or {}) db.session.commit() diff --git a/app/models.py b/app/models.py index 07806365f..953624126 100644 --- a/app/models.py +++ b/app/models.py @@ -109,6 +109,7 @@ class User(db.Model): id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) name = db.Column(db.String, nullable=False, index=True, unique=False) email_address = db.Column(db.String(255), nullable=False, index=True, unique=True) + login_uuid = db.Column(db.Text, nullable=True, index=True, unique=True) created_at = db.Column( db.DateTime, index=False, diff --git a/app/user/rest.py b/app/user/rest.py index 098d23de8..8f5f38833 100644 --- a/app/user/rest.py +++ b/app/user/rest.py @@ -19,6 +19,7 @@ from app.dao.users_dao import ( create_secret_code, create_user_code, dao_archive_user, + get_login_gov_user, get_user_and_accounts, get_user_by_email, get_user_by_id, @@ -528,6 +529,16 @@ def set_permissions(user_id, service_id): return jsonify({}), 204 +@user_blueprint.route("/get-login-gov-user", methods=["POST"]) +def get_user_login_gov_user(): + request_args = request.get_json() + login_uuid = request_args["login_uuid"] + email = request_args["email"] + user = get_login_gov_user(login_uuid, email) + result = user.serialize() + return jsonify(data=result) + + @user_blueprint.route("/email", methods=["POST"]) def fetch_user_by_email(): email = email_data_request_schema.load(request.get_json()) diff --git a/migrations/versions/0411_add_login_uuid.py b/migrations/versions/0411_add_login_uuid.py new file mode 100644 index 000000000..88032bf89 --- /dev/null +++ b/migrations/versions/0411_add_login_uuid.py @@ -0,0 +1,20 @@ +""" + +Revision ID: 0411_add_login_uuid +Revises: 410_enums_for_everything +Create Date: 2023-04-24 11:35:22.873930 + +""" +import sqlalchemy as sa +from alembic import op + +revision = "0411_add_login_uuid" +down_revision = "0410_enums_for_everything" + + +def upgrade(): + op.add_column("users", sa.Column("login_uuid", sa.Text)) + + +def downgrade(): + op.drop_column("users", "login_uuid") diff --git a/tests/app/dao/test_users_dao.py b/tests/app/dao/test_users_dao.py index 57ed65619..e38a395b5 100644 --- a/tests/app/dao/test_users_dao.py +++ b/tests/app/dao/test_users_dao.py @@ -15,6 +15,7 @@ from app.dao.users_dao import ( dao_archive_user, delete_codes_older_created_more_than_a_day_ago, delete_model_user, + get_login_gov_user, get_user_by_email, get_user_by_id, increment_failed_login_count, @@ -110,6 +111,12 @@ def test_get_user_by_email(sample_user): assert sample_user == user_from_db +def test_get_login_gov_user(sample_user): + user_from_db = get_login_gov_user("fake_login_gov_uuid", sample_user.email_address) + assert sample_user.email_address == user_from_db.email_address + assert user_from_db.login_uuid is not None + + def test_get_user_by_email_is_case_insensitive(sample_user): email = sample_user.email_address user_from_db = get_user_by_email(email.upper())