backend: Enhance authentication middleware to always include user that is performing the action in a resource
This commit is contained in:
parent
8a403006fd
commit
930541c725
@ -61,14 +61,24 @@ export const {
|
||||
ENABLED_MODULES = ''
|
||||
} = process.env;
|
||||
|
||||
// Base paths for the API
|
||||
export const MEET_API_BASE_PATH = '/meet/api';
|
||||
export const MEET_INTERNAL_API_BASE_PATH_V1 = '/meet/internal-api/v1';
|
||||
export const MEET_API_BASE_PATH_V1 = MEET_API_BASE_PATH + '/v1';
|
||||
|
||||
// Cookie names
|
||||
export const PARTICIPANT_TOKEN_COOKIE_NAME = 'OvMeetParticipantToken';
|
||||
export const ACCESS_TOKEN_COOKIE_NAME = 'OvMeetAccessToken';
|
||||
export const REFRESH_TOKEN_COOKIE_NAME = 'OvMeetRefreshToken';
|
||||
|
||||
// Fixed usernames
|
||||
export const MEET_ANONYMOUS_USER = 'anonymous';
|
||||
export const MEET_API_USER = 'api-user';
|
||||
|
||||
// S3 prefixes
|
||||
export const MEET_S3_ROOMS_PREFIX = 'rooms';
|
||||
export const MEET_S3_RECORDINGS_PREFIX = 'recordings';
|
||||
|
||||
// Time to live for the active recording lock in Redis
|
||||
export const MEET_RECORDING_LOCK_TTL = '6h';
|
||||
|
||||
|
||||
@ -1,9 +1,15 @@
|
||||
import { NextFunction, Request, RequestHandler, Response } from 'express';
|
||||
import { GlobalPreferencesService, LoggerService, TokenService, UserService } from '../services/index.js';
|
||||
import { ACCESS_TOKEN_COOKIE_NAME, MEET_API_KEY, PARTICIPANT_TOKEN_COOKIE_NAME } from '../environment.js';
|
||||
import { LoggerService, TokenService, UserService } from '../services/index.js';
|
||||
import {
|
||||
ACCESS_TOKEN_COOKIE_NAME,
|
||||
MEET_ANONYMOUS_USER,
|
||||
MEET_API_KEY,
|
||||
MEET_API_USER,
|
||||
PARTICIPANT_TOKEN_COOKIE_NAME
|
||||
} from '../environment.js';
|
||||
import { container } from '../config/dependency-injector.config.js';
|
||||
import { ClaimGrants } from 'livekit-server-sdk';
|
||||
import { AuthMode, UserRole } from '@typings-ce';
|
||||
import { User, UserRole } from '@typings-ce';
|
||||
import {
|
||||
errorUnauthorized,
|
||||
errorInvalidToken,
|
||||
@ -13,6 +19,14 @@ import {
|
||||
OpenViduMeetError
|
||||
} from '../models/index.js';
|
||||
|
||||
/**
|
||||
* This middleware allows to chain multiple validators to check if the request is authorized.
|
||||
* If any of the validators grants access, the request is allowed to continue, skipping the rest of the validators.
|
||||
* If none of the validators grants access, the request is rejected with an unauthorized error.
|
||||
*
|
||||
* @param validators List of validators to check if the request is authorized
|
||||
* @returns RequestHandler middleware
|
||||
*/
|
||||
export const withAuth = (...validators: ((req: Request) => Promise<void>)[]): RequestHandler => {
|
||||
return async (req: Request, res: Response, next: NextFunction) => {
|
||||
let lastError: OpenViduMeetError | null = null;
|
||||
@ -103,39 +117,43 @@ export const apiKeyValidator = async (req: Request) => {
|
||||
if (apiKey !== MEET_API_KEY) {
|
||||
throw errorInvalidApiKey();
|
||||
}
|
||||
|
||||
const apiUser = {
|
||||
username: MEET_API_USER,
|
||||
role: UserRole.APP
|
||||
};
|
||||
|
||||
req.session = req.session || {};
|
||||
req.session.user = apiUser;
|
||||
};
|
||||
|
||||
// Allow anonymous access
|
||||
export const allowAnonymous = async (req: Request) => {
|
||||
const anonymousUser = {
|
||||
username: 'anonymous',
|
||||
role: UserRole.USER
|
||||
};
|
||||
let user: User | null = null;
|
||||
|
||||
// Check if there is a user already authenticated
|
||||
const token = req.cookies[ACCESS_TOKEN_COOKIE_NAME];
|
||||
|
||||
if (token) {
|
||||
try {
|
||||
const tokenService = container.get(TokenService);
|
||||
const payload = await tokenService.verifyToken(token);
|
||||
const username = payload.sub;
|
||||
const userService = container.get(UserService);
|
||||
user = username ? await userService.getUser(username) : null;
|
||||
} catch (error) {
|
||||
const logger = container.get(LoggerService);
|
||||
logger.debug('Token found but invalid:' + error);
|
||||
}
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
user = {
|
||||
username: MEET_ANONYMOUS_USER,
|
||||
role: UserRole.USER
|
||||
};
|
||||
}
|
||||
|
||||
req.session = req.session || {};
|
||||
req.session.user = anonymousUser;
|
||||
};
|
||||
|
||||
export const configureProfileAuth = async (req: Request, res: Response, next: NextFunction) => {
|
||||
const logger = container.get(LoggerService);
|
||||
const globalPrefService = container.get(GlobalPreferencesService);
|
||||
let requireAuthForRoomCreation: boolean;
|
||||
let authMode: AuthMode;
|
||||
|
||||
try {
|
||||
const { securityPreferences } = await globalPrefService.getGlobalPreferences();
|
||||
requireAuthForRoomCreation = securityPreferences.roomCreationPolicy.requireAuthentication;
|
||||
authMode = securityPreferences.authentication.authMode;
|
||||
} catch (error) {
|
||||
logger.error('Error checking authentication preferences:' + error);
|
||||
return res.status(500).json({ message: 'Internal server error' });
|
||||
}
|
||||
|
||||
const authValidators = [tokenAndRoleValidator(UserRole.ADMIN)];
|
||||
|
||||
if (requireAuthForRoomCreation || authMode !== AuthMode.NONE) {
|
||||
authValidators.push(tokenAndRoleValidator(UserRole.USER));
|
||||
}
|
||||
|
||||
return withAuth(...authValidators)(req, res, next);
|
||||
req.session.user = user;
|
||||
};
|
||||
|
||||
@ -3,8 +3,9 @@ import { Router } from 'express';
|
||||
import bodyParser from 'body-parser';
|
||||
import * as authCtrl from '../controllers/auth.controller.js';
|
||||
import rateLimit from 'express-rate-limit';
|
||||
import { configureProfileAuth } from '../middlewares/auth.middleware.js';
|
||||
import { tokenAndRoleValidator, withAuth } from '../middlewares/auth.middleware.js';
|
||||
import { validateLoginRequest } from '../middlewares/request-validators/auth-validator.middleware.js';
|
||||
import { UserRole } from '@typings-ce';
|
||||
|
||||
export const authRouter = Router();
|
||||
|
||||
@ -22,4 +23,8 @@ authRouter.use(bodyParser.json());
|
||||
authRouter.post('/login', validateLoginRequest, loginLimiter, authCtrl.login);
|
||||
authRouter.post('/logout', authCtrl.logout);
|
||||
authRouter.post('/refresh', authCtrl.refreshToken);
|
||||
authRouter.get('/profile', configureProfileAuth, authCtrl.getProfile);
|
||||
authRouter.get(
|
||||
'/profile',
|
||||
withAuth(tokenAndRoleValidator(UserRole.ADMIN), tokenAndRoleValidator(UserRole.USER)),
|
||||
authCtrl.getProfile
|
||||
);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user