refactor: Improve logging for access control.

This commit is contained in:
Ruben Verborgh 2021-01-15 18:25:37 +01:00
parent c469df2ebb
commit 7dcde1e0e3
2 changed files with 22 additions and 14 deletions

View File

@ -40,20 +40,21 @@ export class WebAclAuthorizer extends Authorizer {
* Will throw an error if this is not the case. * Will throw an error if this is not the case.
* @param input - Relevant data needed to check if access can be granted. * @param input - Relevant data needed to check if access can be granted.
*/ */
public async handle(input: AuthorizerArgs): Promise<void> { public async handle({ identifier, permissions, credentials }: AuthorizerArgs): Promise<void> {
const store = await this.getAclRecursive(input.identifier);
if (await this.aclManager.isAclDocument(input.identifier)) {
// Solid, §4.3.3: "To discover, read, create, or modify an ACL auxiliary resource, an acl:agent MUST // Solid, §4.3.3: "To discover, read, create, or modify an ACL auxiliary resource, an acl:agent MUST
// have acl:Control privileges per the ACL inheritance algorithm on the resource directly associated with it." // have acl:Control privileges per the ACL inheritance algorithm on the resource directly associated with it."
// https://solid.github.io/specification/protocol#auxiliary-resources-reserved // https://solid.github.io/specification/protocol#auxiliary-resources-reserved
this.checkPermission(input.credentials, store, 'control'); const modes = await this.aclManager.isAclDocument(identifier) ?
} else { [ 'control' ] :
(Object.keys(input.permissions) as (keyof PermissionSet)[]).forEach((key): void => { (Object.keys(permissions) as (keyof PermissionSet)[]).filter((key): boolean => permissions[key]);
if (input.permissions[key]) {
this.checkPermission(input.credentials, store, key); // Verify that all required modes are set for the given agent
} this.logger.debug(`Checking if ${credentials.webId} has ${modes.join()} permissions for ${identifier.path}`);
}); const store = await this.getAclRecursive(identifier);
for (const mode of modes) {
this.checkPermission(credentials, store, mode);
} }
this.logger.debug(`${credentials.webId} has ${modes.join()} permissions for ${identifier.path}`);
} }
/** /**

View File

@ -35,7 +35,7 @@ describe('A WebAclAuthorizer', (): void => {
permissions = { permissions = {
read: true, read: true,
append: false, append: false,
write: false, write: true,
}; };
credentials = {}; credentials = {};
identifier = { path: 'http://test.com/foo' }; identifier = { path: 'http://test.com/foo' };
@ -56,6 +56,7 @@ describe('A WebAclAuthorizer', (): void => {
quad(nn('auth'), nn(`${acl}agentClass`), nn('http://xmlns.com/foaf/0.1/Agent')), quad(nn('auth'), nn(`${acl}agentClass`), nn('http://xmlns.com/foaf/0.1/Agent')),
quad(nn('auth'), nn(`${acl}accessTo`), nn(identifier.path)), quad(nn('auth'), nn(`${acl}accessTo`), nn(identifier.path)),
quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Read`)), quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Read`)),
quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Write`)),
]) } as Representation); ]) } as Representation);
await expect(authorizer.handle({ identifier, permissions, credentials })).resolves.toBeUndefined(); await expect(authorizer.handle({ identifier, permissions, credentials })).resolves.toBeUndefined();
}); });
@ -70,6 +71,7 @@ describe('A WebAclAuthorizer', (): void => {
quad(nn('auth'), nn(`${acl}agentClass`), nn('http://xmlns.com/foaf/0.1/Agent')), quad(nn('auth'), nn(`${acl}agentClass`), nn('http://xmlns.com/foaf/0.1/Agent')),
quad(nn('auth'), nn(`${acl}default`), nn(identifierStrategy.getParentContainer(identifier).path)), quad(nn('auth'), nn(`${acl}default`), nn(identifierStrategy.getParentContainer(identifier).path)),
quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Read`)), quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Read`)),
quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Write`)),
]), ]),
} as Representation; } as Representation;
}; };
@ -81,6 +83,7 @@ describe('A WebAclAuthorizer', (): void => {
quad(nn('auth'), nn(`${acl}agentClass`), nn('http://xmlns.com/foaf/0.1/AuthenticatedAgent')), quad(nn('auth'), nn(`${acl}agentClass`), nn('http://xmlns.com/foaf/0.1/AuthenticatedAgent')),
quad(nn('auth'), nn(`${acl}accessTo`), nn(identifier.path)), quad(nn('auth'), nn(`${acl}accessTo`), nn(identifier.path)),
quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Read`)), quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Read`)),
quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Write`)),
]) } as Representation); ]) } as Representation);
credentials.webId = 'http://test.com/user'; credentials.webId = 'http://test.com/user';
await expect(authorizer.handle({ identifier, permissions, credentials })).resolves.toBeUndefined(); await expect(authorizer.handle({ identifier, permissions, credentials })).resolves.toBeUndefined();
@ -91,6 +94,7 @@ describe('A WebAclAuthorizer', (): void => {
quad(nn('auth'), nn(`${acl}agentClass`), nn('http://xmlns.com/foaf/0.1/AuthenticatedAgent')), quad(nn('auth'), nn(`${acl}agentClass`), nn('http://xmlns.com/foaf/0.1/AuthenticatedAgent')),
quad(nn('auth'), nn(`${acl}accessTo`), nn(identifier.path)), quad(nn('auth'), nn(`${acl}accessTo`), nn(identifier.path)),
quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Read`)), quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Read`)),
quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Write`)),
]) } as Representation); ]) } as Representation);
await expect(authorizer.handle({ identifier, permissions, credentials })).rejects.toThrow(UnauthorizedHttpError); await expect(authorizer.handle({ identifier, permissions, credentials })).rejects.toThrow(UnauthorizedHttpError);
}); });
@ -101,6 +105,7 @@ describe('A WebAclAuthorizer', (): void => {
quad(nn('auth'), nn(`${acl}agent`), nn(credentials.webId!)), quad(nn('auth'), nn(`${acl}agent`), nn(credentials.webId!)),
quad(nn('auth'), nn(`${acl}accessTo`), nn(identifier.path)), quad(nn('auth'), nn(`${acl}accessTo`), nn(identifier.path)),
quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Read`)), quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Read`)),
quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Write`)),
]) } as Representation); ]) } as Representation);
await expect(authorizer.handle({ identifier, permissions, credentials })).resolves.toBeUndefined(); await expect(authorizer.handle({ identifier, permissions, credentials })).resolves.toBeUndefined();
}); });
@ -111,6 +116,7 @@ describe('A WebAclAuthorizer', (): void => {
quad(nn('auth'), nn(`${acl}agent`), nn('http://test.com/differentUser')), quad(nn('auth'), nn(`${acl}agent`), nn('http://test.com/differentUser')),
quad(nn('auth'), nn(`${acl}accessTo`), nn(identifier.path)), quad(nn('auth'), nn(`${acl}accessTo`), nn(identifier.path)),
quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Read`)), quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Read`)),
quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Write`)),
]) } as Representation); ]) } as Representation);
await expect(authorizer.handle({ identifier, permissions, credentials })).rejects.toThrow(ForbiddenHttpError); await expect(authorizer.handle({ identifier, permissions, credentials })).rejects.toThrow(ForbiddenHttpError);
}); });
@ -134,6 +140,7 @@ describe('A WebAclAuthorizer', (): void => {
quad(nn('auth'), nn(`${acl}agent`), nn(credentials.webId!)), quad(nn('auth'), nn(`${acl}agent`), nn(credentials.webId!)),
quad(nn('auth'), nn(`${acl}accessTo`), nn(identifier.path)), quad(nn('auth'), nn(`${acl}accessTo`), nn(identifier.path)),
quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Read`)), quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Read`)),
quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Write`)),
]) } as Representation); ]) } as Representation);
identifier = await aclManager.getAclDocument(identifier); identifier = await aclManager.getAclDocument(identifier);
await expect(authorizer.handle({ identifier, permissions, credentials })).rejects.toThrow(ForbiddenHttpError); await expect(authorizer.handle({ identifier, permissions, credentials })).rejects.toThrow(ForbiddenHttpError);