UNPKG

@elsikora/nestjs-crud-automator

Version:

A library for automating the creation of CRUD operations in NestJS.

203 lines (200 loc) 11 kB
'use strict'; 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