feat(ssf): 托管机器凭据并支持动态恢复
Gateway 连接表单接收认证中心一次性交付的 machine Client 凭据,后端立即写入 SecretStore,数据库和公开响应只保留引用及公开 Client ID。SSF 管理 Token、Verification 和 RFC 7662 内省统一从动态凭据读取,支持现有连接无重启修复及进程重启恢复,环境变量仅保留为旧部署回退。\n\n验证:go test ./apps/api/...;pnpm nx test web;真实重启、OIDC 登录与 session-revoked 1.29 秒失效验收。
This commit is contained in:
@@ -40,7 +40,7 @@ describe('security event connection transport', () => {
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
it('sends only the public transmitter issuer and concurrency headers', async () => {
|
||||
it('sends the one-time machine credential only in the connection request', async () => {
|
||||
const fetchMock = vi.fn().mockResolvedValue(new Response(JSON.stringify({ connected: true }), {
|
||||
status: 202,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
@@ -48,12 +48,15 @@ describe('security event connection transport', () => {
|
||||
vi.stubGlobal('fetch', fetchMock);
|
||||
vi.stubGlobal('crypto', { randomUUID: () => '00000000-0000-4000-8000-000000000000' });
|
||||
|
||||
await connectSecurityEventTransmitter('manager-token', 'https://auth.example/ssf');
|
||||
await connectSecurityEventTransmitter('manager-token', 'https://auth.example/ssf', 'gateway-machine', 'one-time-machine-secret');
|
||||
|
||||
const [, init] = fetchMock.mock.calls[0] as [string, RequestInit];
|
||||
expect(init.method).toBe('PUT');
|
||||
expect(JSON.parse(String(init.body))).toEqual({ transmitter_issuer: 'https://auth.example/ssf' });
|
||||
expect(String(init.body)).not.toMatch(/secret|bearer|scope|credential/i);
|
||||
expect(JSON.parse(String(init.body))).toEqual({
|
||||
transmitter_issuer: 'https://auth.example/ssf',
|
||||
management_client_id: 'gateway-machine',
|
||||
management_client_secret: 'one-time-machine-secret',
|
||||
});
|
||||
expect(new Headers(init.headers).get('Idempotency-Key')).toContain('ssf-connect-');
|
||||
expect(new Headers(init.headers).has('If-Match')).toBe(false);
|
||||
});
|
||||
@@ -66,7 +69,7 @@ describe('security event connection transport', () => {
|
||||
vi.stubGlobal('fetch', fetchMock);
|
||||
vi.stubGlobal('crypto', { randomUUID: () => '00000000-0000-4000-8000-000000000000' });
|
||||
|
||||
await connectSecurityEventTransmitter('manager-token', 'https://auth.example/ssf', 7);
|
||||
await connectSecurityEventTransmitter('manager-token', 'https://auth.example/ssf', 'gateway-machine', 'one-time-machine-secret', 7);
|
||||
|
||||
const [, init] = fetchMock.mock.calls[0] as [string, RequestInit];
|
||||
expect(new Headers(init.headers).get('If-Match')).toBe('W/"7"');
|
||||
|
||||
Reference in New Issue
Block a user