diff --git a/backend/src/middlewares/room.middleware.ts b/backend/src/middlewares/room.middleware.ts index 7032435..ed97a66 100644 --- a/backend/src/middlewares/room.middleware.ts +++ b/backend/src/middlewares/room.middleware.ts @@ -3,9 +3,9 @@ import { NextFunction, Request, Response } from 'express'; import { LoggerService } from '../services/logger.service.js'; import { GlobalPreferencesService } from '../services/index.js'; import { allowAnonymous, apiKeyValidator, tokenAndRoleValidator, withAuth } from './auth.middleware.js'; -import { UserRole } from '@typings-ce'; +import { AuthMode, ParticipantRole, UserRole } from '@typings-ce'; -export const configureRoomAuth = async (req: Request, res: Response, next: NextFunction) => { +export const configureCreateRoomAuth = async (req: Request, res: Response, next: NextFunction) => { const logger = container.get(LoggerService); const globalPrefService = container.get(GlobalPreferencesService); let allowRoomCreation: boolean; @@ -31,3 +31,59 @@ export const configureRoomAuth = async (req: Request, res: Response, next: NextF return withAuth(...authValidators)(req, res, next); }; + +/** + * Middleware that configures authorization for accessing a specific room. + * + * This middleware runs after authentication and applies additional authorization rules + * based on the user's role and global authentication settings. + * + * - If there is no token in the session, the user is granted access (admin or API key). + * - If the user does not belong to the requested room, access is denied. + * - If the user is a moderator and global authentication requires it, + * an extra validation step is added with `withAuth(tokenAndRoleValidator(UserRole.USER))`. + * - If the user is not a moderator, access is denied. + */ +export const configureRoomAuthorization = async (req: Request, res: Response, next: NextFunction) => { + const roomName = req.params.roomName as string; + const payload = req.session?.tokenClaims; + + // If there is no token, the user is admin or it is invoked using the API key + // In this case, the user is allowed to access the resource + if (!payload) { + return next(); + } + + const sameRoom = payload.video?.room === roomName; + const metadata = JSON.parse(payload.metadata || '{}'); + const role = metadata.role as ParticipantRole; + + if (!sameRoom) { + return res.status(403).json({ message: 'Insufficient permissions to access this resource' }); + } + + const logger = container.get(LoggerService); + const globalPrefService = container.get(GlobalPreferencesService); + let authMode: AuthMode; + + try { + const { securityPreferences } = await globalPrefService.getGlobalPreferences(); + authMode = securityPreferences.authentication.authMode; + } catch (error) { + logger.error('Error checking authentication preferences', error); + return res.status(500).json({ message: 'Internal server error' }); + } + + // If the user is a moderator, it is necessary to add the user role validator + // in case the room requires some authentication + if (role === ParticipantRole.MODERATOR) { + if (authMode !== AuthMode.NONE) { + return withAuth(tokenAndRoleValidator(UserRole.USER))(req, res, next); + } + + return next(); + } + + // If the user is not a moderator, it is not allowed to access the resource + return res.status(403).json({ message: 'Insufficient permissions to access this resource' }); +}; diff --git a/backend/src/routes/room.routes.ts b/backend/src/routes/room.routes.ts index 1172734..434dfa3 100644 --- a/backend/src/routes/room.routes.ts +++ b/backend/src/routes/room.routes.ts @@ -1,13 +1,18 @@ import { Router } from 'express'; import bodyParser from 'body-parser'; import * as roomCtrl from '../controllers/room.controller.js'; -import { withAuth, tokenAndRoleValidator, apiKeyValidator } from '../middlewares/auth.middleware.js'; +import { + withAuth, + tokenAndRoleValidator, + apiKeyValidator, + participantTokenValidator +} from '../middlewares/auth.middleware.js'; import { validateGetRoomQueryParams, validateRoomRequest } from '../middlewares/request-validators/room-validator.middleware.js'; import { UserRole } from '@typings-ce'; -import { configureRoomAuth } from '../middlewares/room.middleware.js'; +import { configureCreateRoomAuth, configureRoomAuthorization } from '../middlewares/room.middleware.js'; export const roomRouter = Router(); @@ -15,7 +20,7 @@ roomRouter.use(bodyParser.urlencoded({ extended: true })); roomRouter.use(bodyParser.json()); // Room Routes -roomRouter.post('/', configureRoomAuth, validateRoomRequest, roomCtrl.createRoom); +roomRouter.post('/', configureCreateRoomAuth, validateRoomRequest, roomCtrl.createRoom); roomRouter.get( '/', withAuth(apiKeyValidator, tokenAndRoleValidator(UserRole.ADMIN)), @@ -24,7 +29,8 @@ roomRouter.get( ); roomRouter.get( '/:roomName', - withAuth(apiKeyValidator, tokenAndRoleValidator(UserRole.ADMIN), tokenAndRoleValidator(UserRole.USER)), + withAuth(apiKeyValidator, tokenAndRoleValidator(UserRole.ADMIN), participantTokenValidator), + configureRoomAuthorization, validateGetRoomQueryParams, roomCtrl.getRoom );