开发者
SSO·SCIM 对接规范
OIDC、SAML 2.0、SCIM 2.0 对接所需的值和行为规范。
屏幕设置步骤请参见 SSO 与 SCIM。
下表中的 {API} 是您所用环境的 Keural API 地址(例如 https://api.keural.ai)。实际值请使用 组织管理 → SSO 界面上显示的地址。
注册值汇总
| 项目 | 值 |
|---|---|
| OIDC 重定向 URI | {API}/api/sso/callback |
| OIDC·SAML 登录发起 | {API}/api/sso/{orgId}/login |
| SAML SP EntityID | {API}/api/sso/saml/metadata |
| SAML ACS URL | {API}/api/sso/saml/callback |
| SCIM Base URL | {API}/scim/v2 |
登录始终从 Keural 端发起(SP-initiated)。在登录界面输入已注册域名的邮箱后,会跳转到登录发起地址。成功后返回 Keural 首页,失败则返回 /login?error=sso。
OIDC
| 项目 | 行为 |
|---|---|
| 流程 | Authorization Code |
| authorize 请求 | response_type=code、client_id、redirect_uri、scope=openid email profile、state、nonce |
| state · nonce | 一次性使用,有效期 10 分钟。登录窗口开启超过 10 分钟时,需从头重新登录。 |
| 令牌交换 | 向 token endpoint 发送 POST,application/x-www-form-urlencoded。客户端认证方式为 client_secret_post(请求体中包含 client_id 和 client_secret)。 |
| ID 令牌签名 | 仅接受 RS256。密钥通过 kid 从 jwks_uri 中查找。 |
| ID 令牌校验 | 签名、exp、aud 包含 client_id、nonce 一致、iss 与 Issuer URL 一致(忽略末尾的 /) |
| 邮箱 | ID 令牌中的 email 声明。若没有,则以 Authorization: Bearer <access_token> 调用 userinfo endpoint 读取 email。 |
| 名称 | ID 令牌中的 name 声明 |
| 端点 | 从 Issuer URL 下的 /.well-known/openid-configuration 查找。无法找到的 IdP 请在 打开高级设置 中直接输入 authorization、token、JWKS 和 userinfo 地址。 |
| 时间限制 | 每次调用 IdP 为 15 秒 |
IdP 应用必须允许 client_secret_post。如果仅允许 client_secret_basic 或 private_key_jwt,令牌交换将失败。
SAML 2.0
| 项目 | 行为 |
|---|---|
| 请求 | 以 HTTP-Redirect 绑定发送 AuthnRequest。请求不签名。 |
| 请求内容 | Destination=IdP SSO URL、AssertionConsumerServiceURL=ACS URL、ProtocolBinding=HTTP-POST、Issuer=SP EntityID、NameIDPolicy Format=…:nameid-format:unspecified、AllowCreate=true |
| 响应 | HTTP-POST 绑定,包含 SAMLResponse 和 RelayState。RelayState 必须原样返回 Keural 发送的值。 |
| 签名 | Response 或 Assertion 之一必须带有有效签名。验证时只使用在界面上注册的证书。 |
| 断言 | 响应中必须恰好有一个断言。不接受加密断言(EncryptedAssertion)。 |
| 状态 | StatusCode 为 urn:oasis:names:tc:SAML:2.0:status:Success |
| Issuer | 如果填写了 IdP EntityID,则必须与断言中的 Issuer 一致。 |
| 条件 | NotBefore、NotOnOrAfter(允许误差 300 秒),Audience=SP EntityID |
| SubjectConfirmationData | Recipient=ACS URL、NotOnOrAfter(允许误差 300 秒)、InResponseTo=Keural 发送的请求 ID |
| 邮箱 | 属性的 Name 或 FriendlyName 为以下之一(不区分大小写):email、mail、emailAddress、E-Mail-Addresses、http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress。如果都没有,则使用包含 @ 的 NameID。 |
| 名称 | displayName、name、cn、http://schemas.microsoft.com/identity/claims/displayname |
| 证书 | 一个 X.509 证书,PEM 或 Base64(DER)格式。更换时,请输入新证书并保存。 |
| 元数据 | 不上传 IdP 元数据 XML,而是输入 IdP EntityID、IdP SSO URL 和证书三个值。 |
用户匹配
| 项目 | 行为 |
|---|---|
| 转入 SSO 的条件 | 邮箱 @ 之后的部分与 邮箱域名 列表中的某一项完全相同(不区分大小写)。子域名需要单独注册。 |
| 查找账户 | 使用 IdP 返回的邮箱(小写)查找 Keural 账户。 |
| 没有账户时 | 如果 首次登录时自动创建用户(JIT)已开启,则创建账户;如果关闭,则拒绝登录。 |
| 加入组织 | 如果不是组织成员,则以 成员 身份加入。席位已满或属于其他组织的账户不会加入,只能登录。 |
| 保存邮箱域名的条件 | 通过 DNS TXT 验证的域名。排除公共邮箱域名。 |
域名验证
| 项目 | 值 |
|---|---|
| 记录类型 | TXT |
| 主机 | 按注册时的域名原样填写(例如 acme.com)。不要使用前缀子域名。 |
| 值 | keural-verify=<UUID>,与界面上显示的值完全一致 |
| 检查时机 | 点击 确认验证 时查询一次。 |
SCIM 2.0
| 项目 | 值 |
|---|---|
| Base URL | {API}/scim/v2 |
| 认证 | Authorization: Bearer <SCIM 令牌>。令牌以 scim_ 开头,签发时仅显示一次。 |
| Content-Type | 请求为 application/scim+json 或 application/json,响应为 application/scim+json |
| 状态码 | 返回实际的 HTTP 状态码。错误正文采用 SCIM Error 格式(schemas、status、detail、scimType)。 |
端点
| 方法 | 路径 | 行为 |
|---|---|---|
GET | /Users | 列表。filter=userName eq "…"、startIndex(默认 1)、count(默认 100,最大 200) |
GET | /Users/{id} | 查询一人 |
POST | /Users | 创建(201)。若已有相同邮箱,返回 409 |
PATCH | /Users/{id} | 修改 active、displayName、name.formatted、name.givenName |
PUT | /Users/{id} | 应用 displayName、name、active。省略 active 时视为启用。 |
DELETE | /Users/{id} | 停用账户(204)。不删除数据。 |
GET | /Groups、/Groups/{id} | 查询两个固定分组。filter=displayName eq "…" |
PATCH | /Groups/{id} | 添加、移除或替换成员 |
GET | /ServiceProviderConfig、/ResourceTypes、/Schemas | 查询支持的功能 |
用户属性
| 属性 | 用途 |
|---|---|
userName | 邮箱。若没有,则使用 emails[0].value。 |
displayName · name.formatted · name.givenName+name.familyName | 显示名称 |
active | false 为停用(阻止登录),true 为恢复 |
id | Keural 用户 ID。包含在响应中。 |
不保存 externalId。在 IdP 中查找用户时,请使用 userName 过滤器。
分组
| id | displayName | 添加成员时 | 移除成员时 |
|---|---|---|---|
keural-admins | Keural Admins | 管理员 | 成员 |
keural-members | Keural Members | 成员 | 不变 |
组织所有者的角色不会通过 SCIM 更改。创建或删除分组(POST、DELETE /Groups)返回 501。分组成员的 value 为 Keural 用户 ID(/Users 中的 id)。
支持范围
| 功能 | 是否支持 |
|---|---|
| PATCH | 是 |
| 过滤器 | userName eq、displayName eq |
| Bulk · 排序 · ETag · 修改密码 | 否 |
错误
| 状态 | scimType | 原因 |
|---|---|---|
400 | invalidValue | userName 和 emails 都缺失 |
401 | — | 令牌缺失或错误,或 SCIM 自动配置已关闭 |
404 | — | 不属于此组织的用户或分组 |
409 | uniqueness | 已存在相同邮箱的账户,或超出席位数 |
501 | — | 创建或删除分组 |