Skip to content

Commit

Permalink
Work in progress with Sam
Browse files Browse the repository at this point in the history
  • Loading branch information
wcalderipe committed Feb 7, 2024
1 parent ed11311 commit 8cb4862
Show file tree
Hide file tree
Showing 16 changed files with 300 additions and 115 deletions.
9 changes: 9 additions & 0 deletions apps/authz/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,21 @@ authz/test/type:
authz/test/unit:
npx nx test:unit ${AUTHZ_PROJECT_NAME} -- ${ARGS}

authz/test/unit/watch:
make authz/test/unit ARGS=--watch

authz/test/integration:
npx nx test:integration ${AUTHZ_PROJECT_NAME} -- ${ARGS}

authz/test/integration/watch:
make authz/test/integration ARGS=--watch

authz/test/e2e:
npx nx test:e2e ${AUTHZ_PROJECT_NAME} -- ${ARGS}

authz/test/e2e/watch:
make authz/test/e2e ARGS=--watch

# === Open Policy Agent & Rego ===

authz/rego/compile:
Expand Down
51 changes: 51 additions & 0 deletions apps/authz/src/app/__test__/e2e/admin.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -436,4 +436,55 @@ describe('Admin Endpoints', () => {
expect(status).toEqual(HttpStatus.CREATED)
})
})

describe.only('POST /policies', () => {
it('sets the organization policies', async () => {
const payload = {
authentication: {
sig: '0x746ed2e4bf7311da76bc157c7fe8c0520b6e4c27ab96abf5a8d16fecbaac98b669418b2db9da8e6d3cbd4e1eaff1a9d9e765f0470e9b86c6694145778a8d46f81c',
alg: 'ES256K',
pubKey: '0xd75D626a116D4a1959fE3bB938B2e7c116A05890'
},
approvals: [
{
sig: '0xe86dffd265b7a76a9de0ee9078137271cbe32bb2bb8ee28a2935cc37f023193a51cd608701b9c40fc42be69eeb45c0bb375b5898828f1af4bf12e37ff1fe697f1c',
alg: 'ES256K',
pubKey: '0x501D5c2Ce1EF208aadf9131a98BAa593258CfA06'
},
{
sig: '0xaffbddca4f16079f86a56d58f9ebb151c353e73c11a09791eb97f01ea0046c545ea0bd765ab1dc844ee0369f9123476b6f84b00b42b7ac1a16676b9a11e1a4031c',
alg: 'ES256K',
pubKey: '0xab88c8785D0C00082dE75D801Fcb1d5066a6311e'
}
],
request: {
action: 'setPolicyRules',
data: [
{
then: 'permit',
name: 'examplePermitPolicy',
when: [
{
criterion: 'checkAction',
args: ['fooo']
}
]
}
]
}
}

const { status, body } = await request(app.getHttpServer())
.post('/admin/policies')
.set(REQUEST_HEADER_ORG_ID, org.uid)
.send(payload)

console.dir(body, { depth: null })

// expect(body).toMatchObject({
// tokens: payload.request.tokens
// })
expect(status).toEqual(HttpStatus.CREATED)
})
})
})
4 changes: 2 additions & 2 deletions apps/authz/src/app/core/admin.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
CreateCredentialRequest,
CreateOrganizationRequest,
CreateUserRequest,
PolicyCriterionBuilder,
Policy,
RegisterTokensRequest,
RegisterWalletRequest,
SetPolicyRulesRequest,
Expand Down Expand Up @@ -102,7 +102,7 @@ export class AdminService {
return payload.request.tokens
}

async setPolicyRules(payload: SetPolicyRulesRequest): Promise<PolicyCriterionBuilder[]> {
async setPolicyRules(payload: SetPolicyRulesRequest): Promise<Policy[]> {
await this.opaService.generateRegoFile(payload.request.data)

return payload.request.data
Expand Down
14 changes: 9 additions & 5 deletions apps/authz/src/app/http/rest/controller/admin.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import { CreateOrganizationResponseDto } from '@app/authz/app/http/rest/dto/crea
import { CreateUserRequestDto } from '@app/authz/app/http/rest/dto/create-user-request.dto'
import { CreateUserResponseDto } from '@app/authz/app/http/rest/dto/create-user-response.dto'
import { SetPolicyRulesRequestDto } from '@app/authz/app/http/rest/dto/policy-rules/set-policy-rules-request.dto'
import { SetPolicyRulesResponseDto } from '@app/authz/app/http/rest/dto/policy-rules/set-policy-rules-response.dto'
import { RegisterTokensRequestDto } from '@app/authz/app/http/rest/dto/register-tokens-request.dto'
import { RegisterTokensResponseDto } from '@app/authz/app/http/rest/dto/register-tokens-response.dto'
import { RegisterWalletRequestDto } from '@app/authz/app/http/rest/dto/register-wallet-request.dto'
Expand All @@ -34,7 +33,7 @@ import {
SetPolicyRulesRequest,
UpdateUserRequest
} from '@narval/authz-shared'
import { Body, Controller, Logger, Patch, Post } from '@nestjs/common'
import { Body, Controller, Logger, Patch, Post, UsePipes, ValidationPipe } from '@nestjs/common'

@Controller('/admin')
export class AdminController {
Expand Down Expand Up @@ -141,13 +140,18 @@ export class AdminController {
return response
}

@Post('/policy-rules')
@Post('/policies')
@UsePipes(ValidationPipe)
async setPolicyRules(@Body() body: SetPolicyRulesRequestDto) {
const payload: SetPolicyRulesRequest = body

const policyRules = await this.adminService.setPolicyRules(payload)

const response = new SetPolicyRulesResponseDto(policyRules)
return response
// const response = new SetPolicyRulesResponseDto(policyRules)
// return response

console.log('## ctrl', policyRules)

return policyRules
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import { Action, Criterion } from '@narval/authz-shared'
import { ApiProperty } from '@nestjs/swagger'
import { IsDefined, IsEnum } from 'class-validator'
import { Action } from '@narval/authz-shared'

export class ActionCriterionDto {
@IsDefined()
@ApiProperty()
criterion: typeof Criterion.CHECK_ACTION
// @IsDefined()
// @ApiProperty()
// criterion: typeof Criterion.CHECK_ACTION

@IsDefined()
@IsEnum(Action, { each: true })
@ApiProperty({ isArray: true, enum: Action })
// @IsDefined()
// @IsEnum(Action, { each: true })
// @ApiProperty({ isArray: true, enum: Action })
args: Action[]
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
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
// @IsDefined()
// @ApiProperty()
// criterion: typeof Criterion.CHECK_RESOURCE_INTEGRITY

@ApiProperty()
args: null
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
import { PolicyCriterionBuilder, Then } from '@narval/authz-shared'
import { PolicyCriterionDto } from '@app/authz/app/http/rest/dto/policy-rules/policy-criterion.dto'
import { Then } from '@narval/authz-shared'
import { ApiProperty } from '@nestjs/swagger'
import { Type } from 'class-transformer'
import { IsDefined, IsIn, IsString, ValidateNested } from 'class-validator'
import { PolicyCriterionDto } from './policy-criterion.dto'

export class PolicyCriterionBuilderDto {
constructor(data: PolicyCriterionBuilder) {
this.name = data.name
this.when = data.when
this.then = data.then
}

export class PolicyDto {
@IsString()
@IsDefined()
@ApiProperty()
Expand All @@ -31,4 +25,8 @@ export class PolicyCriterionBuilderDto {
default: Then.FORBID
})
then: Then

constructor(partial: Partial<PolicyDto>) {
Object.assign(this, partial)
}
}
Original file line number Diff line number Diff line change
@@ -1,28 +1,25 @@
import { Criterion } from '@narval/authz-shared'
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) })
// @IsIn(Object.values(Criterion))
// @IsDefined()
// @ApiProperty({ enum: Object.values(Criterion) })
criterion: Criterion

@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
// @ValidateNested()
// @Type((opts) => {
// switch (opts?.object.criterion) {
// case Criterion.CHECK_ACTION:
// return ActionCriterionDto
// case Criterion.CHECK_RESOURCE_INTEGRITY:
// return ResourceIntegrityCriterionDto
// default:
// throw Error('boom, sam change in the future')
// }
// })
// @IsDefined()
// @ApiProperty({
// oneOf: [{ $ref: getSchemaPath(ActionCriterionDto) }, { $ref: getSchemaPath(ResourceIntegrityCriterionDto) }]
// })
// args: ActionCriterionDto | ResourceIntegrityCriterionDto
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
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 { Action, Policy } from '@narval/authz-shared'
import { ApiProperty } from '@nestjs/swagger'
import { Type } from 'class-transformer'
import { IsDefined, IsIn, ValidateNested } from 'class-validator'
import { PolicyCriterionBuilderDto } from './policy-criterion-builder.dto'

export class SetPolicyRulesDto extends BaseActionDto {
@IsIn(Object.values(Action))
Expand All @@ -15,9 +15,13 @@ export class SetPolicyRulesDto extends BaseActionDto {
action: typeof Action.SET_POLICY_RULES

@IsDefined()
@ValidateNested()
@ApiProperty()
data: PolicyCriterionBuilderDto[]
@Type(() => Policy)
@ValidateNested({ each: true })
@ApiProperty({
type: () => Policy,
isArray: true
})
data: Policy[]
}

export class SetPolicyRulesRequestDto extends BaseAdminRequestPayloadDto {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import { PolicyCriterionBuilder } from '@narval/authz-shared'
import { Policy } from '@narval/authz-shared'
import { ApiProperty } from '@nestjs/swagger'
import { Type } from 'class-transformer'
import { IsDefined, ValidateNested } from 'class-validator'
import { PolicyCriterionBuilderDto } from './policy-criterion-builder.dto'

export class SetPolicyRulesResponseDto {
constructor(policyRules: PolicyCriterionBuilder[]) {
this.policyRules = policyRules.map((rule) => new PolicyCriterionBuilderDto(rule))
}

@IsDefined()
@Type(() => Policy)
@ValidateNested()
@ApiProperty()
policyRules: PolicyCriterionBuilderDto[]
@ApiProperty({
type: () => Policy,
isArray: true
})
policyRules: Policy[]

constructor(partial: Partial<SetPolicyRulesResponseDto>) {
Object.assign(this, partial)
}
}
4 changes: 2 additions & 2 deletions apps/authz/src/app/opa/opa.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { AdminRepository } from '@app/authz/app/persistence/repository/admin.repository'
import { RegoData, User, UserGroup, WalletGroup } from '@app/authz/shared/types/entities.types'
import { OpaResult, RegoInput } from '@app/authz/shared/types/rego'
import { Criterion, PolicyCriterionBuilder, Then } from '@narval/authz-shared'
import { Criterion, Policy, Then } from '@narval/authz-shared'
import { Injectable, Logger, OnApplicationBootstrap } from '@nestjs/common'
import { loadPolicy } from '@open-policy-agent/opa-wasm'
import { readFileSync, writeFileSync } from 'fs'
Expand Down Expand Up @@ -40,7 +40,7 @@ export class OpaService implements OnApplicationBootstrap {
return evalResult.map(({ result }) => result)
}

generateRegoFile(policies: PolicyCriterionBuilder[]): void {
generateRegoFile(policies: Policy[]): void {
Handlebars.registerHelper('criterion', function (item) {
const criterion: Criterion = item.criterion
const args = item.args
Expand Down
22 changes: 22 additions & 0 deletions apps/authz/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,30 @@
import { INestApplication, Logger, ValidationPipe } from '@nestjs/common'
import { ConfigService } from '@nestjs/config'
import { NestFactory } from '@nestjs/core'
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'
import { lastValueFrom, map, of, switchMap } from 'rxjs'
import { AppModule } from './app/app.module'

/**
* Adds Swagger documentation to the application.
*
* @param app - The INestApplication instance.
* @returns The modified INestApplication instance.
*/
const withSwagger = (app: INestApplication): INestApplication => {
const document = SwaggerModule.createDocument(
app,
new DocumentBuilder()
.setTitle('Policy Engine')
.setDescription('The next generation of authorization for web3')
.setVersion('1.0')
.build()
)
SwaggerModule.setup('docs', app, document)

return app
}

/**
* Adds global pipes to the application.
*
Expand All @@ -28,6 +49,7 @@ async function bootstrap() {

await lastValueFrom(
of(application).pipe(
map(withSwagger),
map(withGlobalPipes),
switchMap((app) => app.listen(port))
)
Expand Down
6 changes: 3 additions & 3 deletions apps/authz/src/opa/template/mockData.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Action, Criterion, PolicyCriterionBuilder, Then } from '@narval/authz-shared'
import { Action, Criterion, Policy, Then } from '@narval/authz-shared'
import { Intents } from '@narval/transaction-request-intent'

export const examplePermitPolicy: PolicyCriterionBuilder = {
export const examplePermitPolicy: Policy = {
then: Then.PERMIT,
name: 'examplePermitPolicy',
when: [
Expand Down Expand Up @@ -57,7 +57,7 @@ export const examplePermitPolicy: PolicyCriterionBuilder = {
]
}

export const exampleForbidPolicy: PolicyCriterionBuilder = {
export const exampleForbidPolicy: Policy = {
then: Then.FORBID,
name: 'exampleForbidPolicy',
when: [
Expand Down
5 changes: 3 additions & 2 deletions packages/authz-shared/src/lib/type/action.type.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PolicyCriterionBuilder } from './policy-builder.type'
import { Policy } from '@narval/authz-shared'

export const Action = {
CREATE_ORGANIZATION: 'CREATE_ORGANIZATION',
Expand Down Expand Up @@ -266,9 +266,10 @@ export type RegisterTokensAction = BaseAction & {
export type RegisterTokensRequest = BaseAdminRequest & {
request: RegisterTokensAction
}

export type SetPolicyRulesAction = BaseAction & {
action: typeof Action.SET_POLICY_RULES
data: PolicyCriterionBuilder[]
data: Policy[]
}

export type SetPolicyRulesRequest = BaseAdminRequest & {
Expand Down
Loading

0 comments on commit 8cb4862

Please sign in to comment.