UNPKG

a-seal

Version:
223 lines (162 loc) 7.31 kB
import acl, { ANY, AuthenticatedRequest } from './index.js' import { Response } from 'express' describe('A Seal', () => { afterEach(() => { acl.reset() }) it('matches and returns an allow function', () => { let obj = acl.match(/\/foo/).for(['GET']) expect(obj.allow).toBeTypeOf('function') obj = acl.match(/\/foo/).for(['GET']) expect(obj.allow).toBeTypeOf('function') obj = acl.match(/^foo/).for(['GET']) expect(obj.allow).toBeTypeOf('function') obj = acl.match(/^foo/).for(['GET', 'POST']) expect(obj.allow).toBeTypeOf('function') }) it('support labelling with scopes', () => { const rule = acl.match(/\/foo\/bar?/).for(['GET']).allow(['user']).as('READ_FOO') expect(rule.resource).toEqual(/\/foo\/bar?/) expect(rule.actions).toEqual(['GET']) expect(rule.roles).toEqual(['user']) expect(rule.scope).toEqual('READ_FOO') }) it('creates access control rules', () => { acl.match(/\/foo\/bar?/).for(['GET']).allow(['user']) expect(acl.rules[0].resource).toEqual(/\/foo\/bar?/) expect(acl.rules[0].actions).toEqual(['GET']) expect(acl.rules[0].roles).toEqual(['user']) expect(acl.rules.length).toBe(1) acl.match(/\/foo\/bar$/).for(['GET', 'POST']).allow(['user', 'admin']) expect(acl.rules[1].resource).toEqual(/\/foo\/bar$/) expect(acl.rules[1].actions).toEqual(['GET', 'POST']) expect(acl.rules[1].roles).toEqual(['user', 'admin']) expect(acl.rules.length).toBe(2) //overwrite existing rule expect(() => { acl.match(/\/foo\/bar?/).for(['GET']).allow(['admin']) }).toThrowError() }) it('checks if a role is allowed for a given resource and action', () => { let allowed //RESOURCES //its a whitelist... allowed = acl.isAllowed('admin', '/resource', '*') expect(allowed).toBe(false) //add rules acl.match(/^\/resource/).for(['GET']).allow(['admin']) //test... allowed = acl.isAllowed('admin', '/resource', '*') expect(allowed).toBe(true) allowed = acl.isAllowed('admin', '/resource/more', '*') expect(allowed).toBe(true) //ACTIONS //its a whitelist... allowed = acl.isAllowed('admin', '/actions', '*') expect(allowed).toBe(false) allowed = acl.isAllowed('admin', '/actions', '*') expect(allowed).toBe(false) //add rules acl.match(/\/actions-1/).for(['GET']).allow(['admin']) acl.match(/\/actions-1/).for(['POST']).allow(['admin']) acl.match(/\/actions-2/).for(['GET', 'POST']).allow(['admin']) acl.match(/\/actions-3/).for(['GET', 'POST']).allow(['admin']) //test... allowed = acl.isAllowed('admin', '/actions-1', '*') expect(allowed).toBe(true) allowed = acl.isAllowed('admin', '/actions-1', 'GET') expect(allowed).toBe(true) allowed = acl.isAllowed('admin', '/actions-1', 'POST') expect(allowed).toBe(true) allowed = acl.isAllowed('admin', '/actions-1', 'BLAH') expect(allowed).toBe(false) allowed = acl.isAllowed('admin', '/actions-2', '*') expect(allowed).toBe(true) allowed = acl.isAllowed('admin', '/actions-2', 'GET') expect(allowed).toBe(true) allowed = acl.isAllowed('admin', '/actions-2', 'POST') expect(allowed).toBe(true) allowed = acl.isAllowed('admin', '/actions-2', 'BLAH') expect(allowed).toBe(false) allowed = acl.isAllowed('admin', '/actions-3', '*') expect(allowed).toBe(true) allowed = acl.isAllowed('admin', '/actions-3', 'GET') expect(allowed).toBe(true) allowed = acl.isAllowed('admin', '/actions-3', 'POST') expect(allowed).toBe(true) allowed = acl.isAllowed('admin', '/actions-3', 'BLAH') expect(allowed).toBe(false) //ROLES //its a whitelist... allowed = acl.isAllowed('admin', '/roles', 'admin') expect(allowed).toBe(false) allowed = acl.isAllowed('admin', '/roles', 'admin') expect(allowed).toBe(false) //add rules acl.match(/\/roles/).for(['GET']).allow([ANY]) acl.match(/\/roles/).for(['POST']).allow(['admin', 'user']) acl.match(/\/roles/).for(['DELETE']).allow(['hacker']) acl.match(/\/roles/).for(['PUT']).allow(['hacker', 'cleaner']) //test... allowed = acl.isAllowed('anon', '/roles', 'GET') expect(allowed).toBe(true) allowed = acl.isAllowed('anon', '/roles', 'FOO') expect(allowed).toBe(false) allowed = acl.isAllowed('admin', '/roles', 'GET') expect(allowed).toBe(true) allowed = acl.isAllowed('user', '/roles', 'GET') expect(allowed).toBe(true) allowed = acl.isAllowed('admin', '/roles', 'POST') expect(allowed).toBe(true) allowed = acl.isAllowed('user', '/roles', 'POST') expect(allowed).toBe(true) allowed = acl.isAllowed('hacker', '/roles', 'POST') expect(allowed).toBe(false) allowed = acl.isAllowed('hacker', '/roles', 'DELETE') expect(allowed).toBe(true) allowed = acl.isAllowed('cleaner', '/roles', 'PUT') expect(allowed).toBe(true) }) it('authorizes requests with middleware', () => { const req: Record<string, any> = { method: 'GET', } const res: Partial<Response> = {} const next = vi.fn() acl.match(/\/public/).for(['GET']).allow(['foo', 'admin']) acl.match(/\/secret/).for(['GET']).allow(['admin']).as('SECRET_GETTER') const middleware = acl.middleware({ anon: 'foo' }) req.path = `/public` req.user = null middleware(req as AuthenticatedRequest, res as Response, next) expect(req.scope).toBeUndefined() expect(next).toHaveBeenCalledTimes(1) expect(next.mock.lastCall.length).toBe(0) next.mockClear() req.user = { role: 'admin' } middleware(req as AuthenticatedRequest, res as Response, next) expect(req.scope).toBeUndefined() expect(next).toHaveBeenCalledTimes(1) expect(next.mock.lastCall.length).toBe(0) next.mockClear() req.path = `/secret` req.user = { role: 'foo' } // configured anon role middleware(req as AuthenticatedRequest, res as Response, next) expect(req.scope).toBeUndefined() expect(next).toHaveBeenCalledTimes(1) expect(next.mock.lastCall[0].status).toBe(401) next.mockClear() req.user = { role: 'foobar' } // not anon role middleware(req as AuthenticatedRequest, res as Response, next) expect(req.scope).toBeUndefined() expect(next).toHaveBeenCalledTimes(1) expect(next.mock.lastCall[0].status).toBe(403) next.mockClear() req.user = { role: 'admin' } middleware(req as AuthenticatedRequest, res as Response, next) expect(req.scope).toBe('SECRET_GETTER') expect(next).toHaveBeenCalledTimes(1) expect(next.mock.lastCall.length).toBe(0) next.mockClear() }) })