@elsikora/nestjs-crud-automator
Version:
A library for automating the creation of CRUD operations in NestJS.
203 lines (200 loc) • 11 kB
JavaScript
;
var tslib_es6 = require('../../../external/tslib/tslib.es6.js');
var engine_class = require('./engine.class.js');
require('./hook/permission/cache.class.js');
var resolver_class = require('./hook/permission/resolver.class.js');
require('./iam/attachment/cache.class.js');
var resolver_class$1 = require('./iam/attachment/resolver.class.js');
require('./iam/document/cache.class.js');
var resolver_class$2 = require('./iam/document/resolver.class.js');
require('./iam/document/validator.class.js');
var engine_class$1 = require('./iam/engine.class.js');
require('./iam/query-planner.class.js');
var auditSinkToken_constant = require('../../../constant/class/authorization/audit-sink-token.constant.js');
var principalResolverToken_constant = require('../../../constant/class/authorization/principal-resolver-token.constant.js');
var tokenRegistry_constant = require('../../../constant/class/authorization/token-registry.constant.js');
require('../../../enum/class/authorization/cache-mode.enum.js');
require('../../../enum/class/authorization/decision-type.enum.js');
require('../../../enum/class/authorization/effect.enum.js');
var mode_enum = require('../../../enum/class/authorization/mode.enum.js');
require('../../../enum/class/authorization/permission-match.enum.js');
require('../../../enum/class/authorization/policy/attachment-type.enum.js');
require('../../../enum/class/authorization/policy/on-type.enum.js');
require('../../../enum/class/authorization/policy/source-type.enum.js');
require('../../../enum/class/authorization/policy/status.enum.js');
require('../../../enum/class/authorization/principal-type.enum.js');
require('../../../enum/decorator/api/route/subscriber-authorization-expectation.enum.js');
var type_enum = require('../../../enum/decorator/api/route/type.enum.js');
var common = require('@nestjs/common');
var resolveDefaultPrincipal_utility = require('../../../utility/authorization/resolve-default-principal.utility.js');
require('typeorm');
var exception_utility = require('../../../utility/error/exception.utility.js');
var logger_utility = require('../../../utility/logger.utility.js');
const authorizationRuntimeLogger = logger_utility.LoggerUtility.getLogger("ApiAuthorizationRuntime");
exports.ApiAuthorizationRuntime = class ApiAuthorizationRuntime {
policyRegistry;
authorizationEngine;
hookPermissionResolver;
iamAttachmentResolver;
iamDocumentResolver;
iamEngine;
principalResolver;
auditSink;
constructor(policyRegistry, authorizationEngine, hookPermissionResolver, iamAttachmentResolver, iamDocumentResolver, iamEngine, principalResolver, auditSink) {
this.policyRegistry = policyRegistry;
this.authorizationEngine = authorizationEngine;
this.hookPermissionResolver = hookPermissionResolver;
this.iamAttachmentResolver = iamAttachmentResolver;
this.iamDocumentResolver = iamDocumentResolver;
this.iamEngine = iamEngine;
this.principalResolver = principalResolver;
this.auditSink = auditSink;
}
async evaluate(options) {
const principal = await this.resolvePrincipal(options.principal, options.authenticationRequest);
const mode = this.resolveMode(options.authorization, options.routeAuthorization);
authorizationRuntimeLogger.verbose(`Dispatching authorization evaluation for entity "${options.entity.name}" action "${options.action}" principal "${principal.id}" using mode "${mode}".`);
const decision = mode === mode_enum.EApiAuthorizationMode.HOOKS
? await this.evaluateHooks({
action: options.action,
authenticationRequest: options.authenticationRequest,
entity: options.entity,
principal,
requestMetadata: options.requestMetadata,
resource: options.resource,
routeType: options.routeType,
})
: await this.evaluateIam({
action: options.action,
authorization: options.authorization,
principal,
requestMetadata: options.requestMetadata,
resource: options.resource,
routeType: options.routeType,
});
if (this.auditSink) {
authorizationRuntimeLogger.verbose(`Recording authorization audit event for principal "${principal.id}" action "${options.action}".`);
await this.auditSink.record(decision);
}
authorizationRuntimeLogger.verbose(`Completed authorization evaluation for entity "${options.entity.name}" action "${options.action}" with effect "${decision.effect}".`);
return decision;
}
createImplicitDenyHookPolicy(entity, action) {
return {
action,
entity,
policyId: `${entity.name?.toLowerCase() ?? "unknown"}-hooks-policy`,
policyIds: [],
rules: [],
};
}
async evaluateHooks(options) {
const permissions = await this.hookPermissionResolver.resolve(options.principal);
authorizationRuntimeLogger.verbose(`Resolved ${permissions.length} hook permissions for principal "${options.principal.id}" on entity "${options.entity.name}".`);
const policy = (await this.policyRegistry.buildAggregatedPolicy(options.entity, options.action, {
authenticationRequest: options.authenticationRequest,
permissions,
principal: options.principal,
requestMetadata: options.requestMetadata,
routeType: options.routeType,
})) ?? this.createImplicitDenyHookPolicy(options.entity, options.action);
return await this.authorizationEngine.evaluate({
action: options.action,
mode: mode_enum.EApiAuthorizationMode.HOOKS,
permissions,
policy,
principal: options.principal,
resource: options.resource,
resourceType: options.entity.name ?? "UnknownResource",
});
}
async evaluateIam(options) {
if (!options.authorization.policyNamespace) {
authorizationRuntimeLogger.error("IAM authorization requires policyNamespace");
throw exception_utility.ErrorException("IAM authorization requires policyNamespace");
}
if (!options.authorization.resourceDefinition) {
authorizationRuntimeLogger.error("IAM authorization requires resourceDefinition");
throw exception_utility.ErrorException("IAM authorization requires resourceDefinition");
}
const attachments = await this.iamAttachmentResolver.resolve(options.principal);
authorizationRuntimeLogger.verbose(`Resolved ${attachments.attachments.length} IAM attachments and ${attachments.boundaries.length} boundaries for principal "${options.principal.id}".`);
const policyIds = [...attachments.attachments.map((attachment) => attachment.policyId), ...attachments.boundaries.map((attachment) => attachment.policyId)];
const documents = await this.iamDocumentResolver.resolve(policyIds);
authorizationRuntimeLogger.verbose(`Resolved ${documents.length} IAM policy documents for namespace "${options.authorization.policyNamespace}" and principal "${options.principal.id}".`);
return await this.iamEngine.evaluate({
action: this.resolveIamAction(options.authorization.policyNamespace, options.action, options.routeType),
attachments,
documents,
policyNamespace: options.authorization.policyNamespace,
principal: options.principal,
requestMetadata: options.requestMetadata,
resource: options.resource,
resourceDefinition: options.authorization.resourceDefinition,
});
}
resolveIamAction(policyNamespace, action, routeType) {
let resolvedAction;
switch (routeType) {
case type_enum.EApiRouteType.CREATE: {
resolvedAction = "create";
break;
}
case type_enum.EApiRouteType.DELETE: {
resolvedAction = "delete";
break;
}
case type_enum.EApiRouteType.GET: {
resolvedAction = "read";
break;
}
case type_enum.EApiRouteType.GET_LIST: {
resolvedAction = "list";
break;
}
case type_enum.EApiRouteType.PARTIAL_UPDATE: {
resolvedAction = "update";
break;
}
case type_enum.EApiRouteType.UPDATE: {
resolvedAction = "update";
break;
}
}
return resolvedAction ? `${policyNamespace}:${resolvedAction}` : `${policyNamespace}:${action}`;
}
resolveMode(authorization, routeAuthorization) {
const mode = routeAuthorization?.mode ?? authorization.defaultMode;
if (mode !== mode_enum.EApiAuthorizationMode.HOOKS && mode !== mode_enum.EApiAuthorizationMode.IAM) {
authorizationRuntimeLogger.error(`Unknown authorization mode "${String(mode)}"`);
throw exception_utility.ErrorException(`Unknown authorization mode "${String(mode)}"`);
}
return mode;
}
async resolvePrincipal(principal, authenticationRequest) {
if (principal) {
authorizationRuntimeLogger.verbose(`Using explicit authorization principal "${principal.id}".`);
return principal;
}
if (this.principalResolver) {
authorizationRuntimeLogger.verbose("Resolving authorization principal via configured principalResolver.");
return await this.principalResolver.resolve(authenticationRequest?.user, authenticationRequest);
}
authorizationRuntimeLogger.verbose("Resolving authorization principal via default principal resolver.");
return resolveDefaultPrincipal_utility.AuthorizationResolveDefaultPrincipal(authenticationRequest?.user);
}
};
exports.ApiAuthorizationRuntime = tslib_es6.__decorate([
common.Injectable(),
tslib_es6.__param(0, common.Inject(tokenRegistry_constant.AUTHORIZATION_POLICY_REGISTRY_TOKEN)),
tslib_es6.__param(6, common.Inject(principalResolverToken_constant.AUTHORIZATION_PRINCIPAL_RESOLVER_TOKEN)),
tslib_es6.__param(6, common.Optional()),
tslib_es6.__param(7, common.Inject(auditSinkToken_constant.AUTHORIZATION_AUDIT_SINK_TOKEN)),
tslib_es6.__param(7, common.Optional()),
tslib_es6.__metadata("design:paramtypes", [Object, engine_class.ApiAuthorizationEngine,
resolver_class.ApiAuthorizationHookPermissionResolver,
resolver_class$1.ApiAuthorizationIamAttachmentResolver,
resolver_class$2.ApiAuthorizationIamDocumentResolver,
engine_class$1.ApiAuthorizationIamEngine, Object, Object])
], exports.ApiAuthorizationRuntime);
//# sourceMappingURL=runtime.class.js.map