1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
"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<User | null> {
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<User> {
// 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<boolean> {
return (
samlData !== null &&
samlData !== undefined &&
typeof samlData === 'object' &&
'email' in samlData &&
'name' in samlData &&
typeof (samlData as Record<string, unknown>).email === 'string' &&
typeof (samlData as Record<string, unknown>).name === 'string' &&
(samlData as Record<string, unknown>).email.includes('@') &&
(samlData as Record<string, unknown>).name.length > 0
);
}
|