تخطَّ إلى المحتوى

تسجيل الدخول الموحّد

يتيح تسجيل الدخول الموحّد لموفّر هوية خارجي (IdP) أن يقرر من يجوز له تسجيل الدخول إلى خادم Control Center لديك. البروتوكولان المدعومان — SAML 2.0 وOpenID Connect — يصلان إلى الموضع نفسه: بيانات اعتماد جهاز تُصدَر للتو، لا يميّزها أي مسار لاحق عن دعوة أو اقتران برمز QR.

تسجيلات الدخول عبر SAML تتم بوساطة المتصفح. لا يفتح IdP اتصالًا بخادمك أبدًا، ومتصفح المستخدم هو الذي يحمل كل شيء:

browser ──> /saml/login ──> IdP ──POST SAMLResponse──> /saml/acs
│ verify
▼
provision user (maybe)
│
▼
browser handoff: device PSK in the URL
fragment (never a query parameter)

لأن المتصفح هو الناقل، يصلح خادم خلف NAT لتسجيل الدخول: localhost أو LAN أو Tailscale أو VPN أو نفق، كلها تفي بالغرض — والشرط الوحيد أن يبلغ متصفح المستخدم عنوان ACS. مرحّل WebSocket الذي يستخدمه التحكم عن بُعد من الهاتف لا يستطيع حمل جولة HTTP ذهابًا وإيابًا، ولهذا تستهدف نقاط دخول SSO دائمًا أصل HTTP الخاص بالخادم.

يتبع OpenID Connect الشكل نفسه بجولة رمز تفويض مع PKCE، وتُقرأ المطالبات من نقطة نهاية الرمز لدى المُصدِر عبر TLS، فلا يقدّم المتصفح بيانات الهوية أصلًا.

تفصل Control Center المسؤولية عن قصد:

الجزء الموضع يملك
cc_saml الأصلي packages/cc_natives/native/saml/ التحقق من XML-DSig، والتحويل إلى الصيغة القياسية، والتحقق من ملف تعريف SAML — تُسنَد إلى حزمة saml المكتوبة بـ Rust خالص والمُثبَّت إصدارها، خلف واجهة C ABI بلا حالة
SamlService / OidcService cc_server_core حالة تسجيل الدخول (متتبعات الطلبات المعلّقة، وكشف تكرار إعادة الإرسال)، وعناصر ضبط سياسة التحقق، واستدعاء التوفير المشترك
SsoProvisioner cc_server_core إيجاد المستخدم أو إنشاؤه، وتثبيت المعرّف الثابت لدى الموفّر، ومنح العضويات وفق سياسة الإضافة التلقائية إلى كل مساحة عمل
ScimService cc_server_core سطح الدفع في SCIM 2.0 (دورة حياة التوفير وإلغاء التوفير)
SsoSettingsService cc_server_core صفوف الاتصال المحفوظة، وإعادة تطبيقها فورًا، ورمز وصول SCIM

هناك، عن قصد، لا مسار تراجع لتشفير SAML بـ Dart خالص: التنفيذ اليدوي لـ XML-DSig وللتحويل إلى الصيغة القياسية هو بالضبط حيث تكمن ثغرات التفاف التوقيع، فغياب مكتبة cc_saml يرفض تسجيل الدخول عبر SAML وإقلاع الخادم معًا. المكتبة الأصلية بلا حالة عن تصميم — الحالة العابرة بين الطلبات تعيش في خدمات Dart، وهي أحادية الاستخدام وقصيرة العمر.

داخل المكتبة الأصلية التي تُجري التحقق، وفي الخدمة، بالترتيب:

  1. توقيع التأكيد (مطلوب دائمًا، وتوقيع مغلّف الاستجابة اختياري حسب التهيئة) — وهو مقاوم من حيث البنية لالتفاف التوقيع، لأن الحمولة المتحقَّق منها مربوطة بالعنصر الذي جرى التحقق من توقيعه،
  2. المُصدِر يطابق IdP المُهيَّأ،
  3. الجمهور يسمّي موفّر الخدمة هذا،
  4. الوجهة هي عنوان ACS الخاص بنا،
  5. يطابق InResponseTo طلب AuthnRequest معلّقًا أصدرناه (الاستجابات غير المطلوبة، المبدوءة من IdP، متوقفة افتراضيًا)،
  6. تبقى نوافذ مدة الصلاحية سارية ضمن انحراف الساعة (الافتراضي 90 ثانية)، و
  7. معرّف التأكيد لم يُرَ من قبل (ذاكرة منع إعادة الإرسال).

تعود الإخفاقات برموز مسمّاة — signature، expired، audience، destination، issuer، request-match — وترد نقاط النهاية بأخطاء عامة، فلا يتبيّن المهاجم سبب فشل التزوير.

الحسابات وتثبيت المعرّف الثابت

قسم بعنوان “الحسابات وتثبيت المعرّف الثابت”

يثبّت أول تسجيل دخول عبر SSO المعرّف الثابت لدى الموفّر (issuer مع NameID في SAML أو sub في OIDC، أو externalId في SCIM) على الحساب. من بعد ذلك، هذا المعرّف — لا البريد الإلكتروني — هو الذي يحدّد تسجيل الدخول. إذا قدّم شخص آخر لاحقًا البريد نفسه من IdP نفسه أو من غيره، يرفضه الحساب الذي ثُبّت عليه هذا المعرّف. هذا ما يمنع بريدًا أعاد الموفّر تخصيصه من أن يصير استيلاءً على الحساب.

يحدث توفير JIT عند تسجيل الدخول (SsoProvisioner). SCIM سطح دفع منفصل (ScimService) يثبّت المعرّف الثابت نفسه على صف المستخدم، ولا يمنح عضويات في مساحات العمل. إلغاء التوفير — active: false أو DELETE في SCIM — يُرفض إذا كان الحساب مالك مساحة عمل (انقل الملكية أولًا). وإلا يُبطِل أولًا كل بيانات اعتماد جهاز (تسقط الجلسات خلال ثوانٍ عبر مراقبة الأجهزة)، ويزيل كل عضوية في مساحات العمل، ويختم الحساب بأنه مُعطَّل. يبقى صف المستخدم: الإسناد دائم. إعادة التفعيل تعيد تسجيل الدخول، ولا تعيد منح العضويات أبدًا.

  • يحدث تعيين المجموعات إلى الأدوار عند تسجيل الدخول من سمات SAML ومطالبات OIDC — مجموعات SCIM التي تُدفَع لا تُخزَّن.
  • لا يمكن بلوغ دور المالك من SSO — لا بوصفه الدور الافتراضي ولا عبر تعيين مجموعة.
  • مرحّل WebSocket ليس قناة SSO أبدًا، والهواتف التي لا تصل إلى الخادم إلا عبر المرحّل لا تستطيع إكمال جولة المتصفح ذهابًا وإيابًا مقابله.