补充 AD HTTPS 表单的浏览器回归验证

This commit is contained in:
2026-09-25 21:08:25 +00:00
parent d14151928d
commit 939870346d
2 changed files with 33 additions and 1 deletions
+2 -1
View File
@@ -96,7 +96,8 @@ LDAP endpoint identification 或用信任所有证书的 socket factory。连接
2026-09-25:JVM 测试共 12 项通过(原有 6 项、新增 AD 6 项),`bootJar` 构建通过。 2026-09-25:JVM 测试共 12 项通过(原有 6 项、新增 AD 6 项),`bootJar` 构建通过。
实际 JVM 使用受信 CA 完成 Samba AD RootDSE 查询,HTTPS 页面返回 200。 实际 JVM 使用受信 CA 完成 Samba AD RootDSE 查询,HTTPS 页面返回 200。
浏览器已检查登录表单渲染、真实 CSRF 原生 POST 和失败后清空密码;只使用在访问 AD 前 浏览器已检查登录表单渲染、真实 CSRF 原生 POST 和失败后清空密码;只使用在访问 AD 前
即拒绝的合成外域用户名,不尝试猜测人类密码。 即拒绝的合成外域用户名,不尝试猜测人类密码。浏览器回归共 1 项通过,包含移动端布局。
复现:`IAM_AD_URL=https://验收域名:端口 npm --prefix frontend run test:browser -- ad-login.spec.ts`。
实际人类密码与组结果仍需维护者 实际人类密码与组结果仍需维护者
在 HTTPS 页面输入凭据验收,不在聊天、命令行或日志中传递人类密码。 在 HTTPS 页面输入凭据验收,不在聊天、命令行或日志中传递人类密码。
新增 AD 路径尚未进行 Native 测试,不能复用旧 UI 原型的 Native 结论。 新增 AD 路径尚未进行 Native 测试,不能复用旧 UI 原型的 Native 结论。
+31
View File
@@ -0,0 +1,31 @@
import { test, expect } from "@playwright/test";
// Explicit opt-in: never submit synthetic credentials to an arbitrary configured directory.
// The external-domain username below must be rejected before any LDAP bind.
test("AD HTTPS page uses native POST and keeps failed credentials out of the response", async ({ page, context }) => {
test.skip(!process.env.IAM_AD_URL, "Set IAM_AD_URL to the HTTPS first-factor PoC");
const url = new URL("/signin", process.env.IAM_AD_URL!);
expect(url.protocol).toBe("https:");
const requests: { method: string; type: string; path: string }[] = [];
page.on("request", request => requests.push({
method: request.method(), type: request.resourceType(), path: new URL(request.url()).pathname,
}));
await page.goto(url.toString());
await expect(page.getByRole("heading", { name: "登录你的账号" })).toBeVisible();
await expect(page.locator("form")).toHaveAttribute("method", "post");
await expect(page.locator("input[name=_csrf]")).toHaveCount(1);
const session = (await context.cookies()).find(cookie => cookie.name === "JSESSIONID");
expect(session).toMatchObject({ secure: true, httpOnly: true, sameSite: "Lax" });
await page.getByLabel("用户名", { exact: true }).fill("[email protected]");
await page.getByLabel("密码", { exact: true }).fill("synthetic-ui-check");
await page.getByRole("button", { name: "继续", exact: true }).click();
await expect(page.getByRole("alert")).toContainText("无法验证账号");
await expect(page.getByLabel("密码", { exact: true })).toHaveValue("");
expect(await page.content()).not.toContain("synthetic-ui-check");
expect(requests.filter(request => request.method === "POST")).toEqual([
{ method: "POST", type: "document", path: "/signin/password" },
]);
expect(requests.filter(request => ["fetch", "xhr"].includes(request.type))).toHaveLength(0);
await page.setViewportSize({ width: 390, height: 844 });
expect(await page.evaluate(() => document.documentElement.scrollWidth > innerWidth)).toBe(false);
});