فهرست منبع

fix(core): Prevent Customers from logging in to admin API

Closes #77
Michael Bromley 6 سال پیش
والد
کامیت
09eb30c521

+ 18 - 0
packages/core/e2e/auth.e2e-spec.ts

@@ -11,6 +11,7 @@ import { TEST_SETUP_TIMEOUT_MS, testConfig } from '../../../e2e-common/test-conf
 import {
     CreateAdministrator,
     CreateRole,
+    GetCustomerList,
     Me,
     MutationCreateProductArgs,
     MutationLoginArgs,
@@ -22,6 +23,7 @@ import {
     CREATE_ADMINISTRATOR,
     CREATE_PRODUCT,
     CREATE_ROLE,
+    GET_CUSTOMER_LIST,
     GET_PRODUCT_LIST,
     ME,
     UPDATE_PRODUCT,
@@ -66,6 +68,22 @@ describe('Authorization & permissions', () => {
             });
         });
 
+        describe('Customer user', () => {
+            let customerEmailAddress: string;
+            beforeAll(async () => {
+                await adminClient.asSuperAdmin();
+                const { customers } = await adminClient.query<GetCustomerList.Query>(GET_CUSTOMER_LIST);
+                customerEmailAddress = customers.items[0].emailAddress;
+            });
+
+            it(
+                'cannot login',
+                assertThrowsWithMessage(async () => {
+                    await adminClient.asUserWithCredentials(customerEmailAddress, 'test');
+                }, 'The credentials did not match. Please check and try again'),
+            );
+        });
+
         describe('ReadCatalog permission', () => {
             beforeAll(async () => {
                 await adminClient.asSuperAdmin();

+ 10 - 4
packages/core/src/api/resolvers/admin/auth.resolver.ts

@@ -3,6 +3,7 @@ import { LoginResult, MutationLoginArgs, Permission } from '@vendure/common/lib/
 import { Request, Response } from 'express';
 
 import { ConfigService } from '../../../config/config.service';
+import { AdministratorService } from '../../../service/services/administrator.service';
 import { AuthService } from '../../../service/services/auth.service';
 import { ChannelService } from '../../../service/services/channel.service';
 import { CustomerService } from '../../../service/services/customer.service';
@@ -14,8 +15,13 @@ import { BaseAuthResolver } from '../base/base-auth.resolver';
 
 @Resolver()
 export class AuthResolver extends BaseAuthResolver {
-    constructor(authService: AuthService, userService: UserService, configService: ConfigService) {
-        super(authService, userService, configService);
+    constructor(
+        authService: AuthService,
+        userService: UserService,
+        configService: ConfigService,
+        administratorService: AdministratorService,
+    ) {
+        super(authService, userService, administratorService, configService);
     }
 
     @Mutation()
@@ -26,7 +32,7 @@ export class AuthResolver extends BaseAuthResolver {
         @Context('req') req: Request,
         @Context('res') res: Response,
     ): Promise<LoginResult> {
-        return super.login(args, ctx, req, res);
+        return super.login(args, ctx, req, res, 'admin');
     }
 
     @Mutation()
@@ -42,6 +48,6 @@ export class AuthResolver extends BaseAuthResolver {
     @Query()
     @Allow(Permission.Authenticated, Permission.Owner)
     me(@Ctx() ctx: RequestContext) {
-        return super.me(ctx);
+        return super.me(ctx, 'admin');
     }
 }

+ 20 - 3
packages/core/src/api/resolvers/base/base-auth.resolver.ts

@@ -7,13 +7,15 @@ import {
 import { unique } from '@vendure/common/lib/unique';
 import { Request, Response } from 'express';
 
-import { ForbiddenError, InternalServerError } from '../../../common/error/errors';
+import { ForbiddenError, InternalServerError, UnauthorizedError } from '../../../common/error/errors';
 import { ConfigService } from '../../../config/config.service';
 import { User } from '../../../entity/user/user.entity';
 import { getUserChannelsPermissions } from '../../../service/helpers/utils/get-user-channels-permissions';
+import { AdministratorService } from '../../../service/services/administrator.service';
 import { AuthService } from '../../../service/services/auth.service';
 import { UserService } from '../../../service/services/user.service';
 import { extractAuthToken } from '../../common/extract-auth-token';
+import { ApiType } from '../../common/get-api-type';
 import { RequestContext } from '../../common/request-context';
 import { setAuthToken } from '../../common/set-auth-token';
 
@@ -21,6 +23,7 @@ export class BaseAuthResolver {
     constructor(
         protected authService: AuthService,
         protected userService: UserService,
+        protected administratorService: AdministratorService,
         protected configService: ConfigService,
     ) {}
 
@@ -33,8 +36,9 @@ export class BaseAuthResolver {
         ctx: RequestContext,
         req: Request,
         res: Response,
+        apiType: ApiType,
     ): Promise<LoginResult> {
-        return await this.createAuthenticatedSession(ctx, args, req, res);
+        return await this.createAuthenticatedSession(ctx, args, req, res, apiType);
     }
 
     async logout(ctx: RequestContext, req: Request, res: Response): Promise<boolean> {
@@ -56,11 +60,17 @@ export class BaseAuthResolver {
     /**
      * Returns information about the current authenticated user.
      */
-    async me(ctx: RequestContext) {
+    async me(ctx: RequestContext, apiType: ApiType) {
         const userId = ctx.activeUserId;
         if (!userId) {
             throw new ForbiddenError();
         }
+        if (apiType === 'admin') {
+            const administrator = await this.administratorService.findOneByUserId(userId);
+            if (!administrator) {
+                throw new ForbiddenError();
+            }
+        }
         const user = userId && (await this.userService.getUserById(userId));
         return user ? this.publiclyAccessibleUser(user) : null;
     }
@@ -73,8 +83,15 @@ export class BaseAuthResolver {
         args: MutationLoginArgs,
         req: Request,
         res: Response,
+        apiType?: ApiType,
     ) {
         const session = await this.authService.authenticate(ctx, args.username, args.password);
+        if (apiType && apiType === 'admin') {
+            const administrator = await this.administratorService.findOneByUserId(session.user.id);
+            if (!administrator) {
+                throw new UnauthorizedError();
+            }
+        }
         setAuthToken({
             req,
             res,

+ 8 - 6
packages/core/src/api/resolvers/shop/shop-auth.resolver.ts

@@ -20,6 +20,7 @@ import {
     VerificationTokenError,
 } from '../../../common/error/errors';
 import { ConfigService } from '../../../config/config.service';
+import { AdministratorService } from '../../../service/services/administrator.service';
 import { AuthService } from '../../../service/services/auth.service';
 import { CustomerService } from '../../../service/services/customer.service';
 import { UserService } from '../../../service/services/user.service';
@@ -31,12 +32,13 @@ import { BaseAuthResolver } from '../base/base-auth.resolver';
 @Resolver()
 export class ShopAuthResolver extends BaseAuthResolver {
     constructor(
-        protected authService: AuthService,
-        protected userService: UserService,
+        authService: AuthService,
+        userService: UserService,
+        administratorService: AdministratorService,
+        configService: ConfigService,
         protected customerService: CustomerService,
-        protected configService: ConfigService,
     ) {
-        super(authService, userService, configService);
+        super(authService, userService, administratorService, configService);
     }
 
     @Mutation()
@@ -47,7 +49,7 @@ export class ShopAuthResolver extends BaseAuthResolver {
         @Context('req') req: Request,
         @Context('res') res: Response,
     ): Promise<LoginResult> {
-        return super.login(args, ctx, req, res);
+        return super.login(args, ctx, req, res, 'shop');
     }
 
     @Mutation()
@@ -63,7 +65,7 @@ export class ShopAuthResolver extends BaseAuthResolver {
     @Query()
     @Allow(Permission.Authenticated)
     me(@Ctx() ctx: RequestContext) {
-        return super.me(ctx);
+        return super.me(ctx, 'shop');
     }
 
     @Mutation()