From a043f4353e5de9159d3afa6c8c4c13befb9c9d4c Mon Sep 17 00:00:00 2001 From: Michael Dimitras Date: Tue, 1 Oct 2024 14:16:41 -0700 Subject: [PATCH] Throw error message if user has no email from firebase (#121) If there are multiple users with the same email in Identity Platform for a particular tenant, an authentication attempt to firebase will return a user with an empty email. On the frontend we display an error message when that happens: https://github.com/p0-security/app/blob/5237e1a54597dc63258e56566353ad09ecd3e187/frontend/src/components/Login/hook.ts#L301-L306 But on the CLI we had no such check. This PR adds the same check as on the frontend. Now when a user logs in, if they have multiple identities in Identity Platform they will see the message `Can not sign in: this user has previously signed in with a different identity provider.\nPlease contact support@p0.dev to enable this user.` https://github.com/user-attachments/assets/7d5f94f5-199f-4ec1-96d2-ef73d1802787 --- src/commands/__tests__/login.test.ts | 18 ++++++++++++++++++ src/drivers/auth.ts | 3 +++ 2 files changed, 21 insertions(+) diff --git a/src/commands/__tests__/login.test.ts b/src/commands/__tests__/login.test.ts index 5e58c5b..481a689 100644 --- a/src/commands/__tests__/login.test.ts +++ b/src/commands/__tests__/login.test.ts @@ -23,6 +23,7 @@ jest.mock("../../drivers/auth", () => ({ jest.mock("../../drivers/stdio"); jest.mock("../../plugins/login"); +const mockSignInWithCredential = signInWithCredential as jest.Mock; const mockReadFile = readFile as jest.Mock; const mockWriteFile = writeFile as jest.Mock; @@ -51,6 +52,14 @@ describe("login", () => { mockWriteFile.mockImplementation(async (_path, data) => { credentialData = data; }); + mockSignInWithCredential.mockImplementation( + async (_auth, _firebaseCredential) => + Promise.resolve({ + user: { + email: "user@p0.dev", + }, + }) + ); beforeEach(() => { credentialData = ""; jest.clearAllMocks(); @@ -72,5 +81,14 @@ describe("login", () => { await login({ org: "test-org" }); expect((signInWithCredential as jest.Mock).mock.calls).toMatchSnapshot(); }); + it("returns an error message if firebase cannot determine the user's email", async () => { + mockSignInWithCredential.mockResolvedValueOnce({ + user: {}, + }); + await expect(login({ org: "test-org" })).rejects.toMatchInlineSnapshot(` +"Can not sign in: this user has previously signed in with a different identity provider. +Please contact support@p0.dev to enable this user." +`); + }); }); }); diff --git a/src/drivers/auth.ts b/src/drivers/auth.ts index 1cdb049..2d30bab 100644 --- a/src/drivers/auth.ts +++ b/src/drivers/auth.ts @@ -108,6 +108,9 @@ export const authenticate = async (options?: { }); auth.tenantId = identity.org.tenantId; const userCredential = await signInWithCredential(auth, firebaseCredential); + if (!userCredential?.user?.email) { + throw "Can not sign in: this user has previously signed in with a different identity provider.\nPlease contact support@p0.dev to enable this user."; + } return { userCredential, identity }; };