- replace bearer auth with session+CSRF flow and add admin user directory - update frontend moderation flow, force password change gate, and new CLI - refresh changelog/docs/feature plan + ensure swagger dev experience
149 lines
4.6 KiB
JavaScript
149 lines
4.6 KiB
JavaScript
const { requireAdminAuth } = require('../../src/middlewares/auth');
|
|
const AdminAuthService = require('../../src/services/AdminAuthService');
|
|
const AdminUserRepository = require('../../src/repositories/AdminUserRepository');
|
|
const dbManager = require('../../src/database/DatabaseManager');
|
|
|
|
describe('Auth Middleware Unit Test (Session based)', () => {
|
|
let req, res, next;
|
|
|
|
beforeEach(() => {
|
|
req = { session: null };
|
|
res = {
|
|
status: jest.fn().mockReturnThis(),
|
|
json: jest.fn(),
|
|
locals: {}
|
|
};
|
|
next = jest.fn();
|
|
});
|
|
|
|
test('should reject when no session exists', () => {
|
|
requireAdminAuth(req, res, next);
|
|
|
|
expect(res.status).toHaveBeenCalledWith(403);
|
|
expect(res.json).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
error: 'Zugriff verweigert',
|
|
reason: 'SESSION_REQUIRED'
|
|
})
|
|
);
|
|
expect(next).not.toHaveBeenCalled();
|
|
});
|
|
|
|
test('should reject when session user is missing', () => {
|
|
req.session = {};
|
|
|
|
requireAdminAuth(req, res, next);
|
|
|
|
expect(res.status).toHaveBeenCalledWith(403);
|
|
expect(res.json).toHaveBeenCalledWith(
|
|
expect.objectContaining({ reason: 'SESSION_REQUIRED' })
|
|
);
|
|
expect(next).not.toHaveBeenCalled();
|
|
});
|
|
|
|
test('should reject non-admin roles', () => {
|
|
req.session = { user: { id: 1, role: 'viewer' } };
|
|
|
|
requireAdminAuth(req, res, next);
|
|
|
|
expect(res.status).toHaveBeenCalledWith(403);
|
|
expect(res.json).toHaveBeenCalledWith(
|
|
expect.objectContaining({ reason: 'SESSION_REQUIRED' })
|
|
);
|
|
expect(next).not.toHaveBeenCalled();
|
|
});
|
|
|
|
test('should pass through for admin sessions and expose user on locals', () => {
|
|
const adminUser = { id: 1, role: 'admin', username: 'testadmin' };
|
|
req.session = { user: adminUser };
|
|
|
|
requireAdminAuth(req, res, next);
|
|
|
|
expect(next).toHaveBeenCalled();
|
|
expect(res.status).not.toHaveBeenCalled();
|
|
expect(res.locals.adminUser).toEqual(adminUser);
|
|
});
|
|
});
|
|
|
|
describe('AdminAuthService', () => {
|
|
beforeEach(async () => {
|
|
await dbManager.run('DELETE FROM admin_users');
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await dbManager.run('DELETE FROM admin_users');
|
|
});
|
|
|
|
test('needsInitialSetup reflects admin count', async () => {
|
|
await expect(AdminAuthService.needsInitialSetup()).resolves.toBe(true);
|
|
|
|
await AdminAuthService.createInitialAdmin({
|
|
username: 'existing',
|
|
password: 'SuperSecure123!'
|
|
});
|
|
|
|
await expect(AdminAuthService.needsInitialSetup()).resolves.toBe(false);
|
|
});
|
|
|
|
test('createInitialAdmin validates input and detects completed setup', async () => {
|
|
await expect(
|
|
AdminAuthService.createInitialAdmin({ username: '', password: 'SuperSecure123!' })
|
|
).rejects.toThrow('USERNAME_REQUIRED');
|
|
|
|
await expect(
|
|
AdminAuthService.createInitialAdmin({ username: 'admin', password: 'short' })
|
|
).rejects.toThrow('PASSWORD_TOO_WEAK');
|
|
|
|
await AdminAuthService.createInitialAdmin({ username: 'seed', password: 'SuperSecure123!' });
|
|
await expect(
|
|
AdminAuthService.createInitialAdmin({ username: 'admin', password: 'SuperSecure123!' })
|
|
).rejects.toThrow('SETUP_ALREADY_COMPLETED');
|
|
});
|
|
|
|
test('createInitialAdmin persists normalized admin when setup allowed', async () => {
|
|
const result = await AdminAuthService.createInitialAdmin({
|
|
username: 'TestAdmin',
|
|
password: 'SuperSecure123!'
|
|
});
|
|
|
|
expect(result.username).toBe('testadmin');
|
|
expect(result.role).toBe('admin');
|
|
|
|
const stored = await AdminUserRepository.getByUsername('testadmin');
|
|
expect(stored).toMatchObject({ username: 'testadmin', role: 'admin', is_active: 1 });
|
|
});
|
|
|
|
test('verifyCredentials handles missing users and password mismatches', async () => {
|
|
await expect(AdminAuthService.verifyCredentials('admin', 'pw')).resolves.toBeNull();
|
|
|
|
const hash = await AdminAuthService.hashPassword('SuperSecure123!');
|
|
await AdminUserRepository.createAdminUser({
|
|
username: 'admin',
|
|
passwordHash: hash,
|
|
role: 'admin',
|
|
requiresPasswordChange: false
|
|
});
|
|
|
|
await expect(AdminAuthService.verifyCredentials('admin', 'wrong')).resolves.toBeNull();
|
|
});
|
|
|
|
test('verifyCredentials returns sanitized user for valid credentials', async () => {
|
|
const hash = await AdminAuthService.hashPassword('SuperSecure123!');
|
|
await AdminUserRepository.createAdminUser({
|
|
username: 'admin',
|
|
passwordHash: hash,
|
|
role: 'admin',
|
|
requiresPasswordChange: true
|
|
});
|
|
|
|
const result = await AdminAuthService.verifyCredentials('admin', 'SuperSecure123!');
|
|
|
|
expect(result).toEqual({
|
|
id: expect.any(Number),
|
|
username: 'admin',
|
|
role: 'admin',
|
|
requiresPasswordChange: true
|
|
});
|
|
});
|
|
});
|