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:
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 { ForbiddenHttpError } from '../util/errors/ForbiddenHttpError';
|
||||
import { NotFoundHttpError } from '../util/errors/NotFoundHttpError';
|
||||
import { NotImplementedHttpError } from '../util/errors/NotImplementedHttpError';
|
||||
import { UnauthorizedHttpError } from '../util/errors/UnauthorizedHttpError';
|
||||
import type { IdentifierStrategy } from '../util/identifiers/IdentifierStrategy';
|
||||
import { ACL, FOAF } from '../util/Vocabularies';
|
||||
@@ -36,6 +37,12 @@ export class WebAclAuthorizer extends Authorizer {
|
||||
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.
|
||||
* 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.
|
||||
* 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 recurse - Only used internally for recursion.
|
||||
*
|
||||
@@ -137,14 +144,12 @@ export class WebAclAuthorizer extends Authorizer {
|
||||
private async getAclRecursive(id: ResourceIdentifier, recurse?: boolean): Promise<Store> {
|
||||
this.logger.debug(`Trying to read the direct ACL document of ${id.path}`);
|
||||
try {
|
||||
const isAcl = this.aclStrategy.isAuxiliaryIdentifier(id);
|
||||
const acl = isAcl ? id : this.aclStrategy.getAuxiliaryIdentifier(id);
|
||||
const acl = this.aclStrategy.getAuxiliaryIdentifier(id);
|
||||
this.logger.debug(`Trying to read the ACL document ${acl.path}`);
|
||||
const data = await this.resourceStore.getRepresentation(acl, { type: { [INTERNAL_QUADS]: 1 }});
|
||||
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, resourceId.path);
|
||||
return this.filterData(data, recurse ? ACL.default : ACL.accessTo, id.path);
|
||||
} catch (error: unknown) {
|
||||
if (NotFoundHttpError.isInstance(error)) {
|
||||
this.logger.debug(`No direct ACL document found for ${id.path}`);
|
||||
|
||||
Reference in New Issue
Block a user