From 1103ffe07b88496967cb03683b08f058ca3bbb9f Mon Sep 17 00:00:00 2001 From: Sabir Hassan Date: Fri, 29 Apr 2022 15:30:41 +0500 Subject: [PATCH] feat: defined register permission and get all permissions api endpoints --- api/src/controllers/index.ts | 1 + api/src/controllers/permission.ts | 176 ++++++++++++++++++++++++++++++ api/src/routes/api/index.ts | 2 + api/src/routes/api/permission.ts | 35 ++++++ 4 files changed, 214 insertions(+) create mode 100644 api/src/controllers/permission.ts create mode 100644 api/src/routes/api/permission.ts diff --git a/api/src/controllers/index.ts b/api/src/controllers/index.ts index 05e8b84..9ff7768 100644 --- a/api/src/controllers/index.ts +++ b/api/src/controllers/index.ts @@ -7,3 +7,4 @@ export * from './session' export * from './stp' export * from './user' export * from './info' +export * from './permission' diff --git a/api/src/controllers/permission.ts b/api/src/controllers/permission.ts new file mode 100644 index 0000000..8ea77d7 --- /dev/null +++ b/api/src/controllers/permission.ts @@ -0,0 +1,176 @@ +import { + Security, + Route, + Tags, + Path, + Example, + Get, + Post, + Delete, + Body +} from 'tsoa' + +import Permission from '../model/Permission' +import User from '../model/User' +import Group from '../model/Group' +import Client from '../model/Client' +import { UserResponse } from './user' +import { GroupResponse } from './group' + +interface PermissionPayload { + /** + * Name of affected resource + * @example "/SASjsApi/code/execute" + */ + uri: string + /** + * The indication of whether (and to what extent) access is provided + * @example "Grant" + */ + setting: string + /** + * Indicates the type of principal + * @example "user" + */ + principalType: string + /** + * The id of user(number), group(name), or client(clientId) to which a rule is assigned. + * @example 123 + */ + principalId: any +} + +interface PermissionDetailsResponse { + permissionId: number + uri: string + setting: string + user?: UserResponse + group?: GroupResponse + clientId?: string +} + +@Security('bearerAuth') +@Route('SASjsApi/permission') +@Tags('Permission') +export class PermissionController { + /** + * @summary Get list of all permissions (uri, setting and userDetail). + * + */ + @Example([ + { + permissionId: 123, + uri: '/SASjsApi/code/execute', + setting: 'Grant', + user: { id: 1, username: 'johnSnow01', displayName: 'John Snow' } + }, + { + permissionId: 124, + uri: '/SASjsApi/code/execute', + setting: 'Grant', + group: { + groupId: 1, + name: 'DCGroup', + description: 'This group represents Data Controller Users' + } + }, + { + permissionId: 125, + uri: '/SASjsApi/code/execute', + setting: 'Deny', + clientId: 'clientId1' + } + ]) + @Get('/') + public async getAllPermissions(): Promise { + return getAllPermissions() + } + + /** + * @summary Create a new permission. Admin only. + * + */ + @Example({ + permissionId: 123, + uri: '/SASjsApi/code/execute', + setting: 'Grant', + user: { id: 1, username: 'johnSnow01', displayName: 'John Snow' } + }) + @Post('/') + public async createPermission( + @Body() body: PermissionPayload + ): Promise { + return createPermission(body) + } +} + +const getAllPermissions = async (): Promise => + (await Permission.find({}) + .select({ + _id: 0, + permissionId: 1, + uri: 1, + setting: 1 + }) + .populate({ path: 'user', select: 'id username displayName -_id' }) + .populate({ + path: 'group', + select: 'groupId name description -_id' + }) + .populate({ + path: 'client', + select: 'clientId -_id' + })) as unknown as PermissionDetailsResponse[] + +const createPermission = async ({ + uri, + setting, + principalType, + principalId +}: PermissionPayload): Promise => { + const permission = new Permission({ + uri, + setting + }) + + let user, group, client + + switch (principalType) { + case 'user': + user = await User.findOne({ id: principalId }) + if (!user) throw new Error('User not found.') + permission.user = user._id + break + case 'group': + group = await Group.findOne({ groupId: principalId }) + if (!group) throw new Error('Group not found.') + permission.group = group._id + break + case 'client': + client = await Client.findOne({ clientId: principalId }) + if (!client) throw new Error('Client not found.') + permission.client = client._id + break + default: + throw new Error('Invalid principal type.') + } + + const savedPermission = await permission.save() + + return { + permissionId: savedPermission.permissionId, + uri: savedPermission.uri, + setting: savedPermission.setting, + user: !!user + ? { id: user.id, username: user.username, displayName: user.displayName } + : undefined, + group: !!group + ? { + groupId: group.groupId, + name: group.name, + description: group.description + } + : undefined, + clientId: !!client ? client.clientId : undefined + } +} diff --git a/api/src/routes/api/index.ts b/api/src/routes/api/index.ts index 7b249a9..9627d7e 100644 --- a/api/src/routes/api/index.ts +++ b/api/src/routes/api/index.ts @@ -18,6 +18,7 @@ import groupRouter from './group' import clientRouter from './client' import authRouter from './auth' import sessionRouter from './session' +import permissionRouter from './permission' const router = express.Router() @@ -36,6 +37,7 @@ router.use('/group', desktopRestrict, groupRouter) router.use('/stp', authenticateAccessToken, stpRouter) router.use('/code', authenticateAccessToken, codeRouter) router.use('/user', desktopRestrict, userRouter) +router.use('/permission', desktopRestrict, permissionRouter) router.use( '/', swaggerUi.serve, diff --git a/api/src/routes/api/permission.ts b/api/src/routes/api/permission.ts new file mode 100644 index 0000000..fc83462 --- /dev/null +++ b/api/src/routes/api/permission.ts @@ -0,0 +1,35 @@ +import express from 'express' +import { PermissionController } from '../../controllers/' +import { authenticateAccessToken, verifyAdmin } from '../../middlewares' +import { registerPermissionValidation } from '../../utils' + +const permissionRouter = express.Router() +const controller = new PermissionController() + +permissionRouter.get('/', authenticateAccessToken, async (req, res) => { + try { + const response = await controller.getAllPermissions() + res.send(response) + } catch (err: any) { + res.status(403).send(err.toString()) + } +}) + +permissionRouter.post( + '/', + authenticateAccessToken, + verifyAdmin, + async (req, res) => { + const { error, value: body } = registerPermissionValidation(req.body) + if (error) return res.status(400).send(error.details[0].message) + + try { + const response = await controller.createPermission(body) + res.send(response) + } catch (err: any) { + res.status(403).send(err.toString()) + } + } +) + +export default permissionRouter