Revamp auth module to support multiple providers linked to a single auth identity (#7521)

This commit is contained in:
Stevche Radevski
2024-06-05 07:47:16 +00:00
committed by GitHub
parent 20cd6a7b51
commit fafc92b875
23 changed files with 640 additions and 216 deletions
@@ -22,7 +22,7 @@ describe("Email password auth provider", () => {
it("return error if email is not passed", async () => {
const resp = await emailpassService.authenticate(
{ body: { password: "otherpass" } },
{}
{} as any
)
expect(resp).toEqual({
@@ -34,7 +34,7 @@ describe("Email password auth provider", () => {
it("return error if password is not passed", async () => {
const resp = await emailpassService.authenticate(
{ body: { email: "test@admin.com" } },
{}
{} as any
)
expect(resp).toEqual({
@@ -50,18 +50,22 @@ describe("Email password auth provider", () => {
const authServiceSpies = {
retrieve: jest.fn().mockImplementation(() => {
return {
entity_id: "test@admin.com",
provider: "emailpass",
provider_metadata: {
password: passwordHash.toString("base64"),
},
provider_identities: [
{
entity_id: "test@admin.com",
provider: "emailpass",
provider_metadata: {
password: passwordHash.toString("base64"),
},
},
],
}
}),
}
const resp = await emailpassService.authenticate(
{ body: { email: "test@admin.com", password: "otherpass" } },
authServiceSpies
authServiceSpies as any
)
expect(authServiceSpies.retrieve).toHaveBeenCalled()
@@ -78,18 +82,22 @@ describe("Email password auth provider", () => {
const authServiceSpies = {
retrieve: jest.fn().mockImplementation(() => {
return {
entity_id: "test@admin.com",
provider: "emailpass",
provider_metadata: {
password: passwordHash.toString("base64"),
},
provider_identities: [
{
entity_id: "test@admin.com",
provider: "emailpass",
provider_metadata: {
password: passwordHash.toString("base64"),
},
},
],
}
}),
}
const resp = await emailpassService.authenticate(
{ body: { email: "test@admin.com", password: "somepass" } },
authServiceSpies
authServiceSpies as any
)
expect(authServiceSpies.retrieve).toHaveBeenCalled()
@@ -97,8 +105,12 @@ describe("Email password auth provider", () => {
expect.objectContaining({
success: true,
authIdentity: expect.objectContaining({
entity_id: "test@admin.com",
provider_metadata: {},
provider_identities: [
expect.objectContaining({
entity_id: "test@admin.com",
provider_metadata: {},
}),
],
}),
})
)
@@ -111,11 +123,15 @@ describe("Email password auth provider", () => {
}),
create: jest.fn().mockImplementation(() => {
return {
entity_id: "test@admin.com",
provider: "emailpass",
provider_metadata: {
password: "somehash",
},
provider_identities: [
{
entity_id: "test@admin.com",
provider: "emailpass",
provider_metadata: {
password: "somehash",
},
},
],
}
}),
}
@@ -128,7 +144,7 @@ describe("Email password auth provider", () => {
expect(authServiceSpies.retrieve).toHaveBeenCalled()
expect(authServiceSpies.create).toHaveBeenCalled()
expect(resp.authIdentity).toEqual(
expect(resp.authIdentity?.provider_identities?.[0]).toEqual(
expect.objectContaining({
entity_id: "test@admin.com",
provider_metadata: {},
@@ -4,6 +4,7 @@ import {
AuthenticationResponse,
AuthenticationInput,
AuthIdentityProviderService,
AuthIdentityDTO,
} from "@medusajs/types"
import {
AbstractAuthModuleProvider,
@@ -53,12 +54,11 @@ export class EmailPassAuthService extends AbstractAuthModuleProvider {
error: "Email should be a string",
}
}
let authIdentity
let authIdentity: AuthIdentityDTO | undefined
try {
authIdentity = await authIdentityService.retrieve({
entity_id: email,
provider: this.provider,
})
} catch (error) {
if (error.type === MedusaError.Types.NOT_FOUND) {
@@ -67,14 +67,16 @@ export class EmailPassAuthService extends AbstractAuthModuleProvider {
const createdAuthIdentity = await authIdentityService.create({
entity_id: email,
provider: this.provider,
provider_metadata: {
password: passwordHash.toString("base64"),
},
})
const copy = JSON.parse(JSON.stringify(createdAuthIdentity))
delete copy.provider_metadata?.password
const providerIdentity = copy.provider_identities?.find(
(pi) => pi.provider === this.provider
)!
delete providerIdentity.provider_metadata?.password
return {
success: true,
@@ -85,7 +87,10 @@ export class EmailPassAuthService extends AbstractAuthModuleProvider {
return { success: false, error: error.message }
}
const passwordHash = authIdentity.provider_metadata?.password
const providerIdentity = authIdentity.provider_identities?.find(
(pi) => pi.provider === this.provider
)!
const passwordHash = providerIdentity.provider_metadata?.password
if (isString(passwordHash)) {
const buf = Buffer.from(passwordHash as string, "base64")
@@ -93,7 +98,10 @@ export class EmailPassAuthService extends AbstractAuthModuleProvider {
if (success) {
const copy = JSON.parse(JSON.stringify(authIdentity))
delete copy.provider_metadata!.password
const providerIdentity = copy.provider_identities?.find(
(pi) => pi.provider === this.provider
)!
delete providerIdentity.provider_metadata?.password
return {
success,
@@ -158,8 +158,12 @@ describe("Google auth provider", () => {
}),
create: jest.fn().mockImplementation(() => {
return {
entity_id: "test@admin.com",
provider: "google",
provider_identities: [
{
entity_id: "test@admin.com",
provider: "google",
},
],
}
}),
}
@@ -177,8 +181,12 @@ describe("Google auth provider", () => {
success: true,
successRedirectUrl: baseUrl,
authIdentity: {
entity_id: "test@admin.com",
provider: "google",
provider_identities: [
{
entity_id: "test@admin.com",
provider: "google",
},
],
},
})
})
@@ -187,8 +195,12 @@ describe("Google auth provider", () => {
const authServiceSpies = {
retrieve: jest.fn().mockImplementation(() => {
return {
entity_id: "test@admin.com",
provider: "google",
provider_identities: [
{
entity_id: "test@admin.com",
provider: "google",
},
],
}
}),
create: jest.fn().mockImplementation(() => {
@@ -209,8 +221,12 @@ describe("Google auth provider", () => {
success: true,
successRedirectUrl: baseUrl,
authIdentity: {
entity_id: "test@admin.com",
provider: "google",
provider_identities: [
{
entity_id: "test@admin.com",
provider: "google",
},
],
},
})
})
@@ -130,13 +130,11 @@ export class GoogleAuthService extends AbstractAuthModuleProvider {
try {
authIdentity = await authIdentityService.retrieve({
entity_id,
provider: this.provider,
})
} catch (error) {
if (error.type === MedusaError.Types.NOT_FOUND) {
const createdAuthIdentity = await authIdentityService.create({
entity_id,
provider: this.provider,
user_metadata: userMetadata,
})
authIdentity = createdAuthIdentity