From f0655817364a1678cb38e4467b4e3db5804901a0 Mon Sep 17 00:00:00 2001 From: Philip Korsholm <88927411+pKorsholm@users.noreply.github.com> Date: Tue, 9 Jan 2024 10:02:02 +0100 Subject: [PATCH] Feat(authentication): Load auth providers (#6023) * initial providers loader implementation * registerAdd providers * remove comment * remove comment --- .../services/module/auth-provider.spec.ts | 30 ++++++------ .../services/module/provider-loaders.ts | 45 +++++++++++++++++ packages/authentication/jest.config.js | 1 + packages/authentication/src/loaders/index.ts | 1 + .../authentication/src/loaders/providers.ts | 49 +++++++++++++++++++ .../authentication/src/module-definition.ts | 3 +- .../authentication/src/providers/index.ts | 1 + .../src/providers/username-password.ts | 21 ++++++++ packages/authentication/tsconfig.json | 3 ++ packages/types/src/authentication/index.ts | 1 + packages/types/src/authentication/provider.ts | 8 +++ 11 files changed, 148 insertions(+), 15 deletions(-) create mode 100644 packages/authentication/integration-tests/__tests__/services/module/provider-loaders.ts create mode 100644 packages/authentication/src/loaders/providers.ts create mode 100644 packages/authentication/src/providers/index.ts create mode 100644 packages/authentication/src/providers/username-password.ts create mode 100644 packages/types/src/authentication/provider.ts diff --git a/packages/authentication/integration-tests/__tests__/services/module/auth-provider.spec.ts b/packages/authentication/integration-tests/__tests__/services/module/auth-provider.spec.ts index 90fe7aeebe..59b80e01f6 100644 --- a/packages/authentication/integration-tests/__tests__/services/module/auth-provider.spec.ts +++ b/packages/authentication/integration-tests/__tests__/services/module/auth-provider.spec.ts @@ -37,20 +37,22 @@ describe("AuthenticationModuleService - AuthProvider", () => { const authProviders = await service.listAuthProviders() const serialized = JSON.parse(JSON.stringify(authProviders)) - expect(serialized).toEqual([ - expect.objectContaining({ - provider: "manual", - }), - expect.objectContaining({ - provider: "disabled", - }), - expect.objectContaining({ - provider: "store", - }), - expect.objectContaining({ - provider: "admin", - }), - ]) + expect(serialized).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + provider: "manual", + }), + expect.objectContaining({ + provider: "disabled", + }), + expect.objectContaining({ + provider: "store", + }), + expect.objectContaining({ + provider: "admin", + }), + ]) + ) }) it("should list authProviders by id", async () => { diff --git a/packages/authentication/integration-tests/__tests__/services/module/provider-loaders.ts b/packages/authentication/integration-tests/__tests__/services/module/provider-loaders.ts new file mode 100644 index 0000000000..36e513f95f --- /dev/null +++ b/packages/authentication/integration-tests/__tests__/services/module/provider-loaders.ts @@ -0,0 +1,45 @@ +import { SqlEntityManager } from "@mikro-orm/postgresql" + +import { MikroOrmWrapper } from "../../../utils" +import { initialize } from "../../../../src" +import { DB_URL } from "@medusajs/pricing/integration-tests/utils" +import { MedusaModule } from "@medusajs/modules-sdk" +import { IAuthenticationModuleService } from "@medusajs/types" + +jest.setTimeout(30000) + +describe("AuthenticationModuleService - AuthProvider", () => { + let service: IAuthenticationModuleService + let testManager: SqlEntityManager + + beforeEach(async () => { + await MikroOrmWrapper.setupDatabase() + testManager = MikroOrmWrapper.forkManager() + + service = await initialize({ + database: { + clientUrl: DB_URL, + schema: process.env.MEDUSA_PRICING_DB_SCHEMA, + }, + }) + }) + + afterEach(async () => { + await MikroOrmWrapper.clearDatabase() + MedusaModule.clearInstances() + }) + + describe("listAuthProviders", () => { + it("should list default AuthProviders", async () => { + const authProviders = await service.listAuthProviders() + const serialized = JSON.parse(JSON.stringify(authProviders)) + + expect(serialized).toEqual([ + expect.objectContaining({ + provider: "usernamePassword", + name: "Username/Password Authentication", + }), + ]) + }) + }) +}) diff --git a/packages/authentication/jest.config.js b/packages/authentication/jest.config.js index 456054fe8a..18fbb3dd05 100644 --- a/packages/authentication/jest.config.js +++ b/packages/authentication/jest.config.js @@ -4,6 +4,7 @@ module.exports = { "^@services": "/src/services", "^@repositories": "/src/repositories", "^@types": "/src/types", + "^@providers": "/src/providers", }, transform: { "^.+\\.[jt]s?$": [ diff --git a/packages/authentication/src/loaders/index.ts b/packages/authentication/src/loaders/index.ts index 3614963d8c..11369b9206 100644 --- a/packages/authentication/src/loaders/index.ts +++ b/packages/authentication/src/loaders/index.ts @@ -1,2 +1,3 @@ export * from "./connection" export * from "./container" +export * from "./providers" diff --git a/packages/authentication/src/loaders/providers.ts b/packages/authentication/src/loaders/providers.ts new file mode 100644 index 0000000000..d21a31db0b --- /dev/null +++ b/packages/authentication/src/loaders/providers.ts @@ -0,0 +1,49 @@ +import { LoaderOptions, ModulesSdkTypes } from "@medusajs/types" +import { asClass } from "awilix" +import * as defaultProviders from "@providers" +import { AuthProviderService } from "@services" +import { ServiceTypes } from "@types" + +export default async ({ + container, + options, +}: LoaderOptions< + | ModulesSdkTypes.ModuleServiceInitializeOptions + | ModulesSdkTypes.ModuleServiceInitializeCustomDataLayerOptions +>): Promise => { + // if(options.providers?.length) { + // TODO: implement plugin provider registration + // } + + const providersToLoad = Object.values(defaultProviders) + + const authProviderService: AuthProviderService = + container.cradle["authProviderService"] + + const providers = await authProviderService.list({ + provider: providersToLoad.map((p) => p.PROVIDER), + }) + + const loadedProviders = new Map(providers.map((p) => [p.provider, p])) + + const providersToCreate: ServiceTypes.CreateAuthProviderDTO[] = [] + + for (const provider of providersToLoad) { + container.registerAdd("providers", asClass(provider).singleton()) + + container.register({ + [`provider_${provider.PROVIDER}`]: asClass(provider).singleton(), + }) + + if (loadedProviders.has(provider.PROVIDER)) { + continue + } + + providersToCreate.push({ + provider: provider.PROVIDER, + name: provider.DISPLAY_NAME, + }) + } + + await authProviderService.create(providersToCreate) +} diff --git a/packages/authentication/src/module-definition.ts b/packages/authentication/src/module-definition.ts index 9b7854ba0a..89b9e240a6 100644 --- a/packages/authentication/src/module-definition.ts +++ b/packages/authentication/src/module-definition.ts @@ -2,9 +2,10 @@ import { ModuleExports } from "@medusajs/types" import { AuthenticationModuleService } from "@services" import loadConnection from "./loaders/connection" import loadContainer from "./loaders/container" +import loadProviders from "./loaders/providers" const service = AuthenticationModuleService -const loaders = [loadContainer, loadConnection] as any +const loaders = [loadContainer, loadConnection, loadProviders] as any export const moduleDefinition: ModuleExports = { service, diff --git a/packages/authentication/src/providers/index.ts b/packages/authentication/src/providers/index.ts new file mode 100644 index 0000000000..77a2d444f7 --- /dev/null +++ b/packages/authentication/src/providers/index.ts @@ -0,0 +1 @@ +export { default as UsernamePasswordProvider } from "./username-password" diff --git a/packages/authentication/src/providers/username-password.ts b/packages/authentication/src/providers/username-password.ts new file mode 100644 index 0000000000..1b3ca03a17 --- /dev/null +++ b/packages/authentication/src/providers/username-password.ts @@ -0,0 +1,21 @@ +import { AuthUserService } from "@services" +import { AbstractAuthenticationModuleProvider } from "@medusajs/types" + +class UsernamePasswordProvider extends AbstractAuthenticationModuleProvider { + public static PROVIDER = "usernamePassword" + public static DISPLAY_NAME = "Username/Password Authentication" + + protected readonly authUserSerivce_: AuthUserService + + constructor({ authUserService: AuthUserService }) { + super() + + this.authUserSerivce_ = AuthUserService + } + + async authenticate(userData: Record) { + return {} + } +} + +export default UsernamePasswordProvider diff --git a/packages/authentication/tsconfig.json b/packages/authentication/tsconfig.json index 7fd528e0e3..ee30d15d78 100644 --- a/packages/authentication/tsconfig.json +++ b/packages/authentication/tsconfig.json @@ -34,6 +34,9 @@ ], "@types": [ "./src/types" + ], + "@providers": [ + "./src/providers" ] } }, diff --git a/packages/types/src/authentication/index.ts b/packages/types/src/authentication/index.ts index 1aa665fd54..711715ff6f 100644 --- a/packages/types/src/authentication/index.ts +++ b/packages/types/src/authentication/index.ts @@ -1,2 +1,3 @@ export * from "./service" export * from "./common" +export * from "./provider" diff --git a/packages/types/src/authentication/provider.ts b/packages/types/src/authentication/provider.ts new file mode 100644 index 0000000000..db950c2077 --- /dev/null +++ b/packages/types/src/authentication/provider.ts @@ -0,0 +1,8 @@ +export abstract class AbstractAuthenticationModuleProvider { + public static PROVIDER: string + public static DISPLAY_NAME: string + + abstract authenticate( + data: Record + ): Promise> +}