Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DB changes #496

Merged
merged 15 commits into from
Jun 30, 2022
Merged

Add DB changes #496

merged 15 commits into from
Jun 30, 2022

Conversation

J0
Copy link
Contributor

@J0 J0 commented Jun 14, 2022

What kind of change does this PR introduce?

Initial DB schema for MFA. Will add the indexes later in the implementation once I have a clearer idea of what to index

Note that I've changed the base branch to mfa and will be using j0_add_mfa as a draft branch

Main Changes since last review

  • We've introduced the concept of a factor_status to differentiate between disabled factors and unverified factors. Factors can only be disabled once they are verified.
  • Challenges also have a verification status. Challenges are marked as verified once there is a successful verification
  • remove factor_ prefix on the factor table and changed simple_name to friendly_name

@J0 J0 requested review from kangmingtay, hf and inian June 14, 2022 07:18
@@ -0,0 +1,47 @@
-- See: https://stackoverflow.com/questions/7624919/check-if-a-user-defined-type-already-exists-in-postgresql/48382296#48382296
DO $$ BEGIN
CREATE TYPE factor_type AS ENUM('phone', 'webauthn');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we just solve this by adding a namespace and prefix the factor type with mfa- ?

Copy link
Contributor Author

@J0 J0 Jun 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm do you mean like:

CREATE TYPE mfa.factor_type AS ENUM('mfa-phone', 'mfa-webauthn');

?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup, or even phone-factor , webauthn-factor whichever you prefer

Copy link
Contributor Author

@J0 J0 Jun 15, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm oh how would that help to guard against factor_type already existing though?

It's not that clear but was hoping to guard against the following scenario:

  1. Migrations are all applied, GoTrue is running
  2. An error occurs and the schema_migrations table is cleared in order to trigger migrations to apply again
  3. A restart occurs and GoTrue tries to reapply migrations, migrations prior to add_mfa_schema are ignored since the tables/changes already exist
  4. The add_mfa_migration is run again but factor_type already exists and thus an error would be thrown if recreation is attempted

Might be missing something but at step 4. seems like we would also run into a type already exists error when factor_type is created under an mfa schema as well

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm how would (2) occur, the schema_migrations table wouldn't be dropped by the migration tool unless the user does it explicitly right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep the main use case I had in mind was a support ticket with migration issues

@J0 J0 requested a review from kangmingtay June 29, 2022 13:59
CREATE TABLE IF NOT EXISTS auth.mfa_factors(
id VARCHAR(256) NOT NULL,
user_id uuid NOT NULL,
friendly_name VARCHAR(256) NULL,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

friendly_name is just an alias that can be specified by the developer right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm seems like there's a unique constraint on (user_id, friendly_name), so i guess friendly_name will be used to identify one of the mfa factors associated to a user?

Copy link
Contributor Author

@J0 J0 Jun 30, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup friendly name is just an alias specified by developer and each user should only be able to specify one factor with given alias (e.g. user123 shouldn't have two factors named "bob" or similar.

migrations/20220607041349_add_mfa_schema.up.sql Outdated Show resolved Hide resolved
migrations/20220607041349_add_mfa_schema.up.sql Outdated Show resolved Hide resolved
migrations/20220607041349_add_mfa_schema.up.sql Outdated Show resolved Hide resolved

-- auth.mfa_recovery_codes definition
CREATE TABLE IF NOT EXISTS auth.mfa_recovery_codes(
id serial PRIMARY KEY,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just wondering, why is this serial while the other tables are using varchar(256) for the id type?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, if you wanna go with serial, you should consider using bigint generated always as identity since this would accommodate up to 8bytes (similar to varchar(256) but autoincrementing)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup great question -- the other two are meant to be of the form prefix_<uuid> (e.g. challenge_1231524) since they are often used together in client lib/endpoint calls and it's purely to help the dev distinguish between the various uuids.

For recovery codes the id is not likely to be used elsewhere/exposed to user so there haven't been any measures. Open to changing it to varchar too though

valid BOOLEAN NOT NULL,
created_at timestamptz NOT NULL,
used_at timestamptz NOT NULL,
CONSTRAINT mfa_recovery_codes_user_id_recovery_code_pkey UNIQUE(user_id, recovery_code),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be UNIQUE(factor_id, recovery_code) instead? or are we allowing a user to use a recovery code to bypass any of the factors?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, good question -- recovery codes are per user instead of per factor. This seems to be the case for most other auth providers -- User can use any one of the eight recovery codes to log in.

This is also quite dangerous so we'll have to guard it well.

@J0 J0 merged commit 61e46a8 into mfa Jun 30, 2022
@J0 J0 deleted the j0_add_db_changes branch June 30, 2022 08:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants