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 功能的 团队企业 许可证。如果设置了 SAML_ENABLED=true 但没有有效的许可证,SAML 路由会被静默跳过,并记录一条警告。

前置条件

  • 一个可通过公共 URL 访问的运行中的 SnapOtter 实例
  • EXTERNAL_URL 设置为该公共 URL(例如 https://photos.example.com
  • 具备 saml_sso 功能的团队或企业许可证密钥
  • 你的 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/callback断言消费者服务(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(断言消费者服务)${EXTERNAL_URL}/api/auth/saml/callback
Entity ID / Audience URI${EXTERNAL_URL}/api/auth/saml/metadata
SP 元数据(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 下,添加 email 并映射到 user.email
  6. 点击 Next,然后点击 Finish
  7. 进入 Sign On 选项卡,点击 View SAML setup instructions,并复制:
    • Identity Provider Single Sign-On URLSAML_IDP_SSO_URL
    • X.509 CertificateSAML_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 URL签名证书 复制到 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 字段来源配置
电子邮件断言属性SAML_EMAIL_ATTRIBUTE(默认:email
用户名断言属性、电子邮件或 NameIDSAML_USERNAME_ATTRIBUTE(见上文派生顺序)
外部 IDNameID始终为 SAML NameID,不可配置

SSO 强制

如果你希望要求所有用户都通过 SAML(或 OIDC)登录并阻止本地密码登录,请启用 SSO 强制:

  1. 确保 sso_enforcement 企业功能已获授权(在团队和企业方案上可用)。
  2. Admin Settings > Security 中,打开 SSO Enforcement
  3. 设置一个 应急用户名:这是唯一一个在 IdP 无法访问时仍可使用密码登录以进行紧急访问的本地账户。

当 SSO 强制处于激活状态时,任何本地登录尝试(应急用户除外)都会返回 403 错误,消息为“Local password login is disabled. Please use SSO.”

TIP

在启用 SSO 强制之前,请务必先配置一个应急用户名。否则,如果你的 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 的值完全一致(scheme、host、port、path)

缺少属性

如果登录后用户名或电子邮件为空,你的 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 功能在团队和企业方案上可用。

登录重定向回来并带有错误

如果点击 SAML 登录按钮后重定向回登录页面并带有错误,请查看服务器日志以了解详情。常见原因:

  • 从服务器无法访问 IdP SSO URL
  • IdP 拒绝了认证请求(请查看 IdP 的审计日志)
  • IdP 返回了未签名的响应(SnapOtter 要求响应和断言都必须签名)