Revamp the authentication setup (#7419)
* feat: Add email pass authentication provider package * feat: Revamp auth module and remove concept of scope * feat: Revamp the auth module to be more standardized in how providers are loaded * feat: Switch from scope to actor type for authentication * feat: Add support for per-actor auth methods * feat: Add emailpass auth provider by default * fix: Add back app_metadata in auth module
This commit is contained in:
@@ -0,0 +1,236 @@
|
||||
import { IAuthModuleService } from "@medusajs/types"
|
||||
import { Modules } from "@medusajs/modules-sdk"
|
||||
import { createAuthIdentities } from "../../__fixtures__/auth-identity"
|
||||
import { moduleIntegrationTestRunner, SuiteOptions } from "medusa-test-utils"
|
||||
|
||||
jest.setTimeout(30000)
|
||||
|
||||
moduleIntegrationTestRunner({
|
||||
moduleName: Modules.AUTH,
|
||||
testSuite: ({
|
||||
MikroOrmWrapper,
|
||||
service,
|
||||
}: SuiteOptions<IAuthModuleService>) => {
|
||||
describe("AuthModuleService - AuthIdentity", () => {
|
||||
beforeEach(async () => {
|
||||
await createAuthIdentities(MikroOrmWrapper.forkManager())
|
||||
})
|
||||
|
||||
describe("listAuthIdentities", () => {
|
||||
it("should list authIdentities", async () => {
|
||||
const authIdentities = await service.list()
|
||||
|
||||
expect(authIdentities).toEqual([
|
||||
expect.objectContaining({
|
||||
provider: "store",
|
||||
}),
|
||||
expect.objectContaining({
|
||||
provider: "manual",
|
||||
}),
|
||||
expect.objectContaining({
|
||||
provider: "manual",
|
||||
}),
|
||||
])
|
||||
})
|
||||
|
||||
it("should list authIdentities by id", async () => {
|
||||
const authIdentities = await service.list({
|
||||
id: ["test-id"],
|
||||
})
|
||||
|
||||
expect(authIdentities).toEqual([
|
||||
expect.objectContaining({
|
||||
id: "test-id",
|
||||
}),
|
||||
])
|
||||
})
|
||||
|
||||
it("should list authIdentities by provider", async () => {
|
||||
const authIdentities = await service.list({
|
||||
provider: "manual",
|
||||
})
|
||||
|
||||
expect(authIdentities).toEqual([
|
||||
expect.objectContaining({
|
||||
id: "test-id",
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: "test-id-1",
|
||||
}),
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe("listAndCountAuthIdentities", () => {
|
||||
it("should list and count authIdentities", async () => {
|
||||
const [authIdentities, count] = await service.listAndCount()
|
||||
|
||||
expect(count).toEqual(3)
|
||||
expect(authIdentities).toEqual([
|
||||
expect.objectContaining({
|
||||
provider: "store",
|
||||
}),
|
||||
expect.objectContaining({
|
||||
provider: "manual",
|
||||
}),
|
||||
expect.objectContaining({
|
||||
provider: "manual",
|
||||
}),
|
||||
])
|
||||
})
|
||||
|
||||
it("should listAndCount authIdentities by provider_id", async () => {
|
||||
const [authIdentities, count] = await service.listAndCount({
|
||||
provider: "manual",
|
||||
})
|
||||
|
||||
expect(count).toEqual(2)
|
||||
expect(authIdentities).toEqual([
|
||||
expect.objectContaining({
|
||||
id: "test-id",
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: "test-id-1",
|
||||
}),
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe("retrieveAuthIdentity", () => {
|
||||
const id = "test-id"
|
||||
|
||||
it("should return an authIdentity for the given id", async () => {
|
||||
const authIdentity = await service.retrieve(id)
|
||||
|
||||
expect(authIdentity).toEqual(
|
||||
expect.objectContaining({
|
||||
id,
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it("should throw an error when an authIdentity with the given id does not exist", async () => {
|
||||
let error
|
||||
|
||||
try {
|
||||
await service.retrieve("does-not-exist")
|
||||
} catch (e) {
|
||||
error = e
|
||||
}
|
||||
|
||||
expect(error.message).toEqual(
|
||||
"AuthIdentity with id: does-not-exist was not found"
|
||||
)
|
||||
})
|
||||
|
||||
it("should not return an authIdentity with password hash", async () => {
|
||||
const authIdentity = await service.retrieve("test-id-1")
|
||||
|
||||
expect(authIdentity).toEqual(
|
||||
expect.objectContaining({
|
||||
id: "test-id-1",
|
||||
})
|
||||
)
|
||||
expect(authIdentity["password_hash"]).toEqual(undefined)
|
||||
})
|
||||
|
||||
it("should throw an error when a authIdentityId is not provided", async () => {
|
||||
let error
|
||||
|
||||
try {
|
||||
await service.retrieve(undefined as unknown as string)
|
||||
} catch (e) {
|
||||
error = e
|
||||
}
|
||||
|
||||
expect(error.message).toEqual("authIdentity - id must be defined")
|
||||
})
|
||||
|
||||
it("should return authIdentity based on config select param", async () => {
|
||||
const authIdentity = await service.retrieve(id, {
|
||||
select: ["id"],
|
||||
})
|
||||
|
||||
expect(authIdentity).toEqual({
|
||||
id,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("deleteAuthIdentity", () => {
|
||||
const id = "test-id"
|
||||
|
||||
it("should delete the authIdentities given an id successfully", async () => {
|
||||
await service.delete([id])
|
||||
|
||||
const authIdentities = await service.list({
|
||||
id: [id],
|
||||
})
|
||||
|
||||
expect(authIdentities).toHaveLength(0)
|
||||
})
|
||||
})
|
||||
|
||||
describe("updateAuthIdentity", () => {
|
||||
const id = "test-id"
|
||||
|
||||
it("should throw an error when a id does not exist", async () => {
|
||||
let error
|
||||
|
||||
try {
|
||||
await service.update([
|
||||
{
|
||||
id: "does-not-exist",
|
||||
},
|
||||
])
|
||||
} catch (e) {
|
||||
error = e
|
||||
}
|
||||
|
||||
expect(error.message).toEqual(
|
||||
'AuthIdentity with id "does-not-exist" not found'
|
||||
)
|
||||
})
|
||||
|
||||
it("should update authIdentity", async () => {
|
||||
await service.update([
|
||||
{
|
||||
id,
|
||||
provider_metadata: { email: "test@email.com" },
|
||||
},
|
||||
])
|
||||
|
||||
const [authIdentity] = await service.list({ id: [id] })
|
||||
expect(authIdentity).toEqual(
|
||||
expect.objectContaining({
|
||||
provider_metadata: { email: "test@email.com" },
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("createAuthIdentity", () => {
|
||||
it("should create a authIdentity successfully", async () => {
|
||||
await service.create([
|
||||
{
|
||||
id: "test",
|
||||
provider: "manual",
|
||||
entity_id: "test",
|
||||
},
|
||||
])
|
||||
|
||||
const [authIdentity, count] = await service.listAndCount({
|
||||
id: ["test"],
|
||||
})
|
||||
|
||||
expect(count).toEqual(1)
|
||||
expect(authIdentity[0]).toEqual(
|
||||
expect.objectContaining({
|
||||
id: "test",
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,110 @@
|
||||
import { Modules } from "@medusajs/modules-sdk"
|
||||
import { IAuthModuleService } from "@medusajs/types"
|
||||
import { moduleIntegrationTestRunner, SuiteOptions } from "medusa-test-utils"
|
||||
import { resolve } from "path"
|
||||
|
||||
let moduleOptions = {
|
||||
providers: [
|
||||
{
|
||||
resolve: resolve(
|
||||
process.cwd() +
|
||||
"/integration-tests/__fixtures__/providers/default-provider"
|
||||
),
|
||||
options: {
|
||||
config: {
|
||||
plaintextpass: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
jest.setTimeout(30000)
|
||||
|
||||
moduleIntegrationTestRunner({
|
||||
moduleName: Modules.AUTH,
|
||||
moduleOptions,
|
||||
testSuite: ({ service }: SuiteOptions<IAuthModuleService>) =>
|
||||
describe("Auth Module Service", () => {
|
||||
beforeEach(async () => {
|
||||
await service.create({
|
||||
entity_id: "test@admin.com",
|
||||
provider: "plaintextpass",
|
||||
provider_metadata: {
|
||||
password: "plaintext",
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it("it fails if the provider does not exist", async () => {
|
||||
const err = await service
|
||||
.authenticate("facebook", {
|
||||
body: {
|
||||
email: "test@admin.com",
|
||||
password: "password",
|
||||
},
|
||||
})
|
||||
.catch((e) => e)
|
||||
|
||||
expect(err).toEqual({
|
||||
success: false,
|
||||
error: "Could not find a auth provider with id: facebook",
|
||||
})
|
||||
})
|
||||
|
||||
it("successfully calls the provider for authentication if correct password", async () => {
|
||||
const result = await service.authenticate("plaintextpass", {
|
||||
body: {
|
||||
email: "test@admin.com",
|
||||
password: "plaintext",
|
||||
},
|
||||
})
|
||||
|
||||
expect(result).toEqual(
|
||||
expect.objectContaining({
|
||||
success: true,
|
||||
authIdentity: expect.objectContaining({
|
||||
id: expect.any(String),
|
||||
entity_id: "test@admin.com",
|
||||
}),
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it("should fail if the password is incorrect", async () => {
|
||||
const result = await service
|
||||
.authenticate("plaintextpass", {
|
||||
body: {
|
||||
email: "test@admin.com",
|
||||
password: "incorrect",
|
||||
},
|
||||
})
|
||||
.catch((e) => e)
|
||||
|
||||
expect(result).toEqual(
|
||||
expect.objectContaining({
|
||||
success: false,
|
||||
error: "Invalid email or password",
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it("successfully create a new entity if nonexistent", async () => {
|
||||
const result = await service.authenticate("plaintextpass", {
|
||||
body: {
|
||||
email: "new@admin.com",
|
||||
password: "newpass",
|
||||
},
|
||||
})
|
||||
|
||||
const dbAuthIdentity = await service.retrieve(result.authIdentity.id)
|
||||
|
||||
expect(dbAuthIdentity).toEqual(
|
||||
expect.objectContaining({
|
||||
id: expect.any(String),
|
||||
entity_id: "new@admin.com",
|
||||
})
|
||||
)
|
||||
})
|
||||
}),
|
||||
})
|
||||
Reference in New Issue
Block a user