diff --git a/src/casl/casl-ability.factory.ts b/src/casl/casl-ability.factory.ts index 14e558e05..b2e3e1821 100644 --- a/src/casl/casl-ability.factory.ts +++ b/src/casl/casl-ability.factory.ts @@ -6,7 +6,7 @@ import { MongoQuery, createMongoAbility, } from "@casl/ability"; -import { Injectable } from "@nestjs/common"; +import { Injectable, InternalServerErrorException } from "@nestjs/common"; import { Attachment } from "src/attachments/schemas/attachment.schema"; import { JWTUser } from "src/auth/interfaces/jwt-user.interface"; // import { Role } from "src/auth/role.enum"; @@ -54,40 +54,42 @@ export type AppAbility = MongoAbility; @Injectable() export class CaslAbilityFactory { - createForUser(user: JWTUser) { + private endpointAccessors: { + [endpoint: string]: (user: JWTUser) => AppAbility; + } = { + datasets: this.datasetEndpointAccess, + "elastic-search": this.elasticSearchEndpointAccess, + jobs: this.jobsEndpointAccess, + instruments: this.instrumentEndpointAccess, + logbooks: this.logbookEndpointAccess, + origdatablocks: this.origDatablockEndpointAccess, + policies: this.policyEndpointAccess, + proposals: this.proposalsEndpointAccess, + publisheddata: this.publishedDataEndpointAccess, + samples: this.samplesEndpointAccess, + users: this.userEndpointAccess, + }; + + endpointAccess(endpoint: string, user: JWTUser) { + const accessFunction = this.endpointAccessors[endpoint]; + if (!accessFunction) { + throw new InternalServerErrorException( + `No endpoint access policies defined for subject: ${endpoint}`, + ); + } + return accessFunction.call(this, user); + } + + datasetEndpointAccess(user: JWTUser) { const { can, cannot, build } = new AbilityBuilder( createMongoAbility, ); - // // admin groups - // const stringAdminGroups = process.env.ADMIN_GROUPS || ""; - // const adminGroups: string[] = stringAdminGroups - // ? stringAdminGroups.split(",").map((v) => v.trim()) - // : []; - // // delete groups - // const stringDeleteGroups = process.env.DELETE_GROUPS || ""; - // const deleteGroups: string[] = stringDeleteGroups - // ? stringDeleteGroups.split(",").map((v) => v.trim()) - // : []; - // // create dataset groups - // const stringCreateDatasetGroups = - // process.env.CREATE_DATASET_GROUPS || "all"; - // const createDatasetGroups: string[] = stringCreateDatasetGroups - // .split(",") - // .map((v) => v.trim()); - - /* - / Set permissions for different type of users for the following subsystems: - / - Datasets (https://scicatproject.github.io/documentation/Development/v4.x/backend/authorization/authorization_datasets.html) - / - OrigDatablocks (https://scicatproject.github.io/documentation/Development/v4.x/backend/authorization/authorization_origdatablocks.html) - */ if (!user) { /** /* unauthenticated users **/ - // ------------------------------------- - // datasets endpoint authorization cannot(Action.DatasetCreate, DatasetClass); can(Action.DatasetRead, DatasetClass); cannot(Action.DatasetUpdate, DatasetClass); @@ -106,47 +108,6 @@ export class CaslAbilityFactory { cannot(Action.DatasetDatablockUpdate, DatasetClass); // - cannot(Action.DatasetLogbookRead, DatasetClass); - // ------------------------------------- - // datasets data instance authorization - can(Action.DatasetReadManyPublic, DatasetClass); - can(Action.DatasetReadOnePublic, DatasetClass, { - isPublished: true, - }); - // - - can(Action.DatasetAttachmentReadPublic, DatasetClass, { - isPublished: true, - }); - // - - can(Action.DatasetOrigdatablockReadPublic, DatasetClass, { - isPublished: true, - }); - // - - can(Action.DatasetDatablockReadPublic, DatasetClass, { - isPublished: true, - }); - - // ------------------------------------- - // origdatablock - // ------------------------------------- - // endpoint authorization - can(Action.OrigdatablockRead, OrigDatablock); - cannot(Action.OrigdatablockCreate, OrigDatablock); - cannot(Action.OrigdatablockUpdate, OrigDatablock); - // ------------------------------------- - // data instance authorization - can(Action.OrigdatablockReadManyAccess, OrigDatablock); - can(Action.OrigdatablockReadOneAccess, OrigDatablock, { - isPublished: true, - }); - - cannot(Action.UserReadOwn, User); - cannot(Action.UserCreateOwn, User); - cannot(Action.UserUpdateOwn, User); - cannot(Action.UserDeleteOwn, User); - cannot(Action.UserReadAny, User); - cannot(Action.UserCreateAny, User); - cannot(Action.UserUpdateAny, User); - cannot(Action.UserDeleteAny, User); } else { if ( user.currentGroups.some((g) => configuration().deleteGroups.includes(g)) @@ -155,54 +116,740 @@ export class CaslAbilityFactory { / user that belongs to any of the group listed in DELETE_GROUPS */ - // ------------------------------------- - // datasets - // ------------------------------------- - // endpoint authorization can(Action.DatasetDelete, DatasetClass); // - can(Action.DatasetOrigdatablockDelete, DatasetClass); // - can(Action.DatasetDatablockDelete, DatasetClass); - // ------------------------------------- - // data instance authorization - can(Action.DatasetDeleteAny, DatasetClass); + } else { + /* + / user that does not belong to any of the group listed in DELETE_GROUPS + */ + + cannot(Action.DatasetDelete, DatasetClass); // - - can(Action.DatasetOrigdatablockDeleteAny, DatasetClass); + cannot(Action.DatasetOrigdatablockDelete, DatasetClass); // - - can(Action.DatasetDatablockDeleteAny, DatasetClass); + cannot(Action.DatasetDatablockDelete, DatasetClass); + } - // ------------------------------------- - // origdatablock - // ------------------------------------- - // endpoint authorization - can(Action.OrigdatablockDelete, OrigDatablock); - // ------------------------------------- - // data instance authorization - can(Action.OrigdatablockDeleteAny, OrigDatablock); + if ( + user.currentGroups.some((g) => configuration().adminGroups.includes(g)) + ) { + /* + / user that belongs to any of the group listed in ADMIN_GROUPS + */ + + can(Action.DatasetCreate, DatasetClass); + can(Action.DatasetRead, DatasetClass); + can(Action.DatasetUpdate, DatasetClass); + // - + can(Action.DatasetAttachmentCreate, DatasetClass); + can(Action.DatasetAttachmentRead, DatasetClass); + can(Action.DatasetAttachmentUpdate, DatasetClass); + can(Action.DatasetAttachmentDelete, DatasetClass); + // - + can(Action.DatasetOrigdatablockCreate, DatasetClass); + can(Action.DatasetOrigdatablockRead, DatasetClass); + can(Action.DatasetOrigdatablockUpdate, DatasetClass); + // - + can(Action.DatasetDatablockCreate, DatasetClass); + can(Action.DatasetDatablockRead, DatasetClass); + can(Action.DatasetDatablockUpdate, DatasetClass); + // - + can(Action.DatasetLogbookRead, DatasetClass); + } else if ( + user.currentGroups.some((g) => + configuration().createDatasetPrivilegedGroups.includes(g), + ) + ) { + /** + /* users belonging to CREATE_DATASET_PRIVILEGED_GROUPS + **/ + + can(Action.DatasetCreate, DatasetClass); + can(Action.DatasetRead, DatasetClass); + can(Action.DatasetUpdate, DatasetClass); + // - + can(Action.DatasetAttachmentCreate, DatasetClass); + can(Action.DatasetAttachmentRead, DatasetClass); + can(Action.DatasetAttachmentUpdate, DatasetClass); + can(Action.DatasetAttachmentDelete, DatasetClass); + // - + can(Action.DatasetOrigdatablockCreate, DatasetClass); + can(Action.DatasetOrigdatablockRead, DatasetClass); + can(Action.DatasetOrigdatablockUpdate, DatasetClass); + // - + can(Action.DatasetDatablockCreate, DatasetClass); + can(Action.DatasetDatablockRead, DatasetClass); + can(Action.DatasetDatablockUpdate, DatasetClass); + // - + can(Action.DatasetLogbookRead, DatasetClass); + } else if ( + user.currentGroups.some((g) => + configuration().createDatasetWithPidGroups.includes(g), + ) || + configuration().createDatasetWithPidGroups.includes("#all") + ) { + /** + /* users belonging to CREATE_DATASET_WITH_PID_GROUPS + **/ + + can(Action.DatasetCreate, DatasetClass); + can(Action.DatasetRead, DatasetClass); + can(Action.DatasetUpdate, DatasetClass); + // - + can(Action.DatasetAttachmentCreate, DatasetClass); + can(Action.DatasetAttachmentRead, DatasetClass); + can(Action.DatasetAttachmentUpdate, DatasetClass); + can(Action.DatasetAttachmentDelete, DatasetClass); + // - + can(Action.DatasetOrigdatablockCreate, DatasetClass); + can(Action.DatasetOrigdatablockRead, DatasetClass); + can(Action.DatasetOrigdatablockUpdate, DatasetClass); + // - + can(Action.DatasetDatablockCreate, DatasetClass); + can(Action.DatasetDatablockRead, DatasetClass); + can(Action.DatasetDatablockUpdate, DatasetClass); + // - + can(Action.DatasetLogbookRead, DatasetClass); + } else if ( + user.currentGroups.some((g) => + configuration().createDatasetGroups.includes(g), + ) || + configuration().createDatasetGroups.includes("#all") + ) { + /** + /* users belonging to CREATE_DATASET_GROUPS + **/ + + can(Action.DatasetCreate, DatasetClass); + can(Action.DatasetRead, DatasetClass); + can(Action.DatasetUpdate, DatasetClass); + // - + can(Action.DatasetAttachmentCreate, DatasetClass); + can(Action.DatasetAttachmentRead, DatasetClass); + can(Action.DatasetAttachmentUpdate, DatasetClass); + can(Action.DatasetAttachmentDelete, DatasetClass); + // - + can(Action.DatasetOrigdatablockCreate, DatasetClass); + can(Action.DatasetOrigdatablockRead, DatasetClass); + can(Action.DatasetOrigdatablockUpdate, DatasetClass); + // - + can(Action.DatasetDatablockCreate, DatasetClass); + can(Action.DatasetDatablockRead, DatasetClass); + can(Action.DatasetDatablockUpdate, DatasetClass); + // - + can(Action.DatasetLogbookRead, DatasetClass); + } else if (user) { + /** + /* authenticated users + **/ + + cannot(Action.DatasetCreate, DatasetClass); + can(Action.DatasetRead, DatasetClass); + cannot(Action.DatasetUpdate, DatasetClass); + // - + cannot(Action.DatasetAttachmentCreate, DatasetClass); + can(Action.DatasetAttachmentRead, DatasetClass); + cannot(Action.DatasetAttachmentUpdate, DatasetClass); + cannot(Action.DatasetAttachmentDelete, DatasetClass); + // - + cannot(Action.DatasetOrigdatablockCreate, DatasetClass); + can(Action.DatasetOrigdatablockRead, DatasetClass); + cannot(Action.DatasetOrigdatablockUpdate, DatasetClass); + // - + cannot(Action.DatasetDatablockCreate, DatasetClass); + can(Action.DatasetDatablockRead, DatasetClass); + cannot(Action.DatasetDatablockUpdate, DatasetClass); + // - + can(Action.DatasetLogbookRead, DatasetClass); + } + } + return build({ + detectSubjectType: (item) => + item.constructor as ExtractSubjectType, + }); + } + + elasticSearchEndpointAccess(user: JWTUser) { + const { can, build } = new AbilityBuilder( + createMongoAbility, + ); + + if ( + user && + user.currentGroups.some((g) => configuration().adminGroups.includes(g)) + ) { + /* + / user that belongs to any of the group listed in ADMIN_GROUPS + */ + can(Action.Manage, ElasticSearchActions); + } + return build({ + detectSubjectType: (item) => + item.constructor as ExtractSubjectType, + }); + } + + instrumentEndpointAccess(user: JWTUser) { + const { can, cannot, build } = new AbilityBuilder( + createMongoAbility, + ); + + if (!user) { + cannot(Action.InstrumentRead, Instrument); + cannot(Action.InstrumentCreate, Instrument); + cannot(Action.InstrumentUpdate, Instrument); + cannot(Action.InstrumentDelete, Instrument); + } else { + if ( + user.currentGroups.some((g) => configuration().deleteGroups.includes(g)) + ) { + /* + * user that belongs to any of the group listed in DELETE_GROUPS + */ + + can(Action.InstrumentDelete, Instrument); + } else { + cannot(Action.InstrumentDelete, Instrument); + } + + if ( + user.currentGroups.some((g) => configuration().adminGroups.includes(g)) + ) { + /** + * authenticated users belonging to any of the group listed in ADMIN_GROUPS + */ - can(Action.Delete, PublishedData); - can(Action.Delete, Policy); + can(Action.InstrumentRead, Instrument); + can(Action.InstrumentCreate, Instrument); + can(Action.InstrumentUpdate, Instrument); } else { + can(Action.InstrumentRead, Instrument); + cannot(Action.InstrumentCreate, Instrument); + cannot(Action.InstrumentUpdate, Instrument); + } + } + + return build({ + detectSubjectType: (item) => + item.constructor as ExtractSubjectType, + }); + } + + jobsEndpointAccess(user: JWTUser) { + const { can, cannot, build } = new AbilityBuilder( + createMongoAbility, + ); + if (!user) { + /** + * unauthenticated users + */ + + cannot(Action.JobsRead, JobClass); + cannot(Action.JobsCreate, JobClass); + cannot(Action.JobsUpdate, JobClass); + } else if ( + user.currentGroups.some((g) => configuration().adminGroups.includes(g)) + ) { + /** + * authenticated users belonging to any of the group listed in ADMIN_GROUPS + */ + + can(Action.JobsRead, JobClass); + can(Action.JobsCreate, JobClass); + can(Action.JobsUpdate, JobClass); + } else if ( + user.currentGroups.some((g) => + configuration().createJobGroups.includes(g), + ) + ) { + /** + * authenticated users belonging to any of the group listed in CREATE_JOBS_GROUPS + */ + + can(Action.JobsRead, JobClass); + can(Action.JobsCreate, JobClass); + can(Action.JobsUpdate, JobClass); + } else if ( + user.currentGroups.some((g) => + configuration().updateJobGroups.includes(g), + ) + ) { + /** + * authenticated users belonging to any of the group listed in UPDATE_JOBS_GROUPS + */ + + cannot(Action.JobsRead, JobClass); + cannot(Action.JobsCreate, JobClass); + can(Action.JobsUpdate, JobClass); + } else if (user) { + /** + * authenticated users + */ + + can(Action.JobsRead, JobClass); + cannot(Action.JobsCreate, JobClass); + cannot(Action.JobsUpdate, JobClass); + } + + return build({ + detectSubjectType: (item) => + item.constructor as ExtractSubjectType, + }); + } + + logbookEndpointAccess(user: JWTUser) { + const { can, build } = new AbilityBuilder( + createMongoAbility, + ); + + if (user) { + /* + / authenticated user + */ + can(Action.Read, Logbook); + } + return build({ + detectSubjectType: (item) => + item.constructor as ExtractSubjectType, + }); + } + + origDatablockEndpointAccess(user: JWTUser) { + const { can, cannot, build } = new AbilityBuilder( + createMongoAbility, + ); + if ( + user.currentGroups.some((g) => configuration().deleteGroups.includes(g)) + ) { + /* + / user that belongs to any of the group listed in DELETE_GROUPS + */ + + can(Action.OrigdatablockDelete, OrigDatablock); + } else { + /* + / user that does not belong to any of the group listed in DELETE_GROUPS + */ + + cannot(Action.OrigdatablockDelete, OrigDatablock); + } + + if ( + user.currentGroups.some((g) => configuration().adminGroups.includes(g)) + ) { + /* + / user that belongs to any of the group listed in ADMIN_GROUPS + */ + + can(Action.OrigdatablockRead, OrigDatablock); + can(Action.OrigdatablockCreate, OrigDatablock); + can(Action.OrigdatablockUpdate, OrigDatablock); + } else if ( + user.currentGroups.some((g) => + configuration().createDatasetPrivilegedGroups.includes(g), + ) + ) { + /** + /* users belonging to CREATE_DATASET_PRIVILEGED_GROUPS + **/ + + can(Action.OrigdatablockRead, OrigDatablock); + can(Action.OrigdatablockCreate, OrigDatablock); + can(Action.OrigdatablockUpdate, OrigDatablock); + } else if ( + user.currentGroups.some((g) => + configuration().createDatasetWithPidGroups.includes(g), + ) || + configuration().createDatasetWithPidGroups.includes("#all") + ) { + /** + /* users belonging to CREATE_DATASET_WITH_PID_GROUPS + **/ + + can(Action.OrigdatablockRead, OrigDatablock); + can(Action.OrigdatablockCreate, OrigDatablock); + can(Action.OrigdatablockUpdate, OrigDatablock); + } else if ( + user.currentGroups.some((g) => + configuration().createDatasetGroups.includes(g), + ) || + configuration().createDatasetGroups.includes("#all") + ) { + /** + /* users belonging to CREATE_DATASET_GROUPS + **/ + + can(Action.OrigdatablockRead, OrigDatablock); + can(Action.OrigdatablockCreate, OrigDatablock); + can(Action.OrigdatablockUpdate, OrigDatablock); + } else if (user) { + /** + /* authenticated users + **/ + + can(Action.OrigdatablockRead, OrigDatablock); + cannot(Action.OrigdatablockCreate, OrigDatablock); + cannot(Action.OrigdatablockUpdate, OrigDatablock); + } + return build({ + detectSubjectType: (item) => + item.constructor as ExtractSubjectType, + }); + } + + policyEndpointAccess(user: JWTUser) { + const { can, build } = new AbilityBuilder( + createMongoAbility, + ); + if ( + user && + user.currentGroups.some((g) => configuration().deleteGroups.includes(g)) + ) { + /* + / user that belongs to any of the group listed in DELETE_GROUPS + */ + can(Action.Delete, Policy); + } else if ( + user && + user.currentGroups.some((g) => configuration().adminGroups.includes(g)) + ) { + /* + / user that belongs to any of the group listed in ADMIN_GROUPS + */ + + can(Action.Update, Policy); + can(Action.Read, Policy); + can(Action.Create, Policy); + } + return build({ + detectSubjectType: (item) => + item.constructor as ExtractSubjectType, + }); + } + + proposalsEndpointAccess(user: JWTUser) { + const { can, cannot, build } = new AbilityBuilder( + createMongoAbility, + ); + if (!user) { + /** + * unauthenticated users + */ + + can(Action.ProposalsRead, ProposalClass); + cannot(Action.ProposalsCreate, ProposalClass); + cannot(Action.ProposalsUpdate, ProposalClass); + cannot(Action.ProposalsDelete, ProposalClass); + can(Action.ProposalsAttachmentRead, ProposalClass); + cannot(Action.ProposalsAttachmentCreate, ProposalClass); + cannot(Action.ProposalsAttachmentUpdate, ProposalClass); + cannot(Action.ProposalsAttachmentDelete, ProposalClass); + } else if ( + user.currentGroups.some((g) => configuration().deleteGroups.includes(g)) + ) { + /* + / user that belongs to any of the group listed in DELETE_GROUPS + */ + + can(Action.ProposalsDelete, ProposalClass); + } else if ( + user.currentGroups.some((g) => configuration().adminGroups.includes(g)) + ) { + /** + * authenticated users belonging to any of the group listed in ADMIN_GROUPS + */ + + can(Action.ProposalsRead, ProposalClass); + can(Action.ProposalsCreate, ProposalClass); + can(Action.ProposalsUpdate, ProposalClass); + cannot(Action.ProposalsDelete, ProposalClass); + can(Action.ProposalsAttachmentRead, ProposalClass); + can(Action.ProposalsAttachmentCreate, ProposalClass); + can(Action.ProposalsAttachmentUpdate, ProposalClass); + can(Action.ProposalsAttachmentDelete, ProposalClass); + } else if ( + user.currentGroups.some((g) => { + return configuration().proposalGroups.includes(g); + }) + ) { + /** + * authenticated users belonging to any of the group listed in PROPOSAL_GROUPS + */ + + can(Action.ProposalsRead, ProposalClass); + can(Action.ProposalsCreate, ProposalClass); + can(Action.ProposalsUpdate, ProposalClass); + cannot(Action.ProposalsDelete, ProposalClass); + can(Action.ProposalsAttachmentRead, ProposalClass); + can(Action.ProposalsAttachmentCreate, ProposalClass); + can(Action.ProposalsAttachmentUpdate, ProposalClass); + can(Action.ProposalsAttachmentDelete, ProposalClass); + cannot(Action.ProposalsDatasetRead, ProposalClass); + } else if (user) { + /** + * authenticated users + */ + + can(Action.ProposalsRead, ProposalClass); + cannot(Action.ProposalsCreate, ProposalClass); + cannot(Action.ProposalsUpdate, ProposalClass); + cannot(Action.ProposalsDelete, ProposalClass); + can(Action.ProposalsAttachmentRead, ProposalClass); + cannot(Action.ProposalsAttachmentCreate, ProposalClass); + cannot(Action.ProposalsAttachmentUpdate, ProposalClass); + cannot(Action.ProposalsAttachmentDelete, ProposalClass); + can(Action.ProposalsDatasetRead, ProposalClass); + } + return build({ + detectSubjectType: (item) => + item.constructor as ExtractSubjectType, + }); + } + + publishedDataEndpointAccess(user: JWTUser) { + const { can, build } = new AbilityBuilder( + createMongoAbility, + ); + if (user) { + can(Action.Read, PublishedData); + can(Action.Update, PublishedData); + can(Action.Create, PublishedData); + } + + if ( + user && + user.currentGroups.some((g) => configuration().deleteGroups.includes(g)) + ) { + /* + / user that belongs to any of the group listed in DELETE_GROUPS + */ + can(Action.Delete, PublishedData); + } + return build({ + detectSubjectType: (item) => + item.constructor as ExtractSubjectType, + }); + } + + samplesEndpointAccess(user: JWTUser) { + const { can, cannot, build } = new AbilityBuilder( + createMongoAbility, + ); + + if (!user) { + // ------------------------------------- + // unauthenticated users + // ------------------------------------- + + can(Action.SampleRead, SampleClass); + cannot(Action.SampleCreate, SampleClass); + cannot(Action.SampleUpdate, SampleClass); + cannot(Action.SampleDelete, SampleClass); + can(Action.SampleAttachmentRead, SampleClass); + cannot(Action.SampleAttachmentCreate, SampleClass); + cannot(Action.SampleAttachmentUpdate, SampleClass); + cannot(Action.SampleAttachmentDelete, SampleClass); + cannot(Action.SampleDatasetRead, SampleClass); + } else { + // ------------------------------------- + // authenticated users + // ------------------------------------- + + if ( + user.currentGroups.some((g) => configuration().deleteGroups.includes(g)) + ) { + // ------------------------------------- + // users that belong to any of the group listed in DELETE_GROUPS + // ------------------------------------- + + can(Action.SampleDelete, SampleClass); + can(Action.SampleAttachmentDelete, SampleClass); + } else { + // ------------------------------------- + // users that do not belong to any of the group listed in DELETE_GROUPS + // ------------------------------------- + + cannot(Action.SampleDelete, SampleClass); + } + + if ( + user.currentGroups.some((g) => configuration().adminGroups.includes(g)) + ) { + // ------------------------------------- + // users belonging to any of the group listed in ADMIN_GROUPS + // ------------------------------------- + + can(Action.SampleRead, SampleClass); + can(Action.SampleCreate, SampleClass); + can(Action.SampleUpdate, SampleClass); + can(Action.SampleAttachmentRead, SampleClass); + can(Action.SampleAttachmentCreate, SampleClass); + can(Action.SampleAttachmentUpdate, SampleClass); + can(Action.SampleAttachmentDelete, SampleClass); + can(Action.SampleDatasetRead, SampleClass); + } else if ( + user.currentGroups.some((g) => + configuration().samplePrivilegedGroups.includes(g), + ) + ) { + // ------------------------------------- + // users belonging to any of the group listed in SAMPLE_GROUPS + // + + can(Action.SampleRead, SampleClass); + can(Action.SampleCreate, SampleClass); + can(Action.SampleUpdate, SampleClass); + can(Action.SampleAttachmentRead, SampleClass); + can(Action.SampleAttachmentCreate, SampleClass); + can(Action.SampleAttachmentUpdate, SampleClass); + can(Action.SampleAttachmentDelete, SampleClass); + can(Action.SampleDatasetRead, SampleClass); + } else if ( + user.currentGroups.some((g) => + configuration().sampleGroups.includes(g), + ) || + configuration().sampleGroups.includes("#all") + ) { + // ------------------------------------- + // users belonging to any of the group listed in SAMPLE_GROUPS + // + + can(Action.SampleRead, SampleClass); + can(Action.SampleCreate, SampleClass); + can(Action.SampleUpdate, SampleClass); + can(Action.SampleAttachmentRead, SampleClass); + can(Action.SampleAttachmentCreate, SampleClass); + can(Action.SampleAttachmentUpdate, SampleClass); + can(Action.SampleAttachmentDelete, SampleClass); + can(Action.SampleDatasetRead, SampleClass); + } else { + // ------------------------------------- + // users with no elevated permissions + // ------------------------------------- + + can(Action.SampleRead, SampleClass); + cannot(Action.SampleCreate, SampleClass); + cannot(Action.SampleUpdate, SampleClass); + can(Action.SampleAttachmentRead, SampleClass); + cannot(Action.SampleAttachmentCreate, SampleClass); + cannot(Action.SampleAttachmentUpdate, SampleClass); + if ( + !user.currentGroups.some((g) => + configuration().deleteGroups.includes(g), + ) + ) { + cannot(Action.SampleAttachmentDelete, SampleClass); + } + } + } + + return build({ + detectSubjectType: (item) => + item.constructor as ExtractSubjectType, + }); + } + + userEndpointAccess(user: JWTUser) { + const { can, cannot, build } = new AbilityBuilder( + createMongoAbility, + ); + + if (!user) { + /** + /* unauthenticated users + **/ + + cannot(Action.UserReadOwn, User); + cannot(Action.UserCreateOwn, User); + cannot(Action.UserUpdateOwn, User); + cannot(Action.UserDeleteOwn, User); + cannot(Action.UserReadAny, User); + cannot(Action.UserCreateAny, User); + cannot(Action.UserUpdateAny, User); + cannot(Action.UserDeleteAny, User); + } else { + if ( + user.currentGroups.some((g) => configuration().adminGroups.includes(g)) + ) { + /* + / user that belongs to any of the group listed in ADMIN_GROUPS + */ + + // can(Action.ReadAll, UserIdentity); NOT used? + + // ------------------------------------- + // user endpoint, including useridentity + can(Action.UserReadAny, User); + can(Action.UserReadOwn, User); + can(Action.UserCreateAny, User); + can(Action.UserUpdateAny, User); + can(Action.UserDeleteAny, User); + can(Action.UserCreateJwt, User); + + // ------------------------------------- + } else if (user) { + /** + /* authenticated users + **/ + cannot(Action.UserReadAny, User); + cannot(Action.UserCreateAny, User); + cannot(Action.UserUpdateAny, User); + cannot(Action.UserDeleteAny, User); + cannot(Action.UserCreateJwt, User); + } + can(Action.UserReadOwn, User, { _id: user._id }); + can(Action.UserCreateOwn, User, { _id: user._id }); + can(Action.UserUpdateOwn, User, { _id: user._id }); + can(Action.UserDeleteOwn, User, { _id: user._id }); + } + return build({ + detectSubjectType: (item) => + item.constructor as ExtractSubjectType, + }); + } + + datasetInstanceAccess(user: JWTUser) { + const { can, build } = new AbilityBuilder( + createMongoAbility, + ); + + if (!user) { + /** + /* unauthenticated users + **/ + + can(Action.DatasetReadManyPublic, DatasetClass); + can(Action.DatasetReadOnePublic, DatasetClass, { + isPublished: true, + }); + // - + can(Action.DatasetAttachmentReadPublic, DatasetClass, { + isPublished: true, + }); + // - + can(Action.DatasetOrigdatablockReadPublic, DatasetClass, { + isPublished: true, + }); + // - + can(Action.DatasetDatablockReadPublic, DatasetClass, { + isPublished: true, + }); + } else { + if ( + user.currentGroups.some((g) => configuration().deleteGroups.includes(g)) + ) { /* - / user that does not belong to any of the group listed in DELETE_GROUPS + / user that belongs to any of the group listed in DELETE_GROUPS */ - // ------------------------------------- - // datasets - // ------------------------------------- - // endpoint authorization - cannot(Action.DatasetDelete, DatasetClass); + can(Action.DatasetDeleteAny, DatasetClass); // - - cannot(Action.DatasetOrigdatablockDelete, DatasetClass); + can(Action.DatasetOrigdatablockDeleteAny, DatasetClass); // - - cannot(Action.DatasetDatablockDelete, DatasetClass); - - // ------------------------------------- - // origdatablock - // ------------------------------------- - // endpoint authorization - cannot(Action.OrigdatablockDelete, OrigDatablock); + can(Action.DatasetDatablockDeleteAny, DatasetClass); } if ( @@ -212,41 +859,6 @@ export class CaslAbilityFactory { / user that belongs to any of the group listed in ADMIN_GROUPS */ - // this tests should be all removed, once we are done with authorization review - //can(Action.ListAll, DatasetClass); - // can(Action.ListAll, ProposalClass); - can(Action.ReadAll, UserIdentity); - - // ------------------------------------- - // elasticsearch - // ------------------------------------- - // endpoint authorization - can(Action.Manage, ElasticSearchActions); - - // ------------------------------------- - // datasets - // ------------------------------------- - // endpoint authorization - can(Action.DatasetCreate, DatasetClass); - can(Action.DatasetRead, DatasetClass); - can(Action.DatasetUpdate, DatasetClass); - // - - can(Action.DatasetAttachmentCreate, DatasetClass); - can(Action.DatasetAttachmentRead, DatasetClass); - can(Action.DatasetAttachmentUpdate, DatasetClass); - can(Action.DatasetAttachmentDelete, DatasetClass); - // - - can(Action.DatasetOrigdatablockCreate, DatasetClass); - can(Action.DatasetOrigdatablockRead, DatasetClass); - can(Action.DatasetOrigdatablockUpdate, DatasetClass); - // - - can(Action.DatasetDatablockCreate, DatasetClass); - can(Action.DatasetDatablockRead, DatasetClass); - can(Action.DatasetDatablockUpdate, DatasetClass); - // - - can(Action.DatasetLogbookRead, DatasetClass); - // ------------------------------------- - // data instance authorization can(Action.DatasetCreateAny, DatasetClass); can(Action.DatasetReadAny, DatasetClass); can(Action.DatasetUpdateAny, DatasetClass); @@ -265,34 +877,6 @@ export class CaslAbilityFactory { can(Action.DatasetDatablockUpdateAny, DatasetClass); // ------------------------------------- can(Action.DatasetLogbookReadAny, DatasetClass); - - // ------------------------------------- - // origdatablock - // ------------------------------------- - // endpoint authorization - can(Action.OrigdatablockRead, OrigDatablock); - can(Action.OrigdatablockCreate, OrigDatablock); - can(Action.OrigdatablockUpdate, OrigDatablock); - // ------------------------------------- - // data instance authorization - can(Action.OrigdatablockReadAny, OrigDatablock); - can(Action.OrigdatablockCreateAny, OrigDatablock); - can(Action.OrigdatablockUpdateAny, OrigDatablock); - - // ------------------------------------- - // user endpoint, including useridentity - can(Action.UserReadAny, User); - can(Action.UserReadOwn, User); - can(Action.UserCreateAny, User); - can(Action.UserUpdateAny, User); - can(Action.UserDeleteAny, User); - can(Action.UserCreateJwt, User); - - // ------------------------------------- - // policies - can(Action.Update, Policy); - can(Action.Read, Policy); - can(Action.Create, Policy); } else if ( user.currentGroups.some((g) => configuration().createDatasetPrivilegedGroups.includes(g), @@ -302,30 +886,6 @@ export class CaslAbilityFactory { /* users belonging to CREATE_DATASET_PRIVILEGED_GROUPS **/ - // ------------------------------------- - // datasets - // ------------------------------------- - // endpoint authorization - can(Action.DatasetCreate, DatasetClass); - can(Action.DatasetRead, DatasetClass); - can(Action.DatasetUpdate, DatasetClass); - // - - can(Action.DatasetAttachmentCreate, DatasetClass); - can(Action.DatasetAttachmentRead, DatasetClass); - can(Action.DatasetAttachmentUpdate, DatasetClass); - can(Action.DatasetAttachmentDelete, DatasetClass); - // - - can(Action.DatasetOrigdatablockCreate, DatasetClass); - can(Action.DatasetOrigdatablockRead, DatasetClass); - can(Action.DatasetOrigdatablockUpdate, DatasetClass); - // - - can(Action.DatasetDatablockCreate, DatasetClass); - can(Action.DatasetDatablockRead, DatasetClass); - can(Action.DatasetDatablockUpdate, DatasetClass); - // - - can(Action.DatasetLogbookRead, DatasetClass); - // ------------------------------------- - // data instance authorization can(Action.DatasetCreateAny, DatasetClass); can(Action.DatasetReadManyAccess, DatasetClass); can(Action.DatasetReadOneAccess, DatasetClass, { @@ -389,30 +949,6 @@ export class CaslAbilityFactory { can(Action.DatasetLogbookReadOwner, DatasetClass, { ownerGroup: { $in: user.currentGroups }, }); - - // ------------------------------------- - // origdatablock - // ------------------------------------- - // endpoint authorization - can(Action.OrigdatablockRead, OrigDatablock); - can(Action.OrigdatablockCreate, OrigDatablock); - can(Action.OrigdatablockUpdate, OrigDatablock); - // ------------------------------------- - // data instance authorization - can(Action.OrigdatablockCreateAny, OrigDatablock); - can(Action.OrigdatablockReadManyAccess, OrigDatablock); - can(Action.OrigdatablockReadOneAccess, OrigDatablock, { - ownerGroup: { $in: user.currentGroups }, - }); - can(Action.OrigdatablockReadOneAccess, OrigDatablock, { - accessGroups: { $in: user.currentGroups }, - }); - can(Action.OrigdatablockReadOneAccess, OrigDatablock, { - ownerGroup: { $in: user.currentGroups }, - }); - can(Action.OrigdatablockUpdateOwner, OrigDatablock, { - ownerGroup: { $in: user.currentGroups }, - }); } else if ( user.currentGroups.some((g) => configuration().createDatasetWithPidGroups.includes(g), @@ -423,28 +959,6 @@ export class CaslAbilityFactory { /* users belonging to CREATE_DATASET_WITH_PID_GROUPS **/ - // ------------------------------------- - // datasets endpoint authorization - can(Action.DatasetCreate, DatasetClass); - can(Action.DatasetRead, DatasetClass); - can(Action.DatasetUpdate, DatasetClass); - // - - can(Action.DatasetAttachmentCreate, DatasetClass); - can(Action.DatasetAttachmentRead, DatasetClass); - can(Action.DatasetAttachmentUpdate, DatasetClass); - can(Action.DatasetAttachmentDelete, DatasetClass); - // - - can(Action.DatasetOrigdatablockCreate, DatasetClass); - can(Action.DatasetOrigdatablockRead, DatasetClass); - can(Action.DatasetOrigdatablockUpdate, DatasetClass); - // - - can(Action.DatasetDatablockCreate, DatasetClass); - can(Action.DatasetDatablockRead, DatasetClass); - can(Action.DatasetDatablockUpdate, DatasetClass); - // - - can(Action.DatasetLogbookRead, DatasetClass); - // ------------------------------------- - // datasets data instance authorization can(Action.DatasetCreateOwnerWithPid, DatasetClass, { ownerGroup: { $in: user.currentGroups }, }); @@ -516,32 +1030,6 @@ export class CaslAbilityFactory { can(Action.DatasetLogbookReadOwner, DatasetClass, { ownerGroup: { $in: user.currentGroups }, }); - - // ------------------------------------- - // origdatablock - // ------------------------------------- - // endpoint authorization - can(Action.OrigdatablockRead, OrigDatablock); - can(Action.OrigdatablockCreate, OrigDatablock); - can(Action.OrigdatablockUpdate, OrigDatablock); - // ------------------------------------- - // data instance authorization - can(Action.OrigdatablockCreateOwner, OrigDatablock, { - ownerGroup: { $in: user.currentGroups }, - }); - can(Action.OrigdatablockReadManyAccess, OrigDatablock); - can(Action.OrigdatablockReadOneAccess, OrigDatablock, { - ownerGroup: { $in: user.currentGroups }, - }); - can(Action.OrigdatablockReadOneAccess, OrigDatablock, { - accessGroups: { $in: user.currentGroups }, - }); - can(Action.OrigdatablockReadOneAccess, OrigDatablock, { - isPublished: true, - }); - can(Action.OrigdatablockUpdateOwner, OrigDatablock, { - ownerGroup: { $in: user.currentGroups }, - }); } else if ( user.currentGroups.some((g) => configuration().createDatasetGroups.includes(g), @@ -552,28 +1040,6 @@ export class CaslAbilityFactory { /* users belonging to CREATE_DATASET_GROUPS **/ - // ------------------------------------- - // datasets endpoint authorization - can(Action.DatasetCreate, DatasetClass); - can(Action.DatasetRead, DatasetClass); - can(Action.DatasetUpdate, DatasetClass); - // - - can(Action.DatasetAttachmentCreate, DatasetClass); - can(Action.DatasetAttachmentRead, DatasetClass); - can(Action.DatasetAttachmentUpdate, DatasetClass); - can(Action.DatasetAttachmentDelete, DatasetClass); - // - - can(Action.DatasetOrigdatablockCreate, DatasetClass); - can(Action.DatasetOrigdatablockRead, DatasetClass); - can(Action.DatasetOrigdatablockUpdate, DatasetClass); - // - - can(Action.DatasetDatablockCreate, DatasetClass); - can(Action.DatasetDatablockRead, DatasetClass); - can(Action.DatasetDatablockUpdate, DatasetClass); - // - - can(Action.DatasetLogbookRead, DatasetClass); - // ------------------------------------- - // datasets data instance authorization can(Action.DatasetCreateOwnerNoPid, DatasetClass, { ownerGroup: { $in: user.currentGroups }, pid: { $eq: "" }, @@ -647,59 +1113,11 @@ export class CaslAbilityFactory { can(Action.DatasetLogbookReadOwner, DatasetClass, { ownerGroup: { $in: user.currentGroups }, }); - - // ------------------------------------- - // origdatablock - // ------------------------------------- - // endpoint authorization - can(Action.OrigdatablockRead, OrigDatablock); - can(Action.OrigdatablockCreate, OrigDatablock); - can(Action.OrigdatablockUpdate, OrigDatablock); - // ------------------------------------- - // data instance authorization - can(Action.OrigdatablockCreateOwner, OrigDatablock, { - ownerGroup: { $in: user.currentGroups }, - }); - can(Action.OrigdatablockReadManyAccess, OrigDatablock); - can(Action.OrigdatablockReadOneAccess, OrigDatablock, { - ownerGroup: { $in: user.currentGroups }, - }); - can(Action.OrigdatablockReadOneAccess, OrigDatablock, { - accessGroups: { $in: user.currentGroups }, - }); - can(Action.OrigdatablockReadOneAccess, OrigDatablock, { - isPublished: true, - }); - can(Action.OrigdatablockUpdateOwner, OrigDatablock, { - ownerGroup: { $in: user.currentGroups }, - }); } else if (user) { /** /* authenticated users **/ - // ------------------------------------- - // datasets endpoint authorization - cannot(Action.DatasetCreate, DatasetClass); - can(Action.DatasetRead, DatasetClass); - cannot(Action.DatasetUpdate, DatasetClass); - // - - cannot(Action.DatasetAttachmentCreate, DatasetClass); - can(Action.DatasetAttachmentRead, DatasetClass); - cannot(Action.DatasetAttachmentUpdate, DatasetClass); - cannot(Action.DatasetAttachmentDelete, DatasetClass); - // - - cannot(Action.DatasetOrigdatablockCreate, DatasetClass); - can(Action.DatasetOrigdatablockRead, DatasetClass); - cannot(Action.DatasetOrigdatablockUpdate, DatasetClass); - // - - cannot(Action.DatasetDatablockCreate, DatasetClass); - can(Action.DatasetDatablockRead, DatasetClass); - cannot(Action.DatasetDatablockUpdate, DatasetClass); - // - - can(Action.DatasetLogbookRead, DatasetClass); - // ------------------------------------- - // datasets data instance authorization can(Action.DatasetReadManyAccess, DatasetClass); can(Action.DatasetReadOneAccess, DatasetClass, { ownerGroup: { $in: user.currentGroups }, @@ -744,70 +1162,140 @@ export class CaslAbilityFactory { can(Action.DatasetLogbookReadOwner, DatasetClass, { ownerGroup: { $in: user.currentGroups }, }); - - // ------------------------------------- - // origdatablock - // ------------------------------------- - // endpoint authorization - can(Action.OrigdatablockRead, OrigDatablock); - cannot(Action.OrigdatablockCreate, OrigDatablock); - cannot(Action.OrigdatablockUpdate, OrigDatablock); - // ------------------------------------- - // data instance authorization - can(Action.OrigdatablockReadManyAccess, OrigDatablock); - can(Action.OrigdatablockReadOneAccess, OrigDatablock, { - ownerGroup: { $in: user.currentGroups }, - }); - can(Action.OrigdatablockReadOneAccess, OrigDatablock, { - accessGroups: { $in: user.currentGroups }, - }); - can(Action.OrigdatablockReadOneAccess, OrigDatablock, { - isPublished: true, - }); - cannot(Action.UserReadAny, User); - cannot(Action.UserCreateAny, User); - cannot(Action.UserUpdateAny, User); - cannot(Action.UserDeleteAny, User); - cannot(Action.UserCreateJwt, User); } - can(Action.UserReadOwn, User, { _id: user._id }); - can(Action.UserCreateOwn, User, { _id: user._id }); - can(Action.UserUpdateOwn, User, { _id: user._id }); - can(Action.UserDeleteOwn, User, { _id: user._id }); } + return build({ + detectSubjectType: (item) => + item.constructor as ExtractSubjectType, + }); + } + + origDatablockInstanceAccess(user: JWTUser) { + const { can, build } = new AbilityBuilder( + createMongoAbility, + ); + if ( + user.currentGroups.some((g) => configuration().deleteGroups.includes(g)) + ) { + /* + / user that belongs to any of the group listed in DELETE_GROUPS + */ + + can(Action.OrigdatablockDeleteAny, OrigDatablock); + } + if ( + user.currentGroups.some((g) => configuration().adminGroups.includes(g)) + ) { + /* + / user that belongs to any of the group listed in ADMIN_GROUPS + */ + + can(Action.OrigdatablockReadAny, OrigDatablock); + can(Action.OrigdatablockCreateAny, OrigDatablock); + can(Action.OrigdatablockUpdateAny, OrigDatablock); + } else if ( + user.currentGroups.some((g) => + configuration().createDatasetPrivilegedGroups.includes(g), + ) + ) { + /** + /* users belonging to CREATE_DATASET_PRIVILEGED_GROUPS + **/ + can(Action.OrigdatablockCreateAny, OrigDatablock); + can(Action.OrigdatablockReadManyAccess, OrigDatablock); + can(Action.OrigdatablockReadOneAccess, OrigDatablock, { + ownerGroup: { $in: user.currentGroups }, + }); + can(Action.OrigdatablockReadOneAccess, OrigDatablock, { + accessGroups: { $in: user.currentGroups }, + }); + can(Action.OrigdatablockReadOneAccess, OrigDatablock, { + ownerGroup: { $in: user.currentGroups }, + }); + can(Action.OrigdatablockUpdateOwner, OrigDatablock, { + ownerGroup: { $in: user.currentGroups }, + }); + } else if ( + user.currentGroups.some((g) => + configuration().createDatasetWithPidGroups.includes(g), + ) || + configuration().createDatasetWithPidGroups.includes("#all") + ) { + /** + /* users belonging to CREATE_DATASET_WITH_PID_GROUPS + **/ - // ************************************ - // JOBS AUTHORIZATION - // ************************************ + can(Action.OrigdatablockCreateOwner, OrigDatablock, { + ownerGroup: { $in: user.currentGroups }, + }); + can(Action.OrigdatablockReadManyAccess, OrigDatablock); + can(Action.OrigdatablockReadOneAccess, OrigDatablock, { + ownerGroup: { $in: user.currentGroups }, + }); + can(Action.OrigdatablockReadOneAccess, OrigDatablock, { + accessGroups: { $in: user.currentGroups }, + }); + can(Action.OrigdatablockReadOneAccess, OrigDatablock, { + isPublished: true, + }); + can(Action.OrigdatablockUpdateOwner, OrigDatablock, { + ownerGroup: { $in: user.currentGroups }, + }); + } else if ( + user.currentGroups.some((g) => + configuration().createDatasetGroups.includes(g), + ) || + configuration().createDatasetGroups.includes("#all") + ) { + /** + /* users belonging to CREATE_DATASET_GROUPS + **/ - if (!user) { + can(Action.OrigdatablockCreateOwner, OrigDatablock, { + ownerGroup: { $in: user.currentGroups }, + }); + can(Action.OrigdatablockReadManyAccess, OrigDatablock); + can(Action.OrigdatablockReadOneAccess, OrigDatablock, { + ownerGroup: { $in: user.currentGroups }, + }); + can(Action.OrigdatablockReadOneAccess, OrigDatablock, { + accessGroups: { $in: user.currentGroups }, + }); + can(Action.OrigdatablockReadOneAccess, OrigDatablock, { + isPublished: true, + }); + can(Action.OrigdatablockUpdateOwner, OrigDatablock, { + ownerGroup: { $in: user.currentGroups }, + }); + } else if (user) { /** - * unauthenticated users - */ + /* authenticated users + **/ - // ------------------------------------- - // jobs - // ------------------------------------- - // endpoint authorization - cannot(Action.JobsRead, JobClass); - cannot(Action.JobsCreate, JobClass); - cannot(Action.JobsUpdate, JobClass); - } else if ( + can(Action.OrigdatablockReadManyAccess, OrigDatablock); + can(Action.OrigdatablockReadOneAccess, OrigDatablock, { + ownerGroup: { $in: user.currentGroups }, + }); + can(Action.OrigdatablockReadOneAccess, OrigDatablock, { + accessGroups: { $in: user.currentGroups }, + }); + can(Action.OrigdatablockReadOneAccess, OrigDatablock, { + isPublished: true, + }); + } + return build({ + detectSubjectType: (item) => + item.constructor as ExtractSubjectType, + }); + } + + jobsInstanceAccess(user: JWTUser) { + const { can, build } = new AbilityBuilder( + createMongoAbility, + ); + if ( user.currentGroups.some((g) => configuration().adminGroups.includes(g)) ) { - /** - * authenticated users belonging to any of the group listed in ADMIN_GROUPS - */ - - // ------------------------------------- - // jobs - // ------------------------------------- - // endpoint authorization - can(Action.JobsRead, JobClass); - can(Action.JobsCreate, JobClass); - can(Action.JobsUpdate, JobClass); - // ------------------------------------- - // data instance authorization can(Action.JobsReadAny, JobClass); can(Action.JobsCreateAny, JobClass); can(Action.JobsUpdateAny, JobClass); @@ -820,15 +1308,6 @@ export class CaslAbilityFactory { * authenticated users belonging to any of the group listed in CREATE_JOBS_GROUPS */ - // ------------------------------------- - // jobs - // ------------------------------------- - // endpoint authorization - can(Action.JobsRead, JobClass); - can(Action.JobsCreate, JobClass); - can(Action.JobsUpdate, JobClass); - // ------------------------------------- - // data instance authorization can(Action.JobsCreateAny, JobClass, { ownerGroup: { $in: user.currentGroups }, }); @@ -847,15 +1326,6 @@ export class CaslAbilityFactory { * authenticated users belonging to any of the group listed in UPDATE_JOBS_GROUPS */ - // ------------------------------------- - // jobs - // ------------------------------------- - // endpoint authorization - cannot(Action.JobsRead, JobClass); - cannot(Action.JobsCreate, JobClass); - can(Action.JobsUpdate, JobClass); - // ------------------------------------- - // data instance authorization can(Action.JobsUpdateAny, JobClass, { ownerGroup: { $in: user.currentGroups }, }); @@ -864,44 +1334,26 @@ export class CaslAbilityFactory { * authenticated users */ - // ------------------------------------- - // jobs - // ------------------------------------- - // endpoint authorization - can(Action.JobsRead, JobClass); - cannot(Action.JobsCreate, JobClass); - cannot(Action.JobsUpdate, JobClass); - // ------------------------------------- - // data instance authorization can(Action.JobsReadAccess, JobClass, { ownerGroup: { $in: user.currentGroups }, }); } - // ************************************ - // PROPOSALS AUTHORIZATION - // ************************************ + return build({ + detectSubjectType: (item) => + item.constructor as ExtractSubjectType, + }); + } + proposalsInstanceAccess(user: JWTUser) { + const { can, cannot, build } = new AbilityBuilder( + createMongoAbility, + ); if (!user) { /** * unauthenticated users */ - // ------------------------------------- - // proposals - // ------------------------------------- - // endpoint authorization - can(Action.ProposalsRead, ProposalClass); - cannot(Action.ProposalsCreate, ProposalClass); - cannot(Action.ProposalsUpdate, ProposalClass); - cannot(Action.ProposalsDelete, ProposalClass); - can(Action.ProposalsAttachmentRead, ProposalClass); - cannot(Action.ProposalsAttachmentCreate, ProposalClass); - cannot(Action.ProposalsAttachmentUpdate, ProposalClass); - cannot(Action.ProposalsAttachmentDelete, ProposalClass); - - // ------------------------------------- - // data instance authorization can(Action.ProposalsReadManyPublic, ProposalClass); can(Action.ProposalsReadOnePublic, ProposalClass, { isPublished: true, @@ -915,16 +1367,6 @@ export class CaslAbilityFactory { /* / user that belongs to any of the group listed in DELETE_GROUPS */ - - // ------------------------------------- - // proposals - // ------------------------------------- - // endpoint authorization - can(Action.ProposalsDelete, ProposalClass); - - // ------------------------------------- - // data instance authorization - can(Action.ProposalsDeleteAny, ProposalClass); } else if ( user.currentGroups.some((g) => configuration().adminGroups.includes(g)) @@ -933,20 +1375,6 @@ export class CaslAbilityFactory { * authenticated users belonging to any of the group listed in ADMIN_GROUPS */ - // ------------------------------------- - // proposals - // ------------------------------------- - // endpoint authorization - can(Action.ProposalsRead, ProposalClass); - can(Action.ProposalsCreate, ProposalClass); - can(Action.ProposalsUpdate, ProposalClass); - cannot(Action.ProposalsDelete, ProposalClass); - can(Action.ProposalsAttachmentRead, ProposalClass); - can(Action.ProposalsAttachmentCreate, ProposalClass); - can(Action.ProposalsAttachmentUpdate, ProposalClass); - can(Action.ProposalsAttachmentDelete, ProposalClass); - // ------------------------------------- - // data instance authorization can(Action.ProposalsReadAny, ProposalClass); can(Action.ProposalsCreateAny, ProposalClass); can(Action.ProposalsUpdateAny, ProposalClass); @@ -964,22 +1392,6 @@ export class CaslAbilityFactory { * authenticated users belonging to any of the group listed in PROPOSAL_GROUPS */ - // ------------------------------------- - // proposals - // ------------------------------------- - // endpoint authorization - - can(Action.ProposalsRead, ProposalClass); - can(Action.ProposalsCreate, ProposalClass); - can(Action.ProposalsUpdate, ProposalClass); - cannot(Action.ProposalsDelete, ProposalClass); - can(Action.ProposalsAttachmentRead, ProposalClass); - can(Action.ProposalsAttachmentCreate, ProposalClass); - can(Action.ProposalsAttachmentUpdate, ProposalClass); - can(Action.ProposalsAttachmentDelete, ProposalClass); - cannot(Action.ProposalsDatasetRead, ProposalClass); - // ------------------------------------- - // data instance authorization can(Action.ProposalsCreateAny, ProposalClass); can(Action.ProposalsReadManyAccess, ProposalClass); can(Action.ProposalsReadOneAccess, ProposalClass, { @@ -1013,21 +1425,6 @@ export class CaslAbilityFactory { * authenticated users */ - // ------------------------------------- - // proposals - // ------------------------------------- - // endpoint authorization - can(Action.ProposalsRead, ProposalClass); - cannot(Action.ProposalsCreate, ProposalClass); - cannot(Action.ProposalsUpdate, ProposalClass); - cannot(Action.ProposalsDelete, ProposalClass); - can(Action.ProposalsAttachmentRead, ProposalClass); - cannot(Action.ProposalsAttachmentCreate, ProposalClass); - cannot(Action.ProposalsAttachmentUpdate, ProposalClass); - cannot(Action.ProposalsAttachmentDelete, ProposalClass); - can(Action.ProposalsDatasetRead, ProposalClass); - // ------------------------------------- - // data instance authorization can(Action.ProposalsReadManyAccess, ProposalClass); can(Action.ProposalsReadOneAccess, ProposalClass, { ownerGroup: { $in: user.currentGroups }, @@ -1049,29 +1446,22 @@ export class CaslAbilityFactory { isPublished: true, }); } + return build({ + detectSubjectType: (item) => + item.constructor as ExtractSubjectType, + }); + } + + samplesInstanceAccess(user: JWTUser) { + const { can, cannot, build } = new AbilityBuilder( + createMongoAbility, + ); - // ************************************ - // SAMPLES AUTHORIZATION - // ************************************ if (!user) { // ------------------------------------- // unauthenticated users // ------------------------------------- - // ------------------------------------- - // endpoint authorization - can(Action.SampleRead, SampleClass); - cannot(Action.SampleCreate, SampleClass); - cannot(Action.SampleUpdate, SampleClass); - cannot(Action.SampleDelete, SampleClass); - can(Action.SampleAttachmentRead, SampleClass); - cannot(Action.SampleAttachmentCreate, SampleClass); - cannot(Action.SampleAttachmentUpdate, SampleClass); - cannot(Action.SampleAttachmentDelete, SampleClass); - cannot(Action.SampleDatasetRead, SampleClass); - - // ------------------------------------- - // data instance authorization can(Action.SampleReadManyPublic, SampleClass); can(Action.SampleReadOnePublic, SampleClass, { isPublished: true, @@ -1091,13 +1481,6 @@ export class CaslAbilityFactory { // users that belong to any of the group listed in DELETE_GROUPS // ------------------------------------- - // ------------------------------------- - // endpoint authorization - can(Action.SampleDelete, SampleClass); - can(Action.SampleAttachmentDelete, SampleClass); - - // ------------------------------------- - // data instance authorization can(Action.SampleDeleteAny, SampleClass); can(Action.SampleAttachmentDeleteAny, SampleClass); } else { @@ -1105,12 +1488,6 @@ export class CaslAbilityFactory { // users that do not belong to any of the group listed in DELETE_GROUPS // ------------------------------------- - // ------------------------------------- - // endpoint authorization - cannot(Action.SampleDelete, SampleClass); - - // ------------------------------------- - // data instance authorization cannot(Action.SampleDeleteAny, SampleClass); cannot(Action.SampleDeleteOwner, SampleClass); } @@ -1122,19 +1499,6 @@ export class CaslAbilityFactory { // users belonging to any of the group listed in ADMIN_GROUPS // ------------------------------------- - // ------------------------------------- - // endpoint authorization - can(Action.SampleRead, SampleClass); - can(Action.SampleCreate, SampleClass); - can(Action.SampleUpdate, SampleClass); - can(Action.SampleAttachmentRead, SampleClass); - can(Action.SampleAttachmentCreate, SampleClass); - can(Action.SampleAttachmentUpdate, SampleClass); - can(Action.SampleAttachmentDelete, SampleClass); - can(Action.SampleDatasetRead, SampleClass); - - // ------------------------------------- - // data instance authorization can(Action.SampleReadAny, SampleClass); can(Action.SampleCreateAny, SampleClass); can(Action.SampleUpdateAny, SampleClass); @@ -1151,19 +1515,6 @@ export class CaslAbilityFactory { // users belonging to any of the group listed in SAMPLE_GROUPS // - // ------------------------------------- - // endpoint authorization - can(Action.SampleRead, SampleClass); - can(Action.SampleCreate, SampleClass); - can(Action.SampleUpdate, SampleClass); - can(Action.SampleAttachmentRead, SampleClass); - can(Action.SampleAttachmentCreate, SampleClass); - can(Action.SampleAttachmentUpdate, SampleClass); - can(Action.SampleAttachmentDelete, SampleClass); - can(Action.SampleDatasetRead, SampleClass); - - // ------------------------------------- - // data instance authorization can(Action.SampleCreateAny, SampleClass); can(Action.SampleUpdateOwner, SampleClass, { ownerGroup: { $in: user.currentGroups }, @@ -1204,19 +1555,6 @@ export class CaslAbilityFactory { // users belonging to any of the group listed in SAMPLE_GROUPS // - // ------------------------------------- - // endpoint authorization - can(Action.SampleRead, SampleClass); - can(Action.SampleCreate, SampleClass); - can(Action.SampleUpdate, SampleClass); - can(Action.SampleAttachmentRead, SampleClass); - can(Action.SampleAttachmentCreate, SampleClass); - can(Action.SampleAttachmentUpdate, SampleClass); - can(Action.SampleAttachmentDelete, SampleClass); - can(Action.SampleDatasetRead, SampleClass); - - // ------------------------------------- - // data instance authorization can(Action.SampleCreateOwner, SampleClass, { ownerGroup: { $in: user.currentGroups }, }); @@ -1256,24 +1594,6 @@ export class CaslAbilityFactory { // users with no elevated permissions // ------------------------------------- - // ------------------------------------- - // endpoint authorization - can(Action.SampleRead, SampleClass); - cannot(Action.SampleCreate, SampleClass); - cannot(Action.SampleUpdate, SampleClass); - can(Action.SampleAttachmentRead, SampleClass); - cannot(Action.SampleAttachmentCreate, SampleClass); - cannot(Action.SampleAttachmentUpdate, SampleClass); - if ( - !user.currentGroups.some((g) => - configuration().deleteGroups.includes(g), - ) - ) { - cannot(Action.SampleAttachmentDelete, SampleClass); - } - - // ------------------------------------- - // data instance authorization can(Action.SampleReadManyAccess, SampleClass); can(Action.SampleReadOneAccess, SampleClass, { ownerGroup: { $in: user.currentGroups }, @@ -1296,121 +1616,6 @@ export class CaslAbilityFactory { } } - // ************************************ - // INSTRUMENT AUTHORIZATION - // ************************************ - - if (!user) { - cannot(Action.InstrumentRead, Instrument); - cannot(Action.InstrumentCreate, Instrument); - cannot(Action.InstrumentUpdate, Instrument); - cannot(Action.InstrumentDelete, Instrument); - } else { - if ( - user.currentGroups.some((g) => configuration().deleteGroups.includes(g)) - ) { - /* - * user that belongs to any of the group listed in DELETE_GROUPS - */ - - // ------------------------------------- - // endpoint authorization - can(Action.InstrumentDelete, Instrument); - } else { - cannot(Action.InstrumentDelete, Instrument); - } - - if ( - user.currentGroups.some((g) => configuration().adminGroups.includes(g)) - ) { - /** - * authenticated users belonging to any of the group listed in ADMIN_GROUPS - */ - - // ------------------------------------- - // endpoint authorization - can(Action.InstrumentRead, Instrument); - can(Action.InstrumentCreate, Instrument); - can(Action.InstrumentUpdate, Instrument); - } else { - can(Action.InstrumentRead, Instrument); - cannot(Action.InstrumentCreate, Instrument); - cannot(Action.InstrumentUpdate, Instrument); - } - } - - // Instrument permissions - //can(Action.Read, Instrument); - //if (user.currentGroups.some((g) => adminGroups.includes(g))) { - // can(Action.Manage, Instrument); - //} - - //can(Action.Manage, JobClass); - - can(Action.Read, Logbook); - - can(Action.Read, PublishedData); - can(Action.Update, PublishedData); - can(Action.Create, PublishedData); - - // can(Action.Manage, Attachment, { - // ownerGroup: { $in: user.currentGroups }, - // }); - // can(Action.Manage, Datablock, { - // ownerGroup: { $in: user.currentGroups }, - // }); - // can(Action.Manage, OrigDatablock, { - // ownerGroup: { $in: user.currentGroups }, - // }); - - // if (user.currentGroups.includes(Role.Admin)) { - // can(Action.Manage, "all"); - // } - // if (user.currentGroups.includes(Role.ArchiveManager)) { - // //cannot(Action.Create, DatasetClass); - // //cannot(Action.Update, DatasetClass); - // //can(Action.Delete, DatasetClass); - // cannot(Action.Manage, OrigDatablock); - // cannot(Action.Create, OrigDatablock); - // cannot(Action.Update, OrigDatablock); - // can(Action.Delete, OrigDatablock); - // cannot(Action.Manage, Datablock); - // cannot(Action.Create, Datablock); - // cannot(Action.Update, Datablock); - // can(Action.Delete, Datablock); - // can(Action.Delete, PublishedData); - // //-------------------------------- - // // instrument - // cannot(Action.InstrumentRead, Instrument); - // cannot(Action.InstrumentCreate, Instrument); - // cannot(Action.InstrumentUpdate, Instrument); - // can(Action.InstrumentDelete, Instrument); - // } - //if (user.currentGroups.includes(Role.GlobalAccess)) { - // can(Action.Read, "all"); - //} - // if (user.currentGroups.includes(Role.Ingestor)) { - // can(Action.Create, Attachment); - - // //cannot(Action.Delete, DatasetClass); - // //can(Action.Create, DatasetClass); - // //can(Action.Update, DatasetClass); - - // can(Action.Create, Instrument); - // can(Action.Update, Instrument); - // } - // if (user.currentGroups.includes(Role.ProposalIngestor)) { - // cannot(Action.Delete, ProposalClass); - // can(Action.Create, ProposalClass); - // can(Action.Update, ProposalClass); - // can(Action.Read, ProposalClass); - // can(Action.ListAll, ProposalClass); - // } - - //can(Action.Create, UserSettings, { userId: user._id }); - //can(Action.Read, UserSettings, { userId: user._id }); - //can(Action.Update, UserSettings, { userId: user._id }); - return build({ detectSubjectType: (item) => item.constructor as ExtractSubjectType, diff --git a/src/casl/decorators/check-policies.decorator.ts b/src/casl/decorators/check-policies.decorator.ts index 6ac4f3550..ec4af992a 100644 --- a/src/casl/decorators/check-policies.decorator.ts +++ b/src/casl/decorators/check-policies.decorator.ts @@ -3,5 +3,5 @@ import { PolicyHandler } from "../interfaces/policy-handler.interface"; export const CHECK_POLICIES_KEY = "check_policy"; -export const CheckPolicies = (...handlers: PolicyHandler[]) => - SetMetadata(CHECK_POLICIES_KEY, handlers); +export const CheckPolicies = (endpoint: string, ...handlers: PolicyHandler[]) => + SetMetadata(CHECK_POLICIES_KEY, { endpoint, handlers }); diff --git a/src/casl/guards/policies.guard.ts b/src/casl/guards/policies.guard.ts index 17ff148ce..0aa563ac0 100644 --- a/src/casl/guards/policies.guard.ts +++ b/src/casl/guards/policies.guard.ts @@ -12,22 +12,27 @@ export class PoliciesGuard implements CanActivate { ) {} async canActivate(context: ExecutionContext): Promise { - const policyHandlers = - this.reflector.get( - CHECK_POLICIES_KEY, - context.getHandler(), - ) || []; + const policyData = this.reflector.get<{ + endpoint: string; + handlers: PolicyHandler[]; + }>(CHECK_POLICIES_KEY, context.getHandler()); + if (!policyData) { + return false; + } + + const policyHandlers = policyData["handlers"]; + const endpoint = policyData["endpoint"]; const req = context.switchToHttp().getRequest(); const user = req.user; - const ability = this.caslAbilityFactory.createForUser(user); + + const ability = this.caslAbilityFactory.endpointAccess(endpoint, user); return policyHandlers.every((handler) => this.execPolicyHandler(handler, ability), ); } private execPolicyHandler(handler: PolicyHandler, ability: AppAbility) { - //console.log('PoliciesGuard:execPolicyHandler ', handler, ability) if (typeof handler === "function") { const res = handler(ability); //console.log("PoliciesGuard:execPolicyHandler ", res); diff --git a/src/datasets/datasets.controller.ts b/src/datasets/datasets.controller.ts index 6655d3b5f..0d7706ee1 100644 --- a/src/datasets/datasets.controller.ts +++ b/src/datasets/datasets.controller.ts @@ -160,7 +160,7 @@ export class DatasetsController { ): IFilters { const user: JWTUser = request.user as JWTUser; - const ability = this.caslAbilityFactory.createForUser(user); + const ability = this.caslAbilityFactory.datasetInstanceAccess(user); const canViewAny = ability.can(Action.DatasetReadAny, DatasetClass); const canViewOwner = ability.can(Action.DatasetReadManyOwner, DatasetClass); const canViewAccess = ability.can( @@ -205,7 +205,7 @@ export class DatasetsController { const datasetInstance = await this.generateDatasetInstanceForPermissions(dataset); - const ability = this.caslAbilityFactory.createForUser(user); + const ability = this.caslAbilityFactory.datasetInstanceAccess(user); let canDoAction = false; @@ -290,7 +290,7 @@ export class DatasetsController { const datasetInstance = await this.generateDatasetInstanceForPermissions(dataset); - const ability = this.caslAbilityFactory.createForUser(user); + const ability = this.caslAbilityFactory.datasetInstanceAccess(user); const canView = ability.can(Action.DatasetReadAny, DatasetClass) || ability.can(Action.DatasetReadOneOwner, datasetInstance) || @@ -355,7 +355,7 @@ export class DatasetsController { const datasetInstance = await this.generateDatasetInstanceForPermissions(dataset); // instantiate the casl matrix for the user - const ability = this.caslAbilityFactory.createForUser(user); + const ability = this.caslAbilityFactory.datasetInstanceAccess(user); // check if he/she can create this dataset const canCreate = ability.can(Action.DatasetCreateAny, DatasetClass) || @@ -389,7 +389,7 @@ export class DatasetsController { // POST /datasets @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("datasets", (ability: AppAbility) => ability.can(Action.DatasetCreate, DatasetClass), ) @UseInterceptors( @@ -510,7 +510,7 @@ export class DatasetsController { } @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("datasets", (ability: AppAbility) => ability.can(Action.DatasetCreate, DatasetClass), ) @UseInterceptors( @@ -568,7 +568,7 @@ export class DatasetsController { // GET /datasets @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("datasets", (ability: AppAbility) => ability.can(Action.DatasetRead, DatasetClass), ) @UseInterceptors(MainDatasetsPublicInterceptor) @@ -650,7 +650,7 @@ export class DatasetsController { // GET /datasets/fullquery @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("datasets", (ability: AppAbility) => ability.can(Action.DatasetRead, DatasetClass), ) @UseInterceptors(SubDatasetsPublicInterceptor, FullQueryInterceptor) @@ -691,7 +691,7 @@ export class DatasetsController { const user: JWTUser = request.user as JWTUser; const fields: IDatasetFields = JSON.parse(filters.fields ?? "{}"); - const ability = this.caslAbilityFactory.createForUser(user); + const ability = this.caslAbilityFactory.datasetInstanceAccess(user); const canViewAny = ability.can(Action.DatasetReadAny, DatasetClass); if (!canViewAny && !fields.isPublished) { @@ -729,7 +729,7 @@ export class DatasetsController { // GET /fullfacets @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("datasets", (ability: AppAbility) => ability.can(Action.DatasetRead, DatasetClass), ) @UseInterceptors(SubDatasetsPublicInterceptor) @@ -769,7 +769,7 @@ export class DatasetsController { const user: JWTUser = request.user as JWTUser; const fields: IDatasetFields = JSON.parse(filters.fields ?? "{}"); - const ability = this.caslAbilityFactory.createForUser(user); + const ability = this.caslAbilityFactory.datasetInstanceAccess(user); const canViewAny = ability.can(Action.DatasetReadAny, DatasetClass); if (!canViewAny && !fields.isPublished) { @@ -811,7 +811,7 @@ export class DatasetsController { // GET /datasets/metadataKeys @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("datasets", (ability: AppAbility) => ability.can(Action.DatasetRead, DatasetClass), ) @UseInterceptors(SubDatasetsPublicInterceptor) @@ -850,7 +850,7 @@ export class DatasetsController { const user: JWTUser = request.user as JWTUser; const fields: IDatasetFields = JSON.parse(filters.fields ?? "{}"); - const ability = this.caslAbilityFactory.createForUser(user); + const ability = this.caslAbilityFactory.datasetInstanceAccess(user); const canViewAny = ability.can(Action.DatasetReadAny, DatasetClass); if (!canViewAny && !fields.isPublished) { @@ -890,7 +890,7 @@ export class DatasetsController { // GET /datasets/findOne @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("datasets", (ability: AppAbility) => ability.can(Action.DatasetRead, DatasetClass), ) @Get("/findOne") @@ -961,7 +961,7 @@ export class DatasetsController { // GET /datasets/count @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("datasets", (ability: AppAbility) => ability.can(Action.DatasetRead, DatasetClass), ) @Get("/count") @@ -1001,7 +1001,7 @@ export class DatasetsController { // GET /datasets/:id //@UseGuards(PoliciesGuard) @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("datasets", (ability: AppAbility) => ability.can(Action.DatasetRead, DatasetClass), ) @Get("/:pid") @@ -1032,7 +1032,7 @@ export class DatasetsController { // PATCH /datasets/:id // body: modified fields @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("datasets", (ability: AppAbility) => ability.can(Action.DatasetUpdate, DatasetClass), ) @UseInterceptors( @@ -1098,7 +1098,7 @@ export class DatasetsController { // instantiate the casl matrix for the user const user: JWTUser = request.user as JWTUser; - const ability = this.caslAbilityFactory.createForUser(user); + const ability = this.caslAbilityFactory.datasetInstanceAccess(user); // check if he/she can create this dataset const canUpdate = ability.can(Action.DatasetUpdateAny, DatasetClass) || @@ -1113,7 +1113,7 @@ export class DatasetsController { // PUT /datasets/:id @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("datasets", (ability: AppAbility) => ability.can(Action.DatasetUpdate, DatasetClass), ) @UseInterceptors( @@ -1177,7 +1177,7 @@ export class DatasetsController { // instantiate the casl matrix for the user const user: JWTUser = request.user as JWTUser; - const ability = this.caslAbilityFactory.createForUser(user); + const ability = this.caslAbilityFactory.datasetInstanceAccess(user); // check if he/she can create this dataset const canUpdate = ability.can(Action.DatasetUpdateAny, DatasetClass) || @@ -1195,7 +1195,7 @@ export class DatasetsController { // DELETE /datasets/:id @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("datasets", (ability: AppAbility) => ability.can(Action.DatasetDelete, DatasetClass), ) @Delete("/:pid") @@ -1227,7 +1227,7 @@ export class DatasetsController { // instantiate the casl matrix for the user const user: JWTUser = request.user as JWTUser; - const ability = this.caslAbilityFactory.createForUser(user); + const ability = this.caslAbilityFactory.datasetInstanceAccess(user); // check if he/she can create this dataset const canUpdate = ability.can(Action.DatasetDeleteAny, DatasetClass) || @@ -1241,7 +1241,7 @@ export class DatasetsController { } @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("datasets", (ability: AppAbility) => ability.can(Action.DatasetUpdate, DatasetClass), ) @Post("/:pid/appendToArrayField") @@ -1278,7 +1278,7 @@ export class DatasetsController { @Query("data") data: string, ): Promise { const user: JWTUser = request.user as JWTUser; - const ability = this.caslAbilityFactory.createForUser(user); + const ability = this.caslAbilityFactory.datasetInstanceAccess(user); const datasetToUpdate = await this.datasetsService.findOne({ where: { pid: pid }, }); @@ -1312,7 +1312,7 @@ export class DatasetsController { // GET /datasets/:id/thumbnail @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("datasets", (ability: AppAbility) => ability.can(Action.DatasetRead, DatasetClass), ) // @UseGuards(PoliciesGuard) @@ -1356,7 +1356,7 @@ export class DatasetsController { // POST /datasets/:id/attachments @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("datasets", (ability: AppAbility) => ability.can(Action.DatasetAttachmentCreate, DatasetClass), ) @HttpCode(HttpStatus.CREATED) @@ -1406,7 +1406,7 @@ export class DatasetsController { // GET /datasets/:id/attachments @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("datasets", (ability: AppAbility) => ability.can(Action.DatasetAttachmentRead, DatasetClass), ) @Get("/:pid/attachments") @@ -1443,7 +1443,7 @@ export class DatasetsController { // PATCH /datasets/:id/attachments/:fk @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("datasets", (ability: AppAbility) => ability.can(Action.DatasetAttachmentUpdate, DatasetClass), ) @Put("/:pid/attachments/:aid") @@ -1490,7 +1490,7 @@ export class DatasetsController { // DELETE /datasets/:pid/attachments/:aid @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("datasets", (ability: AppAbility) => ability.can(Action.DatasetAttachmentDelete, DatasetClass), ) @Delete("/:pid/attachments/:aid") @@ -1534,7 +1534,7 @@ export class DatasetsController { // POST /datasets/:id/origdatablocks @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => { + @CheckPolicies("datasets", (ability: AppAbility) => { return ability.can(Action.DatasetOrigdatablockCreate, DatasetClass); }) @UseInterceptors( @@ -1600,7 +1600,7 @@ export class DatasetsController { // POST /datasets/:id/origdatablocks/isValid @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => { + @CheckPolicies("datasets", (ability: AppAbility) => { return ability.can(Action.DatasetOrigdatablockCreate, DatasetClass); }) @HttpCode(HttpStatus.OK) @@ -1649,7 +1649,7 @@ export class DatasetsController { // GET /datasets/:id/origdatablocks @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => { + @CheckPolicies("datasets", (ability: AppAbility) => { return ability.can(Action.DatasetOrigdatablockRead, DatasetClass); }) @Get("/:pid/origdatablocks") @@ -1686,7 +1686,7 @@ export class DatasetsController { // PATCH /datasets/:id/origdatablocks/:fk @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => { + @CheckPolicies("datasets", (ability: AppAbility) => { return ability.can(Action.DatasetOrigdatablockUpdate, DatasetClass); }) @UseInterceptors( @@ -1757,7 +1757,7 @@ export class DatasetsController { // DELETE /datasets/:id/origdatablocks/:fk @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("datasets", (ability: AppAbility) => ability.can(Action.DatasetOrigdatablockDelete, DatasetClass), ) @Delete("/:pid/origdatablocks/:oid") @@ -1819,7 +1819,7 @@ export class DatasetsController { // POST /datasets/:id/datablocks @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("datasets", (ability: AppAbility) => ability.can(Action.DatasetDatablockCreate, DatasetClass), ) @UseInterceptors( @@ -1880,7 +1880,7 @@ export class DatasetsController { // GET /datasets/:id/datablocks @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("datasets", (ability: AppAbility) => ability.can(Action.DatasetDatablockRead, DatasetClass), ) @Get("/:pid/datablocks") @@ -1917,7 +1917,7 @@ export class DatasetsController { // PATCH /datasets/:id/datablocks/:fk @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("datasets", (ability: AppAbility) => ability.can(Action.DatasetDatablockUpdate, DatasetClass), ) @UseInterceptors( @@ -1987,7 +1987,7 @@ export class DatasetsController { // DELETE /datasets/:id/datablocks/:fk @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("datasets", (ability: AppAbility) => ability.can(Action.DatasetDatablockDelete, DatasetClass), ) @Delete("/:pid/datablocks/:did") @@ -2056,7 +2056,7 @@ export class DatasetsController { } @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("datasets", (ability: AppAbility) => ability.can(Action.DatasetLogbookRead, DatasetClass), ) @Get("/:pid/logbook") diff --git a/src/elastic-search/elastic-search.controller.ts b/src/elastic-search/elastic-search.controller.ts index ebc875cbd..de2498da6 100644 --- a/src/elastic-search/elastic-search.controller.ts +++ b/src/elastic-search/elastic-search.controller.ts @@ -37,7 +37,7 @@ export class ElasticSearchServiceController { ) {} @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("elastic-search", (ability: AppAbility) => ability.can(Action.Manage, ElasticSearchActions), ) @HttpCode(HttpStatus.CREATED) @@ -53,7 +53,7 @@ export class ElasticSearchServiceController { } @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("elastic-search", (ability: AppAbility) => ability.can(Action.Manage, ElasticSearchActions), ) @HttpCode(HttpStatus.OK) @@ -70,7 +70,7 @@ export class ElasticSearchServiceController { } @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("elastic-search", (ability: AppAbility) => ability.can(Action.Manage, ElasticSearchActions), ) @HttpCode(HttpStatus.OK) @@ -88,7 +88,7 @@ export class ElasticSearchServiceController { } @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("elastic-search", (ability: AppAbility) => ability.can(Action.Manage, ElasticSearchActions), ) @HttpCode(HttpStatus.OK) @@ -104,7 +104,7 @@ export class ElasticSearchServiceController { } @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("elastic-search", (ability: AppAbility) => ability.can(Action.Manage, ElasticSearchActions), ) @HttpCode(HttpStatus.OK) @@ -120,7 +120,7 @@ export class ElasticSearchServiceController { } @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("elastic-search", (ability: AppAbility) => ability.can(Action.Manage, ElasticSearchActions), ) @HttpCode(HttpStatus.OK) diff --git a/src/instruments/instruments.controller.ts b/src/instruments/instruments.controller.ts index b09fc7876..7ee9a6216 100644 --- a/src/instruments/instruments.controller.ts +++ b/src/instruments/instruments.controller.ts @@ -42,7 +42,7 @@ export class InstrumentsController { constructor(private readonly instrumentsService: InstrumentsService) {} @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("instruments", (ability: AppAbility) => ability.can(Action.InstrumentCreate, Instrument), ) @UseInterceptors( @@ -69,7 +69,7 @@ export class InstrumentsController { } @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("instruments", (ability: AppAbility) => ability.can(Action.InstrumentRead, Instrument), ) @Get() @@ -87,7 +87,7 @@ export class InstrumentsController { // GET /instrument/findOne @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("instruments", (ability: AppAbility) => ability.can(Action.InstrumentRead, Instrument), ) @Get("/findOne") @@ -117,7 +117,7 @@ export class InstrumentsController { } @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("instruments", (ability: AppAbility) => ability.can(Action.InstrumentRead, Instrument), ) @Get(":id") @@ -126,7 +126,7 @@ export class InstrumentsController { } @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("instruments", (ability: AppAbility) => ability.can(Action.InstrumentUpdate, Instrument), ) @UseInterceptors( @@ -152,7 +152,7 @@ export class InstrumentsController { } @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("instruments", (ability: AppAbility) => ability.can(Action.InstrumentDelete, Instrument), ) @Delete(":id") diff --git a/src/jobs/jobs.controller.ts b/src/jobs/jobs.controller.ts index 6430ca9ff..588f202f9 100644 --- a/src/jobs/jobs.controller.ts +++ b/src/jobs/jobs.controller.ts @@ -288,7 +288,9 @@ export class JobsController { } @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => ability.can(Action.Read, JobClass)) + @CheckPolicies("jobs", (ability: AppAbility) => + ability.can(Action.Read, JobClass), + ) @Get() @ApiQuery({ name: "filter", @@ -304,7 +306,9 @@ export class JobsController { } @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => ability.can(Action.Read, JobClass)) + @CheckPolicies("jobs", (ability: AppAbility) => + ability.can(Action.Read, JobClass), + ) @Get("/fullquery") async fullquery( @Query() filters: { fields?: string; limits?: string }, @@ -317,7 +321,9 @@ export class JobsController { } @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => ability.can(Action.Read, JobClass)) + @CheckPolicies("jobs", (ability: AppAbility) => + ability.can(Action.Read, JobClass), + ) @Get("/fullfacet") async fullfacet( @Query() filters: { fields?: string; facets?: string }, @@ -330,14 +336,18 @@ export class JobsController { } @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => ability.can(Action.Read, JobClass)) + @CheckPolicies("jobs", (ability: AppAbility) => + ability.can(Action.Read, JobClass), + ) @Get(":id") async findOne(@Param("id") id: string): Promise { return this.jobsService.findOne({ _id: id }); } @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => ability.can(Action.Update, JobClass)) + @CheckPolicies("jobs", (ability: AppAbility) => + ability.can(Action.Update, JobClass), + ) @Patch(":id") async update( @Param("id") id: string, @@ -356,7 +366,9 @@ export class JobsController { } @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => ability.can(Action.Delete, JobClass)) + @CheckPolicies("jobs", (ability: AppAbility) => + ability.can(Action.Delete, JobClass), + ) @Delete(":id") async remove(@Param("id") id: string): Promise { return this.jobsService.remove({ _id: id }); diff --git a/src/logbooks/logbooks.controller.ts b/src/logbooks/logbooks.controller.ts index 58df20cda..628997c7c 100644 --- a/src/logbooks/logbooks.controller.ts +++ b/src/logbooks/logbooks.controller.ts @@ -22,7 +22,9 @@ export class LogbooksController { constructor(private readonly logbooksService: LogbooksService) {} @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => ability.can(Action.Read, Logbook)) + @CheckPolicies("logbooks", (ability: AppAbility) => + ability.can(Action.Read, Logbook), + ) @UseInterceptors(UsersLogbooksInterceptor) @Get() findAll() { @@ -30,7 +32,9 @@ export class LogbooksController { } @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => ability.can(Action.Read, Logbook)) + @CheckPolicies("logbooks", (ability: AppAbility) => + ability.can(Action.Read, Logbook), + ) @UseInterceptors(UsersLogbooksInterceptor) @Get("/:name") async findByName( diff --git a/src/origdatablocks/origdatablocks.controller.ts b/src/origdatablocks/origdatablocks.controller.ts index ce68d9f22..f1a0f13be 100644 --- a/src/origdatablocks/origdatablocks.controller.ts +++ b/src/origdatablocks/origdatablocks.controller.ts @@ -90,7 +90,7 @@ export class OrigDatablocksController { // newDatasetClass.ownerGroup = dataset.ownerGroup; // if (user) { - // const ability = this.caslAbilityFactory.createForUser(user); + // const ability = this.caslAbilityFactory.createOrigDatablockForUser(user); // const canUpdate = ability.can(Action.Update, newDatasetClass); // if (!canUpdate) { // throw new ForbiddenException("Unauthorized access"); @@ -128,7 +128,7 @@ export class OrigDatablocksController { const origDatablockInstance = await this.generateOrigDatablockInstanceInstanceForPermissions(dataset); - const ability = this.caslAbilityFactory.createForUser(user); + const ability = this.caslAbilityFactory.origDatablockInstanceAccess(user); let canDoAction = false; @@ -157,7 +157,7 @@ export class OrigDatablocksController { // POST /origdatablocks @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("origdatablocks", (ability: AppAbility) => ability.can(Action.OrigdatablockCreate, OrigDatablock), ) @HttpCode(HttpStatus.CREATED) @@ -226,7 +226,7 @@ export class OrigDatablocksController { } @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("origdatablocks", (ability: AppAbility) => ability.can(Action.OrigdatablockCreate, OrigDatablock), ) @HttpCode(HttpStatus.OK) @@ -271,7 +271,7 @@ export class OrigDatablocksController { // GET /origdatablock @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("origdatablocks", (ability: AppAbility) => ability.can(Action.OrigdatablockRead, OrigDatablock), ) @Get() @@ -302,7 +302,7 @@ export class OrigDatablocksController { const user: JWTUser = request.user as JWTUser; const parsedFilters: IFilters = JSON.parse(filter ?? "{}"); - const ability = this.caslAbilityFactory.createForUser(user); + const ability = this.caslAbilityFactory.origDatablockInstanceAccess(user); const canViewAny = ability.can(Action.OrigdatablockReadAny, OrigDatablock); if (!canViewAny) { parsedFilters.where = parsedFilters.where ?? {}; @@ -337,7 +337,7 @@ export class OrigDatablocksController { // GET /origdatablocks/fullquery @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("origdatablocks", (ability: AppAbility) => ability.can(Action.OrigdatablockRead, OrigDatablock), ) @Get("/fullquery") @@ -363,7 +363,7 @@ export class OrigDatablocksController { const user: JWTUser = request.user as JWTUser; const fields: IOrigDatablockFields = JSON.parse(filters.fields ?? "{}"); - const ability = this.caslAbilityFactory.createForUser(user); + const ability = this.caslAbilityFactory.origDatablockInstanceAccess(user); const canViewAny = ability.can(Action.OrigdatablockReadAny, OrigDatablock); if (!canViewAny) { @@ -401,7 +401,7 @@ export class OrigDatablocksController { // GET /origdatablocks/fullquery/files @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("origdatablocks", (ability: AppAbility) => ability.can(Action.OrigdatablockRead, OrigDatablock), ) @Get("/fullquery/files") @@ -426,7 +426,7 @@ export class OrigDatablocksController { ): Promise { const user: JWTUser = request.user as JWTUser; const fields: IOrigDatablockFields = JSON.parse(filters.fields ?? "{}"); - const ability = this.caslAbilityFactory.createForUser(user); + const ability = this.caslAbilityFactory.origDatablockInstanceAccess(user); const canViewAny = ability.can(Action.OrigdatablockReadAny, OrigDatablock); if (!canViewAny) { const canViewAccess = ability.can( @@ -456,7 +456,7 @@ export class OrigDatablocksController { // GET /origdatablocks/fullfacet @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("origdatablocks", (ability: AppAbility) => ability.can(Action.OrigdatablockRead, OrigDatablock), ) @Get("/fullfacet") @@ -467,7 +467,7 @@ export class OrigDatablocksController { const user: JWTUser = request.user as JWTUser; const fields: IOrigDatablockFields = JSON.parse(filters.fields ?? "{}"); - const ability = this.caslAbilityFactory.createForUser(user); + const ability = this.caslAbilityFactory.origDatablockInstanceAccess(user); const canViewAny = ability.can(Action.OrigdatablockReadAny, OrigDatablock); if (!canViewAny) { const canViewAccess = ability.can( @@ -497,7 +497,7 @@ export class OrigDatablocksController { // GET /origdatablocks/fullfacet/files @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("origdatablocks", (ability: AppAbility) => ability.can(Action.OrigdatablockRead, OrigDatablock), ) @Get("/fullfacet/files") @@ -508,7 +508,7 @@ export class OrigDatablocksController { const user: JWTUser = request.user as JWTUser; const fields: IOrigDatablockFields = JSON.parse(filters.fields ?? "{}"); - const ability = this.caslAbilityFactory.createForUser(user); + const ability = this.caslAbilityFactory.origDatablockInstanceAccess(user); const canViewAny = ability.can(Action.OrigdatablockReadAny, OrigDatablock); if (!canViewAny) { const canViewAccess = ability.can( @@ -542,7 +542,7 @@ export class OrigDatablocksController { // GET /origdatablocks/:id @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("origdatablocks", (ability: AppAbility) => ability.can(Action.OrigdatablockRead, OrigDatablock), ) @Get("/:id") @@ -576,7 +576,7 @@ export class OrigDatablocksController { // PATCH /origdatablocks/:id @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("origdatablocks", (ability: AppAbility) => ability.can(Action.OrigdatablockUpdate, OrigDatablock), ) @Patch("/:id") @@ -623,7 +623,7 @@ export class OrigDatablocksController { // DELETE /origdatablocks/:id @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("origdatablocks", (ability: AppAbility) => ability.can(Action.OrigdatablockDelete, OrigDatablock), ) @Delete("/:id") diff --git a/src/policies/policies.controller.ts b/src/policies/policies.controller.ts index 0ee2ea98f..bbc9353dd 100644 --- a/src/policies/policies.controller.ts +++ b/src/policies/policies.controller.ts @@ -84,7 +84,8 @@ export class PoliciesController { const user: JWTUser = request.user as JWTUser; if (user) { - const ability = this.caslAbilityFactory.createForUser(user); + const ability = this.caslAbilityFactory.policyEndpointAccess(user); + // these actions are not defined in casl const canViewAll = ability.can(Action.ListAll, Policy); const canViewTheirOwn = ability.can(Action.ListOwn, Policy); if (!canViewAll && canViewTheirOwn) { @@ -102,14 +103,18 @@ export class PoliciesController { return mergedFilters; } @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => ability.can(Action.Create, Policy)) + @CheckPolicies("policies", (ability: AppAbility) => + ability.can(Action.Create, Policy), + ) @Post() async create(@Body() createPolicyDto: CreatePolicyDto): Promise { return this.policiesService.create(createPolicyDto); } @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => ability.can(Action.Read, Policy)) + @CheckPolicies("policies", (ability: AppAbility) => + ability.can(Action.Read, Policy), + ) @Get() @ApiQuery({ name: "filter", @@ -133,7 +138,9 @@ export class PoliciesController { } @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => ability.can(Action.Read, Policy)) + @CheckPolicies("policies", (ability: AppAbility) => + ability.can(Action.Read, Policy), + ) @Get("/count") async count(@Query("where") where?: string): Promise<{ count: number }> { const parsedWhere: FilterQuery = JSON.parse(where ?? "{}"); @@ -141,7 +148,9 @@ export class PoliciesController { } @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => ability.can(Action.Update, Policy)) + @CheckPolicies("policies", (ability: AppAbility) => + ability.can(Action.Update, Policy), + ) @UseInterceptors(HistoryInterceptor) @HttpCode(HttpStatus.OK) @Post("/updateWhere") @@ -153,14 +162,18 @@ export class PoliciesController { } @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => ability.can(Action.Read, Policy)) + @CheckPolicies("policies", (ability: AppAbility) => + ability.can(Action.Read, Policy), + ) @Get(":id") async findOne(@Param("id") id: string): Promise { return this.policiesService.findOne({ _id: id }); } @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => ability.can(Action.Update, Policy)) + @CheckPolicies("policies", (ability: AppAbility) => + ability.can(Action.Update, Policy), + ) @Patch(":id") async update( @Param("id") id: string, @@ -170,7 +183,9 @@ export class PoliciesController { } @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => ability.can(Action.Delete, Policy)) + @CheckPolicies("policies", (ability: AppAbility) => + ability.can(Action.Delete, Policy), + ) @Delete(":id") async remove(@Param("id") id: string): Promise { return this.policiesService.remove({ _id: id }); diff --git a/src/proposals/proposals.controller.ts b/src/proposals/proposals.controller.ts index 3fddfa348..ff509c0fc 100644 --- a/src/proposals/proposals.controller.ts +++ b/src/proposals/proposals.controller.ts @@ -99,7 +99,7 @@ export class ProposalsController { ); const user: JWTUser = request.user as JWTUser; - const ability = this.caslAbilityFactory.createForUser(user); + const ability = this.caslAbilityFactory.proposalsInstanceAccess(user); try { switch (group) { @@ -208,7 +208,7 @@ export class ProposalsController { mergedFilters.where = mergedFilters.where || {}; if (user) { - const ability = this.caslAbilityFactory.createForUser(user); + const ability = this.caslAbilityFactory.proposalsInstanceAccess(user); const canViewAll = ability.can(Action.ProposalsReadAny, ProposalClass); if (!canViewAll) { const canViewAccess = ability.can( @@ -243,7 +243,7 @@ export class ProposalsController { // POST /proposals @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("proposals", (ability: AppAbility) => ability.can(Action.ProposalsCreate, ProposalClass), ) @UseInterceptors( @@ -291,7 +291,7 @@ export class ProposalsController { } @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("proposals", (ability: AppAbility) => ability.can(Action.ProposalsCreate, ProposalClass), ) @HttpCode(HttpStatus.OK) @@ -330,7 +330,7 @@ export class ProposalsController { // GET /proposals @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("proposals", (ability: AppAbility) => ability.can(Action.ProposalsRead, ProposalClass), ) @Get() @@ -366,7 +366,7 @@ export class ProposalsController { // GET /proposals/fullquery @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("proposals", (ability: AppAbility) => ability.can(Action.ProposalsRead, ProposalClass), ) @Get("/fullquery") @@ -407,7 +407,7 @@ export class ProposalsController { const fields: IProposalFields = JSON.parse(filters.fields ?? "{}"); const limits: ILimitsFilter = JSON.parse(filters.limits ?? "{}"); if (user) { - const ability = this.caslAbilityFactory.createForUser(user); + const ability = this.caslAbilityFactory.proposalsInstanceAccess(user); const canViewAll = ability.can(Action.ProposalsReadAny, ProposalClass); if (!canViewAll) { @@ -445,7 +445,7 @@ export class ProposalsController { // GET /proposals/fullfacet @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("proposals", (ability: AppAbility) => ability.can(Action.ProposalsRead, ProposalClass), ) @Get("/fullfacet") @@ -478,7 +478,7 @@ export class ProposalsController { const fields: IProposalFields = JSON.parse(filters.fields ?? "{}"); const facets = JSON.parse(filters.facets ?? "[]"); if (user) { - const ability = this.caslAbilityFactory.createForUser(user); + const ability = this.caslAbilityFactory.proposalsInstanceAccess(user); const canViewAll = ability.can(Action.ProposalsReadAny, ProposalClass); if (!canViewAll) { @@ -517,7 +517,7 @@ export class ProposalsController { // GET /proposals/:pid @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("proposals", (ability: AppAbility) => ability.can(Action.ProposalsRead, ProposalClass), ) @Get("/:pid") @@ -551,7 +551,7 @@ export class ProposalsController { // GET /proposals/:pid/authorization @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("proposals", (ability: AppAbility) => ability.can(Action.ProposalsRead, ProposalClass), ) @Get("/:pid/authorization") @@ -590,7 +590,7 @@ export class ProposalsController { // PATCH /proposals/:pid @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("proposals", (ability: AppAbility) => ability.can(Action.ProposalsUpdate, ProposalClass), ) @UseInterceptors( @@ -638,7 +638,7 @@ export class ProposalsController { // DELETE /proposals/:id @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("proposals", (ability: AppAbility) => ability.can(Action.ProposalsDelete, ProposalClass), ) @Delete("/:pid") @@ -669,7 +669,7 @@ export class ProposalsController { // POST /proposals/:id/attachments @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("proposals", (ability: AppAbility) => ability.can(Action.ProposalsAttachmentCreate, ProposalClass), ) @Post("/:pid/attachments") @@ -714,7 +714,7 @@ export class ProposalsController { // GET /proposals/:pid/attachments @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("proposals", (ability: AppAbility) => ability.can(Action.ProposalsAttachmentRead, ProposalClass), ) @Get("/:pid/attachments") @@ -750,7 +750,7 @@ export class ProposalsController { // PATCH /proposals/:pid/attachments/:aid @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("proposals", (ability: AppAbility) => ability.can(Action.ProposalsAttachmentUpdate, ProposalClass), ) @Patch("/:pid/attachments/:aid") @@ -797,7 +797,7 @@ export class ProposalsController { // DELETE /proposals/:pid/attachments/:aid @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("proposals", (ability: AppAbility) => ability.can(Action.ProposalsAttachmentDelete, ProposalClass), ) @Delete("/:pid/attachments/:aid") @@ -841,7 +841,7 @@ export class ProposalsController { // GET /proposals/:id/datasets @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("proposals", (ability: AppAbility) => ability.can(Action.ProposalsDatasetRead, ProposalClass), ) @Get("/:pid/datasets") @@ -869,7 +869,7 @@ export class ProposalsController { @Param("pid") proposalId: string, ): Promise { const user: JWTUser = request.user as JWTUser; - const ability = this.caslAbilityFactory.createForUser(user); + const ability = this.caslAbilityFactory.proposalsInstanceAccess(user); const canViewAny = ability.can(Action.DatasetReadAny, DatasetClass); const fields: IDatasetFields = JSON.parse("{}"); diff --git a/src/published-data/published-data.controller.ts b/src/published-data/published-data.controller.ts index c8030b6ca..3d8199c7d 100644 --- a/src/published-data/published-data.controller.ts +++ b/src/published-data/published-data.controller.ts @@ -69,7 +69,7 @@ export class PublishedDataController { // POST /publisheddata @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("publisheddata", (ability: AppAbility) => ability.can(Action.Create, PublishedData), ) @Post() @@ -155,7 +155,7 @@ export class PublishedDataController { // GET /publisheddata/formpopulate @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("publisheddata", (ability: AppAbility) => ability.can(Action.Read, PublishedData), ) @Get("/formpopulate") @@ -221,7 +221,7 @@ export class PublishedDataController { // PATCH /publisheddata/:id @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("publisheddata", (ability: AppAbility) => ability.can(Action.Update, PublishedData), ) @Patch("/:id") @@ -237,7 +237,7 @@ export class PublishedDataController { // DELETE /publisheddata/:id @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("publisheddata", (ability: AppAbility) => ability.can(Action.Delete, PublishedData), ) @Delete("/:id") @@ -247,7 +247,7 @@ export class PublishedDataController { // POST /publisheddata/:id/register @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("publisheddata", (ability: AppAbility) => ability.can(Action.Update, PublishedData), ) @Post("/:id/register") @@ -428,7 +428,7 @@ export class PublishedDataController { // POST /publisheddata/:id/resync @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("publisheddata", (ability: AppAbility) => ability.can(Action.Update, PublishedData), ) @ApiOperation({ diff --git a/src/samples/samples.controller.ts b/src/samples/samples.controller.ts index a5077fcdf..030960896 100644 --- a/src/samples/samples.controller.ts +++ b/src/samples/samples.controller.ts @@ -97,7 +97,7 @@ export class SamplesController { ); const user: JWTUser = request.user as JWTUser; - const ability = this.caslAbilityFactory.createForUser(user); + const ability = this.caslAbilityFactory.samplesInstanceAccess(user); try { switch (group) { @@ -198,7 +198,7 @@ export class SamplesController { /* eslint-disable @typescript-eslint/no-explicit-any */ const authorizationFilter: Record = { where: {} }; if (user) { - const ability = this.caslAbilityFactory.createForUser(user); + const ability = this.caslAbilityFactory.samplesInstanceAccess(user); const canViewAll = ability.can(Action.SampleReadAny, SampleClass); if (!canViewAll) { const canViewAccess = ability.can( @@ -243,7 +243,7 @@ export class SamplesController { } // POST /samples @UseGuards(AuthenticatedPoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("samples", (ability: AppAbility) => ability.can(Action.SampleCreate, SampleClass), ) @UseInterceptors( @@ -281,7 +281,7 @@ export class SamplesController { // GET /samples @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("samples", (ability: AppAbility) => ability.can(Action.SampleRead, SampleClass), ) @Get() @@ -315,7 +315,7 @@ export class SamplesController { // GET /samples/fullquery @UseGuards(AuthenticatedPoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("samples", (ability: AppAbility) => ability.can(Action.SampleRead, SampleClass), ) @Get("/fullquery") @@ -356,7 +356,7 @@ export class SamplesController { const fields: ISampleFields = JSON.parse(filters.fields ?? "{}"); const limits: ILimitsFilter = JSON.parse(filters.limits ?? "{}"); if (user) { - const ability = this.caslAbilityFactory.createForUser(user); + const ability = this.caslAbilityFactory.samplesInstanceAccess(user); const canViewAll = ability.can(Action.SampleReadAny, SampleClass); if (!canViewAll) { @@ -392,7 +392,7 @@ export class SamplesController { // GET /samples/metadataKeys @UseGuards(AuthenticatedPoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("samples", (ability: AppAbility) => ability.can(Action.SampleRead, SampleClass), ) @Get("/metadataKeys") @@ -427,7 +427,7 @@ export class SamplesController { const fields: ISampleFields = JSON.parse(filters.fields ?? "{}"); const limits: ILimitsFilter = JSON.parse(filters.limits ?? "{}"); if (user) { - const ability = this.caslAbilityFactory.createForUser(user); + const ability = this.caslAbilityFactory.samplesInstanceAccess(user); const canViewAll = ability.can(Action.SampleReadAny, SampleClass); if (!canViewAll) { @@ -464,7 +464,7 @@ export class SamplesController { // GET /samples/findOne @UseGuards(AuthenticatedPoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("samples", (ability: AppAbility) => ability.can(Action.SampleRead, SampleClass), ) @Get("/findOne") @@ -523,7 +523,7 @@ export class SamplesController { // GET /samples/:id @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("samples", (ability: AppAbility) => ability.can(Action.SampleRead, SampleClass), ) @Get("/:id") @@ -556,7 +556,7 @@ export class SamplesController { // GET /samples/:id/authorization @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("samples", (ability: AppAbility) => ability.can(Action.SampleRead, SampleClass), ) @Get("/:id/authorization") @@ -594,7 +594,7 @@ export class SamplesController { // PATCH /samples/:id @UseGuards(AuthenticatedPoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("samples", (ability: AppAbility) => ability.can(Action.SampleUpdate, SampleClass), ) @UseInterceptors( @@ -634,7 +634,7 @@ export class SamplesController { // DELETE /samples/:id @UseGuards() - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("samples", (ability: AppAbility) => ability.can(Action.SampleDelete, SampleClass), ) @Delete("/:id") @@ -661,7 +661,7 @@ export class SamplesController { // POST /samples/:id/attachments @UseGuards(AuthenticatedPoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("samples", (ability: AppAbility) => ability.can(Action.SampleAttachmentDelete, SampleClass), ) @Post("/:id/attachments") @@ -713,7 +713,7 @@ export class SamplesController { // GET /samples/:id/attachments @UseGuards(PoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("samples", (ability: AppAbility) => ability.can(Action.SampleAttachmentRead, SampleClass), ) @Get("/:id/attachments") @@ -747,7 +747,7 @@ export class SamplesController { // GET /samples/:id/attachments/:fk @UseGuards(AuthenticatedPoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("samples", (ability: AppAbility) => ability.can(Action.SampleAttachmentRead, SampleClass), ) @Get("/:id/attachments/:fk") @@ -790,7 +790,7 @@ export class SamplesController { // DELETE /samples/:id/attachments/:fk @UseGuards(AuthenticatedPoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("samples", (ability: AppAbility) => ability.can(Action.SampleAttachmentDelete, SampleClass), ) @Delete("/:id/attachments/:fk") @@ -832,7 +832,7 @@ export class SamplesController { // POST /samples/:id/datasets /* @UseGuards(AuthenticatedPoliciesGuard) - @CheckPolicies((ability: AppAbility) => ability.can(Action.Create, Dataset)) + @CheckPolicies("samples", (ability: AppAbility) => ability.can(Action.Create, Dataset)) @Post("/:id/datasets") async createDataset( @Param("id") id: string, @@ -845,7 +845,7 @@ export class SamplesController { // GET /samples/:id/datasets @UseGuards(AuthenticatedPoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("samples", (ability: AppAbility) => ability.can(Action.SampleDatasetRead, SampleClass), ) @Get("/:id/datasets") @@ -870,7 +870,7 @@ export class SamplesController { @Param("id") sampleId: string, ): Promise { const user: JWTUser = request.user as JWTUser; - const ability = this.caslAbilityFactory.createForUser(user); + const ability = this.caslAbilityFactory.samplesInstanceAccess(user); const canViewAny = ability.can(Action.DatasetReadAny, DatasetClass); const fields: IDatasetFields = JSON.parse("{}"); @@ -908,7 +908,7 @@ export class SamplesController { // PATCH /samples/:id/datasets/:fk /* @UseGuards(AuthenticatedPoliciesGuard) - @CheckPolicies((ability: AppAbility) => ability.can(Action.Update, Dataset)) + @CheckPolicies("samples", (ability: AppAbility) => ability.can(Action.Update, Dataset)) @Patch("/:id/datasets/:fk") async findOneDatasetAndUpdate( @Param("id") sampleId: string, @@ -923,7 +923,7 @@ export class SamplesController { // DELETE /samples/:id/datasets/:fk /* @UseGuards(AuthenticatedPoliciesGuard) - @CheckPolicies((ability: AppAbility) => ability.can(Action.Delete, Dataset)) + @CheckPolicies("samples", (ability: AppAbility) => ability.can(Action.Delete, Dataset)) @Delete("/:id/datasets/:fk") async findOneDatasetAndRemove( @Param("id") sampleId: string, diff --git a/src/users/user-identities.controller.ts b/src/users/user-identities.controller.ts index a20b421b3..99fa923f2 100644 --- a/src/users/user-identities.controller.ts +++ b/src/users/user-identities.controller.ts @@ -30,6 +30,7 @@ export class UserIdentitiesController { @UseGuards(AuthenticatedPoliciesGuard) @CheckPolicies( + "users", (ability: AppAbility) => ability.can(Action.UserReadOwn, User) || ability.can(Action.UserReadAny, User), @@ -56,7 +57,7 @@ export class UserIdentitiesController { const authenticatedUser: JWTUser = request.user as JWTUser; const ability = - await this.caslAbilityFactory.createForUser(authenticatedUser); + await this.caslAbilityFactory.userEndpointAccess(authenticatedUser); if ( !ability.can(Action.UserReadAny, User) && diff --git a/src/users/users.controller.ts b/src/users/users.controller.ts index 56e415374..1e1dcceed 100644 --- a/src/users/users.controller.ts +++ b/src/users/users.controller.ts @@ -71,7 +71,8 @@ export class UsersController { viewedUserSchema._id = viewedUserId; viewedUserSchema.id = viewedUserId; - const ability = this.caslAbilityFactory.createForUser(authenticatedUser); + const ability = + this.caslAbilityFactory.userEndpointAccess(authenticatedUser); // const authorized = actions.map( action => // ability.can(action, viewedUserSchema) // ) as Array; @@ -118,7 +119,9 @@ export class UsersController { } @UseGuards(AuthenticatedPoliciesGuard) - @CheckPolicies((ability: AppAbility) => ability.can(Action.UserReadOwn, User)) + @CheckPolicies("users", (ability: AppAbility) => + ability.can(Action.UserReadOwn, User), + ) @UseInterceptors(CreateUserSettingsInterceptor) @Get("/my/self") @ApiOperation({ @@ -143,7 +146,9 @@ export class UsersController { } @UseGuards(AuthenticatedPoliciesGuard) - @CheckPolicies((ability: AppAbility) => ability.can(Action.UserReadOwn, User)) + @CheckPolicies("users", (ability: AppAbility) => + ability.can(Action.UserReadOwn, User), + ) @Get("/my/identity") async getMyUserIdentity( @Req() request: Request, @@ -158,7 +163,9 @@ export class UsersController { } @UseGuards(AuthenticatedPoliciesGuard) - @CheckPolicies((ability: AppAbility) => ability.can(Action.UserReadOwn, User)) + @CheckPolicies("users", (ability: AppAbility) => + ability.can(Action.UserReadOwn, User), + ) @Get("/my/settings") async getMySettings(@Req() request: Request): Promise { const authenticatedUserId: string = (request.user as JWTUser)._id; @@ -172,6 +179,7 @@ export class UsersController { @UseGuards(AuthenticatedPoliciesGuard) @CheckPolicies( + "users", (ability: AppAbility) => ability.can(Action.UserReadOwn, User) || ability.can(Action.UserReadAny, User), @@ -192,6 +200,7 @@ export class UsersController { @UseGuards(AuthenticatedPoliciesGuard) @CheckPolicies( + "users", (ability: AppAbility) => ability.can(Action.UserReadOwn, User) || ability.can(Action.UserReadAny, User), @@ -211,6 +220,7 @@ export class UsersController { @UseGuards(AuthenticatedPoliciesGuard) @CheckPolicies( + "users", (ability: AppAbility) => ability.can(Action.UserCreateOwn, User) || ability.can(Action.UserCreateAny, User), @@ -231,6 +241,7 @@ export class UsersController { @UseGuards(AuthenticatedPoliciesGuard) @CheckPolicies( + "users", (ability: AppAbility) => ability.can(Action.UserReadOwn, User) || ability.can(Action.UserReadAny, User), @@ -250,6 +261,7 @@ export class UsersController { @UseGuards(AuthenticatedPoliciesGuard) @CheckPolicies( + "users", (ability: AppAbility) => ability.can(Action.UserUpdateOwn, User) || ability.can(Action.UserUpdateAny, User), @@ -273,6 +285,7 @@ export class UsersController { @UseGuards(AuthenticatedPoliciesGuard) @CheckPolicies( + "users", (ability: AppAbility) => ability.can(Action.UserUpdateOwn, User) || ability.can(Action.UserUpdateAny, User), @@ -296,6 +309,7 @@ export class UsersController { @UseGuards(AuthenticatedPoliciesGuard) @CheckPolicies( + "users", (ability: AppAbility) => ability.can(Action.UserDeleteOwn, User) || ability.can(Action.UserDeleteAny, User), @@ -330,7 +344,7 @@ export class UsersController { } @UseGuards(AuthenticatedPoliciesGuard) - @CheckPolicies((ability: AppAbility) => { + @CheckPolicies("users", (ability: AppAbility) => { return ( ability.can(Action.UserReadOwn, User) || ability.can(Action.UserReadAny, User) @@ -350,7 +364,7 @@ export class UsersController { const viewedUser = (await this.usersService.findById2JWTUser( id, )) as JWTUser; - const ability = this.caslAbilityFactory.createForUser(viewedUser); + const ability = this.caslAbilityFactory.datasetEndpointAccess(viewedUser); const canCreateDataset = ability.can(Action.DatasetCreate, DatasetClass); @@ -375,7 +389,7 @@ export class UsersController { } @UseGuards(AuthenticatedPoliciesGuard) - @CheckPolicies((ability: AppAbility) => + @CheckPolicies("users", (ability: AppAbility) => ability.can(Action.UserCreateJwt, User), ) @Post("/:id/jwt") diff --git a/test/config/jobconfig.json b/test/config/jobconfig.json new file mode 100755 index 000000000..e69de29bb