diff --git a/packages/core/e2e/authentication-strategy.e2e-spec.ts b/packages/core/e2e/authentication-strategy.e2e-spec.ts index 5f7aec5102..74a7ac6f2d 100644 --- a/packages/core/e2e/authentication-strategy.e2e-spec.ts +++ b/packages/core/e2e/authentication-strategy.e2e-spec.ts @@ -18,12 +18,24 @@ import { VALID_AUTH_TOKEN, } from './fixtures/test-authentication-strategies'; import { CURRENT_USER_FRAGMENT } from './graphql/fragments'; -import { CurrentUserFragment, CustomerFragment, HistoryEntryType } from './graphql/generated-e2e-admin-types'; +import { + AttemptLoginDocument, + CurrentUserFragment, + CustomerFragment, + HistoryEntryType, +} from './graphql/generated-e2e-admin-types'; import * as Codegen from './graphql/generated-e2e-admin-types'; import { RegisterMutation, RegisterMutationVariables } from './graphql/generated-e2e-shop-types'; import { CREATE_CUSTOMER, DELETE_CUSTOMER, GET_CUSTOMER_HISTORY, ME } from './graphql/shared-definitions'; import { REGISTER_ACCOUNT } from './graphql/shop-definitions'; +const currentUserGuard: ErrorResultGuard = createErrorResultGuard( + input => input.identifier != null, +); +const customerGuard: ErrorResultGuard = createErrorResultGuard( + input => input.emailAddress != null, +); + describe('AuthenticationStrategy', () => { const { server, adminClient, shopClient } = createTestEnvironment( mergeConfig(testConfig(), { @@ -52,13 +64,6 @@ describe('AuthenticationStrategy', () => { await server.destroy(); }); - const currentUserGuard: ErrorResultGuard = createErrorResultGuard( - input => input.identifier != null, - ); - const customerGuard: ErrorResultGuard = createErrorResultGuard( - input => input.emailAddress != null, - ); - describe('external auth', () => { const userData = { email: 'test@email.com', @@ -386,6 +391,40 @@ describe('AuthenticationStrategy', () => { }); }); +describe('No NativeAuthStrategy on Shop API', () => { + const { server, adminClient, shopClient } = createTestEnvironment( + mergeConfig(testConfig(), { + authOptions: { + shopAuthenticationStrategy: [new TestAuthenticationStrategy()], + }, + }), + ); + + beforeAll(async () => { + await server.init({ + initialData, + productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-minimal.csv'), + customerCount: 1, + }); + await adminClient.asSuperAdmin(); + }, TEST_SETUP_TIMEOUT_MS); + + afterAll(async () => { + await server.destroy(); + }); + + // https://github.com/vendure-ecommerce/vendure/issues/2282 + it('can log in to Admin API', async () => { + const { login } = await adminClient.query(AttemptLoginDocument, { + username: 'superadmin', + password: 'superadmin', + }); + + currentUserGuard.assertSuccess(login); + expect(login.identifier).toBe('superadmin'); + }); +}); + const AUTHENTICATE = gql` mutation Authenticate($input: AuthenticationInput!) { authenticate(input: $input) { diff --git a/packages/core/src/api/resolvers/admin/auth.resolver.ts b/packages/core/src/api/resolvers/admin/auth.resolver.ts index 9fbea3cc14..ae35ff2446 100644 --- a/packages/core/src/api/resolvers/admin/auth.resolver.ts +++ b/packages/core/src/api/resolvers/admin/auth.resolver.ts @@ -10,7 +10,9 @@ import { import { Request, Response } from 'express'; import { NativeAuthStrategyError } from '../../../common/error/generated-graphql-admin-errors'; +import { NATIVE_AUTH_STRATEGY_NAME } from '../../../config/auth/native-authentication-strategy'; import { ConfigService } from '../../../config/config.service'; +import { Logger } from '../../../config/logger/vendure-logger'; import { AdministratorService } from '../../../service/services/administrator.service'; import { AuthService } from '../../../service/services/auth.service'; import { ChannelService } from '../../../service/services/channel.service'; @@ -79,6 +81,17 @@ export class AuthResolver extends BaseAuthResolver { } protected requireNativeAuthStrategy() { - return super.requireNativeAuthStrategy() as NativeAuthStrategyError | undefined; + const { adminAuthenticationStrategy } = this.configService.authOptions; + const nativeAuthStrategyIsConfigured = !!adminAuthenticationStrategy.find( + strategy => strategy.name === NATIVE_AUTH_STRATEGY_NAME, + ); + if (!nativeAuthStrategyIsConfigured) { + const authStrategyNames = adminAuthenticationStrategy.map(s => s.name).join(', '); + const errorMessage = + 'This GraphQL operation requires that the NativeAuthenticationStrategy be configured for the Admin API.\n' + + `Currently the following AuthenticationStrategies are enabled: ${authStrategyNames}`; + Logger.error(errorMessage); + return new NativeAuthStrategyError(); + } } } diff --git a/packages/core/src/api/resolvers/base/base-auth.resolver.ts b/packages/core/src/api/resolvers/base/base-auth.resolver.ts index 6a6cae0b55..edbdc94bf0 100644 --- a/packages/core/src/api/resolvers/base/base-auth.resolver.ts +++ b/packages/core/src/api/resolvers/base/base-auth.resolver.ts @@ -14,15 +14,13 @@ import { Request, Response } from 'express'; import { isGraphQlErrorResult } from '../../../common/error/error-result'; import { ForbiddenError } from '../../../common/error/errors'; -import { NativeAuthStrategyError as AdminNativeAuthStrategyError } from '../../../common/error/generated-graphql-admin-errors'; import { InvalidCredentialsError, - NativeAuthStrategyError as ShopNativeAuthStrategyError, NotVerifiedError, } from '../../../common/error/generated-graphql-shop-errors'; import { NATIVE_AUTH_STRATEGY_NAME } from '../../../config/auth/native-authentication-strategy'; import { ConfigService } from '../../../config/config.service'; -import { Logger, LogLevel } from '../../../config/logger/vendure-logger'; +import { LogLevel } from '../../../config/logger/vendure-logger'; import { User } from '../../../entity/user/user.entity'; import { getUserChannelsPermissions } from '../../../service/helpers/utils/get-user-channels-permissions'; import { AdministratorService } from '../../../service/services/administrator.service'; @@ -34,19 +32,12 @@ import { RequestContext } from '../../common/request-context'; import { setSessionToken } from '../../common/set-session-token'; export class BaseAuthResolver { - protected readonly nativeAuthStrategyIsConfigured: boolean; - constructor( protected authService: AuthService, protected userService: UserService, protected administratorService: AdministratorService, protected configService: ConfigService, - ) { - this.nativeAuthStrategyIsConfigured = - !!this.configService.authOptions.shopAuthenticationStrategy.find( - strategy => strategy.name === NATIVE_AUTH_STRATEGY_NAME, - ); - } + ) {} /** * Attempts a login given the username and password of a user. If successful, returns @@ -159,20 +150,4 @@ export class BaseAuthResolver { channels: getUserChannelsPermissions(user) as CurrentUserChannel[], }; } - - protected requireNativeAuthStrategy(): - | AdminNativeAuthStrategyError - | ShopNativeAuthStrategyError - | undefined { - if (!this.nativeAuthStrategyIsConfigured) { - const authStrategyNames = this.configService.authOptions.shopAuthenticationStrategy - .map(s => s.name) - .join(', '); - const errorMessage = - 'This GraphQL operation requires that the NativeAuthenticationStrategy be configured for the Shop API.\n' + - `Currently the following AuthenticationStrategies are enabled: ${authStrategyNames}`; - Logger.error(errorMessage); - return new AdminNativeAuthStrategyError(); - } - } } diff --git a/packages/core/src/api/resolvers/shop/shop-auth.resolver.ts b/packages/core/src/api/resolvers/shop/shop-auth.resolver.ts index b929bd1b97..300b1ca3ff 100644 --- a/packages/core/src/api/resolvers/shop/shop-auth.resolver.ts +++ b/packages/core/src/api/resolvers/shop/shop-auth.resolver.ts @@ -34,6 +34,7 @@ import { ForbiddenError } from '../../../common/error/errors'; import { NativeAuthStrategyError } from '../../../common/error/generated-graphql-shop-errors'; import { NATIVE_AUTH_STRATEGY_NAME } from '../../../config/auth/native-authentication-strategy'; import { ConfigService } from '../../../config/config.service'; +import { Logger } from '../../../config/logger/vendure-logger'; import { AdministratorService } from '../../../service/services/administrator.service'; import { AuthService } from '../../../service/services/auth.service'; import { CustomerService } from '../../../service/services/customer.service'; @@ -326,6 +327,17 @@ export class ShopAuthResolver extends BaseAuthResolver { } protected requireNativeAuthStrategy() { - return super.requireNativeAuthStrategy() as NativeAuthStrategyError | undefined; + const { shopAuthenticationStrategy } = this.configService.authOptions; + const nativeAuthStrategyIsConfigured = !!shopAuthenticationStrategy.find( + strategy => strategy.name === NATIVE_AUTH_STRATEGY_NAME, + ); + if (!nativeAuthStrategyIsConfigured) { + const authStrategyNames = shopAuthenticationStrategy.map(s => s.name).join(', '); + const errorMessage = + 'This GraphQL operation requires that the NativeAuthenticationStrategy be configured for the Shop API.\n' + + `Currently the following AuthenticationStrategies are enabled: ${authStrategyNames}`; + Logger.error(errorMessage); + return new NativeAuthStrategyError(); + } } }