89 lines
3.0 KiB
TypeScript
89 lines
3.0 KiB
TypeScript
import { ForbiddenException, UnauthorizedException } from '@nestjs/common';
|
|
import { Reflector } from '@nestjs/core';
|
|
import { describe, expect, it, vi } from 'vitest';
|
|
import { AuthorizationGuard } from './AuthorizationGuard';
|
|
import { Public } from './Public';
|
|
import { RequireRoles } from './RequireRoles';
|
|
|
|
class DummyController {
|
|
@Public()
|
|
publicHandler(): void {}
|
|
|
|
protectedHandler(): void {}
|
|
|
|
@RequireRoles('admin')
|
|
adminHandler(): void {}
|
|
}
|
|
|
|
function createExecutionContext(options: { handler: Function; userId?: string }) {
|
|
const request = options.userId ? { user: { userId: options.userId } } : {};
|
|
|
|
return {
|
|
getHandler: () => options.handler,
|
|
getClass: () => DummyController,
|
|
switchToHttp: () => ({
|
|
getRequest: () => request,
|
|
}),
|
|
};
|
|
}
|
|
|
|
describe('AuthorizationGuard', () => {
|
|
it('allows public routes without a user session', () => {
|
|
const authorizationService = { getRolesForUser: vi.fn() };
|
|
const guard = new AuthorizationGuard(new Reflector(), authorizationService as any);
|
|
|
|
const ctx = createExecutionContext({
|
|
handler: DummyController.prototype.publicHandler,
|
|
});
|
|
|
|
expect(guard.canActivate(ctx as any)).toBe(true);
|
|
expect(authorizationService.getRolesForUser).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('denies non-public routes by default when not authenticated', () => {
|
|
const authorizationService = { getRolesForUser: vi.fn() };
|
|
const guard = new AuthorizationGuard(new Reflector(), authorizationService as any);
|
|
|
|
const ctx = createExecutionContext({
|
|
handler: DummyController.prototype.protectedHandler,
|
|
});
|
|
|
|
expect(() => guard.canActivate(ctx as any)).toThrow(UnauthorizedException);
|
|
});
|
|
|
|
it('allows non-public routes when authenticated', () => {
|
|
const authorizationService = { getRolesForUser: vi.fn().mockReturnValue([]) };
|
|
const guard = new AuthorizationGuard(new Reflector(), authorizationService as any);
|
|
|
|
const ctx = createExecutionContext({
|
|
handler: DummyController.prototype.protectedHandler,
|
|
userId: 'user-1',
|
|
});
|
|
|
|
expect(guard.canActivate(ctx as any)).toBe(true);
|
|
});
|
|
|
|
it('denies routes requiring roles when user does not have any required role', () => {
|
|
const authorizationService = { getRolesForUser: vi.fn().mockReturnValue(['user']) };
|
|
const guard = new AuthorizationGuard(new Reflector(), authorizationService as any);
|
|
|
|
const ctx = createExecutionContext({
|
|
handler: DummyController.prototype.adminHandler,
|
|
userId: 'user-1',
|
|
});
|
|
|
|
expect(() => guard.canActivate(ctx as any)).toThrow(ForbiddenException);
|
|
});
|
|
|
|
it('allows routes requiring roles when user has a required role', () => {
|
|
const authorizationService = { getRolesForUser: vi.fn().mockReturnValue(['admin']) };
|
|
const guard = new AuthorizationGuard(new Reflector(), authorizationService as any);
|
|
|
|
const ctx = createExecutionContext({
|
|
handler: DummyController.prototype.adminHandler,
|
|
userId: 'user-1',
|
|
});
|
|
|
|
expect(guard.canActivate(ctx as any)).toBe(true);
|
|
});
|
|
}); |