mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
feat: Create separate authorizer for auxiliary functions
This commit is contained in:
parent
8339413ab4
commit
7f34fe6ae3
@ -26,7 +26,27 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
"@id": "urn:solid-server:default:AclAuthorizer",
|
"@id": "urn:solid-server:default:AclBasedAuthorizer",
|
||||||
|
"@type": "WaterfallHandler",
|
||||||
|
"WaterfallHandler:_handlers": [
|
||||||
|
{
|
||||||
|
"comment": "This authorizer makes sure that for auxiliary resources, the main authorizer gets called with the associated identifier.",
|
||||||
|
"@type": "AuxiliaryAuthorizer",
|
||||||
|
"AuxiliaryAuthorizer:_resourceAuthorizer": {
|
||||||
|
"@id": "urn:solid-server:default:WebAclAuthorizer"
|
||||||
|
},
|
||||||
|
"AuxiliaryAuthorizer:_auxStrategy": {
|
||||||
|
"@id": "urn:solid-server:default:AuxiliaryStrategy"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@id": "urn:solid-server:default:WebAclAuthorizer"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"@id": "urn:solid-server:default:WebAclAuthorizer",
|
||||||
"@type": "WebAclAuthorizer",
|
"@type": "WebAclAuthorizer",
|
||||||
"WebAclAuthorizer:_aclStrategy": {
|
"WebAclAuthorizer:_aclStrategy": {
|
||||||
"@id": "urn:solid-server:default:AclIdentifierStrategy"
|
"@id": "urn:solid-server:default:AclIdentifierStrategy"
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
"@id": "urn:solid-server:default:PermissionsExtractor"
|
"@id": "urn:solid-server:default:PermissionsExtractor"
|
||||||
},
|
},
|
||||||
"AuthenticatedLdpHandler:_args_authorizer": {
|
"AuthenticatedLdpHandler:_args_authorizer": {
|
||||||
"@id": "urn:solid-server:default:AclAuthorizer"
|
"@id": "urn:solid-server:default:AclBasedAuthorizer"
|
||||||
},
|
},
|
||||||
"AuthenticatedLdpHandler:_args_operationHandler": {
|
"AuthenticatedLdpHandler:_args_operationHandler": {
|
||||||
"@id": "urn:solid-server:default:OperationHandler"
|
"@id": "urn:solid-server:default:OperationHandler"
|
||||||
|
@ -20,6 +20,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"@id": "urn:solid-server:default:AuxiliaryStrategy",
|
||||||
|
"@type": "RoutingAuxiliaryStrategy",
|
||||||
|
"RoutingAuxiliaryStrategy:_sources": [
|
||||||
|
{
|
||||||
|
"@id": "urn:solid-server:default:AclStrategy"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
"@id": "urn:solid-server:default:ResourceStore_Locking",
|
"@id": "urn:solid-server:default:ResourceStore_Locking",
|
||||||
"@type": "LockingResourceStore",
|
"@type": "LockingResourceStore",
|
||||||
|
50
src/authorization/AuxiliaryAuthorizer.ts
Normal file
50
src/authorization/AuxiliaryAuthorizer.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import type { AuxiliaryIdentifierStrategy } from '../ldp/auxiliary/AuxiliaryIdentifierStrategy';
|
||||||
|
import { getLoggerFor } from '../logging/LogUtil';
|
||||||
|
import { NotImplementedHttpError } from '../util/errors/NotImplementedHttpError';
|
||||||
|
import type { AuthorizerArgs } from './Authorizer';
|
||||||
|
import { Authorizer } from './Authorizer';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An authorizer for auxiliary resources such as acl or shape resources.
|
||||||
|
* The access permissions of an auxiliary resource depend on those of the resource it is associated with.
|
||||||
|
* This authorizer calls the source authorizer with the identifier of the associated resource.
|
||||||
|
*/
|
||||||
|
export class AuxiliaryAuthorizer extends Authorizer {
|
||||||
|
protected readonly logger = getLoggerFor(this);
|
||||||
|
|
||||||
|
private readonly resourceAuthorizer: Authorizer;
|
||||||
|
private readonly auxStrategy: AuxiliaryIdentifierStrategy;
|
||||||
|
|
||||||
|
public constructor(resourceAuthorizer: Authorizer, auxStrategy: AuxiliaryIdentifierStrategy) {
|
||||||
|
super();
|
||||||
|
this.resourceAuthorizer = resourceAuthorizer;
|
||||||
|
this.auxStrategy = auxStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async canHandle(auxiliaryAuth: AuthorizerArgs): Promise<void> {
|
||||||
|
const resourceAuth = this.getRequiredAuthorization(auxiliaryAuth);
|
||||||
|
return this.resourceAuthorizer.canHandle(resourceAuth);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async handle(auxiliaryAuth: AuthorizerArgs): Promise<void> {
|
||||||
|
const resourceAuth = this.getRequiredAuthorization(auxiliaryAuth);
|
||||||
|
this.logger.debug(`Checking auth request for ${auxiliaryAuth.identifier.path} on ${resourceAuth.identifier.path}`);
|
||||||
|
return this.resourceAuthorizer.handle(resourceAuth);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async handleSafe(auxiliaryAuth: AuthorizerArgs): Promise<void> {
|
||||||
|
const resourceAuth = this.getRequiredAuthorization(auxiliaryAuth);
|
||||||
|
this.logger.debug(`Checking auth request for ${auxiliaryAuth.identifier.path} to ${resourceAuth.identifier.path}`);
|
||||||
|
return this.resourceAuthorizer.handleSafe(resourceAuth);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getRequiredAuthorization(auxiliaryAuth: AuthorizerArgs): AuthorizerArgs {
|
||||||
|
if (!this.auxStrategy.isAuxiliaryIdentifier(auxiliaryAuth.identifier)) {
|
||||||
|
throw new NotImplementedHttpError('AuxiliaryAuthorizer only supports auxiliary resources.');
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...auxiliaryAuth,
|
||||||
|
identifier: this.auxStrategy.getAssociatedIdentifier(auxiliaryAuth.identifier),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,7 @@ import type { ResourceStore } from '../storage/ResourceStore';
|
|||||||
import { INTERNAL_QUADS } from '../util/ContentTypes';
|
import { INTERNAL_QUADS } from '../util/ContentTypes';
|
||||||
import { ForbiddenHttpError } from '../util/errors/ForbiddenHttpError';
|
import { ForbiddenHttpError } from '../util/errors/ForbiddenHttpError';
|
||||||
import { NotFoundHttpError } from '../util/errors/NotFoundHttpError';
|
import { NotFoundHttpError } from '../util/errors/NotFoundHttpError';
|
||||||
|
import { NotImplementedHttpError } from '../util/errors/NotImplementedHttpError';
|
||||||
import { UnauthorizedHttpError } from '../util/errors/UnauthorizedHttpError';
|
import { UnauthorizedHttpError } from '../util/errors/UnauthorizedHttpError';
|
||||||
import type { IdentifierStrategy } from '../util/identifiers/IdentifierStrategy';
|
import type { IdentifierStrategy } from '../util/identifiers/IdentifierStrategy';
|
||||||
import { ACL, FOAF } from '../util/Vocabularies';
|
import { ACL, FOAF } from '../util/Vocabularies';
|
||||||
@ -36,6 +37,12 @@ export class WebAclAuthorizer extends Authorizer {
|
|||||||
this.identifierStrategy = identifierStrategy;
|
this.identifierStrategy = identifierStrategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async canHandle({ identifier }: AuthorizerArgs): Promise<void> {
|
||||||
|
if (this.aclStrategy.isAuxiliaryIdentifier(identifier)) {
|
||||||
|
throw new NotImplementedHttpError('WebAclAuthorizer does not support permissions on acl files.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if an agent is allowed to execute the requested actions.
|
* Checks if an agent is allowed to execute the requested actions.
|
||||||
* Will throw an error if this is not the case.
|
* Will throw an error if this is not the case.
|
||||||
@ -128,7 +135,7 @@ export class WebAclAuthorizer extends Authorizer {
|
|||||||
/**
|
/**
|
||||||
* Returns the acl triples that are relevant for the given identifier.
|
* Returns the acl triples that are relevant for the given identifier.
|
||||||
* These can either be from a corresponding acl file or an acl file higher up with defaults.
|
* These can either be from a corresponding acl file or an acl file higher up with defaults.
|
||||||
* Rethrows any non-NotFoundHttpErrors thrown by the AclManager or ResourceStore.
|
* Rethrows any non-NotFoundHttpErrors thrown by the ResourceStore.
|
||||||
* @param id - ResourceIdentifier of which we need the acl triples.
|
* @param id - ResourceIdentifier of which we need the acl triples.
|
||||||
* @param recurse - Only used internally for recursion.
|
* @param recurse - Only used internally for recursion.
|
||||||
*
|
*
|
||||||
@ -137,14 +144,12 @@ export class WebAclAuthorizer extends Authorizer {
|
|||||||
private async getAclRecursive(id: ResourceIdentifier, recurse?: boolean): Promise<Store> {
|
private async getAclRecursive(id: ResourceIdentifier, recurse?: boolean): Promise<Store> {
|
||||||
this.logger.debug(`Trying to read the direct ACL document of ${id.path}`);
|
this.logger.debug(`Trying to read the direct ACL document of ${id.path}`);
|
||||||
try {
|
try {
|
||||||
const isAcl = this.aclStrategy.isAuxiliaryIdentifier(id);
|
const acl = this.aclStrategy.getAuxiliaryIdentifier(id);
|
||||||
const acl = isAcl ? id : this.aclStrategy.getAuxiliaryIdentifier(id);
|
|
||||||
this.logger.debug(`Trying to read the ACL document ${acl.path}`);
|
this.logger.debug(`Trying to read the ACL document ${acl.path}`);
|
||||||
const data = await this.resourceStore.getRepresentation(acl, { type: { [INTERNAL_QUADS]: 1 }});
|
const data = await this.resourceStore.getRepresentation(acl, { type: { [INTERNAL_QUADS]: 1 }});
|
||||||
this.logger.info(`Reading ACL statements from ${acl.path}`);
|
this.logger.info(`Reading ACL statements from ${acl.path}`);
|
||||||
|
|
||||||
const resourceId = isAcl ? this.aclStrategy.getAssociatedIdentifier(id) : id;
|
return this.filterData(data, recurse ? ACL.default : ACL.accessTo, id.path);
|
||||||
return this.filterData(data, recurse ? ACL.default : ACL.accessTo, resourceId.path);
|
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
if (NotFoundHttpError.isInstance(error)) {
|
if (NotFoundHttpError.isInstance(error)) {
|
||||||
this.logger.debug(`No direct ACL document found for ${id.path}`);
|
this.logger.debug(`No direct ACL document found for ${id.path}`);
|
||||||
|
@ -10,6 +10,7 @@ export * from './authentication/UnsecureWebIdExtractor';
|
|||||||
// Authorization
|
// Authorization
|
||||||
export * from './authorization/AllowEverythingAuthorizer';
|
export * from './authorization/AllowEverythingAuthorizer';
|
||||||
export * from './authorization/Authorizer';
|
export * from './authorization/Authorizer';
|
||||||
|
export * from './authorization/AuxiliaryAuthorizer';
|
||||||
export * from './authorization/WebAclAuthorizer';
|
export * from './authorization/WebAclAuthorizer';
|
||||||
|
|
||||||
// Init
|
// Init
|
||||||
|
76
test/unit/authorization/AuxiliaryAuthorizer.test.ts
Normal file
76
test/unit/authorization/AuxiliaryAuthorizer.test.ts
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
import type { Authorizer } from '../../../src/authorization/Authorizer';
|
||||||
|
import { AuxiliaryAuthorizer } from '../../../src/authorization/AuxiliaryAuthorizer';
|
||||||
|
import type { AuxiliaryIdentifierStrategy } from '../../../src/ldp/auxiliary/AuxiliaryIdentifierStrategy';
|
||||||
|
import type { PermissionSet } from '../../../src/ldp/permissions/PermissionSet';
|
||||||
|
import type { ResourceIdentifier } from '../../../src/ldp/representation/ResourceIdentifier';
|
||||||
|
import { NotImplementedHttpError } from '../../../src/util/errors/NotImplementedHttpError';
|
||||||
|
|
||||||
|
describe('An AuxiliaryAuthorizer', (): void => {
|
||||||
|
const suffix = '.dummy';
|
||||||
|
const credentials = {};
|
||||||
|
const associatedIdentifier = { path: 'http://test.com/foo' };
|
||||||
|
const auxiliaryIdentifier = { path: 'http://test.com/foo.dummy' };
|
||||||
|
let permissions: PermissionSet;
|
||||||
|
let source: Authorizer;
|
||||||
|
let strategy: AuxiliaryIdentifierStrategy;
|
||||||
|
let authorizer: AuxiliaryAuthorizer;
|
||||||
|
|
||||||
|
beforeEach(async(): Promise<void> => {
|
||||||
|
permissions = {
|
||||||
|
read: true,
|
||||||
|
write: true,
|
||||||
|
append: true,
|
||||||
|
control: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
source = {
|
||||||
|
canHandle: jest.fn(),
|
||||||
|
handle: jest.fn(),
|
||||||
|
handleSafe: jest.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
|
strategy = {
|
||||||
|
isAuxiliaryIdentifier: jest.fn((identifier: ResourceIdentifier): boolean => identifier.path.endsWith(suffix)),
|
||||||
|
getAssociatedIdentifier: jest.fn((identifier: ResourceIdentifier): ResourceIdentifier =>
|
||||||
|
({ path: identifier.path.slice(0, -suffix.length) })),
|
||||||
|
} as any;
|
||||||
|
authorizer = new AuxiliaryAuthorizer(source, strategy);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can handle auxiliary resources if the source supports the associated resource.', async(): Promise<void> => {
|
||||||
|
await expect(authorizer.canHandle({ identifier: auxiliaryIdentifier, credentials, permissions }))
|
||||||
|
.resolves.toBeUndefined();
|
||||||
|
expect(source.canHandle).toHaveBeenLastCalledWith(
|
||||||
|
{ identifier: associatedIdentifier, credentials, permissions },
|
||||||
|
);
|
||||||
|
await expect(authorizer.canHandle({ identifier: associatedIdentifier, credentials, permissions }))
|
||||||
|
.rejects.toThrow(NotImplementedHttpError);
|
||||||
|
source.canHandle = jest.fn().mockRejectedValue(new Error('no source support'));
|
||||||
|
await expect(authorizer.canHandle({ identifier: auxiliaryIdentifier, credentials, permissions }))
|
||||||
|
.rejects.toThrow('no source support');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles resources by sending the updated parameters to the source.', async(): Promise<void> => {
|
||||||
|
await expect(authorizer.handle({ identifier: auxiliaryIdentifier, credentials, permissions }))
|
||||||
|
.resolves.toBeUndefined();
|
||||||
|
expect(source.handle).toHaveBeenLastCalledWith(
|
||||||
|
{ identifier: associatedIdentifier, credentials, permissions },
|
||||||
|
);
|
||||||
|
// Safety checks are not present when calling `handle`
|
||||||
|
await expect(authorizer.handle({ identifier: associatedIdentifier, credentials, permissions }))
|
||||||
|
.rejects.toThrow(NotImplementedHttpError);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('combines both checking and handling when calling handleSafe.', async(): Promise<void> => {
|
||||||
|
await expect(authorizer.handleSafe({ identifier: auxiliaryIdentifier, credentials, permissions }))
|
||||||
|
.resolves.toBeUndefined();
|
||||||
|
expect(source.handleSafe).toHaveBeenLastCalledWith(
|
||||||
|
{ identifier: associatedIdentifier, credentials, permissions },
|
||||||
|
);
|
||||||
|
await expect(authorizer.handleSafe({ identifier: associatedIdentifier, credentials, permissions }))
|
||||||
|
.rejects.toThrow(NotImplementedHttpError);
|
||||||
|
source.handleSafe = jest.fn().mockRejectedValue(new Error('no source support'));
|
||||||
|
await expect(authorizer.handleSafe({ identifier: auxiliaryIdentifier, credentials, permissions }))
|
||||||
|
.rejects.toThrow('no source support');
|
||||||
|
});
|
||||||
|
});
|
@ -1,5 +1,4 @@
|
|||||||
import { namedNode, quad } from '@rdfjs/data-model';
|
import { namedNode, quad } from '@rdfjs/data-model';
|
||||||
import streamifyArray from 'streamify-array';
|
|
||||||
import type { Credentials } from '../../../src/authentication/Credentials';
|
import type { Credentials } from '../../../src/authentication/Credentials';
|
||||||
import { WebAclAuthorizer } from '../../../src/authorization/WebAclAuthorizer';
|
import { WebAclAuthorizer } from '../../../src/authorization/WebAclAuthorizer';
|
||||||
import type { AuxiliaryIdentifierStrategy } from '../../../src/ldp/auxiliary/AuxiliaryIdentifierStrategy';
|
import type { AuxiliaryIdentifierStrategy } from '../../../src/ldp/auxiliary/AuxiliaryIdentifierStrategy';
|
||||||
@ -9,8 +8,10 @@ import type { ResourceIdentifier } from '../../../src/ldp/representation/Resourc
|
|||||||
import type { ResourceStore } from '../../../src/storage/ResourceStore';
|
import type { ResourceStore } from '../../../src/storage/ResourceStore';
|
||||||
import { ForbiddenHttpError } from '../../../src/util/errors/ForbiddenHttpError';
|
import { ForbiddenHttpError } from '../../../src/util/errors/ForbiddenHttpError';
|
||||||
import { NotFoundHttpError } from '../../../src/util/errors/NotFoundHttpError';
|
import { NotFoundHttpError } from '../../../src/util/errors/NotFoundHttpError';
|
||||||
|
import { NotImplementedHttpError } from '../../../src/util/errors/NotImplementedHttpError';
|
||||||
import { UnauthorizedHttpError } from '../../../src/util/errors/UnauthorizedHttpError';
|
import { UnauthorizedHttpError } from '../../../src/util/errors/UnauthorizedHttpError';
|
||||||
import { SingleRootIdentifierStrategy } from '../../../src/util/identifiers/SingleRootIdentifierStrategy';
|
import { SingleRootIdentifierStrategy } from '../../../src/util/identifiers/SingleRootIdentifierStrategy';
|
||||||
|
import { guardedStreamFrom } from '../../../src/util/StreamUtil';
|
||||||
|
|
||||||
const nn = namedNode;
|
const nn = namedNode;
|
||||||
|
|
||||||
@ -45,13 +46,15 @@ describe('A WebAclAuthorizer', (): void => {
|
|||||||
authorizer = new WebAclAuthorizer(aclStrategy, store, identifierStrategy);
|
authorizer = new WebAclAuthorizer(aclStrategy, store, identifierStrategy);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('handles all inputs.', async(): Promise<void> => {
|
it('handles all non-acl inputs.', async(): Promise<void> => {
|
||||||
authorizer = new WebAclAuthorizer(aclStrategy, null as any, identifierStrategy);
|
authorizer = new WebAclAuthorizer(aclStrategy, null as any, identifierStrategy);
|
||||||
await expect(authorizer.canHandle({} as any)).resolves.toBeUndefined();
|
await expect(authorizer.canHandle({ identifier } as any)).resolves.toBeUndefined();
|
||||||
|
await expect(authorizer.canHandle({ identifier: aclStrategy.getAuxiliaryIdentifier(identifier) } as any))
|
||||||
|
.rejects.toThrow(NotImplementedHttpError);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('allows access if the acl file allows all agents.', async(): Promise<void> => {
|
it('allows access if the acl file allows all agents.', async(): Promise<void> => {
|
||||||
store.getRepresentation = async(): Promise<Representation> => ({ data: streamifyArray([
|
store.getRepresentation = async(): Promise<Representation> => ({ data: guardedStreamFrom([
|
||||||
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`)),
|
||||||
@ -66,7 +69,7 @@ describe('A WebAclAuthorizer', (): void => {
|
|||||||
throw new NotFoundHttpError();
|
throw new NotFoundHttpError();
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
data: streamifyArray([
|
data: guardedStreamFrom([
|
||||||
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`)),
|
||||||
@ -78,7 +81,7 @@ describe('A WebAclAuthorizer', (): void => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('allows access to authorized agents if the acl files allows all authorized users.', async(): Promise<void> => {
|
it('allows access to authorized agents if the acl files allows all authorized users.', async(): Promise<void> => {
|
||||||
store.getRepresentation = async(): Promise<Representation> => ({ data: streamifyArray([
|
store.getRepresentation = async(): Promise<Representation> => ({ data: guardedStreamFrom([
|
||||||
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`)),
|
||||||
@ -89,7 +92,7 @@ describe('A WebAclAuthorizer', (): void => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('errors if authorization is required but the agent is not authorized.', async(): Promise<void> => {
|
it('errors if authorization is required but the agent is not authorized.', async(): Promise<void> => {
|
||||||
store.getRepresentation = async(): Promise<Representation> => ({ data: streamifyArray([
|
store.getRepresentation = async(): Promise<Representation> => ({ data: guardedStreamFrom([
|
||||||
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`)),
|
||||||
@ -100,7 +103,7 @@ describe('A WebAclAuthorizer', (): void => {
|
|||||||
|
|
||||||
it('allows access to specific agents if the acl files identifies them.', async(): Promise<void> => {
|
it('allows access to specific agents if the acl files identifies them.', async(): Promise<void> => {
|
||||||
credentials.webId = 'http://test.com/user';
|
credentials.webId = 'http://test.com/user';
|
||||||
store.getRepresentation = async(): Promise<Representation> => ({ data: streamifyArray([
|
store.getRepresentation = async(): Promise<Representation> => ({ data: guardedStreamFrom([
|
||||||
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`)),
|
||||||
@ -111,7 +114,7 @@ describe('A WebAclAuthorizer', (): void => {
|
|||||||
|
|
||||||
it('errors if a specific agents wants to access files not assigned to them.', async(): Promise<void> => {
|
it('errors if a specific agents wants to access files not assigned to them.', async(): Promise<void> => {
|
||||||
credentials.webId = 'http://test.com/user';
|
credentials.webId = 'http://test.com/user';
|
||||||
store.getRepresentation = async(): Promise<Representation> => ({ data: streamifyArray([
|
store.getRepresentation = async(): Promise<Representation> => ({ data: guardedStreamFrom([
|
||||||
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`)),
|
||||||
@ -120,19 +123,6 @@ describe('A WebAclAuthorizer', (): void => {
|
|||||||
await expect(authorizer.handle({ identifier, permissions, credentials })).rejects.toThrow(ForbiddenHttpError);
|
await expect(authorizer.handle({ identifier, permissions, credentials })).rejects.toThrow(ForbiddenHttpError);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('errors if an agent tries to edit the acl file without control permissions.', async(): Promise<void> => {
|
|
||||||
credentials.webId = 'http://test.com/user';
|
|
||||||
identifier.path = 'http://test.com/foo';
|
|
||||||
store.getRepresentation = async(): Promise<Representation> => ({ 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}Read`)),
|
|
||||||
quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Write`)),
|
|
||||||
]) } as Representation);
|
|
||||||
identifier = aclStrategy.getAuxiliaryIdentifier(identifier);
|
|
||||||
await expect(authorizer.handle({ identifier, permissions, credentials })).rejects.toThrow(ForbiddenHttpError);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('passes errors of the ResourceStore along.', async(): Promise<void> => {
|
it('passes errors of the ResourceStore along.', async(): Promise<void> => {
|
||||||
store.getRepresentation = async(): Promise<Representation> => {
|
store.getRepresentation = async(): Promise<Representation> => {
|
||||||
throw new Error('TEST!');
|
throw new Error('TEST!');
|
||||||
@ -158,7 +148,7 @@ describe('A WebAclAuthorizer', (): void => {
|
|||||||
append: true,
|
append: true,
|
||||||
control: false,
|
control: false,
|
||||||
};
|
};
|
||||||
store.getRepresentation = async(): Promise<Representation> => ({ data: streamifyArray([
|
store.getRepresentation = async(): Promise<Representation> => ({ data: guardedStreamFrom([
|
||||||
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}Write`)),
|
quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Write`)),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user