Skip to content

Commit

Permalink
Merge pull request #391 from SciCatProject/swap-3156
Browse files Browse the repository at this point in the history
Added user endpoint to return if user is authorized to create datasets
  • Loading branch information
nitrosx authored Mar 20, 2023
2 parents aee6e34 + f6c4df4 commit c0ad80e
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 4 deletions.
2 changes: 0 additions & 2 deletions src/casl/casl-ability.factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 });
Expand Down
3 changes: 2 additions & 1 deletion src/casl/guards/policies.guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) =>
Expand Down
50 changes: 49 additions & 1 deletion src/users/users.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ import {
Delete,
UseInterceptors,
Put,
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";
Expand All @@ -29,6 +30,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")
Expand All @@ -37,6 +39,7 @@ export class UsersController {
constructor(
private authService: AuthService,
private usersService: UsersService,
private caslAbilityFactory: CaslAbilityFactory,
) {}

@AllowAny()
Expand Down Expand Up @@ -133,4 +136,49 @@ export class UsersController {
async removeSettings(@Param("id") userId: string): Promise<unknown> {
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<unknown> {
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) };
}
}
16 changes: 16 additions & 0 deletions src/users/users.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,22 @@ export class UsersService implements OnModuleInit {
return this.userModel.findById(id).exec();
}

async findById2JWTUser(id: string): Promise<JWTUser | null> {
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<UserIdentity> {
Expand Down
14 changes: 14 additions & 0 deletions test/LoginUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down

0 comments on commit c0ad80e

Please sign in to comment.