CommunitySolidServer/test/unit/authorization/AuxiliaryReader.test.ts

92 lines
4.6 KiB
TypeScript

import { CredentialGroup } from '../../../src/authentication/Credentials';
import { AuxiliaryReader } from '../../../src/authorization/AuxiliaryReader';
import type { PermissionReaderInput, PermissionReader } from '../../../src/authorization/PermissionReader';
import type { AccessMap, PermissionMap, PermissionSet } from '../../../src/authorization/permissions/Permissions';
import { AccessMode } from '../../../src/authorization/permissions/Permissions';
import type { AuxiliaryStrategy } from '../../../src/http/auxiliary/AuxiliaryStrategy';
import type { ResourceIdentifier } from '../../../src/http/representation/ResourceIdentifier';
import { map } from '../../../src/util/IterableUtil';
import { IdentifierMap, IdentifierSetMultiMap } from '../../../src/util/map/IdentifierMap';
import { compareMaps } from '../../util/Util';
describe('An AuxiliaryReader', (): void => {
const suffix1 = '.dummy1';
const suffix2 = '.dummy2';
const credentials = {};
const subjectIdentifier = { path: 'http://test.com/foo' };
const auxiliaryIdentifier1 = { path: 'http://test.com/foo.dummy1' };
const auxiliaryIdentifier2 = { path: 'http://test.com/foo.dummy2' };
const permissionSet: PermissionSet = { [CredentialGroup.agent]: { read: true }};
let source: jest.Mocked<PermissionReader>;
let strategy: jest.Mocked<AuxiliaryStrategy>;
let reader: AuxiliaryReader;
function handleSafe({ requestedModes }: PermissionReaderInput): PermissionMap {
return new IdentifierMap(map(requestedModes.distinctKeys(), (identifier): [ResourceIdentifier, PermissionSet] =>
[ identifier, permissionSet ]));
}
beforeEach(async(): Promise<void> => {
source = {
handleSafe: jest.fn(handleSafe),
} as any;
strategy = {
isAuxiliaryIdentifier: jest.fn((identifier: ResourceIdentifier): boolean =>
identifier.path.endsWith(suffix1) || identifier.path.endsWith(suffix2)),
getSubjectIdentifier: jest.fn((identifier: ResourceIdentifier): ResourceIdentifier =>
({ path: identifier.path.slice(0, -suffix1.length) })),
usesOwnAuthorization: jest.fn().mockReturnValue(false),
} as any;
reader = new AuxiliaryReader(source, strategy);
});
it('handles resources by sending the updated parameters to the source.', async(): Promise<void> => {
const requestedModes: AccessMap = new IdentifierSetMultiMap<AccessMode>([
[ auxiliaryIdentifier1, AccessMode.delete ],
[{ path: 'http://example.com/other' }, AccessMode.read ],
]);
const permissionMap: PermissionMap = new IdentifierMap([
[ subjectIdentifier, permissionSet ],
[{ path: 'http://example.com/other' }, permissionSet ],
[ auxiliaryIdentifier1, permissionSet ],
]);
compareMaps(await reader.handle({ credentials, requestedModes }), permissionMap);
const mock = source.handleSafe.mock.calls[0][0];
expect(mock.credentials).toBe(credentials);
expect(mock.requestedModes.get(subjectIdentifier)).toEqual(new Set([ AccessMode.delete ]));
expect(mock.requestedModes.get({ path: 'http://example.com/other' })).toEqual(new Set([ AccessMode.read ]));
expect(mock.requestedModes.size).toBe(2);
expect(mock.requestedModes).not.toEqual(requestedModes);
});
it('applies an empty PermissionSet if no permissions were found for the subject.', async(): Promise<void> => {
source.handleSafe.mockResolvedValueOnce(new IdentifierMap());
const requestedModes: AccessMap = new IdentifierSetMultiMap<AccessMode>([
[ auxiliaryIdentifier1, AccessMode.delete ],
]);
const permissionMap: PermissionMap = new IdentifierMap([
[ auxiliaryIdentifier1, {}],
]);
compareMaps(await reader.handle({ credentials, requestedModes }), permissionMap);
});
it('combines modes if multiple different auxiliary resources have the same subject.', async(): Promise<void> => {
const requestedModes: AccessMap = new IdentifierSetMultiMap<AccessMode>([
[ auxiliaryIdentifier1, AccessMode.write ],
[ auxiliaryIdentifier2, AccessMode.read ],
[ subjectIdentifier, AccessMode.delete ],
]);
const resultSet = { [CredentialGroup.agent]: { read: true, write: true, delete: true }};
source.handleSafe.mockResolvedValueOnce(new IdentifierMap([[ subjectIdentifier, resultSet ]]));
const permissionMap: PermissionMap = new IdentifierMap([
[ subjectIdentifier, resultSet ],
[ auxiliaryIdentifier1, resultSet ],
[ auxiliaryIdentifier2, resultSet ],
]);
compareMaps(await reader.handle({ credentials, requestedModes }), permissionMap);
expect(source.handleSafe.mock.calls[0][0].requestedModes.get(subjectIdentifier))
.toEqual(new Set([ AccessMode.write, AccessMode.read, AccessMode.delete ]));
});
});