"use server"; import { getUserByEmail, createSAMLUser } from './repository'; import { User } from '@/db/schema/users'; import logger from '@/lib/logger'; export interface SAMLUserData { email: string; name: string; companyId?: number; techCompanyId?: number; domain?: string; } /** * SAML JIT (Just-In-Time) 사용자 생성 또는 조회 * * @param samlData SAML에서 받은 사용자 데이터 * @returns DB에 저장된 사용자 정보 */ export async function getOrCreateSAMLUser(samlData: SAMLUserData): Promise { try { logger.info({ email: samlData.email }, 'SAML JIT: Processing user'); // 1. 기존 사용자 조회 const existingUser = await getUserByEmail(samlData.email); if (existingUser) { logger.info({ userId: existingUser.id, email: existingUser.email }, 'SAML JIT: Existing user found'); // 기존 사용자가 있으면 그대로 반환 return existingUser; } // 2. 새 사용자 생성 (JIT) logger.info({ email: samlData.email, name: samlData.name }, 'SAML JIT: Creating new user'); const newUser = await createSAMLUserFromData(samlData); logger.info({ userId: newUser.id, email: newUser.email }, 'SAML JIT: New user created successfully'); return newUser; } catch (error) { logger.error({ error, email: samlData.email }, 'SAML JIT: Failed to get or create user'); return null; } } /** * SAML 데이터로 새 사용자 생성 * * @param samlData SAML 사용자 데이터 * @returns 생성된 사용자 */ async function createSAMLUserFromData(samlData: SAMLUserData): Promise { // 1. UTF-8 name 처리 let userName = samlData.name || samlData.email.split('@')[0]; // 길이 제한 확인 (DB varchar(255) 제한) if (userName.length > 255) { userName = userName.substring(0, 252) + '...'; } // 빈 문자열 방지 if (!userName.trim()) { userName = samlData.email.split('@')[0] || 'SAML User'; } // 2. domain을 evcp로 고정 const domain = 'evcp'; // 3. SAML 사용자 생성 (Repository 함수 재사용하고 싶었으나 domain 정보 입력 불가로 새로운 함수 정의함) const newUser = await createSAMLUser( userName, samlData.email, domain, ); // 4. 생성된 사용자 검증 if (newUser.domain !== 'evcp') { logger.error({ userId: newUser.id, expectedDomain: 'evcp', actualDomain: newUser.domain }, 'SAML JIT: Domain mismatch in created user'); throw new Error('Failed to create SAML user with correct domain'); } logger.info({ userId: newUser.id, email: newUser.email, name: newUser.name, nameLength: newUser.name.length, domain: newUser.domain, companyId: newUser.companyId, techCompanyId: newUser.techCompanyId }, 'SAML JIT: New user created with UTF-8 name and evcp domain'); return newUser; } /** * SAML 사용자 데이터 검증 * * @param samlData 검증할 SAML 데이터 * @returns 유효성 여부 */ export async function validateSAMLUserData(samlData: unknown): Promise { return ( samlData !== null && samlData !== undefined && typeof samlData === 'object' && 'email' in samlData && 'name' in samlData && typeof (samlData as Record).email === 'string' && typeof (samlData as Record).name === 'string' && (samlData as Record).email.includes('@') && (samlData as Record).name.length > 0 ); }