From 6e342209d1bb10ee041ed08268e7084810fb0a60 Mon Sep 17 00:00:00 2001 From: adrien2p Date: Tue, 13 Jun 2023 09:41:57 +0200 Subject: [PATCH] feat: add support for strict options --- .../src/auth-strategies/auth0/admin.ts | 4 +- .../src/auth-strategies/auth0/index.ts | 10 +- .../src/auth-strategies/auth0/store.ts | 5 +- .../src/auth-strategies/azure-oidc/admin.ts | 5 +- .../src/auth-strategies/azure-oidc/index.ts | 10 +- .../src/auth-strategies/azure-oidc/store.ts | 5 +- .../src/auth-strategies/facebook/admin.ts | 10 +- .../src/auth-strategies/facebook/index.ts | 10 +- .../src/auth-strategies/facebook/store.ts | 10 +- .../src/auth-strategies/firebase/admin.ts | 9 +- .../src/auth-strategies/firebase/index.ts | 10 +- .../src/auth-strategies/firebase/store.ts | 9 +- .../__tests__/admin/verify-callback.spec.ts | 160 +++++++++++++----- .../src/auth-strategies/google/admin.ts | 9 +- .../src/auth-strategies/google/index.ts | 10 +- .../src/auth-strategies/google/store.ts | 10 +- .../src/auth-strategies/linkedin/admin.ts | 9 +- .../src/auth-strategies/linkedin/index.ts | 10 +- .../src/auth-strategies/linkedin/store.ts | 10 +- .../src/core/validate-callback.ts | 25 ++- .../medusa-plugin-auth/src/types/index.ts | 24 ++- 21 files changed, 278 insertions(+), 86 deletions(-) diff --git a/packages/medusa-plugin-auth/src/auth-strategies/auth0/admin.ts b/packages/medusa-plugin-auth/src/auth-strategies/auth0/admin.ts index ef8167b..d92e8c2 100644 --- a/packages/medusa-plugin-auth/src/auth-strategies/auth0/admin.ts +++ b/packages/medusa-plugin-auth/src/auth-strategies/auth0/admin.ts @@ -10,7 +10,8 @@ export class Auth0AdminStrategy extends PassportStrategy(Auth0Strategy, AUTH0_AD constructor( protected readonly container: MedusaContainer, protected readonly configModule: ConfigModule, - protected readonly strategyOptions: Auth0Options + protected readonly strategyOptions: Auth0Options, + protected readonly strictOptions: { admin_strict: boolean; strict: boolean } ) { super({ domain: strategyOptions.auth0Domain, @@ -47,6 +48,7 @@ export class Auth0AdminStrategy extends PassportStrategy(Auth0Strategy, AUTH0_AD const validateRes = await validateAdminCallback(profile, { container: this.container, strategyErrorIdentifier: 'auth0', + strict: this.strictOptions.admin_strict ?? this.strictOptions.strict, }); return { ...validateRes, diff --git a/packages/medusa-plugin-auth/src/auth-strategies/auth0/index.ts b/packages/medusa-plugin-auth/src/auth-strategies/auth0/index.ts index c0a1758..dc5c7ff 100644 --- a/packages/medusa-plugin-auth/src/auth-strategies/auth0/index.ts +++ b/packages/medusa-plugin-auth/src/auth-strategies/auth0/index.ts @@ -11,11 +11,17 @@ export * from './types'; export default { load: (container: MedusaContainer, configModule: ConfigModule, options: AuthOptions): void => { if (options.auth0?.admin) { - new Auth0AdminStrategy(container, configModule, options.auth0); + new Auth0AdminStrategy(container, configModule, options.auth0, { + admin_strict: options.admin_strict, + strict: options.strict, + }); } if (options.auth0?.store) { - new Auth0StoreStrategy(container, configModule, options.auth0); + new Auth0StoreStrategy(container, configModule, options.auth0, { + store_strict: options.store_strict, + strict: options.strict, + }); } }, getRouter: (configModule: ConfigModule, options: AuthOptions): Router[] => { diff --git a/packages/medusa-plugin-auth/src/auth-strategies/auth0/store.ts b/packages/medusa-plugin-auth/src/auth-strategies/auth0/store.ts index cd3e450..2f2187b 100644 --- a/packages/medusa-plugin-auth/src/auth-strategies/auth0/store.ts +++ b/packages/medusa-plugin-auth/src/auth-strategies/auth0/store.ts @@ -10,7 +10,8 @@ export class Auth0StoreStrategy extends PassportStrategy(Auth0Strategy, AUTH0_ST constructor( protected readonly container: MedusaContainer, protected readonly configModule: ConfigModule, - protected readonly strategyOptions: Auth0Options + protected readonly strategyOptions: Auth0Options, + protected readonly strictOptions: { store_strict: boolean; strict: boolean } ) { super({ domain: strategyOptions.auth0Domain, @@ -44,9 +45,11 @@ export class Auth0StoreStrategy extends PassportStrategy(Auth0Strategy, AUTH0_ST accessToken, }; } + const validateRes = await validateStoreCallback(profile, { container: this.container, strategyErrorIdentifier: 'auth0', + strict: this.strictOptions.store_strict ?? this.strictOptions.strict, }); return { ...validateRes, diff --git a/packages/medusa-plugin-auth/src/auth-strategies/azure-oidc/admin.ts b/packages/medusa-plugin-auth/src/auth-strategies/azure-oidc/admin.ts index fea4944..dcc34b1 100644 --- a/packages/medusa-plugin-auth/src/auth-strategies/azure-oidc/admin.ts +++ b/packages/medusa-plugin-auth/src/auth-strategies/azure-oidc/admin.ts @@ -10,7 +10,8 @@ export class AzureAdminStrategy extends PassportStrategy(AzureStrategy, AZURE_AD constructor( protected readonly container: MedusaContainer, protected readonly configModule: ConfigModule, - protected readonly strategyOptions: AzureAuthOptions + protected readonly strategyOptions: AzureAuthOptions, + protected readonly strictOptions: { admin_strict: boolean; strict: boolean } ) { super({ identityMetadata: strategyOptions.admin.identityMetadata, @@ -36,9 +37,11 @@ export class AzureAdminStrategy extends PassportStrategy(AzureStrategy, AZURE_AD emails: [{ value: profile?.upn }], name: { givenName: profile?.name?.givenName, familyName: profile?.name?.familyName }, }; + return await validateAdminCallback(authprofile, { container: this.container, strategyErrorIdentifier: 'azure_oidc', + strict: this.strictOptions.admin_strict ?? this.strictOptions.strict, }); } } diff --git a/packages/medusa-plugin-auth/src/auth-strategies/azure-oidc/index.ts b/packages/medusa-plugin-auth/src/auth-strategies/azure-oidc/index.ts index 526ca38..23dc570 100644 --- a/packages/medusa-plugin-auth/src/auth-strategies/azure-oidc/index.ts +++ b/packages/medusa-plugin-auth/src/auth-strategies/azure-oidc/index.ts @@ -11,11 +11,17 @@ export * from './store'; export default { load: (container: MedusaContainer, configModule: ConfigModule, options: AuthOptions): void => { if (options.azure_oidc?.admin) { - new AzureAdminStrategy(container, configModule, options.azure_oidc); + new AzureAdminStrategy(container, configModule, options.azure_oidc,{ + admin_strict: options.admin_strict, + strict: options.strict, + }); } if (options.azure_oidc?.store) { - new AzureStoreStrategy(container, configModule, options.azure_oidc); + new AzureStoreStrategy(container, configModule, options.azure_oidc, { + store_strict: options.store_strict, + strict: options.strict, + }); } }, getRouter: (configModule: ConfigModule, options: AuthOptions): Router[] => { diff --git a/packages/medusa-plugin-auth/src/auth-strategies/azure-oidc/store.ts b/packages/medusa-plugin-auth/src/auth-strategies/azure-oidc/store.ts index d4e46c1..12418ed 100644 --- a/packages/medusa-plugin-auth/src/auth-strategies/azure-oidc/store.ts +++ b/packages/medusa-plugin-auth/src/auth-strategies/azure-oidc/store.ts @@ -10,7 +10,8 @@ export class AzureStoreStrategy extends PassportStrategy(AzureStrategy, AZURE_ST constructor( protected readonly container: MedusaContainer, protected readonly configModule: ConfigModule, - protected readonly strategyOptions: AzureAuthOptions + protected readonly strategyOptions: AzureAuthOptions, + protected readonly strictOptions: { store_strict: boolean; strict: boolean } ) { super({ identityMetadata: strategyOptions.store.identityMetadata, @@ -36,9 +37,11 @@ export class AzureStoreStrategy extends PassportStrategy(AzureStrategy, AZURE_ST emails: [{ value: profile?.upn }], name: { givenName: profile?.name?.givenName, familyName: profile?.name?.familyName }, }; + return await validateStoreCallback(authprofile, { container: this.container, strategyErrorIdentifier: 'azure_oidc', + strict: this.strictOptions.store_strict ?? this.strictOptions.strict, }); } } diff --git a/packages/medusa-plugin-auth/src/auth-strategies/facebook/admin.ts b/packages/medusa-plugin-auth/src/auth-strategies/facebook/admin.ts index 68b9210..7fca340 100644 --- a/packages/medusa-plugin-auth/src/auth-strategies/facebook/admin.ts +++ b/packages/medusa-plugin-auth/src/auth-strategies/facebook/admin.ts @@ -10,7 +10,8 @@ export class FacebookAdminStrategy extends PassportStrategy(FacebookStrategy, FA constructor( protected readonly container: MedusaContainer, protected readonly configModule: ConfigModule, - protected readonly strategyOptions: FacebookAuthOptions + protected readonly strategyOptions: FacebookAuthOptions, + protected readonly strictOptions: { admin_strict: boolean; strict: boolean } ) { super({ clientID: strategyOptions.clientID, @@ -36,7 +37,12 @@ export class FacebookAdminStrategy extends PassportStrategy(FacebookStrategy, FA profile ); } - return await validateAdminCallback(profile, { container: this.container, strategyErrorIdentifier: 'facebook' }); + + return await validateAdminCallback(profile, { + container: this.container, + strategyErrorIdentifier: 'facebook', + strict: this.strictOptions.admin_strict ?? this.strictOptions.strict, + }); } } diff --git a/packages/medusa-plugin-auth/src/auth-strategies/facebook/index.ts b/packages/medusa-plugin-auth/src/auth-strategies/facebook/index.ts index 83092f0..c9588b4 100644 --- a/packages/medusa-plugin-auth/src/auth-strategies/facebook/index.ts +++ b/packages/medusa-plugin-auth/src/auth-strategies/facebook/index.ts @@ -11,11 +11,17 @@ export * from './types'; export default { load: (container: MedusaContainer, configModule: ConfigModule, options: AuthOptions): void => { if (options.facebook?.admin) { - new FacebookAdminStrategy(container, configModule, options.facebook); + new FacebookAdminStrategy(container, configModule, options.facebook, { + admin_strict: options.admin_strict, + strict: options.strict, + }); } if (options.facebook?.store) { - new FacebookStoreStrategy(container, configModule, options.facebook); + new FacebookStoreStrategy(container, configModule, options.facebook, { + store_strict: options.store_strict, + strict: options.strict, + }); } }, getRouter: (configModule: ConfigModule, options: AuthOptions): Router[] => { diff --git a/packages/medusa-plugin-auth/src/auth-strategies/facebook/store.ts b/packages/medusa-plugin-auth/src/auth-strategies/facebook/store.ts index c20134d..537c3c1 100644 --- a/packages/medusa-plugin-auth/src/auth-strategies/facebook/store.ts +++ b/packages/medusa-plugin-auth/src/auth-strategies/facebook/store.ts @@ -10,7 +10,8 @@ export class FacebookStoreStrategy extends PassportStrategy(FacebookStrategy, FA constructor( protected readonly container: MedusaContainer, protected readonly configModule: ConfigModule, - protected readonly strategyOptions: FacebookAuthOptions + protected readonly strategyOptions: FacebookAuthOptions, + protected readonly strictOptions: { store_strict: boolean; strict: boolean } ) { super({ clientID: strategyOptions.clientID, @@ -36,7 +37,12 @@ export class FacebookStoreStrategy extends PassportStrategy(FacebookStrategy, FA profile ); } - return await validateStoreCallback(profile, { container: this.container, strategyErrorIdentifier: 'facebook' }); + + return await validateStoreCallback(profile, { + container: this.container, + strategyErrorIdentifier: 'facebook', + strict: this.strictOptions.store_strict ?? this.strictOptions.strict, + }); } } diff --git a/packages/medusa-plugin-auth/src/auth-strategies/firebase/admin.ts b/packages/medusa-plugin-auth/src/auth-strategies/firebase/admin.ts index 76b2c1c..f80c6d0 100644 --- a/packages/medusa-plugin-auth/src/auth-strategies/firebase/admin.ts +++ b/packages/medusa-plugin-auth/src/auth-strategies/firebase/admin.ts @@ -11,7 +11,8 @@ export class FirebaseAdminStrategy extends PassportStrategy(FirebaseStrategy, FI constructor( protected readonly container: MedusaContainer, protected readonly configModule: ConfigModule, - protected readonly strategyOptions: FirebaseAuthOptions + protected readonly strategyOptions: FirebaseAuthOptions, + protected readonly strictOptions: { admin_strict: boolean; strict: boolean } ) { super({ jwtFromRequest: strategyOptions.store.jwtFromRequest ?? ExtractJwt.fromAuthHeaderAsBearerToken(), @@ -26,7 +27,11 @@ export class FirebaseAdminStrategy extends PassportStrategy(FirebaseStrategy, FI } const profile: Profile = { emails: [{ value: decodedToken.email }] }; - return await validateAdminCallback(profile, { container: this.container, strategyErrorIdentifier: 'firebase' }); + return await validateAdminCallback(profile, { + container: this.container, + strategyErrorIdentifier: 'firebase', + strict: this.strictOptions.admin_strict ?? this.strictOptions.strict, + }); } } diff --git a/packages/medusa-plugin-auth/src/auth-strategies/firebase/index.ts b/packages/medusa-plugin-auth/src/auth-strategies/firebase/index.ts index f5aace3..fa1cdbc 100644 --- a/packages/medusa-plugin-auth/src/auth-strategies/firebase/index.ts +++ b/packages/medusa-plugin-auth/src/auth-strategies/firebase/index.ts @@ -32,11 +32,17 @@ export default { } if (options.firebase?.admin) { - new FirebaseAdminStrategy(container, configModule, options.firebase); + new FirebaseAdminStrategy(container, configModule, options.firebase, { + admin_strict: options.admin_strict, + strict: options.strict, + }); } if (options.firebase?.store) { - new FirebaseStoreStrategy(container, configModule, options.firebase); + new FirebaseStoreStrategy(container, configModule, options.firebase, { + store_strict: options.store_strict, + strict: options.strict, + }); } }, getRouter: (configModule: ConfigModule, options: AuthOptions): Router[] => { diff --git a/packages/medusa-plugin-auth/src/auth-strategies/firebase/store.ts b/packages/medusa-plugin-auth/src/auth-strategies/firebase/store.ts index d972757..622b3ab 100644 --- a/packages/medusa-plugin-auth/src/auth-strategies/firebase/store.ts +++ b/packages/medusa-plugin-auth/src/auth-strategies/firebase/store.ts @@ -11,7 +11,8 @@ export class FirebaseStoreStrategy extends PassportStrategy(FirebaseStrategy, FI constructor( protected readonly container: MedusaContainer, protected readonly configModule: ConfigModule, - protected readonly strategyOptions: FirebaseAuthOptions + protected readonly strategyOptions: FirebaseAuthOptions, + protected readonly strictOptions: { store_strict: boolean; strict: boolean } ) { super({ jwtFromRequest: strategyOptions.store.jwtFromRequest ?? ExtractJwt.fromAuthHeaderAsBearerToken(), @@ -26,7 +27,11 @@ export class FirebaseStoreStrategy extends PassportStrategy(FirebaseStrategy, FI } const profile: Profile = { emails: [{ value: decodedToken.email }] }; - return await validateStoreCallback(profile, { container: this.container, strategyErrorIdentifier: 'firebase' }); + return await validateStoreCallback(profile, { + container: this.container, + strategyErrorIdentifier: 'firebase', + strict: this.strictOptions.store_strict ?? this.strictOptions.strict, + }); } } diff --git a/packages/medusa-plugin-auth/src/auth-strategies/google/__tests__/admin/verify-callback.spec.ts b/packages/medusa-plugin-auth/src/auth-strategies/google/__tests__/admin/verify-callback.spec.ts index 28bf839..392d6ab 100644 --- a/packages/medusa-plugin-auth/src/auth-strategies/google/__tests__/admin/verify-callback.spec.ts +++ b/packages/medusa-plugin-auth/src/auth-strategies/google/__tests__/admin/verify-callback.spec.ts @@ -57,55 +57,123 @@ describe('Google admin strategy verify callback', function () { return container_[name]; }, } as MedusaContainer; - - googleAdminStrategy = new GoogleAdminStrategy( - container, - {} as ConfigModule, - { clientID: 'fake', clientSecret: 'fake', admin: {} } as GoogleAuthOptions - ); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - it('should succeed', async () => { - profile = { - emails: [{ value: existsEmailWithProviderKey }], - }; - - const data = await googleAdminStrategy.validate(req, accessToken, refreshToken, profile); - expect(data).toEqual( - expect.objectContaining({ - id: 'test2', - }) - ); - }); - - it('should fail when a user exists without the auth provider metadata', async () => { - profile = { - emails: [{ value: existsEmail }], - }; - - const err = await googleAdminStrategy.validate(req, accessToken, refreshToken, profile).catch((err) => err); - expect(err).toEqual(new Error(`Admin with email ${existsEmail} already exists`)); }); - it('should fail when a user exists with the wrong auth provider key', async () => { - profile = { - emails: [{ value: existsEmailWithWrongProviderKey }], - }; - - const err = await googleAdminStrategy.validate(req, accessToken, refreshToken, profile).catch((err) => err); - expect(err).toEqual(new Error(`Admin with email ${existsEmailWithWrongProviderKey} already exists`)); + describe('when admin_strict is set to true', function () { + beforeEach(() => { + googleAdminStrategy = new GoogleAdminStrategy( + container, + {} as ConfigModule, + { clientID: 'fake', clientSecret: 'fake', admin: {} } as GoogleAuthOptions, + { admin_strict: true } + ); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should succeed', async () => { + profile = { + emails: [{ value: existsEmailWithProviderKey }], + }; + + const data = await googleAdminStrategy.validate(req, accessToken, refreshToken, profile); + expect(data).toEqual( + expect.objectContaining({ + id: 'test2', + }) + ); + }); + + it('should fail when a user exists without the auth provider metadata', async () => { + profile = { + emails: [{ value: existsEmail }], + }; + + const err = await googleAdminStrategy.validate(req, accessToken, refreshToken, profile).catch((err) => err); + expect(err).toEqual(new Error(`Admin with email ${existsEmail} already exists`)); + }); + + it('should fail when a user exists with the wrong auth provider key', async () => { + profile = { + emails: [{ value: existsEmailWithWrongProviderKey }], + }; + + const err = await googleAdminStrategy.validate(req, accessToken, refreshToken, profile).catch((err) => err); + expect(err).toEqual(new Error(`Admin with email ${existsEmailWithWrongProviderKey} already exists`)); + }); + + it('should fail when the user does not exist', async () => { + profile = { + emails: [{ value: 'fake' }], + }; + + const err = await googleAdminStrategy.validate(req, accessToken, refreshToken, profile).catch((err) => err); + expect(err).toEqual(new Error(`Unable to authenticate the user with the email fake`)); + }); }); - it('should fail when the user does not exist', async () => { - profile = { - emails: [{ value: 'fake' }], - }; - - const err = await googleAdminStrategy.validate(req, accessToken, refreshToken, profile).catch((err) => err); - expect(err).toEqual(new Error(`Unable to authenticate the user with the email fake`)); + describe('when admin_strict is set to false', function () { + beforeEach(() => { + googleAdminStrategy = new GoogleAdminStrategy( + container, + {} as ConfigModule, + { clientID: 'fake', clientSecret: 'fake', admin: {} } as GoogleAuthOptions, + { admin_strict: false } + ); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should succeed', async () => { + profile = { + emails: [{ value: existsEmailWithProviderKey }], + }; + + const data = await googleAdminStrategy.validate(req, accessToken, refreshToken, profile); + expect(data).toEqual( + expect.objectContaining({ + id: 'test2', + }) + ); + }); + + it('should succeed when a user exists without the auth provider metadata', async () => { + profile = { + emails: [{ value: existsEmail }], + }; + + const data = await googleAdminStrategy.validate(req, accessToken, refreshToken, profile); + expect(data).toEqual( + expect.objectContaining({ + id: 'test', + }) + ); + }); + + it('should succeed when a user exists with the wrong auth provider key', async () => { + profile = { + emails: [{ value: existsEmailWithWrongProviderKey }], + }; + + const data = await googleAdminStrategy.validate(req, accessToken, refreshToken, profile); + expect(data).toEqual( + expect.objectContaining({ + id: 'test3', + }) + ); + }); + + it('should fail when the user does not exist', async () => { + profile = { + emails: [{ value: 'fake' }], + }; + + const err = await googleAdminStrategy.validate(req, accessToken, refreshToken, profile).catch((err) => err); + expect(err).toEqual(new Error(`Unable to authenticate the user with the email fake`)); + }); }); }); diff --git a/packages/medusa-plugin-auth/src/auth-strategies/google/admin.ts b/packages/medusa-plugin-auth/src/auth-strategies/google/admin.ts index 70695bb..0106408 100644 --- a/packages/medusa-plugin-auth/src/auth-strategies/google/admin.ts +++ b/packages/medusa-plugin-auth/src/auth-strategies/google/admin.ts @@ -10,7 +10,8 @@ export class GoogleAdminStrategy extends PassportStrategy(GoogleStrategy, GOOGLE constructor( protected readonly container: MedusaContainer, protected readonly configModule: ConfigModule, - protected readonly strategyOptions: GoogleAuthOptions + protected readonly strategyOptions: GoogleAuthOptions, + protected readonly strictOptions?: { admin_strict?: boolean; strict?: boolean } ) { super({ clientID: strategyOptions.clientID, @@ -36,7 +37,11 @@ export class GoogleAdminStrategy extends PassportStrategy(GoogleStrategy, GOOGLE ); } - return await validateAdminCallback(profile, { container: this.container, strategyErrorIdentifier: 'google' }); + return await validateAdminCallback(profile, { + container: this.container, + strategyErrorIdentifier: 'google', + strict: this.strictOptions.admin_strict ?? this.strictOptions.strict, + }); } } diff --git a/packages/medusa-plugin-auth/src/auth-strategies/google/index.ts b/packages/medusa-plugin-auth/src/auth-strategies/google/index.ts index 5f4cf39..cc1fd82 100644 --- a/packages/medusa-plugin-auth/src/auth-strategies/google/index.ts +++ b/packages/medusa-plugin-auth/src/auth-strategies/google/index.ts @@ -11,11 +11,17 @@ export * from './store'; export default { load: (container: MedusaContainer, configModule: ConfigModule, options: AuthOptions): void => { if (options.google?.admin) { - new GoogleAdminStrategy(container, configModule, options.google); + new GoogleAdminStrategy(container, configModule, options.google, { + admin_strict: options.admin_strict, + strict: options.strict, + }); } if (options.google?.store) { - new GoogleStoreStrategy(container, configModule, options.google); + new GoogleStoreStrategy(container, configModule, options.google, { + store_strict: options.store_strict, + strict: options.strict, + }); } }, getRouter: (configModule: ConfigModule, options: AuthOptions): Router[] => { diff --git a/packages/medusa-plugin-auth/src/auth-strategies/google/store.ts b/packages/medusa-plugin-auth/src/auth-strategies/google/store.ts index 6854634..f92947d 100644 --- a/packages/medusa-plugin-auth/src/auth-strategies/google/store.ts +++ b/packages/medusa-plugin-auth/src/auth-strategies/google/store.ts @@ -10,7 +10,8 @@ export class GoogleStoreStrategy extends PassportStrategy(GoogleStrategy, GOOGLE constructor( protected readonly container: MedusaContainer, protected readonly configModule: ConfigModule, - protected readonly strategyOptions: GoogleAuthOptions + protected readonly strategyOptions: GoogleAuthOptions, + protected readonly strictOptions: { store_strict: boolean; strict: boolean } ) { super({ clientID: strategyOptions.clientID, @@ -35,7 +36,12 @@ export class GoogleStoreStrategy extends PassportStrategy(GoogleStrategy, GOOGLE profile ); } - return await validateStoreCallback(profile, { container: this.container, strategyErrorIdentifier: 'google' }); + + return await validateStoreCallback(profile, { + container: this.container, + strategyErrorIdentifier: 'google', + strict: this.strictOptions.store_strict ?? this.strictOptions.strict, + }); } } diff --git a/packages/medusa-plugin-auth/src/auth-strategies/linkedin/admin.ts b/packages/medusa-plugin-auth/src/auth-strategies/linkedin/admin.ts index e17740b..20f88d8 100644 --- a/packages/medusa-plugin-auth/src/auth-strategies/linkedin/admin.ts +++ b/packages/medusa-plugin-auth/src/auth-strategies/linkedin/admin.ts @@ -10,7 +10,8 @@ export class LinkedinAdminStrategy extends PassportStrategy(LinkedinStrategy, LI constructor( protected readonly container: MedusaContainer, protected readonly configModule: ConfigModule, - protected readonly strategyOptions: LinkedinAuthOptions + protected readonly strategyOptions: LinkedinAuthOptions, + protected readonly strictOptions: { admin_strict: boolean; strict: boolean } ) { super({ clientID: strategyOptions.clientID, @@ -38,7 +39,11 @@ export class LinkedinAdminStrategy extends PassportStrategy(LinkedinStrategy, LI ); } - return await validateAdminCallback(profile, { container: this.container, strategyErrorIdentifier: 'linkedin' }); + return await validateAdminCallback(profile, { + container: this.container, + strategyErrorIdentifier: 'linkedin', + strict: this.strictOptions.admin_strict ?? this.strictOptions.strict, + }); } } diff --git a/packages/medusa-plugin-auth/src/auth-strategies/linkedin/index.ts b/packages/medusa-plugin-auth/src/auth-strategies/linkedin/index.ts index a32df5d..7a99e37 100644 --- a/packages/medusa-plugin-auth/src/auth-strategies/linkedin/index.ts +++ b/packages/medusa-plugin-auth/src/auth-strategies/linkedin/index.ts @@ -15,11 +15,17 @@ export * from './store'; export default { load: (container: MedusaContainer, configModule: ConfigModule, options: AuthOptions): void => { if (options.linkedin?.admin) { - new LinkedinAdminStrategy(container, configModule, options.linkedin); + new LinkedinAdminStrategy(container, configModule, options.linkedin, { + admin_strict: options.admin_strict, + strict: options.strict, + }); } if (options.linkedin?.store) { - new LinkedinStoreStrategy(container, configModule, options.linkedin); + new LinkedinStoreStrategy(container, configModule, options.linkedin, { + store_strict: options.store_strict, + strict: options.strict, + }); } }, getRouter: (configModule: ConfigModule, options: AuthOptions): Router[] => { diff --git a/packages/medusa-plugin-auth/src/auth-strategies/linkedin/store.ts b/packages/medusa-plugin-auth/src/auth-strategies/linkedin/store.ts index fb8b5a4..77d3b7f 100644 --- a/packages/medusa-plugin-auth/src/auth-strategies/linkedin/store.ts +++ b/packages/medusa-plugin-auth/src/auth-strategies/linkedin/store.ts @@ -10,7 +10,8 @@ export class LinkedinStoreStrategy extends PassportStrategy(LinkedinStrategy, LI constructor( protected readonly container: MedusaContainer, protected readonly configModule: ConfigModule, - protected readonly strategyOptions: LinkedinAuthOptions + protected readonly strategyOptions: LinkedinAuthOptions, + protected readonly strictOptions: { store_strict: boolean; strict: boolean } ) { super({ clientID: strategyOptions.clientID, @@ -37,7 +38,12 @@ export class LinkedinStoreStrategy extends PassportStrategy(LinkedinStrategy, LI profile ); } - return await validateStoreCallback(profile, { container: this.container, strategyErrorIdentifier: 'linkedin' }); + + return await validateStoreCallback(profile, { + container: this.container, + strategyErrorIdentifier: 'linkedin', + strict: this.strictOptions.store_strict ?? this.strictOptions.strict, + }); } } diff --git a/packages/medusa-plugin-auth/src/core/validate-callback.ts b/packages/medusa-plugin-auth/src/core/validate-callback.ts index 1dc0f29..4843fdb 100644 --- a/packages/medusa-plugin-auth/src/core/validate-callback.ts +++ b/packages/medusa-plugin-auth/src/core/validate-callback.ts @@ -13,6 +13,10 @@ import { /** * Default validate callback used by an admin passport strategy * + * @param profile + * @param container + * @param strategyErrorIdentifier + * @param strict */ export async function validateAdminCallback< T extends { emails?: { value: string }[] } = { @@ -23,7 +27,8 @@ export async function validateAdminCallback< { container, strategyErrorIdentifier, - }: { container: MedusaContainer; strategyErrorIdentifier: StrategyErrorIdentifierType } + strict, + }: { container: MedusaContainer; strategyErrorIdentifier: StrategyErrorIdentifierType; strict?: boolean } ): Promise<{ id: string } | never> { const userService: UserService = container.resolve('userService'); const email = profile.emails?.[0]?.value; @@ -38,7 +43,11 @@ export async function validateAdminCallback< const user = await userService.retrieveByEmail(email).catch(() => void 0); if (user) { - if (!user.metadata || user.metadata[AUTH_PROVIDER_KEY] !== strategyNames[strategyErrorIdentifier].admin) { + strict ??= true; + if ( + strict && + (!user.metadata || user.metadata[AUTH_PROVIDER_KEY] !== strategyNames[strategyErrorIdentifier].admin) + ) { throw new MedusaError(MedusaError.Types.INVALID_DATA, `Admin with email ${email} already exists`); } } else { @@ -54,6 +63,7 @@ export async function validateAdminCallback< * @param profile * @param strategyErrorIdentifier It will be used to compose the error message in case of an error (e.g Google, Facebook) * @param container + * @param strict */ export async function validateStoreCallback< T extends { @@ -70,7 +80,8 @@ export async function validateStoreCallback< { container, strategyErrorIdentifier, - }: { container: MedusaContainer; strategyErrorIdentifier: StrategyErrorIdentifierType } + strict, + }: { container: MedusaContainer; strategyErrorIdentifier: StrategyErrorIdentifierType; strict?: boolean } ): Promise<{ id: string } | never> { const manager: EntityManager = container.resolve('manager'); const customerService: CustomerService = container.resolve('customerService'); @@ -116,10 +127,12 @@ export async function validateStoreCallback< }); } + strict ??= true; if ( - !customer.metadata || - !customer.metadata[CUSTOMER_METADATA_KEY] || - customer.metadata[AUTH_PROVIDER_KEY] !== strategyNames[strategyErrorIdentifier].store + strict && + (!customer.metadata || + !customer.metadata[CUSTOMER_METADATA_KEY] || + customer.metadata[AUTH_PROVIDER_KEY] !== strategyNames[strategyErrorIdentifier].store) ) { throw new MedusaError(MedusaError.Types.INVALID_DATA, `Customer with email ${email} already exists`); } else { diff --git a/packages/medusa-plugin-auth/src/types/index.ts b/packages/medusa-plugin-auth/src/types/index.ts index 70e0121..ae43c0e 100644 --- a/packages/medusa-plugin-auth/src/types/index.ts +++ b/packages/medusa-plugin-auth/src/types/index.ts @@ -30,7 +30,27 @@ export type StrategyExport = { getRouter?: (configModule: ConfigModule, options: AuthOptions) => Router[]; }; -export type AuthOptions = { +export type AuthOptions = ProviderOptions & { + /** + * When no value is provided, the default is true. + * It means that the default behaviour will be that a user can only login with one provider. + * Set it to false if you want to allow a user to login with multiple providers. + */ + admin_strict?: boolean; + /** + * When no value is provided, the default is true. + * It means that the default behaviour will be that a user can only login with one provider. + * Set it to false if you want to allow a user to login with multiple providers. + */ + store_strict?: boolean; + /** + * It is a shortcut of the `admin_strict` and `store_strict` options. If you set + * this option, both domain will be set to the same value. + */ + strict?: boolean; +}; + +export type ProviderOptions = { google?: GoogleAuthOptions; facebook?: FacebookAuthOptions; linkedin?: LinkedinAuthOptions; @@ -39,7 +59,7 @@ export type AuthOptions = { azure_oidc?: AzureAuthOptions; }; -export type StrategyErrorIdentifierType = keyof AuthOptions; +export type StrategyErrorIdentifierType = keyof ProviderOptions; export type StrategyNames = { [key in StrategyErrorIdentifierType]: { admin: string;