blob: 736440f6fa078080831da1648695569ce4e5cc0e [file] [log] [blame]
import { newEnforcer, Enforcer } from '../src';
interface SpyAdapter {
loadPolicy: jest.Mock<Promise<boolean>, any[]>;
addPolicy: jest.Mock;
removePolicy: jest.Mock;
updatePolicy: jest.Mock;
removeFilteredPolicy: jest.Mock;
addPolicies: jest.Mock;
removePolicies: jest.Mock;
updatePolicies: jest.Mock;
savePolicy: jest.Mock;
}
function createSpyAdapter(): SpyAdapter {
return {
loadPolicy: jest.fn(async () => true),
addPolicy: jest.fn(async () => true),
removePolicy: jest.fn(async () => true),
updatePolicy: jest.fn(async () => true),
removeFilteredPolicy: jest.fn(async () => true),
addPolicies: jest.fn(async () => true),
removePolicies: jest.fn(async () => true),
updatePolicies: jest.fn(async () => true),
savePolicy: jest.fn(async () => true),
};
}
describe('Management self* APIs bypass adapter and update memory', () => {
let e: Enforcer;
let adapter: SpyAdapter;
beforeEach(async () => {
adapter = createSpyAdapter();
e = (await newEnforcer('examples/basic_model.conf', adapter as any)) as Enforcer;
e.enableAutoSave(true);
});
test('selfAddPolicy adds to memory and skips adapter', async () => {
const rule = ['alice', 'data1', 'read'];
const added = await e.selfAddPolicy('p', 'p', rule);
expect(added).toBe(true);
expect(await e.hasPolicy(...rule)).toBe(true);
expect(adapter.addPolicy).not.toHaveBeenCalled();
});
test('selfRemovePolicy removes from memory and skips adapter', async () => {
const rule = ['bob', 'data2', 'write'];
await e.selfAddPolicy('p', 'p', rule);
const removed = await e.selfRemovePolicy('p', 'p', rule);
expect(removed).toBe(true);
expect(await e.hasPolicy(...rule)).toBe(false);
expect(adapter.removePolicy).not.toHaveBeenCalled();
});
test('selfUpdatePolicy updates in memory and skips adapter', async () => {
const oldRule = ['carol', 'data3', 'read'];
const newRule = ['carol', 'data3', 'write'];
await e.selfAddPolicy('p', 'p', oldRule);
const updated = await e.selfUpdatePolicy('p', 'p', oldRule, newRule);
expect(updated).toBe(true);
expect(await e.hasPolicy(...oldRule)).toBe(false);
expect(await e.hasPolicy(...newRule)).toBe(true);
expect(adapter.updatePolicy).not.toHaveBeenCalled();
});
test('selfAddPolicies and selfRemovePolicies work in memory only', async () => {
const rules = [
['dave', 'data4', 'read'],
['erin', 'data5', 'write'],
];
const added = await e.selfAddPolicies('p', 'p', rules);
expect(added).toBe(true);
expect(await e.hasPolicy(...rules[0])).toBe(true);
expect(await e.hasPolicy(...rules[1])).toBe(true);
expect(adapter.addPolicies).not.toHaveBeenCalled();
const removed = await e.selfRemovePolicies('p', 'p', rules);
expect(removed).toBe(true);
expect(await e.hasPolicy(...rules[0])).toBe(false);
expect(await e.hasPolicy(...rules[1])).toBe(false);
expect(adapter.removePolicies).not.toHaveBeenCalled();
});
test('selfRemoveFilteredPolicy removes matching rules without adapter', async () => {
await e.selfAddPolicy('p', 'p', ['frank', 'data6', 'read']);
await e.selfAddPolicy('p', 'p', ['frank', 'data7', 'write']);
const removed = await e.selfRemoveFilteredPolicy('p', 'p', 0, 'frank');
expect(removed).toBe(true);
expect(await e.hasPolicy('frank', 'data6', 'read')).toBe(false);
expect(await e.hasPolicy('frank', 'data7', 'write')).toBe(false);
expect(adapter.removeFilteredPolicy).not.toHaveBeenCalled();
});
test('selfUpdatePolicies updates multiple rules in memory', async () => {
const oldRules = [
['gina', 'data8', 'read'],
['harry', 'data9', 'read'],
];
const newRules = [
['gina', 'data8', 'write'],
['harry', 'data9', 'write'],
];
await e.selfAddPolicies('p', 'p', oldRules);
const updated = await e.selfUpdatePolicies('p', 'p', oldRules, newRules);
expect(updated).toBe(true);
expect(await e.hasPolicy('gina', 'data8', 'write')).toBe(true);
expect(await e.hasPolicy('harry', 'data9', 'write')).toBe(true);
expect(await e.hasPolicy('gina', 'data8', 'read')).toBe(false);
expect(await e.hasPolicy('harry', 'data9', 'read')).toBe(false);
expect(adapter.updatePolicies).not.toHaveBeenCalled();
});
test('selfAddPolicy returns false when policy already exists', async () => {
const rule = ['ivy', 'data10', 'read'];
await e.selfAddPolicy('p', 'p', rule);
const added = await e.selfAddPolicy('p', 'p', rule);
expect(added).toBe(false);
});
test('selfRemovePolicy returns false when policy does not exist', async () => {
const rule = ['nonexistent', 'data11', 'read'];
const removed = await e.selfRemovePolicy('p', 'p', rule);
expect(removed).toBe(false);
});
test('selfUpdatePolicy returns false when old policy does not exist', async () => {
const oldRule = ['nonexistent', 'data12', 'read'];
const newRule = ['nonexistent', 'data12', 'write'];
const updated = await e.selfUpdatePolicy('p', 'p', oldRule, newRule);
expect(updated).toBe(false);
});
test('selfAddPolicies returns false when any policy already exists', async () => {
const rule1 = ['jack', 'data13', 'read'];
await e.selfAddPolicy('p', 'p', rule1);
const rules = [rule1, ['karen', 'data14', 'write']];
const added = await e.selfAddPolicies('p', 'p', rules);
expect(added).toBe(false);
});
test('selfRemovePolicies returns false when any policy does not exist', async () => {
const rule1 = ['leo', 'data15', 'read'];
await e.selfAddPolicy('p', 'p', rule1);
const rules = [rule1, ['nonexistent', 'data16', 'write']];
const removed = await e.selfRemovePolicies('p', 'p', rules);
expect(removed).toBe(false);
});
test('selfUpdatePolicies throws error when array lengths mismatch', async () => {
const oldRules = [['mia', 'data17', 'read']];
const newRules = [
['mia', 'data17', 'write'],
['nancy', 'data18', 'read'],
];
await expect(e.selfUpdatePolicies('p', 'p', oldRules, newRules)).rejects.toThrow(
'the length of oldRules should be equal to the length of newRules'
);
});
test('selfUpdatePolicies returns false when any old policy does not exist', async () => {
const oldRules = [
['oscar', 'data19', 'read'],
['nonexistent', 'data20', 'read'],
];
const newRules = [
['oscar', 'data19', 'write'],
['nonexistent', 'data20', 'write'],
];
await e.selfAddPolicy('p', 'p', oldRules[0]);
const updated = await e.selfUpdatePolicies('p', 'p', oldRules, newRules);
expect(updated).toBe(false);
});
});
describe('Management self* APIs with grouping policies', () => {
let e: Enforcer;
let adapter: SpyAdapter;
beforeEach(async () => {
adapter = createSpyAdapter();
e = (await newEnforcer('examples/rbac_model.conf', adapter as any)) as Enforcer;
e.enableAutoSave(true);
});
test('selfAddPolicy works with g section for role links', async () => {
const rule = ['alice', 'admin'];
const added = await e.selfAddPolicy('g', 'g', rule);
expect(added).toBe(true);
expect(adapter.addPolicy).not.toHaveBeenCalled();
});
test('selfRemovePolicy works with g section for role links', async () => {
const rule = ['bob', 'editor'];
await e.selfAddPolicy('g', 'g', rule);
const removed = await e.selfRemovePolicy('g', 'g', rule);
expect(removed).toBe(true);
expect(adapter.removePolicy).not.toHaveBeenCalled();
});
test('selfUpdatePolicy works with g section for role links', async () => {
const oldRule = ['carol', 'viewer'];
const newRule = ['carol', 'editor'];
await e.selfAddPolicy('g', 'g', oldRule);
const updated = await e.selfUpdatePolicy('g', 'g', oldRule, newRule);
expect(updated).toBe(true);
expect(adapter.updatePolicy).not.toHaveBeenCalled();
});
test('selfAddPolicies works with multiple g policies', async () => {
const rules = [
['dave', 'admin'],
['eve', 'editor'],
];
const added = await e.selfAddPolicies('g', 'g', rules);
expect(added).toBe(true);
expect(adapter.addPolicies).not.toHaveBeenCalled();
});
test('selfRemoveFilteredPolicy works with g section', async () => {
await e.selfAddPolicy('g', 'g', ['frank', 'admin']);
await e.selfAddPolicy('g', 'g', ['frank', 'editor']);
const removed = await e.selfRemoveFilteredPolicy('g', 'g', 0, 'frank');
expect(removed).toBe(true);
expect(adapter.removeFilteredPolicy).not.toHaveBeenCalled();
});
});