本页面由机器翻译。发现错误了吗?帮助改进它。
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 用户的角色。为 admin、editor 或 user 之一。
SAML_PROVIDER_NAME前端 SAML 登录按钮的显示标签(例如“Okta”、“Azure AD”)。如果为空,按钮显示“SAML”。
SAML_USERNAME_ATTRIBUTE用作用户名的 SAML 断言属性。如果为空,则回退为电子邮件的本地部分,然后是 NameID。
SAML_EMAIL_ATTRIBUTEemail用作用户电子邮件地址的 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(断言消费者服务)${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_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 ​

  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 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 URL 和 签名证书 复制到 SAML_IDP_SSO_URL 和 SAML_IDP_CERTIFICATE。

用户预置 ​

自动创建 ​

当 SAML_AUTO_CREATE_USERS 为 true(默认)时,会在某人首次通过 SAML 登录时创建一个本地用户账户。角色设置为 SAML_DEFAULT_ROLE。

用户名按以下顺序派生:

  1. SAML_USERNAME_ATTRIBUTE 指定的断言属性的值(如果已设置且存在)
  2. 电子邮件地址的本地部分(@ 之前的所有内容)
  3. SAML NameID

如果发生用户名冲突,会追加一个数字后缀(例如 jane 变为 jane_2)。

当 SAML_AUTO_LINK_USERS 为 true 时,如果电子邮件地址匹配,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 强制处于激活状态时,只有应急用户可以使用本地密码登录。其他任何本地登录尝试都会被拒绝,并返回与密码错误相同的 401“Invalid credentials”,即使密码正确也是如此,并且会计入登录限流。

TIP

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

缺少属性 ​

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

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

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

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