跳到主要内容

5. Bind 操作 (Bind Operation)

Bind 操作 ([RFC4511] 第 4.2 节) 允许在客户端与服务器之间交换认证信息, 以建立新的授权状态.

Bind 请求通常指定所期望的认证身份. 一些 Bind 机制还允许客户端指定授权身份. 如果未指定授权身份, 服务器将以实现特定的方式从认证身份推导出它.

如果指定了授权身份, 服务器必须验证客户端的认证身份被允许承担 (例如代理) 所断言的授权身份. 如果客户端未经如此授权, 服务器必须在 Bind 响应中以 invalidCredentials 结果码拒绝该 Bind 操作.

5.1 简单认证方法 (Simple Authentication Method)​

Bind 操作的简单认证方法提供三种认证机制:

  • 匿名认证机制 (第 5.1.1 节).

  • 未认证认证机制 (第 5.1.2 节).

  • 名称/口令认证机制, 其凭证由一个名称 (LDAP 可辨识名称 [RFC4514] 形式) 和一个口令组成 (第 5.1.3 节).

5.1.1 简单 Bind 的匿名认证机制 (Anonymous Authentication Mechanism of Simple Bind)​

LDAP 客户端可以使用简单 Bind 方法的匿名认证机制, 通过发送一个 name 值为零长度, 并且指定 simple 认证选择 (其中 password 值为零长度) 的 Bind 请求, 来显式地建立匿名授权状态.

5.1.2 简单 Bind 的未认证认证机制 (Unauthenticated Authentication Mechanism of Simple Bind)​

LDAP 客户端可以使用简单 Bind 方法的未认证认证机制, 通过发送一个带有 name 值 (非零长度的 LDAP 字符串形式 [RFC4514] 可辨识名称) 并且指定 simple 认证选择 (其中 password 值为零长度) 的 Bind 请求, 来建立匿名授权状态.

客户端提供的可辨识名称值仅打算用于追踪 (例如日志) 目的. 该值不做认证或其他验证 (包括验证该 DN 是否指向一个已存在的目录对象). 该值不得 (直接或间接) 用于授权目的.

未认证 Bind 操作可能有重大的安全问题 (见第 6.3.1 节). 特别是, 打算执行名称/口令认证的用户可能无意中提供了空口令, 从而使实现不良的客户端请求未认证访问. 客户端的实现应当要求用户以用户输入空口令以外的方式选择未认证认证机制. 客户端应当禁止在名称/口令认证的用户界面中输入空口令. 此外, 服务器默认应当以 unwillingToPerform 结果码使未认证 Bind 请求失败.

5.1.3 简单 Bind 的名称/口令认证机制 (Name/Password Authentication Mechanism of Simple Bind)​

LDAP 客户端可以使用简单 Bind 方法的名称/口令认证机制, 通过发送一个带有 name 值 (非零长度的 LDAP 字符串形式 [RFC4514] 可辨识名称) 并且指定 simple 认证选择 (其中包含非零长度的 OCTET STRING 口令值) 的 Bind 请求, 来建立已认证的授权状态.

把 Bind 请求中发送的 DN 映射到一个目录条目 (该条目关联有与这种机制一起使用的一个或多个口令的集合) 的服务器, 会把所出示的口令与该口令集合比较. 如果所出示的口令与该集合中的任一成员匹配, 则它被视为有效.

结果码 invalidDNSyntax 表示 name 值中发送的 DN 在语法上无效. 结果码 invalidCredentials 表示该 DN 在语法上正确但对认证目的而言无效, 或口令对该 DN 无效, 或服务器基于其他原因认为凭证无效. 结果码 success 表示凭证有效, 并且服务器愿意向这些凭证所标识的实体提供服务.

对于指定名称/口令认证机制且 name 值为零长度而口令值非零长度的 Bind 请求, 服务器行为未定义.

简单 Bind 方法的名称/口令认证机制不适用于没有保密性保护的环境中的认证.

5.2 SASL 认证方法 (SASL Authentication Method)​

Bind 操作的 sasl 认证方法提供了使用任何 SASL 机制 (包括认证机制和其他服务, 例如数据安全服务) 的设施.

5.2.1 SASL 协议轮廓 (SASL Protocol Profile)​

LDAP 允许通过任何 SASL 机制 [RFC4422] 进行认证. 由于 LDAP 包含原生的匿名与名称/口令 (明文) 认证方法, ANONYMOUS [RFC4505] 和 PLAIN [PLAIN] SASL 机制通常不与 LDAP 一起使用.

每个利用 SASL 服务的协议都必须提供某些信息, 以说明这些服务通过该协议暴露的方式 ([RFC4422] 第 4 节). 本节解释 LDAP 如何满足这些轮廓化要求中的每一项.

5.2.1.1 LDAP 的 SASL 服务名 (SASL Service Name for LDAP)​

LDAP 的 SASL 服务名是 "ldap", 它已在 IANA 注册为 SASL 服务名.

5.2.1.2 SASL 认证的发起与协议交换 (SASL Authentication Initiation and Protocol Exchange)​

SASL 认证通过一个带有以下参数的 BindRequest 消息 ([RFC4511] 第 4.2 节) 发起:

  • version 为 3.

  • AuthenticationChoice 为 sasl.

  • SaslCredentials 序列的 mechanism 元素包含所期望 SASL 机制的值.

  • SaslCredentials 序列的可选 credentials 字段可用于为那些定义为客户端先发数据的机制提供初始客户端响应 (见 [RFC4422] 第 3 节和第 5 节).

一般而言, SASL 认证协议交换由一系列服务器挑战 (challenge) 和客户端响应 (response) 组成, 其内容由相应 SASL 机制定义. 因此, 对于某些 SASL 认证机制, 客户端可能需要通过多次发送 BindRequest 消息来响应一个或多个服务器挑战. 挑战由服务器发送 resultCode 被置为 saslBindInProgress 的 BindResponse 消息来指示. 这表示服务器要求客户端发送一个使用相同 SASL 机制的新 BindRequest 消息, 以继续认证过程.

对 LDAP 消息层而言, 这些挑战和响应是任意长度的不透明二进制令牌. LDAP 服务器使用 BindResponse 消息中的 serverSaslCreds 字段 (一个 OCTET STRING) 来传输每个挑战. LDAP 客户端使用 BindRequest 消息中 SaslCredentials 序列的 credentials 字段 (一个 OCTET STRING) 来传输每个响应. 注意, 与某些使用 SASL 的互联网协议不同, LDAP 不是基于文本的, 并且不对这些挑战和响应值做 Base64 变换.

发送选择了 sasl 选择的 BindRequest 消息的客户端, 应当在 name 字段中发送零长度值. 收到选择了 sasl 选择的 BindRequest 消息的服务器, 应忽略 name 字段中的任何值.

客户端可以通过发送一条 SaslCredentials 的 mechanism 字段取不同值的 BindRequest 消息, 或一条 AuthenticationChoice 不是 sasl 的 BindRequest 消息, 来中止 SASL Bind 协商.

如果客户端发送的 BindRequest 中 sasl mechanism 字段为空字符串, 服务器必须返回一条 resultCode 为 authMethodNotSupported 的 BindResponse. 这允许客户端在中止协商后, 如果愿意可以用同一 SASL 机制再试.

服务器通过发送一条 resultCode 值不为 saslBindInProgress 的 BindResponse 来指示 SASL 挑战-响应交换的完成.

对于被定义为服务器随成功完成指示一起发送附加数据的机制, BindResponse 中的 serverSaslCreds 字段可用于随成功通知包含一个可选的挑战.

5.2.1.3 可选字段 (Optional Fields)​

如上所述, LDAP 在发起 SASL 交换的消息中提供了一个携带初始响应的可选字段, 并在指示认证交换结果的消息中提供了一个携带附加数据的可选字段. 由于这些字段中机制特定的内容可能为零长度, SASL 要求协议规范详述如何区分空字段与缺失字段.

在发起消息 (BindRequest PDU) 中, 零长度初始响应数据与没有初始响应数据的区分依据是: 该 PDU 中是否存在 SaslCredentials.credentials OCTET STRING (长度为零). 如果客户端不打算在发起 SASL 交换的 BindRequest 中发送初始响应, 它必须省略 SaslCredentials.credentials OCTET STRING (而不是包含一个零长度的 OCTET STRING).

在结果消息 (BindResponse PDU) 中, 零长度附加数据与没有附加响应数据的区分依据是: 该 PDU 中是否存在 serverSaslCreds OCTET STRING (长度为零). 如果服务器不打算在指示交换结果的 BindResponse 消息中发送附加数据, 服务器应省略 serverSaslCreds OCTET STRING (而不是包含一个零长度的 OCTET STRING).

5.2.1.4 协商的安全层生效的八位组位置 (Octet Where Negotiated Security Layers Take Effect)​

SASL 层在服务器发送且客户端接收到 SASL 交换中 resultCode 为 success 的最终 BindResponse 之后生效.

一旦提供数据完整性或保密性服务的 SASL 层生效, 该层保持有效, 直到安装了新的层 (即, 在使新层生效的那个 Bind 操作的最终 BindResponse 之后的第一个八位组处). 因此, 已建立的 SASL 层不受一次失败的或非 SASL 的 Bind 影响.

5.2.1.5 支持的 SASL 机制的确定 (Determination of Supported SASL Mechanisms)​

客户端可以通过从根 DSE (DSA-Specific Entry) ([RFC4512] 第 5.1 节) 读取 'supportedSASLMechanisms' 属性来确定服务器支持的 SASL 机制. 该属性 (如果存在) 的值列出了服务器在当前 LDAP 会话状态下支持的机制. LDAP 服务器应当允许所有客户端 -- 包括拥有匿名授权的客户端 -- 在 SASL 认证交换之前和之后检索根 DSE 的 'supportedSASLMechanisms' 属性. 后者的目的是让客户端能够检测可能的降级攻击 (见第 6.4 节和 [RFC4422] 第 6.1.2 节).

由于 SASL 机制提供关键的安全功能, 客户端和服务器应当可配置为指定哪些机制是可接受的, 并且只允许使用那些机制. 客户端和服务器在继续使用会话之前, 都必须确认协商的安全级别满足自己的要求.

5.2.1.6 使用 SASL 层的规则 (Rules for Using SASL Layers)​

安装 SASL 层之后, 客户端应当丢弃或刷新它在发起 SASL 协商之前获得的, 且不是通过安全机制获得的关于该服务器的全部信息.

如果安装了较低级别的安全层 (例如 TLS), 则任何 SASL 层都应叠加在这些安全层之上, 而无论它们协商的先后顺序如何. 在其他所有方面, SASL 层与其他安全层独立运作, 例如, 如果 TLS 层和 SASL 层同时生效, 那么移除 TLS 层不影响 SASL 层的持续服务.

5.2.1.7 对多次认证的支持 (Support for Multiple Authentications)​

LDAP 支持 [RFC4422] 第 4 节定义的多次 SASL 认证.

5.2.1.8 SASL 授权身份 (SASL Authorization Identities)​

一些 SASL 机制允许客户端为 LDAP 会话请求所期望的授权身份 ([RFC4422] 第 3.4 节). 允许或不允许当前认证身份访问所请求授权身份的决定是本地策略问题. 授权身份是一个 UTF-8 [RFC3629] 编码的 [Unicode] 字符串, 对应于以下增广巴科斯-瑙尔范式 (ABNF) [RFC4234] 文法:

      authzId = dnAuthzId / uAuthzId

; distinguished-name-based authz id
dnAuthzId = "dn:" distinguishedName

; unspecified authorization id, UTF-8 encoded
uAuthzId = "u:" userid
userid = *UTF8 ; syntax unspecified

其中 distinguishedName 规则定义于 [RFC4514] 第 3 节, UTF8 规则定义于 [RFC4512] 第 1.4 节.

dnAuthzId 选择用于以可辨识名称的形式断言授权身份, 并依照 distinguishedNameMatch 匹配规则 ([RFC4517] 第 4.2.15 节) 进行匹配. 不要求所断言的 distinguishedName 值是目录中某个条目的 DN.

uAuthzId 选择允许客户端断言不是可辨识名称形式的授权身份. userid 的格式仅定义为 UTF-8 [RFC3629] 编码的 [Unicode] 字符序列, 任何进一步的解释都是本地事务. 例如, userid 可以标识特定目录服务的用户, 可以是登录名, 也可以是电子邮件地址. 不应假定 uAuthzId 是全局唯一的. 为比较 uAuthzId 值, 每个 uAuthzId 值都必须使用 SASLprep [RFC4013] 算法准备为 "query" 字符串 ([RFC3454] 第 7 节), 然后按八位组逐个比较两个值.

上述文法是可扩展的. authzId 产生式可以扩展以支持其他形式的身份. 每种形式由其唯一前缀区分 (注册要求见 [RFC4520] 第 3.12 节).

5.2.2 LDAP 中的 SASL 语义 (SASL Semantics within LDAP)​

实现者在处理那些在 LDAP 协议中具有不同语义的数据时, 必须注意保持 SASL 规范的语义.

例如, SASL DIGEST-MD5 认证机制 [DIGEST-MD5] 利用的认证身份和 realm 在语法上是简单字符串, 在语义上是简单的用户名 [RFC4013] 和 realm 值. 这些值不是 LDAP DN, 并且没有要求把它们表示或当作 LDAP DN 来对待.

5.2.3 SASL EXTERNAL 认证机制 (SASL EXTERNAL Authentication Mechanism)​

客户端可以使用 SASL EXTERNAL ([RFC4422] 附录 A) 机制, 请求 LDAP 服务器使用较低安全层交换的安全凭证 (例如通过 TLS 认证) 来进行认证并建立由此产生的授权身份. 如果客户端的认证凭证尚未在较低安全层建立, SASL EXTERNAL Bind 必须以 inappropriateAuthentication 结果码失败. 虽然这种情况的效果是把 LDAP 会话留在匿名状态 (第 4 节), 但任何已安装安全层的状态不受影响.

客户端可以请求其授权身份从较低安全层交换的认证凭证自动推导得出, 也可以显式提供一个所期望的授权身份. 前者称为隐式断言 (implicit assertion), 后者称为显式断言 (explicit assertion).

5.2.3.1 隐式断言 (Implicit Assertion)​

隐式授权身份断言通过调用一个使用 EXTERNAL 机制名, 且不包含可选 credentials 字段 (位于 BindRequest 的 SaslCredentials 序列中) 的 SASL 形式 Bind 请求来执行. 服务器将根据本地策略, 从安全层 (例如 TLS 层安装期间使用的公钥证书) 提供的认证身份推导出客户端的授权身份. 实现这一点的底层机制是实现特定的.

5.2.3.2 显式断言 (Explicit Assertion)​

显式授权身份断言通过调用一个使用 EXTERNAL 机制名, 且包含 credentials 字段 (位于 BindRequest 的 SaslCredentials 序列中) 的 SASL 形式 Bind 请求来执行. credentials 字段的值 (一个 OCTET STRING) 就是所断言的授权身份, 并且必须按第 5.2.1.8 节的文档构造.