This page was machine-translated. Spotted a mistake?Help improve it.
Skip to content

SAML SSO

SnapOtter 支援 SAML 2.0 進行單一登入。使用者可以透過外部身分供應商(Okta、Azure AD / Entra ID、Google Workspace,或任何標準 SAML 2.0 IdP)登入,取代本機使用者名稱/密碼驗證。

企業版功能

SAML SSO 需要具備 saml_sso 功能的 teamenterprise 授權。若設定了 SAML_ENABLED=true 卻沒有有效授權,SAML 路由會被靜默略過並記錄一則警告。

先決條件

  • 一個可透過公開 URL 存取的執行中 SnapOtter 執行個體
  • EXTERNAL_URL 設為該公開 URL(例如 https://photos.example.com
  • 一個具備 saml_sso 功能的 team 或 enterprise 授權金鑰
  • 你 SAML 身分供應商的管理員存取權

快速開始

將這些環境變數加入你的 docker-compose.yml

yaml
services:
  snapotter:
    image: snapotter/snapotter:latest
    environment:
      EXTERNAL_URL: "https://photos.example.com"
      SNAPOTTER_LICENSE_KEY: "your-license-key"
      SAML_ENABLED: "true"
      SAML_IDP_SSO_URL: "https://idp.example.com/sso/saml"
      SAML_IDP_CERTIFICATE: |
        MIICpDCCAYwCCQDU+pQ4pHgSpDANBgkqhkiG9w0BAQsFADAUMRIw
        ...your IdP's signing certificate in PEM format...
        EAYHKoZIzj0CAQYFK4EEACIDYgAE

重新啟動容器。登入頁面會出現「使用 SAML 登入」按鈕(或由 SAML_PROVIDER_NAME 設定的標籤)。

設定參考

變數預設值說明
SAML_ENABLEDfalse啟用 SAML 登入。
SAML_IDP_SSO_URLIdP 的 SSO 端點 URL。啟用 SAML 時為必填
SAML_IDP_CERTIFICATEIdP 的 PEM 格式 X.509 簽章憑證(憑證文字本身,而非檔案路徑)。啟用 SAML 時為必填
EXTERNAL_URLSnapOtter 可被存取的公開 URL。啟用 SAML 時為必填
SAML_ENTITY_ID${EXTERNAL_URL}/api/auth/saml/metadata送往 IdP 的 SP Entity ID / Audience URI。
SAML_CALLBACK_URL${EXTERNAL_URL}/api/auth/saml/callbackAssertion Consumer Service(ACS)URL。
SAML_AUTO_CREATE_USERStrue在首次 SAML 登入時自動建立本機使用者帳號。
SAML_AUTO_LINK_USERSfalse若電子郵件地址相符,將 SAML 身分連結到現有的本機使用者。
SAML_DEFAULT_ROLEuser指派給自動建立的 SAML 使用者的角色。可為 admineditoruser 其中之一。
SAML_PROVIDER_NAME前端 SAML 登入按鈕的顯示標籤(例如「Okta」、「Azure AD」)。若留空,按鈕會顯示「SAML」。
SAML_USERNAME_ATTRIBUTE用作使用者名稱的 SAML 斷言屬性。若留空,會回退到電子郵件的本機部分,再回退到 NameID。
SAML_EMAIL_ATTRIBUTEemail用作使用者電子郵件地址的 SAML 斷言屬性。

SAML_ENABLED=true 且缺少三個必填變數(SAML_IDP_SSO_URLSAML_IDP_CERTIFICATEEXTERNAL_URL)中的任何一個,伺服器會拒絕啟動。

安全性注意事項

wantAuthnResponseSignedwantAssertionsSigned 兩者都硬式編碼為 true。SnapOtter 會拒絕未簽章或簽章不正確的 SAML 回應。來自受信任 IdP 的斷言會被視為電子郵件已驗證。

僅支援 SP 發起的登入。SnapOtter 不支援 IdP 發起(未經請求)的登入或單一登出(SLO)。登出 SnapOtter 不會將使用者從 IdP 登出。

SP 中繼資料與 URL

你的 IdP 需要來自 SnapOtter 的三個值:

欄位
ACS URL(Assertion Consumer Service)${EXTERNAL_URL}/api/auth/saml/callback
Entity ID / Audience URI${EXTERNAL_URL}/api/auth/saml/metadata
SP Metadata(XML)GET ${EXTERNAL_URL}/api/auth/saml/metadata

舉例來說,如果 EXTERNAL_URLhttps://photos.example.com

  • ACS URL:https://photos.example.com/api/auth/saml/callback
  • Entity ID:https://photos.example.com/api/auth/saml/metadata
  • 中繼資料端點:https://photos.example.com/api/auth/saml/metadata(回傳 XML)

某些 IdP 可以直接匯入 SP 中繼資料 URL,這會自動填入 ACS URL 與 Entity ID。

供應商設定

Okta

  1. 在 Okta 管理主控台中,前往 Applications > Create App Integration
  2. 選擇 SAML 2.0 並點按 Next
  3. 設定名稱(例如「SnapOtter」)並點按 Next
  4. 設定 SAML 設定:
    • Single sign-on URL:你的 ACS URL(例如 https://photos.example.com/api/auth/saml/callback
    • Audience URI (SP Entity ID):你的 Entity ID(例如 https://photos.example.com/api/auth/saml/metadata
    • Name ID format:EmailAddress
    • Application username:Email
  5. Attribute Statements 下,新增對應到 user.emailemail
  6. 點按 Next,再點按 Finish
  7. 前往 Sign On 分頁,點按 View SAML setup instructions,並複製:
    • Identity Provider Single Sign-On URL 填入 SAML_IDP_SSO_URL
    • X.509 Certificate 填入 SAML_IDP_CERTIFICATE

Azure AD / Entra ID

  1. 在 Azure 入口網站中,前往 Microsoft Entra ID > Enterprise applications > New application
  2. 點按 Create your own application,命名為「SnapOtter」,並選擇 Integrate any other application you don't find in the gallery
  3. 前往 Single sign-on > SAML 並在 Basic SAML Configuration 區段點按 Edit
    • Identifier (Entity ID):你的 Entity ID(例如 https://photos.example.com/api/auth/saml/metadata
    • Reply URL (ACS URL):你的 ACS URL(例如 https://photos.example.com/api/auth/saml/callback
  4. SAML Certificates 下,下載 Certificate (Base64)
  5. Set up SnapOtter 下,複製 Login URL
  6. SAML_IDP_SSO_URL 設為 Login URL,並將 SAML_IDP_CERTIFICATE 設為下載的憑證內容。
  7. Users and groups 下將使用者或群組指派給此應用程式。

Google Workspace

  1. 在 Google 管理主控台中,前往 Apps > Web and mobile apps > Add app > Add custom SAML app
  2. 將應用程式命名為「SnapOtter」並點按 Continue
  3. Google Identity Provider details 頁面,複製 SSO URL 並下載 Certificate。點按 Continue
  4. 設定 Service Provider 詳細資訊:
    • ACS URL:你的 ACS URL(例如 https://photos.example.com/api/auth/saml/callback
    • Entity ID:你的 Entity ID(例如 https://photos.example.com/api/auth/saml/metadata
    • Name ID format:EMAIL
    • Name ID:Basic Information > Primary email
  5. 點按 Continue,再點按 Finish
  6. 為你的組織單位將應用程式開啟(ON)
  7. SAML_IDP_SSO_URL 設為步驟 3 的 SSO URL,並將 SAML_IDP_CERTIFICATE 設為下載的憑證內容。

通用 SAML 2.0 IdP

對於任何符合 SAML 2.0 規範的身分供應商:

  1. 在你的 IdP 中建立新的 SAML 應用程式/服務供應商。
  2. ACS URL 設為 ${EXTERNAL_URL}/api/auth/saml/callback
  3. Entity ID / Audience 設為 ${EXTERNAL_URL}/api/auth/saml/metadata
  4. 設定 IdP 在名為 email 的屬性中送出使用者的電子郵件(或設定 SAML_EMAIL_ATTRIBUTE 以符合你 IdP 的屬性名稱)。
  5. IdP SSO URLsigning certificate 複製到 SAML_IDP_SSO_URLSAML_IDP_CERTIFICATE

使用者佈建

自動建立

SAML_AUTO_CREATE_USERStrue(預設)時,會在有人首次透過 SAML 登入時建立本機使用者帳號。角色會設為 SAML_DEFAULT_ROLE

使用者名稱按以下順序衍生:

  1. SAML_USERNAME_ATTRIBUTE 指定的斷言屬性值(若已設定且存在)
  2. 電子郵件地址的本機部分(@ 之前的所有內容)
  3. SAML NameID

若發生使用者名稱衝突,會附加一個數字後綴(例如 jane 會變成 jane_2)。

SAML_AUTO_LINK_USERStrue 時,若電子郵件地址相符,SnapOtter 會將 SAML 身分連結到現有的本機帳號。當你已預先建立使用者帳號,並希望他們在不遺失資料的情況下開始使用 SSO 時,這很有用。

WARNING

只有在你信任你的 SAML IdP 會驗證電子郵件地址時,才啟用自動連結。來自設定錯誤的 IdP 的未經驗證電子郵件,可能讓某人接管其他使用者的帳號。

屬性對應

SnapOtter 欄位來源設定
Email斷言屬性SAML_EMAIL_ATTRIBUTE(預設:email
Username斷言屬性、電子郵件或 NameIDSAML_USERNAME_ATTRIBUTE(請參閱上方的衍生順序)
External IDNameID一律為 SAML NameID,不可設定

SSO 強制

如果你想要求所有使用者透過 SAML(或 OIDC)登入,並封鎖本機密碼登入,請啟用 SSO 強制:

  1. 確保 sso_enforcement 企業版功能已獲授權(team 與 enterprise 方案提供)。
  2. Admin Settings > Security 中,開啟 SSO Enforcement
  3. 設定一個 break-glass 使用者名稱:這是唯一在 IdP 無法連線時仍可用密碼登入以進行緊急存取的本機帳號。

當 SSO 強制啟用時,任何本機登入嘗試(break-glass 使用者除外)都會回傳 403 錯誤,訊息為「Local password login is disabled. Please use SSO.」

TIP

在啟用 SSO 強制之前,一律要先設定 break-glass 使用者名稱。若沒有它,當你的 IdP 停機時,你可能會被鎖在 SnapOtter 之外。

將 SAML 與 OIDC 並用

SAML 與 OIDC 可以同時啟用。當兩者都啟用時,登入頁面會為每個供應商顯示各自的按鈕(由 SAML_PROVIDER_NAMEOIDC_PROVIDER_NAME 標示)。使用者可以用任一方法登入。

兩個供應商各自獨立共用相同的自動建立、自動連結與 SSO 強制設定:每個都有自己的 *_AUTO_CREATE_USERS*_AUTO_LINK_USERS*_DEFAULT_ROLE 變數。

疑難排解

斷言驗證失敗

SAML 回應簽章或斷言簽章無法驗證。請檢查:

  • SAML_IDP_CERTIFICATE 中的憑證與你 IdP 中目前的簽章憑證相符(憑證會輪替,所以請檢查是否過期)
  • 憑證為 PEM 格式(以 -----BEGIN CERTIFICATE----- 開頭)
  • 憑證為完整文字,而非檔案路徑
  • 你 IdP 中設定的 ACS URL 與 Entity ID 與 SnapOtter 的值完全相符(配置方式、主機、連接埠、路徑)

缺少屬性

如果登入後使用者名稱或電子郵件為空,你的 IdP 可能沒有送出預期的屬性。請檢查:

  • 你的 IdP 已設定為釋出 email 屬性(或 SAML_EMAIL_ATTRIBUTE 所設定的任何值)
  • 若使用 SAML_USERNAME_ATTRIBUTE,請驗證該屬性已包含在斷言中
  • 某些 IdP 需要明確的屬性對應設定,才會釋出宣告

時鐘偏差

SAML 斷言包含時間戳記條件(NotBeforeNotOnOrAfter)。如果你的伺服器時鐘與 IdP 時鐘不同步,斷言驗證會失敗。在兩台機器上都執行 NTP 以保持時鐘一致。

「SAML is enabled via env but saml_sso enterprise feature is not licensed」

SAML_ENABLED=true 但授權不包含 saml_sso 功能時,此警告會出現在伺服器記錄中。請驗證你的授權金鑰與方案。saml_sso 功能在 team 與 enterprise 方案提供。

登入重新導向後帶著錯誤返回

如果點按 SAML 登入按鈕後帶著錯誤重新導向回登入頁面,請檢查伺服器記錄以取得詳細資訊。常見原因:

  • 從伺服器無法連線到 IdP SSO URL
  • IdP 拒絕了驗證請求(請檢查 IdP 的稽核記錄)
  • IdP 回傳了未簽章的回應(SnapOtter 要求回應與斷言兩者都必須簽章)