From 61aa2e12bddf3fd2be8f6265750d26c09e5e24a9 Mon Sep 17 00:00:00 2001 From: Joachim Van Herwegen Date: Thu, 7 Jan 2021 15:00:53 +0100 Subject: [PATCH] fix: Update acl authorizer to make write rights imply append rights --- src/authorization/WebAclAuthorizer.ts | 17 ++++++++++++++++- .../unit/authorization/WebAclAuthorizer.test.ts | 16 ++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/authorization/WebAclAuthorizer.ts b/src/authorization/WebAclAuthorizer.ts index f464c428d..66565e2bd 100644 --- a/src/authorization/WebAclAuthorizer.ts +++ b/src/authorization/WebAclAuthorizer.ts @@ -64,7 +64,13 @@ export class WebAclAuthorizer extends Authorizer { */ private checkPermission(agent: Credentials, store: Store, mode: string): void { const modeString = ACL[this.capitalize(mode) as 'Write' | 'Read' | 'Append' | 'Control']; - const auths = store.getQuads(null, ACL.mode, modeString, null).map((quad: Quad): Term => quad.subject); + const auths = this.getModePermissions(store, modeString); + + // Having write permissions implies having append permissions + if (modeString === ACL.Append) { + auths.push(...this.getModePermissions(store, ACL.Write)); + } + if (!auths.some((term): boolean => this.hasAccess(agent, term, store))) { const isLoggedIn = typeof agent.webId === 'string'; if (isLoggedIn) { @@ -87,6 +93,15 @@ export class WebAclAuthorizer extends Authorizer { return `${mode[0].toUpperCase()}${mode.slice(1).toLowerCase()}`; } + /** + * Returns the identifiers of all authorizations that grant the given mode access for a resource. + * @param store - The store containing the quads of the acl resource. + * @param aclMode - A valid acl mode (ACL.Write/Read/...) + */ + private getModePermissions(store: Store, aclMode: string): Term[] { + return store.getQuads(null, ACL.mode, aclMode, null).map((quad: Quad): Term => quad.subject); + } + /** * Checks if the given agent has access to the modes specified by the given authorization. * @param agent - Credentials of agent that needs access. diff --git a/test/unit/authorization/WebAclAuthorizer.test.ts b/test/unit/authorization/WebAclAuthorizer.test.ts index c3719d68a..79ee7460e 100644 --- a/test/unit/authorization/WebAclAuthorizer.test.ts +++ b/test/unit/authorization/WebAclAuthorizer.test.ts @@ -155,4 +155,20 @@ describe('A WebAclAuthorizer', (): void => { await expect(promise).rejects.toThrow('No ACL document found for root container'); await expect(promise).rejects.toThrow(InternalServerError); }); + + it('allows an agent to append if they have write access.', async(): Promise => { + credentials.webId = 'http://test.com/user'; + identifier.path = 'http://test.com/foo'; + permissions = { + read: false, + write: false, + append: true, + }; + store.getRepresentation = async(): Promise => ({ data: streamifyArray([ + quad(nn('auth'), nn(`${acl}agent`), nn(credentials.webId!)), + quad(nn('auth'), nn(`${acl}accessTo`), nn(identifier.path)), + quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Write`)), + ]) } as Representation); + await expect(authorizer.handle({ identifier, permissions, credentials })).resolves.toBeUndefined(); + }); });