bae705aa97
- Add NFC ePassport roadmap (ICAO 9303, eIDAS) - Add TensorFlow.js edge face detection (BlazeFace) - Add structured audit logger (GDPR-compliant) - Risk scoring support Part of KYC Apple Native UX v1.1.0
183 lines
6.1 KiB
JavaScript
183 lines
6.1 KiB
JavaScript
/**
|
|
* ═══════════════════════════════════════════════════════════════════════════
|
|
* AAMOS Ledger — Auth & RBAC Tester
|
|
* ═══════════════════════════════════════════════════════════════════════════
|
|
*/
|
|
|
|
import { describe, it, before } from 'node:test';
|
|
import assert from 'node:assert';
|
|
import jwt from 'jsonwebtoken';
|
|
|
|
// Mocka miljövariabler före import
|
|
process.env.NODE_ENV = 'development';
|
|
process.env.AMOS_JWT_SECRET = 'test-secret-minst-32-tecken-lång-12345';
|
|
process.env.LEDGER_INTERNAL_TOKEN = 'test-internal-token-12345';
|
|
|
|
const auth = await import('../auth.mjs');
|
|
|
|
describe('Auth-konfiguration', () => {
|
|
it('ska validera korrekt med giltiga miljövariabler', () => {
|
|
assert.doesNotThrow(() => auth.validateAuthConfig());
|
|
});
|
|
});
|
|
|
|
describe('JWT-verifiering', () => {
|
|
const secret = process.env.AMOS_JWT_SECRET;
|
|
|
|
it('ska acceptera giltig HS256-token', async () => {
|
|
const token = jwt.sign({ sub: 'user-1', roles: ['viewer'] }, secret, { algorithm: 'HS256' });
|
|
|
|
const req = { headers: { authorization: `Bearer ${token}` } };
|
|
const res = { status: () => ({ json: () => {} }) };
|
|
let nextCalled = false;
|
|
|
|
auth.authenticate(req, res, () => { nextCalled = true; });
|
|
|
|
assert.strictEqual(nextCalled, true);
|
|
assert.strictEqual(req.auth.user_id, 'user-1');
|
|
assert.deepStrictEqual(req.auth.roles, ['viewer']);
|
|
});
|
|
|
|
it('ska neka expired token', async () => {
|
|
const token = jwt.sign({ sub: 'user-1', roles: ['viewer'] }, secret, { algorithm: 'HS256', expiresIn: '-1s' });
|
|
|
|
const req = { headers: { authorization: `Bearer ${token}` } };
|
|
let statusCode = null;
|
|
const res = {
|
|
status: (code) => { statusCode = code; return { json: () => {} }; }
|
|
};
|
|
|
|
auth.authenticate(req, res, () => {});
|
|
|
|
assert.strictEqual(statusCode, 401);
|
|
});
|
|
|
|
it('ska neka token utan roller i production', async () => {
|
|
// Simulera production-beteende genom att testa logiken direkt
|
|
// I production krävs RS256 + publik nyckel, så vi testar att
|
|
// auth-modulen kastar fel vid startup om konfig saknas
|
|
|
|
// Testa att validateAuthConfig kastar fel utan publik nyckel i production
|
|
const originalEnv = process.env.NODE_ENV;
|
|
const originalPath = process.env.JWT_PUBLIC_KEY_PATH;
|
|
|
|
process.env.NODE_ENV = 'production';
|
|
delete process.env.JWT_PUBLIC_KEY_PATH;
|
|
|
|
assert.throws(() => auth.validateAuthConfig(), /JWT_PUBLIC_KEY_PATH/);
|
|
|
|
process.env.NODE_ENV = originalEnv;
|
|
if (originalPath) process.env.JWT_PUBLIC_KEY_PATH = originalPath;
|
|
});
|
|
});
|
|
|
|
describe('Service-to-service token', () => {
|
|
it('ska acceptera giltigt intern token', () => {
|
|
const req = { headers: { authorization: `Bearer ${process.env.LEDGER_INTERNAL_TOKEN}` } };
|
|
let nextCalled = false;
|
|
const res = { status: () => ({ json: () => {} }) };
|
|
|
|
auth.authenticate(req, res, () => { nextCalled = true; });
|
|
|
|
assert.strictEqual(nextCalled, true);
|
|
assert.strictEqual(req.auth.type, 'service');
|
|
assert.deepStrictEqual(req.auth.roles, ['admin']);
|
|
});
|
|
|
|
it('ska neka ogiltigt intern token', () => {
|
|
const req = { headers: { authorization: 'Bearer wrong-token' } };
|
|
let statusCode = null;
|
|
const res = {
|
|
status: (code) => { statusCode = code; return { json: () => {} }; }
|
|
};
|
|
|
|
auth.authenticate(req, res, () => {});
|
|
|
|
assert.strictEqual(statusCode, 401);
|
|
});
|
|
});
|
|
|
|
describe('RBAC — requireRole', () => {
|
|
it('ska tillåta admin att komma åt admin-resurser', () => {
|
|
const req = { auth: { roles: ['admin'] } };
|
|
let nextCalled = false;
|
|
const res = { status: () => ({ json: () => {} }) };
|
|
|
|
auth.requireRole('admin')(req, res, () => { nextCalled = true; });
|
|
|
|
assert.strictEqual(nextCalled, true);
|
|
});
|
|
|
|
it('ska tillåta accountant att komma åt viewer-resurser', () => {
|
|
const req = { auth: { roles: ['accountant'] } };
|
|
let nextCalled = false;
|
|
const res = { status: () => ({ json: () => {} }) };
|
|
|
|
auth.requireRole('viewer')(req, res, () => { nextCalled = true; });
|
|
|
|
assert.strictEqual(nextCalled, true);
|
|
});
|
|
|
|
it('ska neka viewer att komma åt accountant-resurser', () => {
|
|
const req = { auth: { roles: ['viewer'] } };
|
|
let statusCode = null;
|
|
const res = {
|
|
status: (code) => { statusCode = code; return { json: () => {} }; }
|
|
};
|
|
|
|
auth.requireRole('accountant')(req, res, () => {});
|
|
|
|
assert.strictEqual(statusCode, 403);
|
|
});
|
|
});
|
|
|
|
describe('Tenant-isolering', () => {
|
|
it('ska tillåta användare att komma åt sin egen tenant', () => {
|
|
const req = {
|
|
auth: { type: 'user', tenant_id: 'landvex' },
|
|
headers: { 'x-tenant-id': 'landvex' },
|
|
body: {}
|
|
};
|
|
let nextCalled = false;
|
|
const res = { status: () => ({ json: () => {} }) };
|
|
|
|
auth.requireTenantMatch(req, res, () => { nextCalled = true; });
|
|
|
|
assert.strictEqual(nextCalled, true);
|
|
assert.strictEqual(req.tenant_id, 'landvex');
|
|
});
|
|
|
|
it('ska neka användare att komma åt annan tenant', () => {
|
|
const req = {
|
|
auth: { type: 'user', tenant_id: 'landvex' },
|
|
headers: { 'x-tenant-id': 'annan-tenant' },
|
|
body: {}
|
|
};
|
|
let statusCode = null;
|
|
const res = {
|
|
status: (code) => { statusCode = code; return { json: () => {} }; }
|
|
};
|
|
|
|
auth.requireTenantMatch(req, res, () => {});
|
|
|
|
assert.strictEqual(statusCode, 403);
|
|
});
|
|
|
|
it('ska tillåta service-konto att komma åt alla tenants', () => {
|
|
const req = {
|
|
auth: { type: 'service', tenant_id: 'wavult-group' },
|
|
headers: { 'x-tenant-id': 'annan-tenant' },
|
|
body: {}
|
|
};
|
|
let nextCalled = false;
|
|
const res = { status: () => ({ json: () => {} }) };
|
|
|
|
auth.requireTenantMatch(req, res, () => { nextCalled = true; });
|
|
|
|
assert.strictEqual(nextCalled, true);
|
|
assert.strictEqual(req.tenant_id, 'annan-tenant');
|
|
});
|
|
});
|
|
|
|
console.log('✅ Auth-tester klara');
|