diff --git a/apps/authz/src/app/http/rest/controller/admin.controller.ts b/apps/authz/src/app/http/rest/controller/admin.controller.ts index 6b4e31db6..60e97f8e2 100644 --- a/apps/authz/src/app/http/rest/controller/admin.controller.ts +++ b/apps/authz/src/app/http/rest/controller/admin.controller.ts @@ -31,6 +31,7 @@ import { CreateUserRequest, RegisterTokensRequest, RegisterWalletRequest, + SetPolicyRulesRequest, UpdateUserRequest } from '@narval/authz-shared' import { Body, Controller, Logger, Patch, Post } from '@nestjs/common' @@ -142,7 +143,7 @@ export class AdminController { @Post('/policy-rules') async setPolicyRules(@Body() body: SetPolicyRulesRequestDto) { - const payload = body as any + const payload: SetPolicyRulesRequest = body const policyRules = await this.adminService.setPolicyRules(payload) diff --git a/apps/authz/src/app/http/rest/dto/policy-rules/criteria/action-criterion.dto.ts b/apps/authz/src/app/http/rest/dto/policy-rules/criteria/action-criterion.dto.ts new file mode 100644 index 000000000..420ada0ee --- /dev/null +++ b/apps/authz/src/app/http/rest/dto/policy-rules/criteria/action-criterion.dto.ts @@ -0,0 +1,14 @@ +import { Action, Criterion } from '@narval/authz-shared' +import { ApiProperty } from '@nestjs/swagger' +import { IsDefined, IsEnum } from 'class-validator' + +export class ActionCriterionDto { + @IsDefined() + @ApiProperty() + criterion: typeof Criterion.CHECK_ACTION + + @IsDefined() + @IsEnum(Action, { each: true }) + @ApiProperty({ isArray: true, enum: Action }) + args: Action[] +} diff --git a/apps/authz/src/app/http/rest/dto/policy-rules/criteria/resource-integrity-criterion.dto.ts b/apps/authz/src/app/http/rest/dto/policy-rules/criteria/resource-integrity-criterion.dto.ts new file mode 100644 index 000000000..83a837172 --- /dev/null +++ b/apps/authz/src/app/http/rest/dto/policy-rules/criteria/resource-integrity-criterion.dto.ts @@ -0,0 +1,12 @@ +import { Criterion } from '@narval/authz-shared' +import { ApiProperty } from '@nestjs/swagger' +import { IsDefined } from 'class-validator' + +export class ResourceIntegrityCriterionDto { + @IsDefined() + @ApiProperty() + criterion: typeof Criterion.CHECK_RESOURCE_INTEGRITY + + @ApiProperty() + args: null +} diff --git a/apps/authz/src/app/http/rest/dto/policy-rules/policy-criterion.dto.ts b/apps/authz/src/app/http/rest/dto/policy-rules/policy-criterion.dto.ts index c17e25986..43fe56f4d 100644 --- a/apps/authz/src/app/http/rest/dto/policy-rules/policy-criterion.dto.ts +++ b/apps/authz/src/app/http/rest/dto/policy-rules/policy-criterion.dto.ts @@ -1,14 +1,28 @@ import { Criterion } from '@narval/authz-shared' -import { ApiProperty } from '@nestjs/swagger' -import { IsDefined, IsIn } from 'class-validator' +import { ApiProperty, getSchemaPath } from '@nestjs/swagger' +import { Type } from 'class-transformer' +import { IsDefined, IsIn, ValidateNested } from 'class-validator' +import { ActionCriterionDto } from './criteria/action-criterion.dto' +import { ResourceIntegrityCriterionDto } from './criteria/resource-integrity-criterion.dto' export class PolicyCriterionDto { @IsIn(Object.values(Criterion)) @IsDefined() - @ApiProperty({ - enum: Object.values(Criterion) - }) + @ApiProperty({ enum: Object.values(Criterion) }) criterion: Criterion - args: any + @ValidateNested() + @Type((opts) => { + if (opts?.object.criterion === Criterion.CHECK_ACTION) { + return ActionCriterionDto + } + if (opts?.object.criterion === Criterion.CHECK_RESOURCE_INTEGRITY) { + return ResourceIntegrityCriterionDto + } + }) + @IsDefined() + @ApiProperty({ + oneOf: [{ $ref: getSchemaPath(ActionCriterionDto) }, { $ref: getSchemaPath(ResourceIntegrityCriterionDto) }] + }) + args: ActionCriterionDto | ResourceIntegrityCriterionDto } diff --git a/apps/authz/src/app/http/rest/dto/policy-rules/set-policy-rules-request.dto.ts b/apps/authz/src/app/http/rest/dto/policy-rules/set-policy-rules-request.dto.ts index 9d37ebb64..6fc6b8bc4 100644 --- a/apps/authz/src/app/http/rest/dto/policy-rules/set-policy-rules-request.dto.ts +++ b/apps/authz/src/app/http/rest/dto/policy-rules/set-policy-rules-request.dto.ts @@ -1,8 +1,8 @@ +import { BaseActionDto } from '@app/authz/app/http/rest/dto/base-action.dto' +import { BaseAdminRequestPayloadDto } from '@app/authz/app/http/rest/dto/base-admin-request-payload.dto' import { Action } from '@narval/authz-shared' import { ApiProperty } from '@nestjs/swagger' import { IsDefined, IsIn, ValidateNested } from 'class-validator' -import { BaseActionDto } from '../base-action.dto' -import { BaseAdminRequestPayloadDto } from '../base-admin-request-payload.dto' import { PolicyCriterionBuilderDto } from './policy-criterion-builder.dto' export class SetPolicyRulesDto extends BaseActionDto { diff --git a/apps/authz/src/opa/rego/__test__/criteria/resource_test.rego b/apps/authz/src/opa/rego/__test__/criteria/resource_test.rego index 4c9c38573..432daacc1 100644 --- a/apps/authz/src/opa/rego/__test__/criteria/resource_test.rego +++ b/apps/authz/src/opa/rego/__test__/criteria/resource_test.rego @@ -1,7 +1,7 @@ package main test_resource { - checkTransferResourceIntegrity with input as request + checkResourceIntegrity with input as request with data.entities as entities wallet = resource with input as request diff --git a/apps/authz/src/opa/rego/generated/0e1e777c-7385-4f77-a696-4971faa16cf7.rego b/apps/authz/src/opa/rego/generated/0e1e777c-7385-4f77-a696-4971faa16cf7.rego index 84e14a790..b61b69c76 100644 --- a/apps/authz/src/opa/rego/generated/0e1e777c-7385-4f77-a696-4971faa16cf7.rego +++ b/apps/authz/src/opa/rego/generated/0e1e777c-7385-4f77-a696-4971faa16cf7.rego @@ -1,7 +1,7 @@ package main permit[{"policyId": "examplePermitPolicy" }] = reason { - checkTransferResourceIntegrity + checkResourceIntegrity checkNonceExists checkAction({"signTransaction"}) checkPrincipalId({"matt@narval.xyz"}) @@ -14,7 +14,7 @@ package main } forbid[{"policyId": "exampleForbidPolicy" }] = reason { - checkTransferResourceIntegrity + checkResourceIntegrity checkNonceExists checkAction({"signTransaction"}) checkPrincipalId({"matt@narval.xyz"}) diff --git a/apps/authz/src/opa/rego/generated/82b01aaf-5d72-45b0-bfc4-d0146526428c.rego b/apps/authz/src/opa/rego/generated/82b01aaf-5d72-45b0-bfc4-d0146526428c.rego index 85745ef1a..ca14d8733 100644 --- a/apps/authz/src/opa/rego/generated/82b01aaf-5d72-45b0-bfc4-d0146526428c.rego +++ b/apps/authz/src/opa/rego/generated/82b01aaf-5d72-45b0-bfc4-d0146526428c.rego @@ -1,7 +1,7 @@ package main permit[{"policyId": "examplePermitPolicy" }] = reason { - checkTransferResourceIntegrity + checkResourceIntegrity checkNonceExists checkAction({"signTransaction"}) checkPrincipalId({"matt@narval.xyz"}) @@ -14,7 +14,7 @@ permit[{"policyId": "examplePermitPolicy" }] = reason { } forbid[{"policyId": "exampleForbidPolicy" }] = reason { - checkTransferResourceIntegrity + checkResourceIntegrity checkNonceExists checkAction({"signTransaction"}) checkPrincipalId({"matt@narval.xyz"}) diff --git a/apps/authz/src/opa/rego/generated/f0d5badc-6f3f-40f2-a7f4-acc1ff7d560a.rego b/apps/authz/src/opa/rego/generated/f0d5badc-6f3f-40f2-a7f4-acc1ff7d560a.rego index 84e14a790..b61b69c76 100644 --- a/apps/authz/src/opa/rego/generated/f0d5badc-6f3f-40f2-a7f4-acc1ff7d560a.rego +++ b/apps/authz/src/opa/rego/generated/f0d5badc-6f3f-40f2-a7f4-acc1ff7d560a.rego @@ -1,7 +1,7 @@ package main permit[{"policyId": "examplePermitPolicy" }] = reason { - checkTransferResourceIntegrity + checkResourceIntegrity checkNonceExists checkAction({"signTransaction"}) checkPrincipalId({"matt@narval.xyz"}) @@ -14,7 +14,7 @@ package main } forbid[{"policyId": "exampleForbidPolicy" }] = reason { - checkTransferResourceIntegrity + checkResourceIntegrity checkNonceExists checkAction({"signTransaction"}) checkPrincipalId({"matt@narval.xyz"}) diff --git a/apps/authz/src/opa/rego/lib/criteria/resource.rego b/apps/authz/src/opa/rego/lib/criteria/resource.rego index caf7cc1a0..b7ac26678 100644 --- a/apps/authz/src/opa/rego/lib/criteria/resource.rego +++ b/apps/authz/src/opa/rego/lib/criteria/resource.rego @@ -4,7 +4,7 @@ import future.keywords.in resource = data.entities.wallets[input.resource.uid] -checkTransferResourceIntegrity { +checkResourceIntegrity { checkAction({"signTransaction"}) transactionRequestFromAddress = input.transactionRequest.from resourceAddress = extractAddressFromCaip10(input.resource.uid) diff --git a/apps/authz/src/opa/template/mockData.ts b/apps/authz/src/opa/template/mockData.ts index fef2c722b..f382ae188 100644 --- a/apps/authz/src/opa/template/mockData.ts +++ b/apps/authz/src/opa/template/mockData.ts @@ -6,7 +6,7 @@ export const examplePermitPolicy: PolicyCriterionBuilder = { name: 'examplePermitPolicy', when: [ { - criterion: Criterion.CHECK_TRANSFER_RESOURCE_INTEGRITY, + criterion: Criterion.CHECK_RESOURCE_INTEGRITY, args: null }, { @@ -62,7 +62,7 @@ export const exampleForbidPolicy: PolicyCriterionBuilder = { name: 'exampleForbidPolicy', when: [ { - criterion: Criterion.CHECK_TRANSFER_RESOURCE_INTEGRITY, + criterion: Criterion.CHECK_RESOURCE_INTEGRITY, args: null }, { diff --git a/packages/authz-shared/src/lib/type/policy-builder.type.ts b/packages/authz-shared/src/lib/type/policy-builder.type.ts index bdafeae75..30b530316 100644 --- a/packages/authz-shared/src/lib/type/policy-builder.type.ts +++ b/packages/authz-shared/src/lib/type/policy-builder.type.ts @@ -22,7 +22,7 @@ export type Then = (typeof Then)[keyof typeof Then] export const Criterion = { CHECK_ACTION: 'checkAction', - CHECK_TRANSFER_RESOURCE_INTEGRITY: 'checkTransferResourceIntegrity', + CHECK_RESOURCE_INTEGRITY: 'checkResourceIntegrity', CHECK_PRINCIPAL_ID: 'checkPrincipalId', CHECK_PRINCIPAL_ROLE: 'checkPrincipalRole', CHECK_PRINCIPAL_GROUP: 'checkPrincipalGroup', @@ -119,8 +119,8 @@ type ActionCriterion = { args: Action[] } -type TransferResourceIntegrityCriterion = { - criterion: typeof Criterion.CHECK_TRANSFER_RESOURCE_INTEGRITY +type ResourceIntegrityCriterion = { + criterion: typeof Criterion.CHECK_RESOURCE_INTEGRITY args: null } @@ -286,7 +286,7 @@ type SpendingLimitCriterion = { export type PolicyCriterion = | ActionCriterion - | TransferResourceIntegrityCriterion + | ResourceIntegrityCriterion | PrincipalIdCriterion | PrincipalRoleCriterion | PrincipalGroupCriterion