Implement Two-Factor Authentication (2FA) (#13141)
Implementation is very simple Established authentication dynamic is intercepted at getAuthTokensFromLoginToken. If 2FA is required, a pattern similar to EmailVerification is executed. That is, getAuthTokensFromLoginToken mutation fails with either of the following errors: 1. TWO_FACTOR_AUTHENTICATION_VERIFICATION_REQUIRED 2. TWO_FACTOR_AUTHENTICATION_PROVISION_REQUIRED UI knows how to respond accordingly. 2FA provisioning occurs at the 2FA resolver. 2FA verification, currently only OTP, is handled by auth.resolver's getAuthTokensFromOTP --------- Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions <github-actions@twenty.com> Co-authored-by: Jean-Baptiste Ronssin <65334819+jbronssin@users.noreply.github.com> Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com> Co-authored-by: Félix Malfait <felix.malfait@gmail.com> Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
+23
@@ -0,0 +1,23 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class DropOldTwoFactorMethodTable1752170600000
|
||||
implements MigrationInterface
|
||||
{
|
||||
name = 'DropOldTwoFactorMethodTable1752170600000';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."twoFactorMethod" DROP CONSTRAINT "FK_c1044145be65a4ee65c07e0a658"`,
|
||||
);
|
||||
await queryRunner.query(`DROP TABLE "core"."twoFactorMethod"`);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`CREATE TABLE "core"."twoFactorMethod" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "userWorkspaceId" uuid NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, CONSTRAINT "PK_752f0250dd6824289ceddd8b054" PRIMARY KEY ("id"))`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."twoFactorMethod" ADD CONSTRAINT "FK_c1044145be65a4ee65c07e0a658" FOREIGN KEY ("userWorkspaceId") REFERENCES "core"."userWorkspace"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class TwoFactorAuthentication1752839063082
|
||||
implements MigrationInterface
|
||||
{
|
||||
name = 'TwoFactorAuthentication1752839063082';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`CREATE TYPE "core"."twoFactorAuthenticationMethod_strategy_enum" AS ENUM('TOTP')`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE TYPE "core"."twoFactorAuthenticationMethod_status_enum" AS ENUM('PENDING', 'VERIFIED')`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE TABLE "core"."twoFactorAuthenticationMethod" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "userWorkspaceId" uuid NOT NULL, "secret" text NOT NULL, "status" "core"."twoFactorAuthenticationMethod_status_enum" NOT NULL, "strategy" "core"."twoFactorAuthenticationMethod_strategy_enum" NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, CONSTRAINT "PK_c455f6a499e7110fc95e4bea540" PRIMARY KEY ("id"))`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE UNIQUE INDEX "IDX_2909f5139c479e4632df03fd5e" ON "core"."twoFactorAuthenticationMethod" ("userWorkspaceId", "strategy") `,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."workspace" ADD "isTwoFactorAuthenticationEnforced" boolean NOT NULL DEFAULT false`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."twoFactorAuthenticationMethod" ADD CONSTRAINT "FK_b0f44ffd7c794beb48cb1e1b1a9" FOREIGN KEY ("userWorkspaceId") REFERENCES "core"."userWorkspace"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."twoFactorAuthenticationMethod" DROP CONSTRAINT "FK_b0f44ffd7c794beb48cb1e1b1a9"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."workspace" DROP COLUMN "isTwoFactorAuthenticationEnforced"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "core"."IDX_2909f5139c479e4632df03fd5e"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`DROP TABLE "core"."twoFactorAuthenticationMethod"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`DROP TYPE "core"."twoFactorAuthenticationMethod_status_enum"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`DROP TYPE "core"."twoFactorAuthenticationMethod_strategy_enum"`,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user