fix: use supported redirect mode for Workers organization requests
Deploy EG-BIM QA Gateway / deploy (push) Successful in 1m24s

This commit is contained in:
root committed 2026-10-30 12:49:15 +09:00
1 parent c87e0aa0c1
commit ccf48c8224
8 files changed
+126 -4

No files matched your search

+1 -1
View File
@@ -132,7 +132,7 @@ test('fetches each root with identifiers and caches only complete responses', as
assert.equal(parsed.searchParams.get('exposure'), 'identifiers');
assert.equal(init.headers['X-Baron-Key-ID'], config.ORG_CONTEXT_KEY_ID);
assert.equal(init.headers['X-Baron-Key-Secret'], config.ORG_CONTEXT_KEY_SECRET);
assert.equal(init.redirect, 'error');
assert.equal(init.redirect, 'manual');
return response(payload(parsed.searchParams.get('tenantId')));
};
// Use disjoint roots with no repeated tenant parent to emulate two independent subtrees.
+50
View File
@@ -0,0 +1,50 @@
import worker from './index.js';
const ROOT = '038326b6-954a-48a7-a85f-efd83f62b82a';
const USER = '01900000-0000-7000-8000-000000000001';
const DEPT = 'ee2f39ac-fe52-4cfb-b4e3-4ae1d114c916';
const encoder = new TextEncoder();
const encode = (bytes) => btoa(String.fromCharCode(...bytes)).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
function equal(actual, expected, field) {
if (actual !== expected) throw new Error(`${field}: expected ${expected}, received ${actual}`);
}
export default {
async test() {
const user = {
userUuid: USER, ssoSubject: USER, requesterId: USER,
tenantId: DEPT, requesterTenantId: DEPT,
company: 'IS3', companySource: 'sso', department: ''
};
const env = {
SESSION_COOKIE_NAME: 'fixture_session', SESSION_SECRET: 'fixture-session-secret',
ORG_CONTEXT_ENABLED: 'true', ORG_CONTEXT_API_URL: 'https://organization.example.test/org-context',
ORG_CONTEXT_KEY_ID: 'fixture-key-id', ORG_CONTEXT_KEY_SECRET: 'fixture-key-secret',
ORG_CONTEXT_TENANT_IDS: JSON.stringify([ROOT])
};
const payload = encode(encoder.encode(JSON.stringify({ user, expiresAt: Date.now() + 60000 })));
const key = await crypto.subtle.importKey('raw', encoder.encode(env.SESSION_SECRET), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
const signature = encode(new Uint8Array(await crypto.subtle.sign('HMAC', key, encoder.encode(payload))));
const request = () => new Request('https://qa.example.test/auth/session', {
headers: { cookie: `${env.SESSION_COOKIE_NAME}=${payload}.${signature}` }
});
const response = await worker.fetch(request(), env);
const session = await response.json();
equal(response.status, 200, 'session HTTP status');
equal(session.authenticated, true, 'authenticated');
equal(session.user.orgContextStatus, 'resolved', 'organization lookup');
equal(session.user.company, '총괄기획실&기술개발센터', 'company');
equal(session.user.department, 'IS3', 'department');
equal(session.user.requesterId, USER, 'canonical identity');
equal(session.user.orgContextError, undefined, 'error after success');
const rejected = await worker.fetch(request(), {
...env, ORG_CONTEXT_API_URL: 'https://organization.example.test/redirect'
});
const rejectedSession = await rejected.json();
equal(rejectedSession.authenticated, true, 'session after upstream redirect');
equal(rejectedSession.user.orgContextError, 'org_context_http_302', 'redirect rejection');
}
};
+26
View File
@@ -0,0 +1,26 @@
const ROOT = '038326b6-954a-48a7-a85f-efd83f62b82a';
const COMPANY = '9951229e-eea5-4376-96f4-78989bc3a506';
const DEPT = 'ee2f39ac-fe52-4cfb-b4e3-4ae1d114c916';
const USER = '01900000-0000-7000-8000-000000000001';
export default {
fetch(request) {
const url = new URL(request.url);
if (url.origin !== 'https://organization.example.test') throw new Error('Redirect must never be followed');
if (request.headers.get('X-Baron-Key-ID') !== 'fixture-key-id' || request.headers.get('X-Baron-Key-Secret') !== 'fixture-key-secret') {
throw new Error('Expected organization integration credentials');
}
if (url.pathname === '/redirect') return Response.redirect('https://must-not-follow.example.test/', 302);
if (url.searchParams.get('tenantId') !== ROOT || url.searchParams.get('exposure') !== 'identifiers') {
throw new Error('Unexpected organization query');
}
return Response.json({
schemaVersion: 'baron.org-context.v2', scope: { tenantId: ROOT },
tree: { id: ROOT, name: '한맥가족', type: 'COMPANY_GROUP', children: [
{ id: COMPANY, name: '총괄기획실&기술개발센터', type: 'COMPANY', children: [
{ id: DEPT, name: 'IS3', type: 'COMPANY', members: [{ id: USER, isPrimary: true }] }
] }
] }
});
}
};
+19
View File
@@ -0,0 +1,19 @@
using Workerd = import "/workerd/workerd.capnp";
const config :Workerd.Config = (
services = [
(name = "organization", worker = (
compatibilityDate = "2026-09-18",
globalOutbound = "organization-upstream",
modules = [
(name = "test.mjs", esModule = embed "organization-test.mjs"),
(name = "index.js", esModule = embed "../../src/index.js"),
(name = "org-context.js", esModule = embed "../../src/org-context.js")
]
)),
(name = "organization-upstream", worker = (
compatibilityDate = "2026-09-18",
modules = [(name = "upstream.mjs", esModule = embed "organization-upstream.mjs")]
))
]
);
+16
View File
@@ -0,0 +1,16 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import { createRequire } from 'node:module';
import { fileURLToPath } from 'node:url';
import { spawnSync } from 'node:child_process';
const require = createRequire(import.meta.url);
const workerd = require('workerd').default;
test('native Workers runtime resolves session organization and rejects upstream redirects', () => {
const result = spawnSync(workerd, ['test', fileURLToPath(new URL('./runtime/organization.capnp', import.meta.url)), 'organization'], {
encoding: 'utf8', timeout: 20000
});
assert.equal(result.error, undefined, result.error?.message);
assert.equal(result.status, 0, result.stdout + result.stderr);
});