From 085f76577dfba4739d6d8ea7d23150b52664e4c8 Mon Sep 17 00:00:00 2001 From: tawoyinfa Date: Thu, 7 Nov 2024 10:15:56 +0000 Subject: [PATCH] fix(security): implement fine-grained authorization for request approval workflow - Add field-level authorization rules in GraphQL schema - Restrict approver field modifications to prevent injection - Enforce proper authorization for status updates - Implement strict access control for approval-related fields --- .../Mutation.createRequests.init.1.req.vtl | 4 - amplify/backend/api/team/schema.graphql | 76 ++++++++++++++++++- 2 files changed, 74 insertions(+), 6 deletions(-) diff --git a/amplify/backend/api/team/resolvers/Mutation.createRequests.init.1.req.vtl b/amplify/backend/api/team/resolvers/Mutation.createRequests.init.1.req.vtl index 4b9f1b45..769f783b 100644 --- a/amplify/backend/api/team/resolvers/Mutation.createRequests.init.1.req.vtl +++ b/amplify/backend/api/team/resolvers/Mutation.createRequests.init.1.req.vtl @@ -23,10 +23,6 @@ $util.qr($ctx.stash.defaultValues.put("status", "pending")) $util.error('Invalid input') #end -#if ($ctx.args.input.email || $ctx.args.input.status || $ctx.args.input.username || $ctx.args.input.approvers || $ctx.args.input.approver_ids) - $util.error('Invalid input') -#end - $util.qr($ctx.args.input.put("username", $ctx.identity.username)) $util.toJson({ "version": "2018-05-29", diff --git a/amplify/backend/api/team/schema.graphql b/amplify/backend/api/team/schema.graphql index ad9103e9..7ad10baa 100644 --- a/amplify/backend/api/team/schema.graphql +++ b/amplify/backend/api/team/schema.graphql @@ -3,8 +3,8 @@ type requests @auth( rules: [ { allow: groups, groups: ["Auditors"], operations: [read] } - { allow: owner } - { allow: owner, ownerField: "approver_ids", operations: [update, read] } + { allow: owner, operations: [create, read] } + { allow: owner, ownerField: "approver_ids", operations: [read] } { allow: private, provider: iam, operations: [read, update] } ] ) { @@ -15,6 +15,14 @@ type requests sortKeyFields: ["status"] queryField: "requestByEmailAndStatus" ) + @auth( + rules: [ + { allow: groups, groups: ["Auditors"], operations: [read] } + { allow: owner, operations: [read]} + { allow: owner, ownerField: "approver_ids", operations: [read] } + { allow: private, provider: iam, operations: [read, update] } + ] + ) accountId: String! accountName: String! role: String! @@ -23,22 +31,86 @@ type requests duration: String! justification: String status: String + @auth( + rules: [ + { allow: groups, groups: ["Auditors"], operations: [read] } + { allow: owner, operations: [create, read, update] } + { allow: owner, ownerField: "approver_ids", operations: [update, read] } + { allow: private, provider: iam, operations: [read, update] } + ] + ) comment: String + @auth( + rules: [ + { allow: groups, groups: ["Auditors"], operations: [read] } + { allow: owner, operations: [read] } + { allow: owner, ownerField: "approver_ids", operations: [update, read] } + { allow: private, provider: iam, operations: [read, update] } + ] + ) username: String approver: String + @auth( + rules: [ + { allow: groups, groups: ["Auditors"], operations: [read] } + { allow: owner, operations: [read]} + { allow: owner, ownerField: "approver_ids", operations: [read] } + { allow: private, provider: iam, operations: [read, update] } + ] + ) approverId: String @index( name: "byApproverAndStatus" sortKeyFields: ["status"] queryField: "requestByApproverAndStatus" ) + @auth( + rules: [ + { allow: groups, groups: ["Auditors"], operations: [read] } + { allow: owner, operations: [read]} + { allow: owner, ownerField: "approver_ids", operations: [update,read] } + { allow: private, provider: iam, operations: [read, update] } + ] + ) approvers: [String] + @auth( + rules: [ + { allow: groups, groups: ["Auditors"], operations: [read] } + { allow: owner, operations: [read]} + { allow: owner, ownerField: "approver_ids", operations: [read] } + { allow: private, provider: iam, operations: [read, update] } + ] + ) approver_ids: [String] + @auth( + rules: [ + { allow: groups, groups: ["Auditors"], operations: [read] } + { allow: owner, operations: [read]} + { allow: owner, ownerField: "approver_ids", operations: [read] } + { allow: private, provider: iam, operations: [read, update] } + ] + ) revoker: String revokerId: String + @auth( + rules: [ + { allow: groups, groups: ["Auditors"], operations: [read] } + { allow: owner, operations: [read]} + { allow: owner, ownerField: "approver_ids", operations: [update,read] } + { allow: private, provider: iam, operations: [read, update] } + ] + ) endTime: AWSDateTime ticketNo: String revokeComment: String + @auth( + rules: [ + { allow: groups, groups: ["Auditors"], operations: [read] } + { allow: owner, operations: [update,read]} + { allow: owner, ownerField: "approver_ids", operations: [update,read] } + { allow: private, provider: iam, operations: [read,update] } + ] + ) session_duration: String } type sessions