Search K
SAML SSO
SnapOtter 支援 SAML 2.0 進行單一登入。使用者可以透過外部身分供應商(Okta、Azure AD / Entra ID、Google Workspace,或任何標準 SAML 2.0 IdP)登入,取代本機使用者名稱/密碼驗證。
企業版功能
SAML SSO 需要具備 saml_sso 功能的 team 或 enterprise 授權。若設定了 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_ENABLED | false | 啟用 SAML 登入。 |
SAML_IDP_SSO_URL | IdP 的 SSO 端點 URL。啟用 SAML 時為必填。 | |
SAML_IDP_CERTIFICATE | IdP 的 PEM 格式 X.509 簽章憑證(憑證文字本身,而非檔案路徑)。啟用 SAML 時為必填。 | |
EXTERNAL_URL | SnapOtter 可被存取的公開 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/callback | Assertion Consumer Service(ACS)URL。 |
SAML_AUTO_CREATE_USERS | true | 在首次 SAML 登入時自動建立本機使用者帳號。 |
SAML_AUTO_LINK_USERS | false | 若電子郵件地址相符,將 SAML 身分連結到現有的本機使用者。 |
SAML_DEFAULT_ROLE | user | 指派給自動建立的 SAML 使用者的角色。可為 admin、editor 或 user 其中之一。 |
SAML_PROVIDER_NAME | 前端 SAML 登入按鈕的顯示標籤(例如「Okta」、「Azure AD」)。若留空,按鈕會顯示「SAML」。 | |
SAML_USERNAME_ATTRIBUTE | 用作使用者名稱的 SAML 斷言屬性。若留空,會回退到電子郵件的本機部分,再回退到 NameID。 | |
SAML_EMAIL_ATTRIBUTE | email | 用作使用者電子郵件地址的 SAML 斷言屬性。 |
若 SAML_ENABLED=true 且缺少三個必填變數(SAML_IDP_SSO_URL、SAML_IDP_CERTIFICATE、EXTERNAL_URL)中的任何一個,伺服器會拒絕啟動。
安全性注意事項
wantAuthnResponseSigned 與 wantAssertionsSigned 兩者都硬式編碼為 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_URL 是 https://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
- 在 Okta 管理主控台中,前往 Applications > Create App Integration。
- 選擇 SAML 2.0 並點按 Next。
- 設定名稱(例如「SnapOtter」)並點按 Next。
- 設定 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
- Single sign-on URL:你的 ACS URL(例如
- 在 Attribute Statements 下,新增對應到
user.email的email。 - 點按 Next,再點按 Finish。
- 前往 Sign On 分頁,點按 View SAML setup instructions,並複製:
- 將 Identity Provider Single Sign-On URL 填入
SAML_IDP_SSO_URL - 將 X.509 Certificate 填入
SAML_IDP_CERTIFICATE
- 將 Identity Provider Single Sign-On URL 填入
Azure AD / Entra ID
- 在 Azure 入口網站中,前往 Microsoft Entra ID > Enterprise applications > New application。
- 點按 Create your own application,命名為「SnapOtter」,並選擇 Integrate any other application you don't find in the gallery。
- 前往 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)
- Identifier (Entity ID):你的 Entity ID(例如
- 在 SAML Certificates 下,下載 Certificate (Base64)。
- 在 Set up SnapOtter 下,複製 Login URL。
- 將
SAML_IDP_SSO_URL設為 Login URL,並將SAML_IDP_CERTIFICATE設為下載的憑證內容。 - 在 Users and groups 下將使用者或群組指派給此應用程式。
Google Workspace
- 在 Google 管理主控台中,前往 Apps > Web and mobile apps > Add app > Add custom SAML app。
- 將應用程式命名為「SnapOtter」並點按 Continue。
- 在 Google Identity Provider details 頁面,複製 SSO URL 並下載 Certificate。點按 Continue。
- 設定 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
- ACS URL:你的 ACS URL(例如
- 點按 Continue,再點按 Finish。
- 為你的組織單位將應用程式開啟(ON)。
- 將
SAML_IDP_SSO_URL設為步驟 3 的 SSO URL,並將SAML_IDP_CERTIFICATE設為下載的憑證內容。
通用 SAML 2.0 IdP
對於任何符合 SAML 2.0 規範的身分供應商:
- 在你的 IdP 中建立新的 SAML 應用程式/服務供應商。
- 將 ACS URL 設為
${EXTERNAL_URL}/api/auth/saml/callback。 - 將 Entity ID / Audience 設為
${EXTERNAL_URL}/api/auth/saml/metadata。 - 設定 IdP 在名為
email的屬性中送出使用者的電子郵件(或設定SAML_EMAIL_ATTRIBUTE以符合你 IdP 的屬性名稱)。 - 將 IdP SSO URL 與 signing certificate 複製到
SAML_IDP_SSO_URL與SAML_IDP_CERTIFICATE。
使用者佈建
自動建立
當 SAML_AUTO_CREATE_USERS 為 true(預設)時,會在有人首次透過 SAML 登入時建立本機使用者帳號。角色會設為 SAML_DEFAULT_ROLE。
使用者名稱按以下順序衍生:
- 由
SAML_USERNAME_ATTRIBUTE指定的斷言屬性值(若已設定且存在) - 電子郵件地址的本機部分(
@之前的所有內容) - SAML NameID
若發生使用者名稱衝突,會附加一個數字後綴(例如 jane 會變成 jane_2)。
自動連結
當 SAML_AUTO_LINK_USERS 為 true 時,若電子郵件地址相符,SnapOtter 會將 SAML 身分連結到現有的本機帳號。當你已預先建立使用者帳號,並希望他們在不遺失資料的情況下開始使用 SSO 時,這很有用。
WARNING
只有在你信任你的 SAML IdP 會驗證電子郵件地址時,才啟用自動連結。來自設定錯誤的 IdP 的未經驗證電子郵件,可能讓某人接管其他使用者的帳號。
屬性對應
| SnapOtter 欄位 | 來源 | 設定 |
|---|---|---|
| 斷言屬性 | SAML_EMAIL_ATTRIBUTE(預設:email) | |
| Username | 斷言屬性、電子郵件或 NameID | SAML_USERNAME_ATTRIBUTE(請參閱上方的衍生順序) |
| External ID | NameID | 一律為 SAML NameID,不可設定 |
SSO 強制
如果你想要求所有使用者透過 SAML(或 OIDC)登入,並封鎖本機密碼登入,請啟用 SSO 強制:
- 確保
sso_enforcement企業版功能已獲授權(team 與 enterprise 方案提供)。 - 在 Admin Settings > Security 中,開啟 SSO Enforcement。
- 設定一個 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_NAME 與 OIDC_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 斷言包含時間戳記條件(NotBefore、NotOnOrAfter)。如果你的伺服器時鐘與 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 要求回應與斷言兩者都必須簽章)
