$expires, 'path' => '/', 'samesite' => 'Lax', ]; } function auth_json_cookie_encode($value): string { return base64_encode(json_encode($value, JSON_UNESCAPED_UNICODE)); } function auth_json_cookie_decode(string $value, $default) { if ($value === '') { return $default; } $decoded = base64_decode($value, true); if ($decoded === false) { return $default; } $json = json_decode($decoded, true); return $json === null ? $default : $json; } function auth_current_host(): string { return $_SERVER['HTTP_HOST'] ?? 'eg-bim.com'; } function auth_current_scheme(): string { $https = $_SERVER['HTTPS'] ?? ''; $forwardedProto = $_SERVER['HTTP_X_FORWARDED_PROTO'] ?? ''; if ($https === 'on' || $https === '1' || strtolower((string) $forwardedProto) === 'https') { return 'https'; } return 'http'; } function auth_absolute_url(string $path): string { return auth_current_scheme() . '://' . auth_current_host() . $path; } function auth_site_base_url(string $site): string { return $site === 'eng' ? '/eng' : '/egbim'; } function auth_site_qna_url(string $site): string { return auth_site_base_url($site) . '/bbs/descope_qa_list.php'; } function auth_baron_config(): array { $scopes = trim((string) (getenv('BARON_SSO_SCOPE') ?: 'openid profile email')); return [ 'client_id' => trim((string) getenv('BARON_SSO_CLIENT_ID')), 'client_secret' => trim((string) getenv('BARON_SSO_CLIENT_SECRET')), 'authorize_endpoint' => trim((string) getenv('BARON_SSO_AUTHORIZE_ENDPOINT')), 'token_endpoint' => trim((string) getenv('BARON_SSO_TOKEN_ENDPOINT')), 'userinfo_endpoint' => trim((string) getenv('BARON_SSO_USERINFO_ENDPOINT')), 'issuer' => trim((string) getenv('BARON_SSO_ISSUER')), 'redirect_uri' => trim((string) getenv('BARON_SSO_REDIRECT_URI')), 'scope' => $scopes, 'client_auth_method' => trim((string) (getenv('BARON_SSO_CLIENT_AUTH_METHOD') ?: 'basic')), ]; } function auth_baron_redirect_uri(): string { $config = auth_baron_config(); if ($config['redirect_uri'] !== '') { return $config['redirect_uri']; } return auth_absolute_url('/auth/callback'); } function auth_baron_is_configured(): bool { $config = auth_baron_config(); return $config['client_id'] !== '' && $config['client_secret'] !== '' && $config['authorize_endpoint'] !== '' && $config['token_endpoint'] !== ''; } function auth_normalize_user(array $user): array { $loginIds = $user['loginIds'] ?? []; if (!is_array($loginIds)) { $loginIds = []; } $loginId = trim((string) ($loginIds[0] ?? $user['loginId'] ?? $user['email'] ?? '')); if ($loginId !== '' && empty($loginIds)) { $loginIds = [$loginId]; } $customAttributes = $user['customAttributes'] ?? []; $roleNames = $user['roleNames'] ?? []; return [ 'userId' => trim((string) ($user['userId'] ?? $loginId)), 'loginIds' => $loginIds, 'name' => trim((string) ($user['name'] ?? '')), 'email' => trim((string) ($user['email'] ?? $loginId)), 'phone' => trim((string) ($user['phone'] ?? '')), 'customAttributes' => is_array($customAttributes) ? $customAttributes : [], 'roleNames' => is_array($roleNames) ? $roleNames : [], ]; } function auth_descope_user_from_cookies(): ?array { $loginId = trim((string) ($_COOKIE['descope_login_id'] ?? '')); if ($loginId === '') { return null; } return auth_normalize_user([ 'userId' => trim((string) ($_COOKIE['descope_user_id'] ?? $loginId)), 'loginIds' => [$loginId], 'name' => trim((string) ($_COOKIE['descope_user_name'] ?? '')), 'email' => trim((string) ($_COOKIE['descope_user_email'] ?? $loginId)), 'phone' => trim((string) ($_COOKIE['descope_user_phone'] ?? '')), 'customAttributes' => auth_json_cookie_decode((string) ($_COOKIE['descope_custom_attributes'] ?? ''), []), 'roleNames' => auth_json_cookie_decode((string) ($_COOKIE['descope_role_names'] ?? ''), []), ]); } function auth_baron_user_from_cookies(): ?array { $encodedUser = (string) ($_COOKIE['baron_user'] ?? ''); if ($encodedUser === '') { return null; } $user = auth_json_cookie_decode($encodedUser, []); if (!is_array($user) || empty($user)) { return null; } return auth_normalize_user($user); } function auth_restore_user_session(): void { auth_session_start_if_needed(); if (!empty($_SESSION['user']['userId'])) { $_SESSION['user'] = auth_normalize_user($_SESSION['user']); return; } $user = auth_baron_user_from_cookies(); if ($user === null) { $user = auth_descope_user_from_cookies(); } if ($user !== null) { $_SESSION['user'] = $user; } } function auth_apply_user_session(array $user, string $provider, array $tokens = []): array { auth_session_start_if_needed(); session_regenerate_id(true); $normalizedUser = auth_normalize_user($user); $_SESSION['user'] = $normalizedUser; $_SESSION['auth_provider'] = $provider; foreach ($tokens as $key => $value) { $_SESSION[$key] = $value; } return $normalizedUser; } function auth_set_descope_session_cookies(array $user): void { $normalizedUser = auth_normalize_user($user); $expire = time() + 86400; $cookieOptions = auth_cookie_options($expire); setcookie('descope_login_id', (string) ($normalizedUser['loginIds'][0] ?? ''), $cookieOptions); setcookie('descope_user_id', (string) $normalizedUser['userId'], $cookieOptions); setcookie('descope_user_name', (string) $normalizedUser['name'], $cookieOptions); setcookie('descope_user_email', (string) $normalizedUser['email'], $cookieOptions); setcookie('descope_user_phone', (string) $normalizedUser['phone'], $cookieOptions); setcookie('descope_custom_attributes', auth_json_cookie_encode($normalizedUser['customAttributes']), $cookieOptions); setcookie('descope_role_names', auth_json_cookie_encode($normalizedUser['roleNames']), $cookieOptions); } function auth_set_baron_session_cookies(array $user, array $claims = []): void { $normalizedUser = auth_normalize_user($user); $expire = time() + 86400; $cookieOptions = auth_cookie_options($expire); setcookie('baron_user', auth_json_cookie_encode($normalizedUser), $cookieOptions); setcookie('baron_claims', auth_json_cookie_encode($claims), $cookieOptions); setcookie('baron_provider', 'baron', $cookieOptions); } function auth_clear_all_cookies(): void { $expired = auth_cookie_options(time() - 42000); foreach ([ 'PHPSESSID', 'G5sessphp', 'descope_login_id', 'descope_user_id', 'descope_user_name', 'descope_user_email', 'descope_user_phone', 'descope_custom_attributes', 'descope_role_names', 'baron_user', 'baron_claims', 'baron_provider', ] as $cookieName) { setcookie($cookieName, '', $expired); } } function auth_admin_emails(): array { return [ 'b23008@baroncs.co.kr', 'kjy0426@hanmaceng.co.kr', 'b24014@hanmaceng.co.kr', 'b23065@hanmaceng.co.kr', 'shyeom1@samaneng.com', 'cjy627@hanmaceng.co.kr', 'b23072@hanmaceng.co.kr', 'cozyjin@hanmaceng.co.kr', 'm24031@hanmaceng.co.kr', 'b24051@hanmaceng.co.kr', 'rmsgud1202@hanmaceng.co.kr', 'm21318@hanmaceng.co.kr', 'b21367@hanmaceng.co.kr', 'b25023@hanmaceng.co.kr', 'sdi9429@naver.com', 'junsuy@hanmail.net', 'ilphilo92@gmail.com', ]; } function auth_normalize_identity(string $value): string { return strtolower(trim($value)); } function auth_is_admin_login(string $loginId): bool { $normalizedLoginId = auth_normalize_identity($loginId); if ($normalizedLoginId === '') { return false; } foreach (auth_admin_emails() as $adminLoginId) { if ($normalizedLoginId === auth_normalize_identity($adminLoginId)) { return true; } } return false; } function auth_is_admin_user(array $user, ?string $loginId = null): bool { $candidates = []; if ($loginId !== null) { $candidates[] = $loginId; } $loginIds = $user['loginIds'] ?? []; if (is_array($loginIds)) { foreach ($loginIds as $candidate) { if (is_string($candidate)) { $candidates[] = $candidate; } } } $candidates[] = (string) ($user['email'] ?? ''); $customAttributes = $user['customAttributes'] ?? []; if (is_array($customAttributes)) { $candidates[] = (string) ($customAttributes['employeeId'] ?? ''); $candidates[] = (string) ($customAttributes['familyUniqueKey'] ?? ''); } foreach ($candidates as $candidate) { if (auth_is_admin_login((string) $candidate)) { return true; } } $roleNames = $user['roleNames'] ?? []; if (is_array($roleNames)) { foreach ($roleNames as $roleName) { $normalizedRole = auth_normalize_identity((string) $roleName); if ($normalizedRole === 'super' || $normalizedRole === 'admin' || $normalizedRole === 'administrator') { return true; } } } return false; } function auth_sync_gnuboard_session(): array { auth_restore_user_session(); $loginIds = $_SESSION['user']['loginIds'] ?? []; $loginId = (is_array($loginIds) && !empty($loginIds)) ? trim((string) $loginIds[0]) : ''; $userName = trim((string) ($_SESSION['user']['name'] ?? '')); $userEmail = trim((string) ($_SESSION['user']['email'] ?? '')); $isAdmin = !empty($_SESSION['user']) && is_array($_SESSION['user']) ? auth_is_admin_user($_SESSION['user'], $loginId) : false; if ($loginId !== '') { $_SESSION['ss_mb_id'] = $loginId; $_SESSION['ss_mb_level'] = $isAdmin ? 10 : 2; return [ 'loginId' => $loginId, 'isAdmin' => $isAdmin, 'is_member' => true, 'is_admin' => $isAdmin ? 'super' : '', 'member' => [ 'mb_id' => $loginId, 'mb_name' => $userName !== '' ? $userName : $loginId, 'mb_email' => $userEmail, 'mb_level' => $_SESSION['ss_mb_level'], 'mb_nick' => $userName !== '' ? $userName : $loginId, ], ]; } unset($_SESSION['ss_mb_id'], $_SESSION['ss_mb_level']); return [ 'loginId' => '', 'isAdmin' => false, 'is_member' => false, 'is_admin' => '', 'member' => [], ]; } function auth_url_is_safe(string $url, string $site): bool { if ($url === '') { return false; } if (strpos($url, '://') !== false) { return false; } return strpos($url, auth_site_base_url($site) . '/') === 0; } function auth_baron_state_payload(string $site, string $returnUrl): array { return [ 'site' => $site, 'return_url' => auth_url_is_safe($returnUrl, $site) ? $returnUrl : auth_site_qna_url($site), 'nonce' => bin2hex(random_bytes(16)), 'created_at' => time(), ]; } function auth_store_baron_state(array $payload): string { auth_session_start_if_needed(); $state = bin2hex(random_bytes(16)); $_SESSION['baron_oauth_state'] = [ 'value' => $state, 'payload' => $payload, ]; return $state; } function auth_consume_baron_state(string $state): ?array { auth_session_start_if_needed(); $stored = $_SESSION['baron_oauth_state'] ?? null; unset($_SESSION['baron_oauth_state']); if (!is_array($stored) || ($stored['value'] ?? '') !== $state) { return null; } $payload = $stored['payload'] ?? null; return is_array($payload) ? $payload : null; } function auth_http_post_form(string $url, array $data, array $headers = [], ?string $username = null, ?string $password = null): array { $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); $mergedHeaders = array_merge([ 'Accept: application/json', 'Content-Type: application/x-www-form-urlencoded', ], $headers); curl_setopt($ch, CURLOPT_HTTPHEADER, $mergedHeaders); if ($username !== null) { curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_setopt($ch, CURLOPT_USERPWD, $username . ':' . ($password ?? '')); } $response = curl_exec($ch); $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE); $error = curl_error($ch); curl_close($ch); return [ 'body' => $response === false ? '' : $response, 'http_code' => $httpCode, 'error' => $error, ]; } function auth_http_get_json(string $url, string $accessToken): array { $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Accept: application/json', 'Authorization: Bearer ' . $accessToken, ]); $response = curl_exec($ch); $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE); $error = curl_error($ch); curl_close($ch); return [ 'body' => $response === false ? '' : $response, 'http_code' => $httpCode, 'error' => $error, ]; } function auth_jwt_payload(string $jwt): array { $parts = explode('.', $jwt); if (count($parts) < 2) { return []; } $payload = strtr($parts[1], '-_', '+/'); $padding = strlen($payload) % 4; if ($padding > 0) { $payload .= str_repeat('=', 4 - $padding); } $decoded = base64_decode($payload, true); if ($decoded === false) { return []; } $json = json_decode($decoded, true); return is_array($json) ? $json : []; } function auth_first_non_empty_string(...$values): string { foreach ($values as $value) { if (is_string($value)) { $trimmed = trim($value); if ($trimmed !== '') { return $trimmed; } } } return ''; } function auth_claim_list($value): array { if (is_array($value)) { return $value; } $stringValue = trim((string) $value); if ($stringValue === '') { return []; } return [$stringValue]; } function auth_extract_phone_from_claims(array $claims): string { $profile = isset($claims['profile']) && is_array($claims['profile']) ? $claims['profile'] : []; $phones = auth_claim_list($claims['phones'] ?? ($profile['phones'] ?? [])); foreach ($phones as $phoneEntry) { if (is_array($phoneEntry)) { $candidate = auth_first_non_empty_string( $phoneEntry['value'] ?? '', $phoneEntry['phone_number'] ?? '', $phoneEntry['number'] ?? '' ); if ($candidate !== '') { return $candidate; } continue; } $candidate = trim((string) $phoneEntry); if ($candidate !== '') { return $candidate; } } return auth_first_non_empty_string( $claims['phone_number'] ?? '', $claims['phone'] ?? '', $profile['phone_number'] ?? '', $profile['phone'] ?? '' ); } function auth_extract_company_fields(array $claims): array { $company = auth_first_non_empty_string( $claims['company'] ?? '', $claims['company_name'] ?? '', $claims['organization'] ?? '', $claims['organization_name'] ?? '', $claims['tenant_name'] ?? '' ); $familyCompany = auth_first_non_empty_string( $claims['familyCompany'] ?? '', $claims['family_company'] ?? '', $claims['group_name'] ?? '', $claims['affiliate'] ?? '' ); $team = auth_first_non_empty_string( $claims['team'] ?? '', $claims['department'] ?? '', $claims['dept'] ?? '', $claims['division'] ?? '', $claims['org_unit'] ?? '' ); $tenants = auth_claim_list($claims['tenants'] ?? []); $primaryTenant = null; $tenantId = trim((string) ($claims['tenant_id'] ?? '')); foreach ($tenants as $tenantKey => $tenant) { if (!is_array($tenant)) { continue; } $candidateId = trim((string) ($tenant['id'] ?? (is_string($tenantKey) ? $tenantKey : ''))); if (($tenant['isPrimary'] ?? false) === true || ($tenant['representative'] ?? false) === true || ($tenantId !== '' && $candidateId === $tenantId)) { $primaryTenant = $tenant; break; } } if ($primaryTenant === null) { foreach ($tenants as $tenant) { if (is_array($tenant)) { $primaryTenant = $tenant; break; } } } if (is_array($primaryTenant)) { $companyAncestor = ''; $familyCompanyAncestor = ''; $departmentAncestor = ''; $ancestors = $primaryTenant['ancestors'] ?? []; if (is_array($ancestors)) { foreach ($ancestors as $ancestor) { if (!is_array($ancestor)) { continue; } $ancestorType = strtoupper(trim((string) ($ancestor['type'] ?? ''))); $ancestorName = trim((string) ($ancestor['name'] ?? '')); if ($ancestorName === '') { continue; } if ($companyAncestor === '' && $ancestorType === 'COMPANY') { $companyAncestor = $ancestorName; } if ($familyCompanyAncestor === '' && $ancestorType === 'COMPANY_GROUP') { $familyCompanyAncestor = $ancestorName; } if ($ancestorType === 'ORGANIZATION') { $departmentAncestor = $ancestorName; } } } $company = auth_first_non_empty_string( $company, $companyAncestor, trim((string) ($primaryTenant['name'] ?? '')) ); $familyCompany = auth_first_non_empty_string( $familyCompany, $companyAncestor, $familyCompanyAncestor, $company ); $team = auth_first_non_empty_string( $team, $departmentAncestor, trim((string) ($primaryTenant['name'] ?? '')) ); } foreach ($tenants as $tenant) { if (!is_array($tenant)) { if ($company === '') { $company = trim((string) $tenant); } continue; } if ($company === '') { $company = auth_first_non_empty_string( $tenant['name'] ?? '', $tenant['display_name'] ?? '', $tenant['company'] ?? '', $tenant['company_name'] ?? '', $tenant['organization'] ?? '' ); } if ($familyCompany === '') { $familyCompany = auth_first_non_empty_string( $tenant['familyCompany'] ?? '', $tenant['family_company'] ?? '', $tenant['group_name'] ?? '', $tenant['affiliate'] ?? '' ); } if ($team === '') { $team = auth_first_non_empty_string( $tenant['team'] ?? '', $tenant['department'] ?? '', $tenant['dept'] ?? '', $tenant['division'] ?? '', $tenant['org_unit'] ?? '' ); } } return [ 'company' => $company, 'familyCompany' => $familyCompany, 'team' => $team, ]; } function auth_baron_user_from_claims(array $claims): array { $profile = isset($claims['profile']) && is_array($claims['profile']) ? $claims['profile'] : []; $email = trim((string) ($claims['email'] ?? $profile['email'] ?? $claims['upn'] ?? $claims['preferred_username'] ?? $claims['sub'] ?? '')); $name = trim((string) ($claims['name'] ?? $profile['name'] ?? $claims['display_name'] ?? $claims['preferred_username'] ?? $email)); $phone = auth_extract_phone_from_claims($claims); $companyFields = auth_extract_company_fields($claims); $company = $companyFields['company']; $familyCompany = $companyFields['familyCompany']; $team = $companyFields['team']; $employeeId = trim((string) ($claims['employee_id'] ?? $profile['employee_id'] ?? $claims['employeeId'] ?? $claims['familyUniqueKey'] ?? '')); $status = trim((string) ($claims['status'] ?? $profile['status'] ?? '')); $tenants = auth_claim_list($claims['tenants'] ?? []); $secondaryEmails = auth_claim_list($claims['secondary_emails'] ?? $claims['secondaryEmails'] ?? ($profile['secondary_emails'] ?? [])); $roles = auth_claim_list($claims['roles'] ?? $claims['roleNames'] ?? []); $position = auth_first_non_empty_string( $claims['position'] ?? '', $profile['position'] ?? '' ); foreach ($tenants as $tenant) { if (!is_array($tenant)) { continue; } if ($position === '') { $position = auth_first_non_empty_string( $tenant['grade'] ?? '', $tenant['position'] ?? '' ); } } return auth_normalize_user([ 'userId' => trim((string) ($claims['sub'] ?? $email)), 'loginIds' => $email !== '' ? [$email] : [], 'name' => $name, 'email' => $email, 'phone' => $phone, 'customAttributes' => [ 'company' => $company, 'familyCompany' => $familyCompany, 'team' => $team, 'position' => $position, 'employeeId' => $employeeId, 'familyUniqueKey' => $employeeId, 'status' => $status, 'tenants' => $tenants, 'secondaryEmails' => $secondaryEmails, ], 'roleNames' => $roles, ]); } function auth_script_redirect(string $message, string $redirectUrl): void { $safeMessage = htmlspecialchars($message, ENT_QUOTES, 'UTF-8'); $safeUrl = htmlspecialchars($redirectUrl, ENT_QUOTES, 'UTF-8'); echo ""; exit; } function auth_is_local_debug(): bool { return (getenv('APP_ENV') ?: '') === 'local'; } function auth_compact_debug_value(string $value, int $maxLength = 300): string { $value = preg_replace('/\s+/', ' ', trim($value)) ?? ''; if (strlen($value) <= $maxLength) { return $value; } return substr($value, 0, $maxLength) . '...'; }