mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
feat: Replace acl specific permissions with generic permissions
This required AuxiliaryStrategy to have a new function indicating if the auxiliary resource just used its associated resource authorization or its own.
This commit is contained in:
@@ -7,7 +7,8 @@ function getPermissions(allow: boolean): Permission {
|
||||
read: allow,
|
||||
write: allow,
|
||||
append: allow,
|
||||
control: allow,
|
||||
create: allow,
|
||||
delete: allow,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { CredentialGroup } from '../../../src/authentication/Credentials';
|
||||
import { AuxiliaryReader } from '../../../src/authorization/AuxiliaryReader';
|
||||
import type { PermissionReader } from '../../../src/authorization/PermissionReader';
|
||||
import type { AuxiliaryIdentifierStrategy } from '../../../src/ldp/auxiliary/AuxiliaryIdentifierStrategy';
|
||||
import type { AuxiliaryStrategy } from '../../../src/ldp/auxiliary/AuxiliaryStrategy';
|
||||
import type { PermissionSet } from '../../../src/ldp/permissions/Permissions';
|
||||
import type { ResourceIdentifier } from '../../../src/ldp/representation/ResourceIdentifier';
|
||||
import { NotImplementedHttpError } from '../../../src/util/errors/NotImplementedHttpError';
|
||||
@@ -12,8 +12,8 @@ describe('An AuxiliaryReader', (): void => {
|
||||
const associatedIdentifier = { path: 'http://test.com/foo' };
|
||||
const auxiliaryIdentifier = { path: 'http://test.com/foo.dummy' };
|
||||
const permissionSet: PermissionSet = { [CredentialGroup.agent]: { read: true }};
|
||||
let source: PermissionReader;
|
||||
let strategy: AuxiliaryIdentifierStrategy;
|
||||
let source: jest.Mocked<PermissionReader>;
|
||||
let strategy: jest.Mocked<AuxiliaryStrategy>;
|
||||
let reader: AuxiliaryReader;
|
||||
|
||||
beforeEach(async(): Promise<void> => {
|
||||
@@ -27,6 +27,7 @@ describe('An AuxiliaryReader', (): void => {
|
||||
isAuxiliaryIdentifier: jest.fn((identifier: ResourceIdentifier): boolean => identifier.path.endsWith(suffix)),
|
||||
getAssociatedIdentifier: jest.fn((identifier: ResourceIdentifier): ResourceIdentifier =>
|
||||
({ path: identifier.path.slice(0, -suffix.length) })),
|
||||
usesOwnAuthorization: jest.fn().mockReturnValue(false),
|
||||
} as any;
|
||||
reader = new AuxiliaryReader(source, strategy);
|
||||
});
|
||||
@@ -39,7 +40,12 @@ describe('An AuxiliaryReader', (): void => {
|
||||
);
|
||||
await expect(reader.canHandle({ identifier: associatedIdentifier, credentials }))
|
||||
.rejects.toThrow(NotImplementedHttpError);
|
||||
source.canHandle = jest.fn().mockRejectedValue(new Error('no source support'));
|
||||
|
||||
strategy.usesOwnAuthorization.mockReturnValueOnce(true);
|
||||
await expect(reader.canHandle({ identifier: auxiliaryIdentifier, credentials }))
|
||||
.rejects.toThrow(NotImplementedHttpError);
|
||||
|
||||
source.canHandle.mockRejectedValue(new Error('no source support'));
|
||||
await expect(reader.canHandle({ identifier: auxiliaryIdentifier, credentials }))
|
||||
.rejects.toThrow('no source support');
|
||||
});
|
||||
@@ -61,9 +67,15 @@ describe('An AuxiliaryReader', (): void => {
|
||||
expect(source.handleSafe).toHaveBeenLastCalledWith(
|
||||
{ identifier: associatedIdentifier, credentials },
|
||||
);
|
||||
|
||||
await expect(reader.handleSafe({ identifier: associatedIdentifier, credentials }))
|
||||
.rejects.toThrow(NotImplementedHttpError);
|
||||
source.handleSafe = jest.fn().mockRejectedValue(new Error('no source support'));
|
||||
|
||||
strategy.usesOwnAuthorization.mockReturnValueOnce(true);
|
||||
await expect(reader.canHandle({ identifier: auxiliaryIdentifier, credentials }))
|
||||
.rejects.toThrow(NotImplementedHttpError);
|
||||
|
||||
source.handleSafe.mockRejectedValue(new Error('no source support'));
|
||||
await expect(reader.handleSafe({ identifier: auxiliaryIdentifier, credentials }))
|
||||
.rejects.toThrow('no source support');
|
||||
});
|
||||
|
||||
@@ -44,13 +44,13 @@ describe('A UnionPermissionReader', (): void => {
|
||||
|
||||
it('merges same fields using false > true > undefined.', async(): Promise<void> => {
|
||||
readers[0].handle.mockResolvedValue(
|
||||
{ [CredentialGroup.agent]: { read: true, write: false, append: undefined, control: true }},
|
||||
{ [CredentialGroup.agent]: { read: true, write: false, append: undefined, create: true, delete: undefined }},
|
||||
);
|
||||
readers[1].handle.mockResolvedValue(
|
||||
{ [CredentialGroup.agent]: { read: false, write: true, append: true, control: true }},
|
||||
{ [CredentialGroup.agent]: { read: false, write: true, append: true, create: true, delete: undefined }},
|
||||
);
|
||||
await expect(unionReader.handle(input)).resolves.toEqual({
|
||||
[CredentialGroup.agent]: { read: false, write: false, append: true, control: true },
|
||||
[CredentialGroup.agent]: { read: false, write: false, append: true, create: true },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -12,7 +12,6 @@ import { INTERNAL_QUADS } from '../../../src/util/ContentTypes';
|
||||
import { ForbiddenHttpError } from '../../../src/util/errors/ForbiddenHttpError';
|
||||
import { InternalServerError } from '../../../src/util/errors/InternalServerError';
|
||||
import { NotFoundHttpError } from '../../../src/util/errors/NotFoundHttpError';
|
||||
import { NotImplementedHttpError } from '../../../src/util/errors/NotImplementedHttpError';
|
||||
import { SingleRootIdentifierStrategy } from '../../../src/util/identifiers/SingleRootIdentifierStrategy';
|
||||
import { guardedStreamFrom } from '../../../src/util/StreamUtil';
|
||||
|
||||
@@ -51,10 +50,8 @@ describe('A WebAclReader', (): void => {
|
||||
reader = new WebAclReader(aclStrategy, store, identifierStrategy, accessChecker);
|
||||
});
|
||||
|
||||
it('handles all non-acl inputs.', async(): Promise<void> => {
|
||||
await expect(reader.canHandle({ identifier, credentials })).resolves.toBeUndefined();
|
||||
await expect(reader.canHandle({ identifier: aclStrategy.getAuxiliaryIdentifier(identifier) } as any))
|
||||
.rejects.toThrow(NotImplementedHttpError);
|
||||
it('handles all input.', async(): Promise<void> => {
|
||||
await expect(reader.canHandle({ } as any)).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it('returns undefined permissions for undefined credentials.', async(): Promise<void> => {
|
||||
@@ -137,15 +134,39 @@ describe('A WebAclReader', (): void => {
|
||||
await expect(promise).rejects.toThrow(ForbiddenHttpError);
|
||||
});
|
||||
|
||||
it('allows an agent to append if they have write access.', async(): Promise<void> => {
|
||||
it('allows an agent to append/create/delete if they have write access.', async(): Promise<void> => {
|
||||
store.getRepresentation.mockResolvedValue({ data: guardedStreamFrom([
|
||||
quad(nn('auth'), nn(`${rdf}type`), nn(`${acl}Authorization`)),
|
||||
quad(nn('auth'), nn(`${acl}accessTo`), nn(identifier.path)),
|
||||
quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Write`)),
|
||||
]) } as Representation);
|
||||
await expect(reader.handle({ identifier, credentials })).resolves.toEqual({
|
||||
[CredentialGroup.public]: { write: true, append: true },
|
||||
[CredentialGroup.agent]: { write: true, append: true },
|
||||
[CredentialGroup.public]: { write: true, append: true, create: true, delete: true },
|
||||
[CredentialGroup.agent]: { write: true, append: true, create: true, delete: true },
|
||||
});
|
||||
});
|
||||
|
||||
it('allows everything on an acl resource if control permissions are granted.', async(): Promise<void> => {
|
||||
store.getRepresentation.mockResolvedValue({ data: guardedStreamFrom([
|
||||
quad(nn('auth'), nn(`${rdf}type`), nn(`${acl}Authorization`)),
|
||||
quad(nn('auth'), nn(`${acl}accessTo`), nn(identifier.path)),
|
||||
quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Control`)),
|
||||
]) } as Representation);
|
||||
await expect(reader.handle({ identifier: { path: `${identifier.path}.acl` }, credentials })).resolves.toEqual({
|
||||
[CredentialGroup.public]: { read: true, write: true, append: true, create: true, delete: true, control: true },
|
||||
[CredentialGroup.agent]: { read: true, write: true, append: true, create: true, delete: true, control: true },
|
||||
});
|
||||
});
|
||||
|
||||
it('rejects everything on an acl resource if there are no control permissions.', async(): Promise<void> => {
|
||||
store.getRepresentation.mockResolvedValue({ data: guardedStreamFrom([
|
||||
quad(nn('auth'), nn(`${rdf}type`), nn(`${acl}Authorization`)),
|
||||
quad(nn('auth'), nn(`${acl}accessTo`), nn(identifier.path)),
|
||||
quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Read`)),
|
||||
]) } as Representation);
|
||||
await expect(reader.handle({ identifier: { path: `${identifier.path}.acl` }, credentials })).resolves.toEqual({
|
||||
[CredentialGroup.public]: {},
|
||||
[CredentialGroup.agent]: {},
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user