From 7713b34e3be44ec44284df29a7438a7ef2ee3264 Mon Sep 17 00:00:00 2001 From: Neil Smyth Date: Fri, 13 Dec 2024 15:55:16 +0100 Subject: [PATCH] added helper method to make it easier to add privilege rule; reverted lookup to check for READ; added privilege rule to Profile, Context + Document to map READ_ABOUT to READ; made addition of READ_ABOUT on Space cascade --- .../innovation.flow.service.authorization.ts | 35 +++--------- .../authorization.policy.service.ts | 22 ++++++++ .../profile/profile.service.authorization.ts | 28 +++------- .../context/context.service.authorization.ts | 28 +++------- .../space/space.service.authorization.ts | 56 ++++++------------- .../document.service.authorization.ts | 9 +++ .../api/lookup/lookup.resolver.fields.ts | 22 +++----- 7 files changed, 82 insertions(+), 118 deletions(-) diff --git a/src/domain/collaboration/innovation-flow/innovation.flow.service.authorization.ts b/src/domain/collaboration/innovation-flow/innovation.flow.service.authorization.ts index 015d63d57d..c4ace31dd5 100644 --- a/src/domain/collaboration/innovation-flow/innovation.flow.service.authorization.ts +++ b/src/domain/collaboration/innovation-flow/innovation.flow.service.authorization.ts @@ -6,8 +6,6 @@ import { ProfileAuthorizationService } from '@domain/common/profile/profile.serv import { AuthorizationPrivilege, LogContext } from '@common/enums'; import { IAuthorizationPolicyRuleCredential } from '@core/authorization/authorization.policy.rule.credential.interface'; import { EntityNotInitializedException } from '@common/exceptions/entity.not.initialized.exception'; -import { IAuthorizationPolicyRulePrivilege } from '@core/authorization/authorization.policy.rule.privilege.interface'; -import { AuthorizationPolicyRulePrivilege } from '@core/authorization/authorization.policy.rule.privilege'; import { PRIVILEGE_RULE_TYPES_INNOVATION_FLOW_UPDATE } from '@common/constants/authorization/policy.rule.constants'; import { RelationshipNotFoundException } from '@common/exceptions/relationship.not.found.exception'; @@ -41,9 +39,13 @@ export class InnovationFlowAuthorizationService { innovationFlow.authorization = this.appendCredentialRules( innovationFlow.authorization ); - innovationFlow.authorization = this.appendPrivilegeRules( - innovationFlow.authorization - ); + innovationFlow.authorization = + this.authorizationPolicyService.appendPrivilegeAuthorizationRuleMapping( + innovationFlow.authorization, + AuthorizationPrivilege.CREATE, + [AuthorizationPrivilege.UPDATE_INNOVATION_FLOW], + PRIVILEGE_RULE_TYPES_INNOVATION_FLOW_UPDATE + ); updatedAuthorizations.push(innovationFlow.authorization); const profileAuthorizations = @@ -78,27 +80,4 @@ export class InnovationFlowAuthorizationService { return rules; } - - private appendPrivilegeRules( - authorization: IAuthorizationPolicy | undefined - ): IAuthorizationPolicy { - if (!authorization) - throw new EntityNotInitializedException( - 'Authorization definition not found', - LogContext.SPACES - ); - const privilegeRules: IAuthorizationPolicyRulePrivilege[] = []; - - const createPrivilege = new AuthorizationPolicyRulePrivilege( - [AuthorizationPrivilege.UPDATE_INNOVATION_FLOW], - AuthorizationPrivilege.CREATE, - PRIVILEGE_RULE_TYPES_INNOVATION_FLOW_UPDATE - ); - privilegeRules.push(createPrivilege); - - return this.authorizationPolicyService.appendPrivilegeAuthorizationRules( - authorization, - privilegeRules - ); - } } diff --git a/src/domain/common/authorization-policy/authorization.policy.service.ts b/src/domain/common/authorization-policy/authorization.policy.service.ts index 0a27ed4b66..e76d1275b1 100644 --- a/src/domain/common/authorization-policy/authorization.policy.service.ts +++ b/src/domain/common/authorization-policy/authorization.policy.service.ts @@ -27,6 +27,7 @@ import { ICredentialDefinition } from '@domain/agent/credential/credential.defin import { AuthorizationPolicyType } from '@common/enums/authorization.policy.type'; import { ConfigService } from '@nestjs/config'; import { AlkemioConfig } from '@src/types'; +import { AuthorizationPolicyRulePrivilege } from '@core/authorization/authorization.policy.rule.privilege'; @Injectable() export class AuthorizationPolicyService { @@ -289,6 +290,27 @@ export class AuthorizationPolicyService { return auth; } + public appendPrivilegeAuthorizationRuleMapping( + authorization: IAuthorizationPolicy | undefined, + sourcePrivilege: AuthorizationPrivilege, + grantedPrivileges: AuthorizationPrivilege[], + name: string + ): IAuthorizationPolicy { + const auth = this.validateAuthorization(authorization); + const existingRules = this.authorizationService.convertPrivilegeRulesStr( + auth.privilegeRules + ); + const newPrivilegeRule = new AuthorizationPolicyRulePrivilege( + grantedPrivileges, + sourcePrivilege, + name + ); + existingRules.push(newPrivilegeRule); + + auth.privilegeRules = JSON.stringify(existingRules); + return auth; + } + appendVerifiedCredentialAuthorizationRules( authorization: IAuthorizationPolicy | undefined, additionalRules: AuthorizationPolicyRuleVerifiedCredential[] diff --git a/src/domain/common/profile/profile.service.authorization.ts b/src/domain/common/profile/profile.service.authorization.ts index 3b4155b82d..deb62f96af 100644 --- a/src/domain/common/profile/profile.service.authorization.ts +++ b/src/domain/common/profile/profile.service.authorization.ts @@ -6,7 +6,6 @@ import { VisualAuthorizationService } from '../visual/visual.service.authorizati import { StorageBucketAuthorizationService } from '@domain/storage/storage-bucket/storage.bucket.service.authorization'; import { LogContext } from '@common/enums/logging.context'; import { RelationshipNotFoundException } from '@common/exceptions'; -import { AuthorizationPolicyRulePrivilege } from '@core/authorization/authorization.policy.rule.privilege'; import { AuthorizationPrivilege } from '@common/enums/authorization.privilege'; import { POLICY_RULE_READ_ABOUT } from '@common/constants/authorization/policy.rule.constants'; @@ -94,9 +93,15 @@ export class ProfileAuthorizationService { profile.authorization, parentAuthorization ); - profile.authorization = this.appendPrivilegeRuleReadAbout( - profile.authorization - ); + // If can READ_ABOUT on Profile, then also allow general READ + profile.authorization = + this.authorizationPolicyService.appendPrivilegeAuthorizationRuleMapping( + profile.authorization, + AuthorizationPrivilege.READ_ABOUT, + [AuthorizationPrivilege.READ], + POLICY_RULE_READ_ABOUT + ); + updatedAuthorizations.push(profile.authorization); for (const reference of profile.references) { @@ -135,19 +140,4 @@ export class ProfileAuthorizationService { return updatedAuthorizations; } - - private appendPrivilegeRuleReadAbout( - authorization: IAuthorizationPolicy - ): IAuthorizationPolicy { - const readAboutPrivilege = new AuthorizationPolicyRulePrivilege( - [AuthorizationPrivilege.READ_ABOUT], - AuthorizationPrivilege.READ, - POLICY_RULE_READ_ABOUT - ); - - return this.authorizationPolicyService.appendPrivilegeAuthorizationRules( - authorization, - [readAboutPrivilege] - ); - } } diff --git a/src/domain/context/context/context.service.authorization.ts b/src/domain/context/context/context.service.authorization.ts index dc9095989f..b73dffcb97 100644 --- a/src/domain/context/context/context.service.authorization.ts +++ b/src/domain/context/context/context.service.authorization.ts @@ -4,7 +4,6 @@ import { IContext } from '@domain/context/context'; import { EcosystemModelAuthorizationService } from '@domain/context/ecosystem-model/ecosystem-model.service.authorization'; import { IAuthorizationPolicy } from '@domain/common/authorization-policy'; import { AuthorizationPolicyService } from '@domain/common/authorization-policy/authorization.policy.service'; -import { AuthorizationPolicyRulePrivilege } from '@core/authorization/authorization.policy.rule.privilege'; import { AuthorizationPrivilege } from '@common/enums/authorization.privilege'; import { POLICY_RULE_READ_ABOUT } from '@common/constants/authorization/policy.rule.constants'; @Injectable() @@ -26,9 +25,15 @@ export class ContextAuthorizationService { context.authorization, parentAuthorization ); - context.authorization = this.appendPrivilegeRuleReadAbout( - context.authorization - ); + + // If can READ_ABOUT on Context, then also allow general READ + context.authorization = + this.authorizationPolicyService.appendPrivilegeAuthorizationRuleMapping( + context.authorization, + AuthorizationPrivilege.READ_ABOUT, + [AuthorizationPrivilege.READ], + POLICY_RULE_READ_ABOUT + ); updatedAuthorizations.push(context.authorization); // cascade @@ -43,19 +48,4 @@ export class ContextAuthorizationService { return updatedAuthorizations; } - - private appendPrivilegeRuleReadAbout( - authorization: IAuthorizationPolicy - ): IAuthorizationPolicy { - const readAboutPrivilege = new AuthorizationPolicyRulePrivilege( - [AuthorizationPrivilege.READ_ABOUT], - AuthorizationPrivilege.READ, - POLICY_RULE_READ_ABOUT - ); - - return this.authorizationPolicyService.appendPrivilegeAuthorizationRules( - authorization, - [readAboutPrivilege] - ); - } } diff --git a/src/domain/space/space/space.service.authorization.ts b/src/domain/space/space/space.service.authorization.ts index a3364e96ce..aa1837766d 100644 --- a/src/domain/space/space/space.service.authorization.ts +++ b/src/domain/space/space/space.service.authorization.ts @@ -29,7 +29,6 @@ import { CREDENTIAL_RULE_SPACE_MEMBERS_READ_ABOUT_SUBSPACES, } from '@common/constants'; import { IAuthorizationPolicyRuleCredential } from '@core/authorization/authorization.policy.rule.credential.interface'; -import { AuthorizationPolicyRulePrivilege } from '@core/authorization/authorization.policy.rule.privilege'; import { ICredentialDefinition } from '@domain/agent/credential/credential.definition.interface'; import { SpaceSettingsService } from '../space.settings/space.settings.service'; import { SpaceLevel } from '@common/enums/space.level'; @@ -181,12 +180,22 @@ export class SpaceAuthorizationService { break; } - space.authorization = this.appendPrivilegeRuleReadAbout( - space.authorization - ); - space.authorization = this.appendPrivilegeRuleCreateSubspace( - space.authorization - ); + // If can READ, then can of course READ_ABOUT + space.authorization = + this.authorizationPolicyService.appendPrivilegeAuthorizationRuleMapping( + space.authorization, + AuthorizationPrivilege.READ, + [AuthorizationPrivilege.READ_ABOUT], + POLICY_RULE_READ_ABOUT + ); + // Ensure that CREATE also allows CREATE_CHALLENGE + space.authorization = + this.authorizationPolicyService.appendPrivilegeAuthorizationRuleMapping( + space.authorization, + AuthorizationPrivilege.CREATE, + [AuthorizationPrivilege.CREATE_SUBSPACE], + POLICY_RULE_SPACE_CREATE_SUBSPACE + ); // Save before proparagating to child entities space.authorization = await this.authorizationPolicyService.save( @@ -350,6 +359,7 @@ export class SpaceAuthorizationService { parentRoleSetMemberCredentials, CREDENTIAL_RULE_SPACE_MEMBERS_READ_ABOUT_SUBSPACES ); + readAboutSubspaces.cascade = true; // means whole tree under context + profile have READ_ABOUT clonedAuthorization = this.authorizationPolicyService.appendCredentialAuthorizationRules( clonedAuthorization, @@ -544,36 +554,4 @@ export class SpaceAuthorizationService { newRules ); } - - private appendPrivilegeRuleReadAbout( - authorization: IAuthorizationPolicy - ): IAuthorizationPolicy { - const readAboutPrivilege = new AuthorizationPolicyRulePrivilege( - [AuthorizationPrivilege.READ_ABOUT], - AuthorizationPrivilege.READ, - POLICY_RULE_READ_ABOUT - ); - - return this.authorizationPolicyService.appendPrivilegeAuthorizationRules( - authorization, - [readAboutPrivilege] - ); - } - - private appendPrivilegeRuleCreateSubspace( - authorization: IAuthorizationPolicy - ): IAuthorizationPolicy { - // Ensure that CREATE also allows CREATE_CHALLENGE - const createSubspacePrivilege = new AuthorizationPolicyRulePrivilege( - [AuthorizationPrivilege.CREATE_SUBSPACE], - AuthorizationPrivilege.CREATE, - POLICY_RULE_SPACE_CREATE_SUBSPACE - ); - this.authorizationPolicyService.appendPrivilegeAuthorizationRules( - authorization, - [createSubspacePrivilege] - ); - - return authorization; - } } diff --git a/src/domain/storage/document/document.service.authorization.ts b/src/domain/storage/document/document.service.authorization.ts index 01672c62db..1f1b9dfcd2 100644 --- a/src/domain/storage/document/document.service.authorization.ts +++ b/src/domain/storage/document/document.service.authorization.ts @@ -11,6 +11,7 @@ import { import { IAuthorizationPolicyRuleCredential } from '@core/authorization/authorization.policy.rule.credential.interface'; import { CREDENTIAL_RULE_DOCUMENT_CREATED_BY } from '@common/constants/authorization/credential.rule.constants'; import { RelationshipNotFoundException } from '@common/exceptions/relationship.not.found.exception'; +import { POLICY_RULE_READ_ABOUT } from '@common/constants/authorization/policy.rule.constants'; @Injectable() export class DocumentAuthorizationService { constructor(private authorizationPolicyService: AuthorizationPolicyService) {} @@ -32,6 +33,14 @@ export class DocumentAuthorizationService { document.authorization, parentAuthorization ); + // If can READ_ABOUT on Document, then also allow general READ + document.authorization = + this.authorizationPolicyService.appendPrivilegeAuthorizationRuleMapping( + document.authorization, + AuthorizationPrivilege.READ_ABOUT, + [AuthorizationPrivilege.READ], + POLICY_RULE_READ_ABOUT + ); // Extend to give the user creating the document more rights document.authorization = this.appendCredentialRules(document); diff --git a/src/services/api/lookup/lookup.resolver.fields.ts b/src/services/api/lookup/lookup.resolver.fields.ts index 08d99b60c3..ae50f87c99 100644 --- a/src/services/api/lookup/lookup.resolver.fields.ts +++ b/src/services/api/lookup/lookup.resolver.fields.ts @@ -109,17 +109,14 @@ export class LookupResolverFields { nullable: true, description: 'Lookup the specified Space', }) - async space( - @CurrentUser() agentInfo: AgentInfo, - @Args('ID', { type: () => UUID }) id: string - ): Promise { + async space(@Args('ID', { type: () => UUID }) id: string): Promise { const space = await this.spaceService.getSpaceOrFail(id); - this.authorizationService.grantAccessOrFail( - agentInfo, - space.authorization, - AuthorizationPrivilege.READ_ABOUT, - `lookup Space: ${space.id}` - ); + // this.authorizationService.grantAccessOrFail( + // agentInfo, + // space.authorization, + // AuthorizationPrivilege.READ_ABOUT, + // `lookup Space: ${space.id}` + // ); return space; } @@ -150,7 +147,6 @@ export class LookupResolverFields { description: 'Lookup the specified RoleSet', }) async roleSet( - @CurrentUser() agentInfo: AgentInfo, @Args('ID', { type: () => UUID }) id: string ): Promise { const roleSet = await this.roleSetService.getRoleSetOrFail(id); @@ -500,7 +496,7 @@ export class LookupResolverFields { this.authorizationService.grantAccessOrFail( agentInfo, context.authorization, - AuthorizationPrivilege.READ_ABOUT, + AuthorizationPrivilege.READ, `lookup Context: ${context.id}` ); @@ -539,7 +535,7 @@ export class LookupResolverFields { this.authorizationService.grantAccessOrFail( agentInfo, profile.authorization, - AuthorizationPrivilege.READ_ABOUT, + AuthorizationPrivilege.READ, `lookup Profile: ${profile.id}` );