@getanthill/datastore
Version:
Event-Sourced Datastore
183 lines (166 loc) • 4.71 kB
text/typescript
import type { Services } from '../typings';
import * as authz from '../typings/authorizations';
import setup from '../../test/setup';
describe('Authz', () => {
let app;
let services: Services;
beforeAll(async () => {
app = await setup.build({
authz: {
isEnabled: true,
},
});
await app.services.models.initInternalModels();
services = app.services;
});
beforeEach(async () => {
jest.restoreAllMocks();
await setup.cleanModel(services, 'attributes');
await setup.cleanModel(services, 'policies');
});
afterAll(async () => {
await setup.teardownDb(services.mongodb);
});
describe('authorize', () => {
it('allows valid authorization request', async () => {
await services.models.factory('policies').create({
name: 'policy',
description: 'policy description',
is_enabled: true,
obligations: [],
scope: ['subject'],
verb: authz.AUTHORIZATION_VERB_ALLOW as authz.PolicyVerb,
rules: [
{
name: 'firstname_john',
description: '',
is_enabled: true,
action: {},
subject: {
type: 'object',
required: ['_attributes'],
properties: {
_attributes: {
type: 'array',
items: {
anyOf: [
{
type: 'object',
properties: {
attribute: {
type: 'string',
enum: ['firstname'],
},
value: {
type: 'string',
enum: ['john'],
},
},
},
],
},
},
},
},
object: {},
context: {},
},
],
});
await services.models.factory('attributes').create({
is_enabled: true,
scope: ['subject'],
description: 'Subject is having attribute `firstname=john`',
name: 'firstname',
value: 'john',
});
const decision = await services.authz.authorize({
action: {
scope: ['action'],
},
subject: {
scope: ['subject'],
},
object: {
scope: ['object'],
},
context: {
scope: ['context'],
},
});
expect(decision).toMatchObject({
verb: 'allow',
});
});
it('denies invalid authorization request', async () => {
await services.models.factory('policies').create({
name: 'policy',
description: 'policy description',
is_enabled: true,
obligations: [],
scope: ['subject'],
verb: authz.AUTHORIZATION_VERB_DENY as authz.PolicyVerb,
rules: [
{
name: 'firstname_john',
description: '',
is_enabled: true,
action: {},
subject: {
type: 'object',
required: ['_attributes'],
properties: {
_attributes: {
type: 'array',
items: {
anyOf: [
{
type: 'object',
properties: {
attribute: {
type: 'string',
enum: ['firstname'],
},
value: {
type: 'string',
not: { enum: ['john'] },
},
},
},
],
},
},
},
},
object: {},
context: {},
},
],
});
await services.models.factory('attributes').create({
is_enabled: true,
scope: ['subject'],
description: 'Subject is having attribute `firstname=alice`',
name: 'firstname',
value: 'alice', // <-- Should have been john
});
const decision = await services.authz.authorize({
action: {
scope: ['action'],
},
subject: {
scope: ['subject'],
},
object: {
scope: ['object'],
},
context: {
scope: ['context'],
},
});
expect(decision).toMatchObject({
verb: 'deny',
});
});
});
});