This commit is contained in:
1 parent
172c3a5a0e
commit
922d24cac7
5 files changed
+157
-19
No files matched your search
@@ -24,7 +24,7 @@ function sessionCookie(env) {
|
||||
function organization() {
|
||||
return { scope: { tenantId: ROOT }, tree: { id: ROOT, name: '분류', type: 'ROOT', children: [
|
||||
{ id: COMPANY, name: '정확한 회사', type: 'COMPANY', children: [
|
||||
{ id: DEPT, name: '정확한 부서', type: 'DEPARTMENT', members: [{ id: USER, isPrimary: true }] }
|
||||
{ id: DEPT, name: '정확한 부서', type: 'COMPANY', members: [{ id: USER, isPrimary: true, grade: '확인된 직급', position: '확인된 직책' }] }
|
||||
] }
|
||||
] } };
|
||||
}
|
||||
@@ -50,7 +50,7 @@ for (const multipart of [false, true]) {
|
||||
saved = init;
|
||||
return json({ id: FEEDBACK });
|
||||
}, async () => {
|
||||
const input = { title: 'fixture', contents: 'body', Category: 'GENERAL_QNA', requester_affiliation: 'forged company', requester_id: 'forged owner' };
|
||||
const input = { title: 'fixture', contents: 'body', Category: 'GENERAL_QNA', requester_affiliation: 'forged company', requester_position: 'forged position', requester_grade: 'forged grade', requester_id: 'forged owner' };
|
||||
let body, headers = { cookie: sessionCookie(env) };
|
||||
if (multipart) {
|
||||
body = new FormData();
|
||||
@@ -62,6 +62,8 @@ for (const multipart of [false, true]) {
|
||||
const payload = multipart ? Object.fromEntries(saved.body.entries()) : JSON.parse(saved.body);
|
||||
assert.equal(payload.requester_affiliation, '정확한 회사');
|
||||
assert.equal(payload.requester_department, '정확한 부서');
|
||||
assert.equal(payload.requester_position, '확인된 직책');
|
||||
assert.equal(payload.requester_grade, '확인된 직급');
|
||||
assert.equal(payload.requester_id, USER);
|
||||
assert.equal(payload.requester_tenant_id, ROOT);
|
||||
assert.equal(saved.headers['x-api-key'], 'project-key');
|
||||
@@ -126,7 +128,9 @@ test('disabled deployment works without organization credentials and enabled dep
|
||||
assert.ok(result.secrets.ORG_CONTEXT_KEY_SECRET);
|
||||
});
|
||||
|
||||
test('OAuth login still completes and uses explicit SSO company instead of email inference', async () => {
|
||||
for (const variant of ['explicit SSO company', 'generic tenant hierarchy', 'platform requester fields']) {
|
||||
const genericHierarchy = variant === 'generic tenant hierarchy';
|
||||
test(`OAuth login resolves company with ${variant}`, async () => {
|
||||
const env = configuration({ ORG_CONTEXT_ENABLED: 'false', OAUTH_COOKIE_NAME: 'fixture_oauth', AUTH_CLIENT_ID: 'fixture-client',
|
||||
AUTH_AUTHORIZE_URL: 'https://identity.example.test/authorize', AUTH_TOKEN_URL: 'https://identity.example.test/token',
|
||||
AUTH_USERINFO_URL: 'https://identity.example.test/userinfo', AUTH_REDIRECT_URI: 'https://qa.example.test/auth/callback' });
|
||||
@@ -134,7 +138,18 @@ test('OAuth login still completes and uses explicit SSO company instead of email
|
||||
assert.equal(start.status, 302);
|
||||
const authorize = new URL(start.headers.get('location'));
|
||||
const stateCookie = start.headers.getSetCookie()[0].split(';')[0];
|
||||
const claims = { sub: USER, nonce: authorize.searchParams.get('nonce'), tenant_id: ROOT, email: 'fixture@brsw.kr', name: '테스트 사용자', company: 'SSO 회사', tenants: [{ id: ROOT, name: 'SSO 부서', ancestors: [{ id: COMPANY, type: 'COMPANY', name: 'SSO 회사' }] }] };
|
||||
const tenantId = DEPT;
|
||||
const ancestors = [
|
||||
...(genericHierarchy ? [{ id: ROOT, type: 'COMPANY_GROUP', name: '분류 그룹' }] : []),
|
||||
{ id: COMPANY, type: 'COMPANY', name: 'SSO 회사' },
|
||||
...(genericHierarchy ? [{ id: 'fixture-division', type: 'COMPANY', name: 'SSO 본부' }] : [])
|
||||
];
|
||||
const claims = { sub: USER, nonce: authorize.searchParams.get('nonce'), tenant_id: tenantId, email: 'fixture@brsw.kr', name: '테스트 사용자', company: genericHierarchy ? '잘못된 부서' : 'SSO 회사', tenants: [{ id: tenantId, ...(genericHierarchy ? { type: 'COMPANY' } : {}), name: 'SSO 부서', ancestors }] };
|
||||
if (variant === 'platform requester fields') {
|
||||
delete claims.company;
|
||||
delete claims.tenants;
|
||||
Object.assign(claims, { requester_affiliation: 'SSO 회사', requester_department: 'SSO 부서', requester_grade: 'SSO 직급', requester_position: 'SSO 직책' });
|
||||
}
|
||||
const token = Buffer.from('{}').toString('base64url') + '.' + Buffer.from(JSON.stringify(claims)).toString('base64url') + '.fixture';
|
||||
await mockedFetch(async (url) => String(url).endsWith('/token') ? json({ id_token: token, access_token: 'fixture-token' }) : json(claims), async () => {
|
||||
const callback = new URL(env.AUTH_REDIRECT_URI);
|
||||
@@ -147,11 +162,16 @@ test('OAuth login still completes and uses explicit SSO company instead of email
|
||||
const session = await worker.fetch(new Request('https://qa.example.test/auth/session', { headers: { cookie } }), env);
|
||||
const { user } = await session.json();
|
||||
assert.equal(user.requesterId, USER);
|
||||
assert.equal(user.requesterTenantId, ROOT);
|
||||
assert.equal(user.requesterTenantId, tenantId);
|
||||
assert.equal(user.company, 'SSO 회사');
|
||||
assert.equal(user.department, 'SSO 부서');
|
||||
if (variant === 'platform requester fields') {
|
||||
assert.equal(user.grade, 'SSO 직급');
|
||||
assert.equal(user.position, 'SSO 직책');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
test('feedback update keeps verified owner headers and cannot overwrite organization or ownership from browser input', async () => {
|
||||
const env = configuration();
|
||||
@@ -172,3 +192,25 @@ test('feedback update keeps verified owner headers and cannot overwrite organiza
|
||||
assert.equal(response.status, 200);
|
||||
});
|
||||
});
|
||||
|
||||
for (const method of ['GET', 'PATCH', 'DELETE']) {
|
||||
test(`${method} preserves the API refusal for another author's or private feedback`, async () => {
|
||||
const env = configuration();
|
||||
await mockedFetch(async (url, init) => {
|
||||
assert.ok(!String(url).includes('org-context'));
|
||||
assert.equal(init.headers['x-requester-id'], USER);
|
||||
assert.equal(init.headers['x-requester-tenant-id'], ROOT);
|
||||
assert.equal(init.method, method);
|
||||
return json({ message: 'Forbidden resource' }, 403);
|
||||
}, async () => {
|
||||
const request = { method, headers: { cookie: sessionCookie(env) } };
|
||||
if (method === 'PATCH') {
|
||||
request.headers['content-type'] = 'application/json';
|
||||
request.body = JSON.stringify({ title: '수정 시도' });
|
||||
}
|
||||
const result = await worker.fetch(new Request('https://qa.example.test/api/feedbacks/' + FEEDBACK, request), env);
|
||||
assert.equal(result.status, 403);
|
||||
assert.equal((await result.json()).message, 'Forbidden resource');
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user