כניסה מאוחדת (SSO)
התחברות ל-Nodaro באירוח עצמי דרך ספק זהות מהימן: הגדירו את EXTERNAL_SSO_PROVIDERS, בחרו כללי קישור חשבונות ואפשרו התחברות רק דרך SSO.
כניסה מאוחדת (SSO) מאפשרת למשתמשים להתחבר ל-Nodaro שלכם באירוח עצמי דרך ספק זהות חיצוני ומהימן. מתארים כל ספק במשתנה EXTERNAL_SSO_PROVIDERS, ודף ההתחברות מציג כפתור SSO. החשבון שהמשתמש מגיע אליו הוא משתמש רגיל בהתקנה שלכם: SSO הוא רק דרך להתחיל סשן. הדף הזה עוסק בצד של מנהל השרת; הפרוטוקול מתואר בדף התחברות חיצונית (SSO) למפתחים.
איזה סוג ספק לבחור
| סוג | מתי להשתמש בו | סטטוס |
|---|---|---|
assertion | המנפיק שלכם לא מדבר OpenID Connect או SAML, אבל יכול לחתום על JWT קצר מועד, למשל אפליקציה שמטמיעה את Nodaro. Nodaro מאמת את האסימון ומחליף אותו בסשן רגיל. | עובד מקצה לקצה. |
oidc | ספק הזהות שלכם מדבר OpenID Connect ומוגדר ב-Supabase Auth של ההתקנה שלכם. הדפדפן עובר הפניית התחברות רגילה של Supabase, ו-Supabase מאמת את התוצאה. | השדה id של הספק חייב להיות השם של ספק ה-OAuth ב-Supabase Auth שלכם, כמו keycloak או azure. |
saml | — | הרשומות עוברות את בדיקת התקינות, אבל דף ההתחברות לא יכול לשלוח דומיין SAML, ולכן אף אחד לא יכול להתחבר דרכן. השתמשו ב-assertion או ב-oidc. |
SSO כבוי כברירת מחדל. כשהמשתנה EXTERNAL_SSO_PROVIDERS לא מוגדר, דף ההתחברות לא מציג כפתור SSO, הנתיב GET /v1/sso/providers מחזיר רשימה ריקה, וכל נתיב של ספק מחזיר 404 unknown_provider.
הגדרת הספקים
הגדירו את EXTERNAL_SSO_PROVIDERS כמערך JSON, ישירות בערך המשתנה, או כ-@/path/to/providers.json כדי לקרוא אותו מקובץ.
[
{
"id": "librechat",
"label": "LibreChat",
"kind": "assertion",
"secret": "a-dedicated-32+char-hmac-key-not-the-idp-session-secret",
"audience": "nodaro",
"claimMap": { "email": "email", "emailVerified": "email_verified", "subject": "sub" },
"initiateUrl": "https://chat.example.com/oauth/nodaro",
"maxLifetimeSeconds": 300
},
{
"id": "keycloak",
"label": "Acme (Keycloak)",
"kind": "oidc",
"supabaseProvider": "keycloak"
}
]ערך פגום עוצר את האתחול. שגיאת הקלדה ברשומה שיש בה סוד לעולם לא אמורה להשמיט ספק בשקט, מה שהיה נראה כמו כשל של SSO עם 404, או להשאיר את ההתחברות מוגדרת למחצה.
במערך השירותים של Compose, הוסיפו את EXTERNAL_SSO_PROVIDERS ואת EXTERNAL_SSO_LINK_EXISTING תחת environment: של השירות nodaro, כי קובץ ה-Compose לא מעביר אותם מהקובץ .env. כדי להשתמש בקובץ, מפו אותו לתוך הקונטיינר וציינו את הנתיב שלו בתוך הקונטיינר.
השדות של ספק
| שדה | חל על | מה הוא עושה |
|---|---|---|
id | כל הסוגים | שם שבטוח לשימוש ב-URL: אות לטינית קטנה או ספרה בהתחלה, ואחריה אותיות קטנות, ספרות, _ או -, בין 1 ל-63 תווים בסך הכול, בלי נקודות. השם מופיע בנתיב /v1/sso/<id> ונשמר ברשומת המשתמש. חייב להיות ייחודי. |
label | כל הסוגים | שם הספק. הוא מופיע על כפתור ההתחברות רק כשיש שני ספקים או יותר, ופרופיל הממשק לא מגדיר auth.ssoLabel. |
kind | כל הסוגים | assertion, oidc או saml. |
secret | assertion, נדרש | מפתח ה-HS256 שמאמת את החתימה של ה-assertion, באורך של 16 תווים לפחות. השתמשו במפתח ייעודי, ואף פעם לא בסוד הסשנים של ספק הזהות עצמו, כדי שדליפה בצד של Nodaro לא תאפשר לזייף את הסשנים של הספק. |
audience | assertion, נדרש | הערך שה-claim aud של ה-assertion חייב להיות שווה לו. |
claimMap | assertion | אילו claims מעבירים את האימייל, את דגל האימות ואת ה-subject. ברירת המחדל היא { "email": "email", "emailVerified": "email_verified", "subject": "sub" }. |
initiateUrl | assertion | כתובת URL מלאה. כשמשתמש לוחץ על כפתור ההתחברות, Nodaro מפנה אותו לשם. המשתמש מתחבר אצל הספק, והספק חוזר עם ה-assertion. בלי השדה הזה, לחיצה על הכפתור נדחית עם 400 no_assertion. |
initiateUrlByHost | assertion | מיפוי של שם מארח, באותיות קטנות ובלי פורט, לכתובת URL מלאה. לחיצה שמגיעה למארח הזה מופנית לכתובת שלו במקום ל-initiateUrl. מיועד להתקנות שעונות בכמה שמות מארח. מפתח שגוי עוצר את האתחול, והמיפוי אף פעם לא מתפרסם. |
maxLifetimeSeconds | assertion | אורך החיים המרבי של assertion, exp פחות iat. ברירת המחדל היא 300, כלומר 5 דקות, והמקסימום הוא 3600. |
supabaseProvider | oidc | עובר בדיקת תקינות, אבל לא בשימוש: דף ההתחברות מעביר ל-Supabase את ה-id של הספק. |
domain | oidc, saml | עובר בדיקת תקינות, אבל לא בשימוש. רשומה מסוג oidc או saml צריכה domain או supabaseProvider. |
רק השדות id, label ו-kind מתפרסמים, דרך GET /v1/sso/providers. הסוד אף פעם לא יוצא מהשרת.
מה Nodaro בודק ב-assertion
שרת הזהות של ספק מסוג assertion חותם על JWT ושולח את הדפדפן אל GET /v1/sso/<id>?assertion=<jwt>. Nodaro מקבל את ה-assertion רק כשכל התנאים האלה מתקיימים:
- ה-assertion חתום ב-HS256 ובערך
secretשל הספק. audשווה לערךaudienceשל הספק.expקיים ועדיין לא עבר, עם סובלנות של 5 שניות, ואורך החיים לא חורג מ-maxLifetimeSeconds.jtiקיים ואף פעם לא נעשה בו שימוש. כל assertion עובד פעם אחת.- ה-claim של האימייל קיים. ה-claim של האימות חייב להיות
trueכדי ליצור חשבון או לקשר חשבון.
assertion שנכשל באחת הבדיקות נדחה עם 401. הנתיב מקבל עד 20 בקשות ב-60 שניות מכתובת IP אחת, ובקשות נוספות נדחות עם 429. החוזה המלא, קודי השגיאה וזרימת ההפניות מתוארים בדף התחברות חיצונית (SSO) למפתחים.
איך חשבונות מקושרים
כש-assertion עובר את הבדיקות, Nodaro מוצא את המשתמש המתאים או יוצר אותו. הכללים מבטיחים ש-assertion לעולם לא יוכל להשתלט על חשבון קיים רק כי יש לו אותה כתובת אימייל.
| מצב | תוצאה |
|---|---|
| אין חשבון עם האימייל הזה, והאימייל מאומת | נוצר משתמש חדש, והוא מקושר לספק. |
| אין חשבון עם האימייל הזה, והאימייל לא מאומת | הבקשה נדחית: 403 email_unverified. |
| החשבון כבר מקושר לספק הזה | המשתמש מתחבר. |
| החשבון מקושר לספק אחר | הבקשה נדחית: 403 account_linked_other_provider, גם עם EXTERNAL_SSO_LINK_EXISTING=true. |
קיים חשבון מקומי בלי SSO, EXTERNAL_SSO_LINK_EXISTING=true, והאימייל מאומת | החשבון מקושר לספק, והמשתמש מתחבר. |
קיים חשבון מקומי בלי SSO, והדגל הוא false או שהאימייל לא מאומת | הבקשה נדחית: 403 account_exists. |
ברירת המחדל של EXTERNAL_SSO_LINK_EXISTING היא false, וזו ההגדרה שמגינה מפני השתלטות. רק הערכים true או 1, באותיות גדולות או קטנות, מפעילים אותו. הפעילו אותו רק כשאתם סומכים על ה-claims של אימייל מאומת שהספקים שלכם שולחים, עד כדי כך שאתם מוכנים לקשר אותם לחשבונות קיימים.
הקודים account_exists ו-email_unverified מנוסחים אותו דבר לכל חשבון, ולכן אי אפשר להשתמש בטופס ההתחברות כדי לגלות אילו כתובות קיימות. יומן השרת רושם לאיזה חשבון כוונה הבקשה.
כפתור ההתחברות
דף ההתחברות מציג כפתור SSO כשמוגדר לפחות ספק אחד.
- ספק אחד: על הכפתור כתוב כניסה מאוחדת (SSO), או הערך של
auth.ssoLabelבפרופיל הממשק. - כמה ספקים: כל כפתור מציג את ה-
labelשל הספק שלו, אלא אם פרופיל הממשק מגדירauth.ssoLabel.
אחרי ההתחברות, המשתמש מגיע ל-/projects. הספק יכול לשלוח אותו לדף אחר אם הוא מוסיף &next=<path> כשהוא מפנה בחזרה. Nodaro מכבד את הפרמטר הזה רק כשהוא נתיב יחסי באותו origin, שמתחיל ב-/ אבל לא ב-//. כל ערך אחר מוביל ל-/projects. במארחים שמופיעים ב-CORS_ORIGIN, ההפניה לדף הנחיתה נשארת יחסית, במארח שהמשתמש הגיע אליו.
התחברות דרך SSO בלבד
במהדורת Business, פרופיל הממשק יכול להסיר את שאר שיטות ההתחברות:
NODARO_SURFACE_PROFILE={"auth":{"methods":["sso"],"ssoLabel":"Sign in with Acme"}}רשימה שכוללת רק את sso מפעילה גם כלל בצד השרת: כל חשבון מחובר צריך להיות חשבון שנוצר או קושר דרך SSO. כל סשן אחר נדחה בקריאה הראשונה שלו ל-API עם 403 sso_required, כך שחשבון שנרשם ישירות בשירות ההתחברות לא יכול להשתמש בהתקנה. הוספת email לרשימה משביתה את הכלל. ראו את הסעיף שיטות התחברות בדף מהדורות ופרופילי ממשק.
סיכום האבטחה
- סוד ייעודי לכל ספק, שונה מסוד הסשנים של הספק עצמו.
- assertions לשימוש חד־פעמי, עם אורך חיים קצר שהשרת אוכף.
- הפניות רק לאותו origin אחרי ההתחברות.
- אף סוד לא יוצא מהשרת. ה-assertions והאסימונים החד־פעמיים מוסרים מיומני הבקשות.
- מגבלות קצב על נתיב ההחלפה, לכל כתובת IP.
- סשנים רגילים. אחרי ההחלפה, המשתמש הוא משתמש רגיל, בלי פרטי גישה מיוחדים.
שאלות נפוצות
האם הכניסה המאוחדת (SSO) מופעלת כברירת מחדל?
לא. כשהמשתנה EXTERNAL_SSO_PROVIDERS לא מוגדר, דף ההתחברות לא מציג כפתור SSO, וכל נתיב SSO מחזיר 404. כדי להפעיל SSO, הגדירו לפחות ספק אחד.
איזה סוג ספק כדאי להגדיר?
השתמשו בסוג assertion למנפיק שיכול להנפיק אסימון חתום קצר מועד, כמו אפליקציה שמטמיעה את Nodaro. השתמשו בסוג oidc לספק זהות שהגדרתם ב-Supabase Auth של ההתקנה שלכם. רשומות מהסוג saml עוברות את בדיקת התקינות, אבל אף אחד לא יכול להתחבר דרכן.
האם SSO יכול להשתלט על חשבון קיים עם אותו אימייל?
לא כברירת מחדל. הערך של EXTERNAL_SSO_LINK_EXISTING הוא false, ולכן assertion לאימייל שכבר יש לו חשבון מקומי נדחה עם account_exists. הגדירו אותו ל-true רק כשאתם סומכים על ה-claims של אימייל מאומת שהספקים שלכם שולחים.
איך מאפשרים התחברות רק דרך SSO?
במהדורת Business, הגדירו בפרופיל הממשק את auth.methods ל-["sso"], יחד עם auth.ssoLabel. כל חשבון חייב אז לעבור דרך SSO, וכל סשן אחר נדחה עם 403 sso_required.
מה קורה אם יש טעות ב-EXTERNAL_SSO_PROVIDERS?
ההתקנה מסרבת לעלות. ערך פגום אף פעם לא משמיט ספק בשקט ולא משאיר את ההתחברות מוגדרת למחצה.
דפים קשורים
התחברות חיצונית (SSO)
מהדורות ופרופילי ממשק
תצורה
המשתמש הראשון והמנהל
עודכן לאחרונה