This commit is contained in:
@@ -67,6 +67,30 @@ const getSsoRequesterFields = (claims: Record<string, unknown>) => {
|
||||
(ancestor) => getStringValue(ancestor.type) === 'COMPANY',
|
||||
);
|
||||
|
||||
const tenantIds = new Set<string>();
|
||||
const addTenantId = (value: unknown) => {
|
||||
if (typeof value === 'string' && value.trim()) tenantIds.add(value.trim());
|
||||
};
|
||||
for (const source of tokenSources) {
|
||||
const directTenantIds = source.tenant_ids ?? source.tenantIds;
|
||||
if (Array.isArray(directTenantIds)) {
|
||||
directTenantIds.forEach(addTenantId);
|
||||
}
|
||||
addTenantId(source.tenant_id);
|
||||
addTenantId(source.tenantId);
|
||||
addTenantId(asRecord(source.tenant)?.id);
|
||||
if (Array.isArray(source.joinedTenants)) {
|
||||
source.joinedTenants.forEach((tenant) => addTenantId(asRecord(tenant)?.id));
|
||||
}
|
||||
if (Array.isArray(source.tenants)) {
|
||||
source.tenants.forEach((tenant) => addTenantId(asRecord(tenant)?.id));
|
||||
} else if (source.tenants && typeof source.tenants === 'object') {
|
||||
Object.values(source.tenants as Record<string, unknown>).forEach((tenant) =>
|
||||
addTenantId(asRecord(tenant)?.id),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
requester_id: readClaim('sub', 'user_id', 'id'),
|
||||
requester_uuid: readClaim('sub', 'user_id', 'id'),
|
||||
@@ -89,6 +113,7 @@ const getSsoRequesterFields = (claims: Record<string, unknown>) => {
|
||||
'employee_number',
|
||||
'employeeNumber',
|
||||
),
|
||||
requester_tenant_ids: JSON.stringify([...tenantIds]),
|
||||
};
|
||||
};
|
||||
const MAX_ATTACHMENT_COUNT = 10;
|
||||
|
||||
@@ -46,6 +46,7 @@ interface SsoOrgMember {
|
||||
grade?: unknown;
|
||||
position?: unknown;
|
||||
jobTitle?: unknown;
|
||||
tenant_ids?: string[];
|
||||
}
|
||||
|
||||
type SsoValueShape =
|
||||
@@ -220,14 +221,25 @@ const getSsoOrgMember = async (
|
||||
tree?: { members?: unknown };
|
||||
tenants?: unknown;
|
||||
};
|
||||
const tenantIds = new Set<string>();
|
||||
const rawTenants = Array.isArray(data.tenants) ?
|
||||
data.tenants
|
||||
: data.tenants && typeof data.tenants === 'object' ?
|
||||
Object.values(data.tenants as Record<string, unknown>)
|
||||
: [];
|
||||
const tenantRecords = rawTenants
|
||||
.map((tenant) => asRecord(tenant))
|
||||
.filter((tenant): tenant is Record<string, unknown> => tenant !== null);
|
||||
for (const tenant of tenantRecords) {
|
||||
const id = asString(tenant.id) ?? asString(tenant.tenant_id);
|
||||
if (id) tenantIds.add(id);
|
||||
}
|
||||
if (tenantId) tenantIds.add(tenantId);
|
||||
const members: Record<string, unknown>[] = [];
|
||||
const treeMembers = Array.isArray(data.tree?.members) ? data.tree.members : [];
|
||||
const tenantMembers = Array.isArray(data.tenants) ?
|
||||
data.tenants.flatMap((tenant) => {
|
||||
const record = asRecord(tenant);
|
||||
return Array.isArray(record?.members) ? record.members : [];
|
||||
})
|
||||
: [];
|
||||
const tenantMembers = tenantRecords.flatMap((tenant) =>
|
||||
Array.isArray(tenant.members) ? tenant.members : [],
|
||||
);
|
||||
|
||||
for (const candidate of [...treeMembers, ...tenantMembers]) {
|
||||
const member = asRecord(candidate);
|
||||
@@ -236,13 +248,14 @@ const getSsoOrgMember = async (
|
||||
|
||||
const subject = asString(info.id) ?? asString(info.sub) ?? asString(info.user_id);
|
||||
const email = asString(info.email);
|
||||
return (
|
||||
members.find((member) => {
|
||||
const matchedMember = members.find((member) => {
|
||||
const memberId = asString(member.id);
|
||||
const memberEmail = asString(member.email);
|
||||
return (subject && memberId === subject) || (email && memberEmail === email);
|
||||
}) ?? null
|
||||
);
|
||||
});
|
||||
return matchedMember || tenantIds.size > 0 ?
|
||||
{ ...(matchedMember ?? {}), tenant_ids: [...tenantIds] }
|
||||
: null;
|
||||
};
|
||||
|
||||
const enrichSsoUserInfo = async (accessToken: string, info: OidcUserInfo) => {
|
||||
@@ -258,6 +271,12 @@ const enrichSsoUserInfo = async (accessToken: string, info: OidcUserInfo) => {
|
||||
grade: asString(info.grade) ?? asString(member.grade),
|
||||
position: asString(info.position) ?? asString(member.position),
|
||||
jobTitle: asString(info.jobTitle) ?? asString(member.jobTitle),
|
||||
tenant_ids: [
|
||||
...new Set([
|
||||
...asStringArray(info.tenant_ids ?? info.tenantIds),
|
||||
...(member.tenant_ids ?? []),
|
||||
]),
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
@@ -539,15 +558,33 @@ const createSupportSession = (info: OidcUserInfo) => {
|
||||
'SSO 사용자 정보에 sub 또는 tenant_id가 없습니다. SUPPORT_TENANT_ID를 확인하세요.',
|
||||
);
|
||||
}
|
||||
const tenantIds = asStringArray(info.tenant_ids ?? info.tenantIds);
|
||||
if (!tenantIds.includes(tenantId)) tenantIds.unshift(tenantId);
|
||||
const tenantIds = new Set(asStringArray(info.tenant_ids ?? info.tenantIds));
|
||||
const addTenantId = (value: unknown) => {
|
||||
const id = asString(value);
|
||||
if (id) tenantIds.add(id);
|
||||
};
|
||||
|
||||
addTenantId(info.tenant_id);
|
||||
addTenantId(info.tenantId);
|
||||
addTenantId(asRecord(info.tenant)?.id);
|
||||
for (const tenant of Array.isArray(info.joinedTenants) ? info.joinedTenants : []) {
|
||||
addTenantId(asRecord(tenant)?.id);
|
||||
}
|
||||
if (Array.isArray(info.tenants)) {
|
||||
for (const tenant of info.tenants) addTenantId(asRecord(tenant)?.id);
|
||||
} else if (info.tenants && typeof info.tenants === 'object') {
|
||||
for (const tenant of Object.values(info.tenants as Record<string, unknown>)) {
|
||||
addTenantId(asRecord(tenant)?.id);
|
||||
}
|
||||
}
|
||||
tenantIds.add(tenantId);
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
return signHs256(
|
||||
{
|
||||
sub: subject,
|
||||
sso_sub: subject,
|
||||
tenant_id: tenantId,
|
||||
tenant_ids: tenantIds,
|
||||
tenant_ids: [...tenantIds],
|
||||
email: asString(info.email),
|
||||
name: asString(info.name),
|
||||
department: asString(info.department),
|
||||
|
||||
@@ -24,6 +24,7 @@ const SSO_TOKEN_CLAIMS_COOKIE_COUNT = `${SSO_TOKEN_CLAIMS_COOKIE}_count`;
|
||||
export interface SupportPrincipal {
|
||||
user_id: string;
|
||||
tenant_id: string;
|
||||
tenant_ids?: string[];
|
||||
email?: string | null;
|
||||
name?: string | null;
|
||||
department?: string | null;
|
||||
|
||||
@@ -87,6 +87,7 @@ export interface SupportTicketRecord extends SupportFeedbackAutomationMetadata {
|
||||
description: string;
|
||||
requester_id: string;
|
||||
requester_tenant_id: string;
|
||||
requester_tenant_ids?: string[];
|
||||
requester_contact: string;
|
||||
requester_email?: string | null;
|
||||
requester_name?: string | null;
|
||||
|
||||
Reference in New Issue
Block a user