@solid/community-server
Version:
Community Solid Server: an open and modular implementation of the Solid specifications
63 lines • 3.32 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.PermissionBasedAuthorizer = void 0;
const global_logger_factory_1 = require("global-logger-factory");
const ForbiddenHttpError_1 = require("../util/errors/ForbiddenHttpError");
const UnauthorizedHttpError_1 = require("../util/errors/UnauthorizedHttpError");
const Authorizer_1 = require("./Authorizer");
/**
* Authorizer that bases its decision on the output it gets from its PermissionReader.
* For each permission it checks if the reader allows that for at least one credential type,
* if yes, authorization is granted.
* `undefined` values for reader results are interpreted as `false`.
*/
class PermissionBasedAuthorizer extends Authorizer_1.Authorizer {
logger = (0, global_logger_factory_1.getLoggerFor)(this);
async handle(input) {
const { credentials, requestedModes, availablePermissions } = input;
// Ensure all required modes are within the agent's permissions.
for (const [identifier, modes] of requestedModes.entrySets()) {
const modeString = [...modes].join(',');
this.logger.debug(`Checking if ${JSON.stringify(credentials)} has ${modeString} permissions for ${identifier.path}`);
const permissionSet = availablePermissions.get(identifier) ?? {};
for (const mode of modes) {
this.requireModePermission(credentials, permissionSet, mode);
}
this.logger.debug(`${JSON.stringify(credentials)} has ${modeString} permissions for ${identifier.path}`);
}
}
/**
* Ensures that at least one of the credentials provides permissions for the given mode.
* Throws a {@link ForbiddenHttpError} or {@link UnauthorizedHttpError} depending on the credentials
* if access is not allowed.
*
* @param credentials - Credentials that require access.
* @param permissionMap - PermissionMap describing the available permissions of the credentials.
* @param mode - Which mode is requested.
*/
requireModePermission(credentials, permissionMap, mode) {
if (!permissionMap[mode]) {
if (this.isAuthenticated(credentials)) {
this.logger.warn(`Agent ${JSON.stringify(credentials)} has no ${mode} permissions`);
throw new ForbiddenHttpError_1.ForbiddenHttpError();
}
else {
// Solid, §2.1: "When a client does not provide valid credentials when requesting a resource that requires it,
// the data pod MUST send a response with a 401 status code (unless 404 is preferred for security reasons)."
// https://solid.github.io/specification/protocol#http-server
this.logger.warn(`Unauthenticated agent has no ${mode} permissions`);
throw new UnauthorizedHttpError_1.UnauthorizedHttpError();
}
}
}
/**
* Checks whether the agent is authenticated (logged in) or not (public/anonymous).
*
* @param credentials - Credentials to check.
*/
isAuthenticated(credentials) {
return Object.values(credentials).some((cred) => cred !== undefined);
}
}
exports.PermissionBasedAuthorizer = PermissionBasedAuthorizer;
//# sourceMappingURL=PermissionBasedAuthorizer.js.map