UNPKG

@elsikora/nestjs-crud-automator

Version:

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

203 lines (200 loc) 10.7 kB
import { __decorate, __param, __metadata } from '../../../external/tslib/tslib.es6.js'; import { ApiAuthorizationEngine } from './engine.class.js'; import './hook/permission/cache.class.js'; import { ApiAuthorizationHookPermissionResolver } from './hook/permission/resolver.class.js'; import './iam/attachment/cache.class.js'; import { ApiAuthorizationIamAttachmentResolver } from './iam/attachment/resolver.class.js'; import './iam/document/cache.class.js'; import { ApiAuthorizationIamDocumentResolver } from './iam/document/resolver.class.js'; import './iam/document/validator.class.js'; import { ApiAuthorizationIamEngine } from './iam/engine.class.js'; import './iam/query-planner.class.js'; import { AUTHORIZATION_AUDIT_SINK_TOKEN } from '../../../constant/class/authorization/audit-sink-token.constant.js'; import { AUTHORIZATION_PRINCIPAL_RESOLVER_TOKEN } from '../../../constant/class/authorization/principal-resolver-token.constant.js'; import { AUTHORIZATION_POLICY_REGISTRY_TOKEN } from '../../../constant/class/authorization/token-registry.constant.js'; import '../../../enum/class/authorization/cache-mode.enum.js'; import '../../../enum/class/authorization/decision-type.enum.js'; import '../../../enum/class/authorization/effect.enum.js'; import { EApiAuthorizationMode } from '../../../enum/class/authorization/mode.enum.js'; import '../../../enum/class/authorization/permission-match.enum.js'; import '../../../enum/class/authorization/policy/attachment-type.enum.js'; import '../../../enum/class/authorization/policy/on-type.enum.js'; import '../../../enum/class/authorization/policy/source-type.enum.js'; import '../../../enum/class/authorization/policy/status.enum.js'; import '../../../enum/class/authorization/principal-type.enum.js'; import '../../../enum/decorator/api/route/subscriber-authorization-expectation.enum.js'; import { EApiRouteType } from '../../../enum/decorator/api/route/type.enum.js'; import { Injectable, Inject, Optional } from '@nestjs/common'; import { AuthorizationResolveDefaultPrincipal } from '../../../utility/authorization/resolve-default-principal.utility.js'; import 'typeorm'; import { ErrorException } from '../../../utility/error/exception.utility.js'; import { LoggerUtility } from '../../../utility/logger.utility.js'; const authorizationRuntimeLogger = LoggerUtility.getLogger("ApiAuthorizationRuntime"); let 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 === 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: 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 ErrorException("IAM authorization requires policyNamespace"); } if (!options.authorization.resourceDefinition) { authorizationRuntimeLogger.error("IAM authorization requires resourceDefinition"); throw 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 EApiRouteType.CREATE: { resolvedAction = "create"; break; } case EApiRouteType.DELETE: { resolvedAction = "delete"; break; } case EApiRouteType.GET: { resolvedAction = "read"; break; } case EApiRouteType.GET_LIST: { resolvedAction = "list"; break; } case EApiRouteType.PARTIAL_UPDATE: { resolvedAction = "update"; break; } case EApiRouteType.UPDATE: { resolvedAction = "update"; break; } } return resolvedAction ? `${policyNamespace}:${resolvedAction}` : `${policyNamespace}:${action}`; } resolveMode(authorization, routeAuthorization) { const mode = routeAuthorization?.mode ?? authorization.defaultMode; if (mode !== EApiAuthorizationMode.HOOKS && mode !== EApiAuthorizationMode.IAM) { authorizationRuntimeLogger.error(`Unknown authorization mode "${String(mode)}"`); throw 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 AuthorizationResolveDefaultPrincipal(authenticationRequest?.user); } }; ApiAuthorizationRuntime = __decorate([ Injectable(), __param(0, Inject(AUTHORIZATION_POLICY_REGISTRY_TOKEN)), __param(6, Inject(AUTHORIZATION_PRINCIPAL_RESOLVER_TOKEN)), __param(6, Optional()), __param(7, Inject(AUTHORIZATION_AUDIT_SINK_TOKEN)), __param(7, Optional()), __metadata("design:paramtypes", [Object, ApiAuthorizationEngine, ApiAuthorizationHookPermissionResolver, ApiAuthorizationIamAttachmentResolver, ApiAuthorizationIamDocumentResolver, ApiAuthorizationIamEngine, Object, Object]) ], ApiAuthorizationRuntime); export { ApiAuthorizationRuntime }; //# sourceMappingURL=runtime.class.js.map