82 lines
2.3 KiB
JavaScript
82 lines
2.3 KiB
JavaScript
// smoke: POST /api/v1/auth/login/mfa
|
||
//
|
||
// Covers:
|
||
// login → mfa_required(已啟用 TOTP 時不回 token)
|
||
// 403 — TOTP 錯誤(29505000)
|
||
// 404 — challenge 不存在(28301000)
|
||
// 403 — tenant slug 不符(28505000)
|
||
// 400 — 缺少 code / challenge_id
|
||
//
|
||
// Happy path(login → login/mfa → JWT)見 journeys/login_mfa_full.js
|
||
import { post, checkError } from '../lib/http.js';
|
||
import { cfg } from '../lib/config.js';
|
||
import { registerAndConfirm, loginExpectMFA } from '../lib/auth.js';
|
||
import { enrollTOTP } from '../lib/member.js';
|
||
|
||
export const options = {
|
||
vus: 1,
|
||
iterations: 1,
|
||
thresholds: { checks: ['rate==1.0'] },
|
||
};
|
||
|
||
export default function () {
|
||
const { identity, tokens } = registerAndConfirm();
|
||
const bearer = { Authorization: `Bearer ${tokens.access_token}` };
|
||
const { otpauthUrl } = enrollTOTP(bearer);
|
||
|
||
const mfa = loginExpectMFA({
|
||
email: identity.email,
|
||
password: identity.password,
|
||
});
|
||
if (mfa.access_token) {
|
||
throw new Error('login with TOTP enrolled should not return access_token');
|
||
}
|
||
|
||
// bad TOTP
|
||
checkError(
|
||
post('/api/v1/auth/login/mfa', {
|
||
tenant_slug: cfg.tenantSlug,
|
||
challenge_id: mfa.mfa_challenge_id,
|
||
code: '000000',
|
||
}),
|
||
'POST /auth/login/mfa (bad totp)',
|
||
403,
|
||
29505000,
|
||
);
|
||
|
||
// unknown challenge — Redis miss 目前回 500(28201000)
|
||
checkError(
|
||
post('/api/v1/auth/login/mfa', {
|
||
tenant_slug: cfg.tenantSlug,
|
||
challenge_id: '00000000-0000-0000-0000-000000000000',
|
||
code: '123456',
|
||
}),
|
||
'POST /auth/login/mfa (unknown challenge)',
|
||
500,
|
||
28201000,
|
||
);
|
||
|
||
// unknown tenant slug(resolveTenant 失敗)
|
||
checkError(
|
||
post('/api/v1/auth/login/mfa', {
|
||
tenant_slug: 'wrong-tenant-slug',
|
||
challenge_id: mfa.mfa_challenge_id,
|
||
code: '123456',
|
||
}),
|
||
'POST /auth/login/mfa (unknown tenant)',
|
||
404,
|
||
29301000,
|
||
);
|
||
|
||
// missing fields
|
||
const missing = post('/api/v1/auth/login/mfa', { tenant_slug: cfg.tenantSlug });
|
||
if (missing.status !== 400) {
|
||
throw new Error(`login/mfa missing fields: expected 400 got ${missing.status}`);
|
||
}
|
||
|
||
// otpauthUrl kept for journey reuse sanity (not used further in smoke)
|
||
if (!otpauthUrl) {
|
||
throw new Error('enrollTOTP did not return otpauthUrl');
|
||
}
|
||
}
|