> For the complete documentation index, see [llms.txt](https://ayakaleaf-pro.ayaka.space/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ayakaleaf-pro.ayaka.space/on-premises/zh-cn/pei-zhi/overleaf-toolkit/authentication/saml-authentication.md).

# SAML 身份验证

此功能由 [yu-i-i/overleaf-cep](https://github.com/yu-i-i/overleaf-cep)。这里我们为您的配置提供一些文档。

### 配置

在内部，Overleaf 的 SAML 模块使用 [passport-saml](https://github.com/node-saml/passport-saml) 库，下面的大多数配置选项都会传递给 `passport-saml`。如果你在配置 SAML 时遇到问题，建议阅读 `passport-saml` 的 README，以了解它所期望的配置。

环境变量 `EXTERNAL_AUTH` 是启用 SAML 认证模块所必需的。此环境变量指定启用哪些外部认证方式。该变量的值是一个列表。如果列表中包含 `saml` ，则会启用 SAML 认证。

例如： `EXTERNAL_AUTH=ldap saml`

当使用 SAML 认证方式时，用户会被重定向到身份提供方（IdP）的认证站点。如果 IdP 成功认证用户，Overleaf 用户数据库将检查是否存在包含一个 `samlIdentifiers` 字段，其结构如下：

```json
samlIdentifiers: [
  {
    externalUserId: "...",
    providerId: "1",
    userIdAttribute: "..."
  }
]
```

该 `externalUserId` 的记录必须与 `userIdAttribute` 所指定的属性值相匹配，该值位于 IdP 服务器返回的用户资料中。

如果没有找到匹配记录，系统会在数据库中搜索主电子邮件地址与 IdP 用户配置文件中的电子邮件匹配的用户：

* 如果找到了这样的用户， `hashedPassword` 字段被删除以禁用本地认证，并添加 `samlIdentifiers` 字段。
* 如果未找到匹配的用户，则会使用电子邮件地址和 `samlIdentifiers` 创建一个新用户。

**注意：** 目前仅支持一个 SAML IdP。 `providerId` 中的 `samlIdentifiers` 字段固定为 `'1'`.

#### 环境变量

* `OVERLEAF_SAML_IDENTITY_SERVICE_NAME`
  * 身份服务的显示名称，用于登录页面（默认： `使用 SAML IdP 登录`).
* `OVERLEAF_SAML_USER_ID_FIELD`
  * 此属性的值将被 Overleaf 用作外部用户 ID，默认为 `nameID`.
* `OVERLEAF_SAML_EMAIL_FIELD`
  * 用户资料中 Email 字段的名称，默认值为 `nameID`.
* `OVERLEAF_SAML_FIRST_NAME_FIELD`
  * 用户资料中 firstName 字段的名称，默认值为 `givenName`.
* `OVERLEAF_SAML_LAST_NAME_FIELD`
  * 用户资料中 lastName 字段的名称，默认值为 `lastName`
* `OVERLEAF_SAML_UPDATE_USER_DETAILS_ON_LOGIN`
  * 如果设置为 `true`，在登录时更新用户 `first_name` 和 `last_name` 字段在登录时更新，并关闭 `/user/settings` 页面。
* `OVERLEAF_SAML_ENTRYPOINT` **（必需）**
  * SAML 身份服务的入口 URL。
    * 示例： `https://idp.example.com/simplesaml/saml2/idp/SSOService.php`
    * Azure 示例： `https://login.microsoftonline.com/8b26b46a-6dd3-45c7-a104-f883f4db1f6b/saml2`
* `OVERLEAF_SAML_ISSUER` **（必需）**
  * 发行方名称。
* `OVERLEAF_SAML_AUDIENCE`
  * 预期的 saml 响应 Audience，默认为 `OVERLEAF_SAML_ISSUER`.
* `OVERLEAF_SAML_IDP_CERT` **（必需）**
  * 包含身份提供方公钥证书的文件路径，用于验证传入 SAML 响应的签名。如果身份提供方有多个有效签名证书，也可以是一个包含证书路径的 JSON 数组。
    * 示例（一个证书）： `/var/lib/overleaf/certs/idp_cert.pem`
    * 示例（多个证书）： `["var/lib/overleaf/certs/idp_cert.pem", "/var/lib/overleaf/certs/idp_cert_old.pem"]`
* `OVERLEAF_SAML_PUBLIC_CERT`
  * 包含用于嵌入到认证请求中的公钥证书的文件路径，以便 IdP 验证传入 SAML 请求的签名。在配置 [元数据端点](https://github.com/yu-i-i/overleaf-cep/wiki/Extended-CE:-SAML-Authentication#metadata-for-the-identity-provider) 时需要这样做，前提是该策略配置了 `OVERLEAF_SAML_PRIVATE_KEY`。可以提供一个包含证书路径的 JSON 数组，以支持证书轮换。当提供证书数组时，数组中的第一个条目应与当前 `OVERLEAF_SAML_PRIVATE_KEY`匹配。数组中的其他条目可用于在更改之前向 IdP 发布即将使用的证书。 `OVERLEAF_SAML_PRIVATE_KEY`.
* `OVERLEAF_SAML_PRIVATE_KEY`
  * 包含与 `OVERLEAF_SAML_PUBLIC_CERT` 匹配的 PEM 格式私钥的文件路径，用于签署 passport-saml 发送的认证请求。
* `OVERLEAF_SAML_DECRYPTION_CERT`
  * 包含公钥证书的文件路径，用于 [元数据端点](https://github.com/yu-i-i/overleaf-cep/wiki/Extended-CE:-SAML-Authentication#metadata-for-the-identity-provider).
* `OVERLEAF_SAML_DECRYPTION_PVK`
  * 包含与 `OVERLEAF_SAML_DECRYPTION_CERT` 匹配的私钥的文件路径，该私钥将用于尝试解密接收到的任何加密断言。
* `OVERLEAF_SAML_SIGNATURE_ALGORITHM`
  * 可选地设置用于签名请求的签名算法，可用值为 'sha1'（默认）、'sha256'（推荐）、'sha512'（最安全，请确认你的 IdP 支持它）。
* `OVERLEAF_SAML_ADDITIONAL_PARAMS`
  * 要添加到所有请求中的附加查询参数的 JSON 字典。
* `OVERLEAF_SAML_ADDITIONAL_AUTHORIZE_PARAMS`
  * 要添加到 'authorize' 请求中的附加查询参数的 JSON 字典。
    * 示例： `{"some_key": "some_value"}`
* `OVERLEAF_SAML_IDENTIFIER_FORMAT`
  * 从身份提供方请求的名称标识符格式（默认： `urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress`）。如果使用 `urn:oasis:names:tc:SAML:2.0:nameid-format:persistent`，请确保 `OVERLEAF_SAML_EMAIL_FIELD` 环境变量已定义。如果 `urn:oasis:names:tc:SAML:2.0:nameid-format:transient` 是必需的，你还必须定义 `OVERLEAF_SAML_ID_FIELD` 环境变量，例如可以将其设置为用户的电子邮件地址。
* `OVERLEAF_SAML_ACCEPTED_CLOCK_SKEW_MS`
  * 在检查 OnBefore 和 NotOnOrAfter 断言条件有效时间戳时，客户端与服务器之间可接受的时间偏差，单位为毫秒。设为 -1 将完全禁用这些条件的检查。默认值为 0。
* `OVERLEAF_SAML_ATTRIBUTE_CONSUMING_SERVICE_INDEX`
  * `AttributeConsumingServiceIndex` 要添加到 AuthnRequest 的属性，用于指示 IdP 附加到响应中的属性集（[链接](http://blog.aniljohn.com/2014/01/data-minimization-front-channel-saml-attribute-requests.html)).
* `OVERLEAF_SAML_AUTHN_CONTEXT`
  * 用于请求认证上下文的名称标识符格式值的 JSON 数组。默认值： `["urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"]`.
* `OVERLEAF_SAML_FORCE_AUTHN`
  * 如果 `true`时，服务提供方发出的初始 SAML 请求会指定 IdP 应强制用户重新认证，即使其已经拥有有效会话。
* `OVERLEAF_SAML_DISABLE_REQUESTED_AUTHN_CONTEXT`
  * 如果 `true`时，不请求特定的认证上下文。例如，你可以将其设置为 `true` 以允许其他上下文，例如无密码登录（`urn:oasis:names:tc:SAML:2.0:ac:classes:X509`）。对其他上下文的支持取决于你的 IdP。
* `OVERLEAF_SAML_AUTHN_REQUEST_BINDING`
  * 如果设置为 `HTTP-POST`时，将通过 HTTP POST 绑定向 IdP 请求认证，否则默认为 HTTP-Redirect。
* `OVERLEAF_SAML_VALIDATE_IN_RESPONSE_TO`
  * 如果 `always`时，将对传入的 SAML 响应中的 InResponseTo 进行验证。
  * 如果 `绝不`时，不会验证 InResponseTo（默认）。
  * 如果 `ifPresent`时，只有当传入的 SAML 响应中存在 InResponseTo 时才会进行验证。
* `OVERLEAF_SAML_WANT_ASSERTIONS_SIGNED` 和 `OVERLEAF_SAML_WANT_AUTHN_RESPONSE_SIGNED`
  * 当设置为 `true` （默认），Overleaf 期望 SAML 断言，或整个 SAML 认证响应，均由 IdP 签名。当两个选项都 `false`时，断言或响应至少有一个必须被签名。
* `OVERLEAF_SAML_REQUEST_ID_EXPIRATION_PERIOD_MS`
  * 定义 SAML 请求生成的 Request ID 在 SAML 响应的 `InResponseTo` 字段中被看到时失效的过期时间。默认值：28800000（8 小时）。
* `OVERLEAF_SAML_LOGOUT_URL`
  * 注销请求调用的基础地址（默认： `entryPoint`).
    * 示例： `https://idp.example.com/simplesaml/saml2/idp/SingleLogoutService.php`
* `OVERLEAF_SAML_ADDITIONAL_LOGOUT_PARAMS`
  * 要添加到 'logout' 请求中的附加查询参数的 JSON 字典。
* `OVERLEAF_SAML_IS_ADMIN_FIELD` 和 `OVERLEAF_SAML_IS_ADMIN_FIELD_VALUE`
  * 当这两个环境变量都设置时，登录过程会更新 `user.isAdmin = true` 如果 SAML IdP 返回的资料包含由 `OVERLEAF_SAML_IS_ADMIN_FIELD` 指定的属性，并且其值匹配 `OVERLEAF_SAML_IS_ADMIN_FIELD_VALUE` 或是一个包含 `OVERLEAF_SAML_IS_ADMIN_FIELD_VALUE`的数组，否则 `user.isAdmin` 会被设置为 `false`。如果这些变量中的任意一个未设置，那么管理员状态只会在 `true` 期间于 Launchpad 中创建管理员用户时被设置。

**身份提供方元数据**

当前版本的 Overleaf CE 包含一个用于检索服务提供方元数据的端点： `http://my-overleaf-instance.com/saml/meta`

需要在身份提供方中配置 Overleaf 服务器，使其被识别为“服务提供方”。有关如何操作，请参阅你的 SAML 服务器文档。

下面是一个合适的服务提供方元数据示例：

<details>

<summary><strong>ol-meta.xml</strong></summary>

```
<?xml version="1.0"?>
<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
                  xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
                  entityID="MyOverleaf"
                  ID="_b508c83b7dda452f5b269383fb391107116f8f57">
  <SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol" AuthnRequestsSigned="true" WantAssertionsSigned="true">
    <KeyDescriptor use="signing">
      <ds:KeyInfo>
        <ds:X509Data>
          <ds:X509Certificate>MII...
[已跳过]
</ds:X509Certificate>
        </ds:X509Data>
      </ds:KeyInfo>
    </KeyDescriptor>
    <KeyDescriptor use="encryption">
      <ds:KeyInfo>
        <ds:X509Data>
          <ds:X509Certificate>MII...
[已跳过]
</ds:X509Certificate>
        </ds:X509Data>
      </ds:KeyInfo>
      <EncryptionMethod Algorithm="http://www.w3.org/2009/xmlenc11#aes256-gcm"/>
      <EncryptionMethod Algorithm="http://www.w3.org/2009/xmlenc11#aes128-gcm"/>
      <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"/>
      <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/>
    </KeyDescriptor>
    <SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
                         Location="https://my-overleaf-instance.com/saml/logout/callback"/>
    <NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</NameIDFormat>
    <AssertionConsumerService index="1"
                              isDefault="true"
                              Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
                              Location="https://my-overleaf-instance.com/saml/login/callback"/>
  </SPSSODescriptor>
</EntityDescriptor>

```

</details>

注意这些证书， `AssertionConsumerService.Location`, `SingleLogoutService.Location` 和 `EntityDescriptor.entityID` 并在你的 IdP 配置中相应设置，或者将元数据文件发送给 IdP 管理员。

<details>

<summary><strong>示例 variables.env 文件（最小）</strong></summary>

<pre><code>OVERLEAF_APP_NAME="Our Overleaf Instance"

ENABLED_LINKED_FILE_TYPES=project_file,project_output_file,url

# 使用 ImageMagick 启用缩略图生成
ENABLE_CONVERSIONS=true

# 禁用邮箱确认要求
EMAIL_CONFIRMATION_DISABLED=true

## Nginx
# NGINX_WORKER_PROCESSES=4
# NGINX_WORKER_CONNECTIONS=768

## 通过 nginx-proxy 设置 TLS
# OVERLEAF_BEHIND_PROXY=true
# OVERLEAF_SECURE_COOKIE=true

OVERLEAF_SITE_URL=http://my-overleaf-instance.com
OVERLEAF_NAV_TITLE=Our Overleaf Instance
# OVERLEAF_HEADER_IMAGE_URL=http://somewhere.com/mylogo.png
OVERLEAF_ADMIN_EMAIL=support@example.com

OVERLEAF_LEFT_FOOTER=[{"text": "联系您的支持团队", "url": "mailto:support@example.com"}]
OVERLEAF_RIGHT_FOOTER=[{"text":"你好，我在右侧", "url":"https://github.com/yu-i-i/overleaf-cep"}]

OVERLEAF_EMAIL_FROM_ADDRESS=team@example.com
OVERLEAF_EMAIL_SMTP_HOST=smtp.example.com
OVERLEAF_EMAIL_SMTP_PORT=587
OVERLEAF_EMAIL_SMTP_SECURE=false
# OVERLEAF_EMAIL_SMTP_USER=
# OVERLEAF_EMAIL_SMTP_PASS=
# OVERLEAF_EMAIL_SMTP_NAME=
OVERLEAF_EMAIL_SMTP_LOGGER=false
OVERLEAF_EMAIL_SMTP_TLS_REJECT_UNAUTH=true
OVERLEAF_EMAIL_SMTP_IGNORE_TLS=false
OVERLEAF_CUSTOM_EMAIL_FOOTER=该系统由 x 部门运行

OVERLEAF_PROXY_LEARN=true
NAV_HIDE_POWERED_BY=true

#################
##     SAML    ##
#################

EXTERNAL_AUTH=saml
OVERLEAF_SAML_ISSUER=MyOverleaf
OVERLEAF_SAML_IDENTITY_SERVICE_NAME='使用 SAML 提供商登录'
OVERLEAF_SAML_EMAIL_FIELD=Email
OVERLEAF_SAML_FIRST_NAME_FIELD=DisplayName
OVERLEAF_SAML_LAST_NAME_FIELD=DisplayName
OVERLEAF_SAML_ENTRYPOINT=http://localhost:18000/login/saml/authorize/admin/SAML_Overleaf
<strong>OVERLEAF_SAML_IDP_CERT=/var/lib/overleaf/certs/idp_cert.pem
</strong>OVERLEAF_SAML_SIGNATURE_ALGORITHM=
</code></pre>

</details>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://ayakaleaf-pro.ayaka.space/on-premises/zh-cn/pei-zhi/overleaf-toolkit/authentication/saml-authentication.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
