backend: Refactor authentication logic to use new global auth configuration
This commit is contained in:
parent
499e36786b
commit
042f7f2fd4
@ -20,7 +20,7 @@ export const login = async (req: Request, res: Response) => {
|
||||
const { username, password } = req.body as { username: string; password: string };
|
||||
|
||||
const authService = container.get(AuthService);
|
||||
const user = authService.authenticate(username, password);
|
||||
const user = await authService.authenticate(username, password);
|
||||
|
||||
if (!user) {
|
||||
logger.warn('Login failed');
|
||||
@ -75,7 +75,7 @@ export const refreshToken = async (req: Request, res: Response) => {
|
||||
|
||||
const username = payload.sub;
|
||||
const userService = container.get(UserService);
|
||||
const user = username ? userService.getUser(username) : null;
|
||||
const user = username ? await userService.getUser(username) : null;
|
||||
|
||||
if (!user) {
|
||||
logger.warn('Invalid refresh token subject');
|
||||
@ -95,7 +95,7 @@ export const refreshToken = async (req: Request, res: Response) => {
|
||||
|
||||
export const getProfile = (req: Request, res: Response) => {
|
||||
const user = req.session?.user;
|
||||
|
||||
|
||||
if (!user) {
|
||||
return res.status(401).json({ message: 'Unauthorized' });
|
||||
}
|
||||
|
||||
@ -1,14 +1,9 @@
|
||||
import { NextFunction, Request, RequestHandler, Response } from 'express';
|
||||
import { TokenService, UserService } from '../services/index.js';
|
||||
import {
|
||||
ACCESS_TOKEN_COOKIE_NAME,
|
||||
MEET_API_KEY,
|
||||
MEET_PRIVATE_ACCESS,
|
||||
PARTICIPANT_TOKEN_COOKIE_NAME
|
||||
} from '../environment.js';
|
||||
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 { container } from '../config/dependency-injector.config.js';
|
||||
import { ClaimGrants } from 'livekit-server-sdk';
|
||||
import { Role } from '@typings-ce';
|
||||
import { AuthMode, UserRole } from '@typings-ce';
|
||||
import {
|
||||
errorUnauthorized,
|
||||
errorInvalidToken,
|
||||
@ -22,9 +17,9 @@ export const withAuth = (...validators: ((req: Request) => Promise<void>)[]): Re
|
||||
return async (req: Request, res: Response, next: NextFunction) => {
|
||||
let lastError: OpenViduMeetError | null = null;
|
||||
|
||||
for (const middleware of validators) {
|
||||
for (const validator of validators) {
|
||||
try {
|
||||
await middleware(req);
|
||||
await validator(req);
|
||||
// If any middleware granted access, it is not necessary to continue checking the rest
|
||||
return next();
|
||||
} catch (error) {
|
||||
@ -44,13 +39,8 @@ export const withAuth = (...validators: ((req: Request) => Promise<void>)[]): Re
|
||||
};
|
||||
|
||||
// Configure token validatior for role-based access
|
||||
export const tokenAndRoleValidator = (role: Role) => {
|
||||
export const tokenAndRoleValidator = (role: UserRole) => {
|
||||
return async (req: Request) => {
|
||||
// Skip token validation if role is USER and access is public
|
||||
if (role == Role.USER && MEET_PRIVATE_ACCESS === 'false') {
|
||||
return;
|
||||
}
|
||||
|
||||
const token = req.cookies[ACCESS_TOKEN_COOKIE_NAME];
|
||||
|
||||
if (!token) {
|
||||
@ -68,7 +58,7 @@ export const tokenAndRoleValidator = (role: Role) => {
|
||||
|
||||
const username = payload.sub;
|
||||
const userService = container.get(UserService);
|
||||
const user = username ? userService.getUser(username) : null;
|
||||
const user = username ? await userService.getUser(username) : null;
|
||||
|
||||
if (!user) {
|
||||
throw errorInvalidTokenSubject();
|
||||
|
||||
@ -1,15 +1,21 @@
|
||||
import { MEET_ADMIN_SECRET, MEET_ADMIN_USER, MEET_PRIVATE_ACCESS, MEET_SECRET, MEET_USER } from '../environment.js';
|
||||
import { MEET_ADMIN_SECRET, MEET_ADMIN_USER } from '../environment.js';
|
||||
import { inject, injectable } from '../config/dependency-injector.config.js';
|
||||
import { User } from '@typings-ce';
|
||||
import { AuthMode, AuthType, SingleUserAuth, User, ValidAuthMethod } from '@typings-ce';
|
||||
import { UserService } from './user.service.js';
|
||||
import { GlobalPreferencesService } from './preferences/global-preferences.service.js';
|
||||
import { LoggerService } from './logger.service.js';
|
||||
|
||||
@injectable()
|
||||
export class AuthService {
|
||||
constructor(@inject(UserService) protected userService: UserService) {}
|
||||
constructor(
|
||||
@inject(LoggerService) protected logger: LoggerService,
|
||||
@inject(UserService) protected userService: UserService,
|
||||
@inject(GlobalPreferencesService) protected globalPrefService: GlobalPreferencesService
|
||||
) {}
|
||||
|
||||
authenticate(username: string, password: string): User | null {
|
||||
async authenticate(username: string, password: string): Promise<User | null> {
|
||||
const isAdmin = this.authenticateAdmin(username, password);
|
||||
const isUser = this.authenticateUser(username, password);
|
||||
const isUser = await this.authenticateUser(username, password);
|
||||
|
||||
if (isAdmin || isUser) {
|
||||
return this.userService.getUser(username);
|
||||
@ -22,9 +28,28 @@ export class AuthService {
|
||||
return username === MEET_ADMIN_USER && password === MEET_ADMIN_SECRET;
|
||||
}
|
||||
|
||||
private authenticateUser(username: string, password: string): boolean {
|
||||
if (MEET_PRIVATE_ACCESS === 'true') {
|
||||
return username === MEET_USER && password === MEET_SECRET;
|
||||
private async authenticateUser(username: string, password: string): Promise<boolean> {
|
||||
let requireAuthForRoomCreation: boolean;
|
||||
let authMode: AuthMode;
|
||||
let authMethod: ValidAuthMethod;
|
||||
|
||||
try {
|
||||
const { securityPreferences } = await this.globalPrefService.getGlobalPreferences();
|
||||
requireAuthForRoomCreation = securityPreferences.roomCreationPolicy.requireAuthentication;
|
||||
({ authMode, method: authMethod } = securityPreferences.authentication);
|
||||
} catch (error) {
|
||||
this.logger.error('Error checking authentication preferences:' + error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (requireAuthForRoomCreation || authMode !== AuthMode.NONE) {
|
||||
if (authMethod.type !== AuthType.SINGLE_USER) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const { username: configuredUsername, passwordHash: configurePassword } = (authMethod as SingleUserAuth)
|
||||
.credentials;
|
||||
return username === configuredUsername && password === configurePassword;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@ -1,21 +1,42 @@
|
||||
import { MEET_ADMIN_USER, MEET_USER } from '../environment.js';
|
||||
import { injectable } from '../config/dependency-injector.config.js';
|
||||
import { Role, User } from '@typings-ce';
|
||||
import { MEET_ADMIN_USER } from '../environment.js';
|
||||
import { inject, injectable } from '../config/dependency-injector.config.js';
|
||||
import { AuthType, UserRole, SingleUserAuth, User } from '@typings-ce';
|
||||
import { LoggerService } from './logger.service.js';
|
||||
import { GlobalPreferencesService } from './preferences/global-preferences.service.js';
|
||||
|
||||
@injectable()
|
||||
export class UserService {
|
||||
getUser(username: string): User | null {
|
||||
constructor(
|
||||
@inject(LoggerService) protected logger: LoggerService,
|
||||
@inject(GlobalPreferencesService) protected globalPrefService: GlobalPreferencesService
|
||||
) {}
|
||||
|
||||
async getUser(username: string): Promise<User | null> {
|
||||
if (username === MEET_ADMIN_USER) {
|
||||
return {
|
||||
username: MEET_ADMIN_USER,
|
||||
role: Role.ADMIN
|
||||
role: UserRole.ADMIN
|
||||
};
|
||||
}
|
||||
|
||||
if (username === MEET_USER) {
|
||||
let configuredUsername: string | undefined;
|
||||
|
||||
try {
|
||||
const { securityPreferences } = await this.globalPrefService.getGlobalPreferences();
|
||||
const method = securityPreferences.authentication.method;
|
||||
|
||||
if (method.type === AuthType.SINGLE_USER) {
|
||||
configuredUsername = (method as SingleUserAuth).credentials.username;
|
||||
}
|
||||
} catch (error) {
|
||||
this.logger.error('Error checking room creation policy:' + error);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (username === configuredUsername) {
|
||||
return {
|
||||
username: MEET_USER,
|
||||
role: Role.USER
|
||||
username: configuredUsername,
|
||||
role: UserRole.USER
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user