From 7fe8275efa52e18593f6a70be7c3ff6d4b42671d Mon Sep 17 00:00:00 2001 From: Max Novelli Date: Fri, 17 Mar 2023 19:28:37 +0100 Subject: [PATCH 1/2] Added user endpoint to return if user is authorized to create datasets --- src/casl/casl-ability.factory.ts | 2 -- src/casl/guards/policies.guard.ts | 3 +- src/users/users.controller.ts | 51 ++++++++++++++++++++++++++++++- src/users/users.service.ts | 16 ++++++++++ test/LoginUtils.js | 14 +++++++++ 5 files changed, 82 insertions(+), 4 deletions(-) diff --git a/src/casl/casl-ability.factory.ts b/src/casl/casl-ability.factory.ts index 35cd2c9ee..4bd8d1615 100644 --- a/src/casl/casl-ability.factory.ts +++ b/src/casl/casl-ability.factory.ts @@ -169,8 +169,6 @@ export class CaslAbilityFactory { can(Action.ListAll, ProposalClass); } - can(Action.Read, UserIdentity, { userId: user._id }); - can(Action.Create, UserSettings, { userId: user._id }); can(Action.Read, UserSettings, { userId: user._id }); can(Action.Update, UserSettings, { userId: user._id }); diff --git a/src/casl/guards/policies.guard.ts b/src/casl/guards/policies.guard.ts index 36d58425b..16a40fdab 100644 --- a/src/casl/guards/policies.guard.ts +++ b/src/casl/guards/policies.guard.ts @@ -18,7 +18,8 @@ export class PoliciesGuard implements CanActivate { context.getHandler(), ) || []; - const { user } = context.switchToHttp().getRequest(); + const req = context.switchToHttp().getRequest(); + const user = req.user; const ability = this.caslAbilityFactory.createForUser(user); return policyHandlers.every((handler) => diff --git a/src/users/users.controller.ts b/src/users/users.controller.ts index 080422156..7e4931f8b 100644 --- a/src/users/users.controller.ts +++ b/src/users/users.controller.ts @@ -9,10 +9,12 @@ import { Delete, UseInterceptors, Put, + ForbiddenException, + UnauthorizedException, } from "@nestjs/common"; import { ApiBearerAuth, ApiBody, ApiTags } from "@nestjs/swagger"; import { Action } from "src/casl/action.enum"; -import { AppAbility } from "src/casl/casl-ability.factory"; +import { AppAbility, CaslAbilityFactory } from "src/casl/casl-ability.factory"; import { CheckPolicies } from "src/casl/decorators/check-policies.decorator"; import { PoliciesGuard } from "src/casl/guards/policies.guard"; import { UserIdentity } from "./schemas/user-identity.schema"; @@ -29,6 +31,7 @@ import { CreateUserSettingsInterceptor } from "./interceptors/create-user-settin import { AuthService } from "src/auth/auth.service"; import { CredentialsDto } from "src/auth/dto/credentials.dto"; import { LocalAuthGuard } from "src/auth/guards/local-auth.guard"; +import { DatasetClass } from "src/datasets/schemas/dataset.schema"; @ApiBearerAuth() @ApiTags("users") @@ -37,6 +40,7 @@ export class UsersController { constructor( private authService: AuthService, private usersService: UsersService, + private caslAbilityFactory: CaslAbilityFactory, ) {} @AllowAny() @@ -133,4 +137,49 @@ export class UsersController { async removeSettings(@Param("id") userId: string): Promise { return this.usersService.findOneAndRemoveUserSettings(userId); } + + async checkUserAuthorization( + authenticatedUserJWT: JWTUser, + viewedUserJWT: JWTUser, + ) { + const ability = await this.caslAbilityFactory.createForUser( + authenticatedUserJWT, + ); + const viewedUser = (await this.usersService.findById( + viewedUserJWT._id, + )) as User; + const viewedUserSchema = new User(); + viewedUserSchema._id = viewedUser._id; + viewedUserSchema.id = viewedUser.id; + viewedUserSchema.realm = viewedUser.realm; + viewedUserSchema.username = viewedUser.username; + viewedUserSchema.email = viewedUser.email; + + if (!ability.can(Action.Read, viewedUserSchema)) { + throw new UnauthorizedException("Unauthorized access"); + } + } + + //@UseGuards(PoliciesGuard) + //@CheckPolicies((ability: AppAbility) => { + // console.log(ability.can(Action.Read, User)); + // return ability.can(Action.Read, User); + //}) + @AllowAny() + @Get("/:id/authorization/dataset/create") + async canUserCreateDataset( + @Req() request: Request, + @Param("id") userId: string, + ): Promise { + const authenticatedUser: JWTUser = request.user as JWTUser; + const viewedUser: JWTUser = + authenticatedUser._id !== userId + ? ((await this.usersService.findById2JWTUser(userId)) as JWTUser) + : authenticatedUser; + await this.checkUserAuthorization(authenticatedUser, viewedUser); + + const ability = await this.caslAbilityFactory.createForUser(viewedUser); + + return { authorization: ability.can(Action.Create, DatasetClass) }; + } } diff --git a/src/users/users.service.ts b/src/users/users.service.ts index 1f16efeb2..4d66851ef 100644 --- a/src/users/users.service.ts +++ b/src/users/users.service.ts @@ -188,6 +188,22 @@ export class UsersService implements OnModuleInit { return this.userModel.findById(id).exec(); } + async findById2JWTUser(id: string): Promise { + const userIdentity = await this.userIdentityModel + .findOne({ userId: id }) + .exec(); + if (userIdentity) { + const userProfile = userIdentity.profile; + return { + _id: userProfile.id, + username: userProfile.username, + email: userProfile.email, + currentGroups: userProfile.accessGroups, + } as JWTUser; + } + return null; + } + async createUserIdentity( createUserIdentityDto: CreateUserIdentityDto, ): Promise { diff --git a/test/LoginUtils.js b/test/LoginUtils.js index 22091544d..c54d0d7ad 100644 --- a/test/LoginUtils.js +++ b/test/LoginUtils.js @@ -15,6 +15,20 @@ exports.getToken = function (appUrl, user, cb) { }); }; +exports.getIdAndToken = function (appUrl, user, cb) { + request(appUrl) + .post("/api/v3/Users/Login?include=user") + .send(user) + .set("Accept", "application/json") + .end((err, res) => { + if (err) { + cb(err); + } else { + cb(res.body.userId,res.body.id); + } + }); +}; + exports.getTokenAD = function (appUrl, user, cb) { request(appUrl) .post("/auth/msad") From f6c4df428f1d239c8c7a5424f2d24a14c24e620e Mon Sep 17 00:00:00 2001 From: Max Novelli Date: Fri, 17 Mar 2023 19:38:39 +0100 Subject: [PATCH 2/2] fixed linting issues --- src/users/users.controller.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/users/users.controller.ts b/src/users/users.controller.ts index 7e4931f8b..e45dade0d 100644 --- a/src/users/users.controller.ts +++ b/src/users/users.controller.ts @@ -9,7 +9,6 @@ import { Delete, UseInterceptors, Put, - ForbiddenException, UnauthorizedException, } from "@nestjs/common"; import { ApiBearerAuth, ApiBody, ApiTags } from "@nestjs/swagger";