530 lines
17 KiB
TypeScript

import { beforeAll, describe, expect, it } from '@jest/globals';
import { MeetUserRole } from '@openvidu-meet/typings';
import { Express } from 'express';
import request from 'supertest';
import { INTERNAL_CONFIG } from '../../../../src/config/internal-config.js';
import { MEET_ENV } from '../../../../src/environment.js';
import {
changePassword,
createUser,
deleteAllUsers,
getFullPath,
loginRootAdmin,
startTestServer
} from '../../../helpers/request-helpers.js';
import { setupTestUsers } from '../../../helpers/test-scenarios.js';
import { TestUsers } from '../../../interfaces/scenarios.js';
const USERS_PATH = getFullPath(`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/users`);
describe('User API Security Tests', () => {
let app: Express;
let rootAdminAccessToken: string;
let testUsers: TestUsers;
beforeAll(async () => {
app = await startTestServer();
({ accessToken: rootAdminAccessToken } = await loginRootAdmin());
testUsers = await setupTestUsers();
});
afterAll(async () => {
await deleteAllUsers();
});
describe('Create User Tests', () => {
const getNewUserData = () => {
const timestamp = Date.now();
return {
userId: `usr_${timestamp}`,
name: 'Test User',
password: 'testpass123',
role: MeetUserRole.USER
};
};
it('should fail when using API key', async () => {
const response = await request(app)
.post(USERS_PATH)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.send(getNewUserData());
expect(response.status).toBe(401);
});
it('should succeed when user is authenticated as root admin', async () => {
const response = await request(app)
.post(USERS_PATH)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, rootAdminAccessToken)
.send(getNewUserData());
expect(response.status).toBe(201);
});
it('should succeed when user is authenticated as ADMIN', async () => {
const response = await request(app)
.post(USERS_PATH)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, testUsers.admin.accessToken)
.send(getNewUserData());
expect(response.status).toBe(201);
});
it('should fail when user is authenticated as USER', async () => {
const response = await request(app)
.post(USERS_PATH)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, testUsers.user.accessToken)
.send(getNewUserData());
expect(response.status).toBe(403);
});
it('should fail when user is authenticated as ROOM_MEMBER', async () => {
const response = await request(app)
.post(USERS_PATH)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, testUsers.roomMember.accessToken)
.send(getNewUserData());
expect(response.status).toBe(403);
});
it('should fail when user is not authenticated', async () => {
const response = await request(app).post(USERS_PATH).send(getNewUserData());
expect(response.status).toBe(401);
});
});
describe('Get Users Tests', () => {
it('should fail when using API key', async () => {
const response = await request(app)
.get(USERS_PATH)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY);
expect(response.status).toBe(401);
});
it('should succeed when user is authenticated as root admin', async () => {
const response = await request(app)
.get(USERS_PATH)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, rootAdminAccessToken);
expect(response.status).toBe(200);
});
it('should succeed when user is authenticated as ADMIN', async () => {
const response = await request(app)
.get(USERS_PATH)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, testUsers.admin.accessToken);
expect(response.status).toBe(200);
});
it('should succeed when user is authenticated as USER', async () => {
const response = await request(app)
.get(USERS_PATH)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, testUsers.user.accessToken);
expect(response.status).toBe(200);
});
it('should fail when user is authenticated as ROOM_MEMBER', async () => {
const response = await request(app)
.get(USERS_PATH)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, testUsers.roomMember.accessToken);
expect(response.status).toBe(403);
});
it('should fail when user is not authenticated', async () => {
const response = await request(app).get(USERS_PATH);
expect(response.status).toBe(401);
});
});
describe('Get User Tests', () => {
let userId: string;
beforeAll(async () => {
const response = await createUser({
userId: `usr_${Date.now()}`,
name: 'Test User',
password: 'testpass123',
role: MeetUserRole.USER
});
expect(response.status).toBe(201);
userId = response.body.userId;
});
it('should fail when using API key', async () => {
const response = await request(app)
.get(`${USERS_PATH}/${userId}`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY);
expect(response.status).toBe(401);
});
it('should succeed when user is authenticated as root admin', async () => {
const response = await request(app)
.get(`${USERS_PATH}/${userId}`)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, rootAdminAccessToken);
expect(response.status).toBe(200);
});
it('should succeed when user is authenticated as ADMIN', async () => {
const response = await request(app)
.get(`${USERS_PATH}/${userId}`)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, testUsers.admin.accessToken);
expect(response.status).toBe(200);
});
it('should succeed when user is authenticated as USER', async () => {
const response = await request(app)
.get(`${USERS_PATH}/${userId}`)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, testUsers.user.accessToken);
expect(response.status).toBe(200);
});
it('should fail when user is authenticated as ROOM_MEMBER', async () => {
const response = await request(app)
.get(`${USERS_PATH}/${userId}`)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, testUsers.roomMember.accessToken);
expect(response.status).toBe(403);
});
it('should fail when user is not authenticated', async () => {
const response = await request(app).get(`${USERS_PATH}/${userId}`);
expect(response.status).toBe(401);
});
});
describe('Reset User Password Tests', () => {
let userId: string;
const newPassword = 'resetpassword123';
beforeAll(async () => {
const response = await createUser({
userId: `usr_${Date.now()}`,
name: 'Test User',
password: 'testpass123',
role: MeetUserRole.USER
});
expect(response.status).toBe(201);
userId = response.body.userId;
});
it('should fail when using API key', async () => {
const response = await request(app)
.put(`${USERS_PATH}/${userId}/password`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.send({ newPassword });
expect(response.status).toBe(401);
});
it('should succeed when user is authenticated as root admin', async () => {
const response = await request(app)
.put(`${USERS_PATH}/${userId}/password`)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, rootAdminAccessToken)
.send({ newPassword });
expect(response.status).toBe(200);
});
it('should succeed when user is authenticated as ADMIN', async () => {
const response = await request(app)
.put(`${USERS_PATH}/${userId}/password`)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, testUsers.admin.accessToken)
.send({ newPassword });
expect(response.status).toBe(200);
});
it('should fail when user is authenticated as USER', async () => {
const response = await request(app)
.put(`${USERS_PATH}/${userId}/password`)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, testUsers.user.accessToken)
.send({ newPassword });
expect(response.status).toBe(403);
});
it('should fail when user is authenticated as ROOM_MEMBER', async () => {
const response = await request(app)
.put(`${USERS_PATH}/${userId}/password`)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, testUsers.roomMember.accessToken)
.send({ newPassword });
expect(response.status).toBe(403);
});
it('should fail when user is not authenticated', async () => {
const response = await request(app).put(`${USERS_PATH}/${userId}/password`).send({ newPassword });
expect(response.status).toBe(401);
});
});
describe('Update User Role Tests', () => {
let userId: string;
beforeAll(async () => {
const response = await createUser({
userId: `usr_${Date.now()}`,
name: 'Test User',
password: 'testpass123',
role: MeetUserRole.USER
});
expect(response.status).toBe(201);
userId = response.body.userId;
});
it('should fail when using API key', async () => {
const response = await request(app)
.put(`${USERS_PATH}/${userId}/role`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.send({ role: MeetUserRole.ADMIN });
expect(response.status).toBe(401);
});
it('should succeed when user is authenticated as root admin', async () => {
const response = await request(app)
.put(`${USERS_PATH}/${userId}/role`)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, rootAdminAccessToken)
.send({ role: MeetUserRole.ADMIN });
expect(response.status).toBe(200);
});
it('should succeed when user is authenticated as ADMIN', async () => {
const response = await request(app)
.put(`${USERS_PATH}/${userId}/role`)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, testUsers.admin.accessToken)
.send({ role: MeetUserRole.ADMIN });
expect(response.status).toBe(200);
});
it('should fail when user is authenticated as USER', async () => {
const response = await request(app)
.put(`${USERS_PATH}/${userId}/role`)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, testUsers.user.accessToken)
.send({ role: MeetUserRole.ADMIN });
expect(response.status).toBe(403);
});
it('should fail when user is authenticated as ROOM_MEMBER', async () => {
const response = await request(app)
.put(`${USERS_PATH}/${userId}/role`)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, testUsers.roomMember.accessToken)
.send({ role: MeetUserRole.ADMIN });
expect(response.status).toBe(403);
});
it('should fail when user is not authenticated', async () => {
const response = await request(app).put(`${USERS_PATH}/${userId}/role`).send({ role: MeetUserRole.ADMIN });
expect(response.status).toBe(401);
});
});
describe('Delete User Tests', () => {
let userId: string;
beforeEach(async () => {
// Create a user to delete in each test
const response = await createUser({
userId: `usr_${Date.now()}`,
name: 'Test User',
password: 'testpass123',
role: MeetUserRole.USER
});
expect(response.status).toBe(201);
userId = response.body.userId;
});
it('should fail when using API key', async () => {
const response = await request(app)
.delete(`${USERS_PATH}/${userId}`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY);
expect(response.status).toBe(401);
});
it('should succeed when user is authenticated as root admin', async () => {
const response = await request(app)
.delete(`${USERS_PATH}/${userId}`)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, rootAdminAccessToken);
expect(response.status).toBe(200);
});
it('should succeed when user is authenticated as ADMIN', async () => {
const response = await request(app)
.delete(`${USERS_PATH}/${userId}`)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, testUsers.admin.accessToken);
expect(response.status).toBe(200);
});
it('should fail when user is authenticated as USER', async () => {
const response = await request(app)
.delete(`${USERS_PATH}/${userId}`)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, testUsers.user.accessToken);
expect(response.status).toBe(403);
});
it('should fail when user is authenticated as ROOM_MEMBER', async () => {
const response = await request(app)
.delete(`${USERS_PATH}/${userId}`)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, testUsers.roomMember.accessToken);
expect(response.status).toBe(403);
});
it('should fail when user is not authenticated', async () => {
const response = await request(app).delete(`${USERS_PATH}/${userId}`);
expect(response.status).toBe(401);
});
});
describe('Bulk Delete Users Tests', () => {
let userId: string;
beforeEach(async () => {
// Create user to delete in each test
const response = await createUser({
userId: `usr_${Date.now()}`,
name: 'Test User',
password: 'testpass123',
role: MeetUserRole.USER
});
expect(response.status).toBe(201);
userId = response.body.userId;
});
it('should fail when using API key', async () => {
const response = await request(app)
.delete(USERS_PATH)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.query({ userIds: userId });
expect(response.status).toBe(401);
});
it('should succeed when user is authenticated as root admin', async () => {
const response = await request(app)
.delete(USERS_PATH)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, rootAdminAccessToken)
.query({ userIds: userId });
expect(response.status).toBe(200);
});
it('should succeed when user is authenticated as ADMIN', async () => {
const response = await request(app)
.delete(USERS_PATH)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, testUsers.admin.accessToken)
.query({ userIds: userId });
expect(response.status).toBe(200);
});
it('should fail when user is authenticated as USER', async () => {
const response = await request(app)
.delete(USERS_PATH)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, testUsers.user.accessToken)
.query({ userIds: userId });
expect(response.status).toBe(403);
});
it('should fail when user is authenticated as ROOM_MEMBER', async () => {
const response = await request(app)
.delete(USERS_PATH)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, testUsers.roomMember.accessToken)
.query({ userIds: userId });
expect(response.status).toBe(403);
});
it('should fail when user is not authenticated', async () => {
const response = await request(app).delete(USERS_PATH).query({ userIds: userId });
expect(response.status).toBe(401);
});
});
describe('Profile Tests', () => {
it('should succeed when user is authenticated as root admin', async () => {
const response = await request(app)
.get(`${USERS_PATH}/me`)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, rootAdminAccessToken);
expect(response.status).toBe(200);
});
it('should succeed when user is authenticated as ADMIN', async () => {
const response = await request(app)
.get(`${USERS_PATH}/me`)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, testUsers.admin.accessToken);
expect(response.status).toBe(200);
});
it('should succeed when user is authenticated as USER', async () => {
const response = await request(app)
.get(`${USERS_PATH}/me`)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, testUsers.user.accessToken);
expect(response.status).toBe(200);
});
it('should succeed when user is authenticated as ROOM_MEMBER', async () => {
const response = await request(app)
.get(`${USERS_PATH}/me`)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, testUsers.roomMember.accessToken);
expect(response.status).toBe(200);
});
it('should fail when user is not authenticated', async () => {
const response = await request(app).get(`${USERS_PATH}/me`);
expect(response.status).toBe(401);
});
});
describe('Change Password Tests', () => {
const newPassword = 'newpassword123';
it('should succeed when user is authenticated as root admin', async () => {
const response = await request(app)
.post(`${USERS_PATH}/change-password`)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, rootAdminAccessToken)
.send({
currentPassword: MEET_ENV.INITIAL_ADMIN_PASSWORD,
newPassword
});
expect(response.status).toBe(200);
// Reset old password
await changePassword(newPassword, MEET_ENV.INITIAL_ADMIN_PASSWORD, rootAdminAccessToken);
});
it('should succeed when user is authenticated as ADMIN', async () => {
const response = await request(app)
.post(`${USERS_PATH}/change-password`)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, testUsers.admin.accessToken)
.send({
currentPassword: testUsers.admin.password,
newPassword
});
expect(response.status).toBe(200);
// Reset old password
await changePassword(newPassword, testUsers.admin.password, testUsers.admin.accessToken);
});
it('should succeed when user is authenticated as USER', async () => {
const response = await request(app)
.post(`${USERS_PATH}/change-password`)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, testUsers.user.accessToken)
.send({
currentPassword: testUsers.user.password,
newPassword
});
expect(response.status).toBe(200);
// Reset old password
await changePassword(newPassword, testUsers.user.password, testUsers.user.accessToken);
});
it('should succeed when user is authenticated as ROOM_MEMBER', async () => {
const response = await request(app)
.post(`${USERS_PATH}/change-password`)
.set(INTERNAL_CONFIG.ACCESS_TOKEN_HEADER, testUsers.roomMember.accessToken)
.send({
currentPassword: testUsers.roomMember.password,
newPassword
});
expect(response.status).toBe(200);
// Reset old password
await changePassword(newPassword, testUsers.roomMember.password, testUsers.roomMember.accessToken);
});
it('should fail when user is not authenticated', async () => {
const response = await request(app).post(`${USERS_PATH}/change-password`).send({
currentPassword: MEET_ENV.INITIAL_ADMIN_PASSWORD,
newPassword
});
expect(response.status).toBe(401);
});
});
});