XMPP翻译:RFC 3920[5](Chapter6-7)

 本篇翻译了XMPP核心协议RFC 3920的第六、七章。内容为简单验证和安全层的应用及资源绑定。

内容提示:

  • Use of SASL //简单验证和安全层的应用
    1. Overview //概述
    2. Narrative //详述
    3. SASL //定义
    4. SASL //错误
    5. Client-to-Server Example //客户端到服务器的例子
    6. Server-to-Server Example //服务器到服务器的例子
  • Resource Binding //资源绑定

6.1. 概述

XMPP包含一个用于认证流的方法,该方法依靠一个特定于XMPP的SASL协议的profile。SASL提供了一个通用的方法,用于给基于连接的协议添加认证支持,而XMPP为SASL使用了一个通用的XML命名空间profile,其与SASL的profile的必要条件相一致。

应用以下规则:

  1. 如果SASL协商发生在两个服务器之间,通信不能(MUST NOT)继续,直到服务器所持有的DNS主机名被确定(参见14.4.节: 服务器到服务器通信)。
  2. 如果初始实体能够进行SASL协商,它必须(MUST)在初始流header中包含一个值至少设置为“1.0”的‘version’属性。
  3. 如果接收实体能够进行SASL协商,在回应从初始实体发来的开的流标识的流中,它必须(MUST)在一个<mechanisms/>元素中注册一个或多个认证机制,该<mechanisms/>元素在‘urn:ietf:params:xml:ns:xmpp-sasl’命名空间下。
  4. 在SASL协商期间,实体不能(MUST NOT)在流的根元素间发送任何空字符(matching production [3] content of XML)来作为元素的间隔(在后面的TLS例子中出现的任何空字符只是为了可读性);这个禁令有助于确保彻底的安全层的字节精确度。
  5. 在SASL协商期间使用的XML元素中所包含的任何XML字符数据必须(MUST)使用base64进行编码,其中的编码技术在RFC 3548[BASE64]第3部分的定义中。
  6. 如果被选的SASL机制支持“simple username”这样的(例如,DIGEST-MD5和CRAM-MD5机制支持,而EXTERNAL和GSSAPI机制不支持),在认证期间,初始实体应该(SHOULD)提供在S/S通信的情况中作为发送域(IP地址或包含于域标识符中的完全限定的域名)的简单用户名,或者在C/S通信的情况中它所注册的帐户名(一个XMPP节点标识符中包含的用户名或节点名)。
  7. 如果初始实体希望代表另一个实体起作用,且所选择的SASL机制能够支持对一个授权实体的的转播,初始实体必须(MUST)在SASL协商期间提供一个授权实体。如果初始实体没想要代表其他实体起作用,它禁止(MUST NOT)提供一个授权实体。正如SASL中定义的,初始实体禁止(MUST NOT)体噢能够一个授权实体,除非此授权实体与由授权实体衍生而来的默认实体不同(在SASL中有描述)。如果提供了,授权实体的值必须(MUST)在服务器那为<domain>(即只有一个域标识符)的形式,在客户端那为<node@domain>(即节点标识符和域标识符)。
  8. 在包含了一个安全层协商的SASL协商的成功后,接收实体必须(MUST)丢弃任何从初始实体获得的,而并非SASL协商本身所获得的信息。
  9. 在包含了一个安全层协商的SASL协商的成功后,初始实体必须(MUST)丢弃任何从接收实体获得的,而并非SASL协商本身所获得的信息。
  10. 参见14.7节(执行托管技术)中有关必须提供的一些(MUST)机制。

 

6.2. 详述

当一个初始实体与一个接收实体使用SASL进行认证,相关的步骤如下:
  1. 初始实体通过在发送到接收实体的开的XML流header中包含一个值为“1.0”的‘version’属性来请求SASL认证。
  2. 在发送了一个回应的XML流header后,接收实体注册了一列可用的SASL认证机制;每个都是一个被<mechanisms/>容器元素作为子元素包含的<mechanism/>元素,这个容器元素命名空间为‘urn:ietf:params:xml:ns:xmpp-sasl’,在流命名空间里的次序上是一个<features/>元素的子元素。如果在可能使用某个特定的认证机制前,需要配置好TLS的使用,接收实体禁止(MUST NOT)在TLS制定前,规定可用的SASL认证机制列表中的那些机制。如果初始实体在优先制定TLS协商期间给出了一个有效的证书,接收实体应该(SHOULD)在SASL协商期间,提供SASL EXTERNAL机制给初始实体(参考SASL),即使EXTERNAL机制也可能(MAY)在其他情况下被给出。
  3. 初始实体通过发送一个在‘urn:ietf:params:xml:ns:xmpp-sasl’ 命名空间下的<auth/>元素给接收实体以及包含一个一个适当的‘mechanism’属性值来选择一个机制。如果机制支持或需要,这个元素可以包含XML字符数据(在SASL术语中叫‘initial response’);如果初始实体需要发送一个0长度的初始响应 ,它必须(MUST)把响应作为一个相等符“=”传输,这样可以表明响应出席了,但是没有带数据。
  4. 如果必需的话,接收实体通过发送一个‘urn:ietf:params:xml:ns:xmpp-sasl’命名空间下的<challenge/>元素给初始实体来召唤(challenge)初始实体;这个元素可以(MAY)包含字符数据(必须(MUST)确定与初始实体选择的SASL机制的定义相一致)。
  5. 初始实体通过发送一个在‘urn:ietf:params:xml:ns:xmpp-sasl’命名空间下的<response/>元素给接收实体来回应这个召唤;这个元素可以(MAY)包含字符数据(必须(MUST)确定与初始实体选择的SASL机制的定义相一致)。
  6. 如果必需的话,接收实体发送更多的召唤,而初始实体则发送更多的回应。

这个召唤/回应对的系列一直持续到下面事件之一发生:

  1. 初始实体通过发送一个在‘urn:ietf:params:xml:ns:xmpp-sasl’命名空间下的<abort/>元素给接收实体来中断这个握手(handshake)。在接收到一个<abort/>元素后,接收实体应该(SHOULD)允许一个可配置且合理的重试次数(至少为2),之后它必须(MUST)终止TCP连接;这样使初始实体能够不用被迫去重新连接,而容忍被错误提供的凭证(例如,一个输错的密码)。
  2. 接收实体通过发送一个在‘urn:ietf:params:xml:ns:xmpp-sasl’命名空间下的<failure/>元素给初始实体来报告握手失败(特定的失败原因应该(SHOULD)在<failure/>元素的一个适当的子节点中传达,定义在SASL Errors中)。如果错误的情况发生,接收实体应该(SHOULD)允许一个可配置且合理的重试次数(至少为2),之后它必须(MUST)终止TCP连接;这样使初始实体(如,一个目标用户客户端)能够不用被迫去重新连接,而容忍被错误提供的凭证(例如,一个输错的密码)。
  3. 接收实体通过发送一个在‘urn:ietf:params:xml:ns:xmpp-sasl’命名空间下的<success/>元素给初始实体来报告握手成功;如果被选择的SASL机制需要,这个元素可以(MAY)包含XML字符数据(在SASL术语中,叫作“additional data with success”)。在接收到<success/>元素后,初始实体必须(MUST)初始化一个新流,通过发送一个开的XML流header给接收实体(没必要先发送一个闭的</stream>标识,因为接收实体与发送实体必须(MUST)考虑初始流在发送或接收了<success/>元素后再关闭)。在接收到了来自初始实体的新的流header,接收实体必须(MUST)通过发送一个新的XML流header给初始实体来响应,连同任何可用的特性(不包括STARTLLS和SASL特性)或一个空的<features/>元素(指明没有附加的特性可用);任何这里没有定义的附加特性,必须(MUST)由XMPP相关的扩展定义。

 

6.3. SASL定义

 SASL要求必备的压型(profiling)要求协议的定义提供以下信息:
服务名称: 
"xmpp"
初始顺序:
在初始实体发送了一个开的XML流header且接收实体也这样回应之后,接收实体给出一个可接受的认证方法的列表。初始实体从列表中选择一个方法,把它作为<auth/>元素的‘mechanism’属性的值发送给接收实体 ,可选的包含一个初始响应以避免往返的传送(round trip)。
交换顺序: 
召唤和响应通过接收实体到初始实体的<challenge/>元素和初始实体到接收实体的<response/>元素的交换携带。接收实体通过发送<failure/>元素报告错误,发送<success/> 元素报告成功;初始实体通过发送<abort/>元素中断交换。成功的协商后,双方认为初始XML流已经关闭,两个实体发送新的XML流header。
安全层协商:
安全层在给接受实体发送了<success/>元素的闭字符“>”后立即生效,也在给初始实体发送了<success/>元素的闭字符“>”后立即生效。层的次序是先TCP,然后TLS,接着SASL,再是XMPP。
使用认证标识符:
认证 标识符可能被XMPP用于指示一个客户端的非默认<node@domain>,或一个服务器发送的<domain>。

6.4. SASL错误

以下定义了SASL相关的错误因素:
  • <aborted/> -- 接收实体肯定应答由初始实体发来的<abort/>元素;给<abort/>元素发送响应。
  • <incorrect-encoding/> -- 初始实体提供的数据由于BASE64编码错误而处理不了(如,编码不符合BASE64的规范);给一个<response/>元素或一个<auth/>元素发送带有初始响应数据的回复。
  • <invalid-authzid/> -- 初始实体提供的的authzid无效,或者因为它被错误的格式化或者因为初始实体没有权限授权此ID;给一个<response/>元素或一个<auth/>元素发送带有初始响应数据的回复。
  • <invalid-mechanism/> -- 初始实体未提供机制或请求到一个不被接受实体支持的机制;发送回复给<auth/>元素。
  • <mechanism-too-weak/> - 初始实体请求的机制比服务器策略允许的弱;给一个<response/>元素或一个<auth/>元素发送带有初始响应数据的回复。
  • <not-authorized/> -- 由于初始实体未提供有效凭证(包含但不局限于未知用户名的情况),认证失败;给一个<response/>元素或一个<auth/>元素发送带有初始响应数据的回复。
  • <temporary-auth-failure/> -- 由于接受实体内临时性的错误因素使得认证失败;给一个<response/>元素或一个<auth/>元素发送回复。

 

6.5. C/S 的例子

下面的例子展示了一个客户端与一个服务器用SASL认证的数据流,通常在成功的TLS协商后(注意:下面交叉的步骤用于阐述失败情况下的协议;它们不是很详尽,且不是必需是例子中传送的数据引发的)。

Step 1: 客户端向服务器初始化流:

<stream:stream
xmlns='jabber:client'
xmlns:stream='http://etherx.jabber.org/streams'
to='example.com'
version='1.0'>

Step 2: 服务器响应,通过发送一个流标识客户端:

<stream:stream
xmlns='jabber:client'
xmlns:stream='http://etherx.jabber.org/streams'
id='c2s_234'
from='example.com'
version='1.0'>

Step 3: 服务器告知客户端可用的认证机制:

<stream:features>
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
<mechanism>DIGEST-MD5</mechanism>
<mechanism>PLAIN</mechanism>
</mechanisms>
</stream:features>

Step 4: 客户端选择一个认证机制:

<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl'
mechanism='DIGEST-MD5'/>

Step 5: 服务器发送一个以BASE64编码的召唤给客户端:

<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
cmVhbG09InNvbWVyZWFsbSIsbm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixxb3A9ImF1dGgi
LGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNzCg==
</challenge>

解码后的召唤是:

realm="somerealm",nonce="OA6MG9tEQGm2hh",\
qop="auth",charset=utf-8,algorithm=md5-sess

Step 5 (alt): 服务器返回错误到客户端:

<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
<incorrect-encoding/>
</failure>
</stream:stream>

Step 6: 客户端发送以BASE64编码的响应给召唤:

<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
dXNlcm5hbWU9InNvbWVub2RlIixyZWFsbT0ic29tZXJlYWxtIixub25jZT0i
T0E2TUc5dEVRR20yaGgiLGNub25jZT0iT0E2TUhYaDZWcVRyUmsiLG5jPTAw
MDAwMDAxLHFvcD1hdXRoLGRpZ2VzdC11cmk9InhtcHAvZXhhbXBsZS5jb20i
LHJlc3BvbnNlPWQzODhkYWQ5MGQ0YmJkNzYwYTE1MjMyMWYyMTQzYWY3LGNo
YXJzZXQ9dXRmLTgK
</response>

解码后的响应是:

username="somenode",realm="somerealm",\
nonce="OA6MG9tEQGm2hh",cnonce="OA6MHXh6VqTrRk",\
nc=00000001,qop=auth,digest-uri="xmpp/example.com",\
response=d388dad90d4bbd760a152321f2143af7,charset=utf-8

Step 7: 服务器发送又一个以BASE64编码的召唤给客户端:

<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZAo=
</challenge>

解码后的召唤是:

rspauth=ea40f60335c427b5527b84dbabcdfffd

Step 7 (alt): 服务器返回错误到客户端:

<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
<temporary-auth-failure/>
</failure>
</stream:stream>

Step 8: 客户端发送响应给召唤:

<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>

Step 9: 服务器告知客户端认证成功:

<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>

Step 9 (alt): 服务器告知客户端认证失败:

<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
<temporary-auth-failure/>
</failure>
</stream:stream>

Step 10: 客户端初始化一个新的流到服务器:

<stream:stream
xmlns='jabber:client'
xmlns:stream='http://etherx.jabber.org/streams'
to='example.com'
version='1.0'>

Step 11: 服务器通过发送一个流header,连同任何附加特性(或者一个空的特性元素)到客户端来响应:

<stream:stream
xmlns='jabber:client'
xmlns:stream='http://etherx.jabber.org/streams'
id='c2s_345'
from='example.com'
version='1.0'>
<stream:features>
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>
<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>
</stream:features>

 

6.6.  S/S 的例子

下面的例子展示了一个服务器与另一个服务器用SASL认证的数据流,通常在成功的TLS协商后(注意:下面交叉的步骤用于阐述失败情况下的协议;它们不是很详尽,且不是必需是例子中传送的数据引发的)。

Step 1: 服务器1向服务器2初始化流:

<stream:stream
xmlns='jabber:server'
xmlns:stream='http://etherx.jabber.org/streams'
to='example.com'
version='1.0'>

Step 2: 服务器2响应,通过发送一个流标识服务器1:

<stream:stream
xmlns='jabber:server'
xmlns:stream='http://etherx.jabber.org/streams'
from='example.com'
id='s2s_234'
version='1.0'>

Step 3: 服务器2告知服务器1可用的认证机制:

<stream:features>
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
<mechanism>DIGEST-MD5</mechanism>
<mechanism>KERBEROS_V4</mechanism>
</mechanisms>
</stream:features>

Step 4: 服务器1选择一个认证机制:

<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl'
mechanism='DIGEST-MD5'/>

Step 5: 服务器2发送一个以BASE64编码的召唤给服务器1:

<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
cmVhbG09InNvbWVyZWFsbSIsbm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixxb3A9
ImF1dGgiLGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz
</challenge>

解码后的召唤是:

realm="somerealm",nonce="OA6MG9tEQGm2hh",\
qop="auth",charset=utf-8,algorithm=md5-sess

Step 5 (alt): 服务器2返回错误到服务器1:

<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
<incorrect-encoding/>
</failure>
</stream:stream>

Step 6: 服务器1发送以BASE64编码的响应给召唤:

<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
dXNlcm5hbWU9ImV4YW1wbGUub3JnIixyZWFsbT0ic29tZXJlYWxtIixub25j
ZT0iT0E2TUc5dEVRR20yaGgiLGNub25jZT0iT0E2TUhYaDZWcVRyUmsiLG5j
PTAwMDAwMDAxLHFvcD1hdXRoLGRpZ2VzdC11cmk9InhtcHAvZXhhbXBsZS5v
cmciLHJlc3BvbnNlPWQzODhkYWQ5MGQ0YmJkNzYwYTE1MjMyMWYyMTQzYWY3
LGNoYXJzZXQ9dXRmLTgK
</response>

解码后的响应是:

username="example.org",realm="somerealm",\
nonce="OA6MG9tEQGm2hh",cnonce="OA6MHXh6VqTrRk",\
nc=00000001,qop=auth,digest-uri="xmpp/example.org",\
response=d388dad90d4bbd760a152321f2143af7,charset=utf-8

Step 7: 服务器2发送又一个以BASE64编码的召唤给服务器1:

<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZAo=
</challenge>

解码后的召唤是:

rspauth=ea40f60335c427b5527b84dbabcdfffd

Step 7 (alt): 服务器2返回错误到服务器1:

<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
<invalid-authzid/>
</failure>
</stream:stream>

Step 8: 服务器1发送响应给召唤:

<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>

Step 8 (alt): 服务器1 中断协商:

<abort xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>

Step 9: 服务器2告知服务器1认证成功:

<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>

Step 9 (alt): 服务器2告知服务器1认证失败:

<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
<aborted/>
</failure>
</stream:stream>

Step 10: 服务器1初始化一个新的流到服务器2:

<stream:stream
xmlns='jabber:server'
xmlns:stream='http://etherx.jabber.org/streams'
to='example.com'
version='1.0'>

Step 11: 服务器2通过发送一个流header,连同任何附加特性(或者一个空的特性元素)到服务器1来响应:

<stream:stream
xmlns='jabber:server'
xmlns:stream='http://etherx.jabber.org/streams'
from='example.com'
id='s2s_345'
version='1.0'>
<stream:features/>
 
 

7.  资源绑定

在与接收实体SASL协商后,初始实体可能(MAY)想或需要绑定一个特定的资源到流。通常这只应用于客户端:为了与编址格式及这里指定的节传输规则相一致,这儿必须(MUST)有一个与客户端的<node@domain>相关的资源标识符(由服务器产生或由客户端应用程序提供);这确保了流中使用的地址是一个<node@domain/resource>形式的“完全的JID”。

在接收到SASL协商中的成功指示后,客户端必须(MUST)发送一个新的流header到服务器,服务器则必须(MUST)响应一个流header及一个可用的流特性列表到客户端。特别是,如果服务器需要客户端在成功的SASL协商后绑定一个资源到流,该服务器必须(MUST)包含一个空的在‘urn:ietf:params:xml:ns:xmpp-bind’命名空间下的<bind/>元素于它呈现给可户端的流特性列表中,此列表是在SASL协商成功后在发送了响应流中的流header后(不是之前)呈现的:

服务器注册资源绑定特性到客户端:

<stream:stream
xmlns='jabber:client'
xmlns:stream='http://etherx.jabber.org/streams'
id='c2s_345'
from='example.com'
version='1.0'>
<stream:features>
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>
</stream:features>

在这样被告知需要绑定资源后,客户端必须(MUST)绑定一个资源到流,通过发送给服务器一个type为“set”的IQ节,它包含在‘urn:ietf:params:xml:ns:xmpp-bind'’命名空间下的数据。

如果客户端希望让服务器为它生成资源标识符,它发送一个type为“set”的IQ节,包含一个空的<bind/>元素:

客户端请求服务器绑定资源:

<iq type='set' id='bind_1'>
  <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>
</iq>

一个支持资源绑定的服务器必须(MUST)能够为客户端生成一个资源标识符。一个由服务器生成的资源标识符必须(MUST)唯一,以<node@domain>这样的形式 。

如果客户端希望指定资源标识符,它发送一个type为“set”的IQ节,包含期望的资源标识符作为一个<resource/>元素的XML字符数据,该<resource/>元素是<bind/>元素的子元素:

客户端绑定一个资源:

<iq type='set' id='bind_2'>
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>
<resource>someresource</resource>
</bind>
</iq>

一旦服务器为客户端生成一个资源标识符,或是接受了客户端提供的资源标识符,它必须(MUST)返回一个type为“result”的IQ节到客户端,此IQ节必须(MUST)包含一个<jid/>子元素,用于为服务器决定的已连接资源指定完全的JID:

服务器告知客户端成功绑定资源:

<iq type='result' id='bind_2'>
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>
<jid>somenode@example.com/someresource</jid>
</bind>
</iq>

一个服务器应该(SHOULD)接受客户端提供的资源标识符,但是可以(MAY)用一个服务器生成的资源标识符重写它;在这种情况下,服务器不应该(SHOULD NOT)返回一个节错误(例如,<forbidden/>)到客户端,但是却应该(SHOULD)在上面展示的IQ结果中传达生成的资源标识符给客户端。

当一个客户端提供一个资源标识符,以下的节错误可能存在(参见节错误):

  • 服务器依照Resourceprep处理不了所提供的资源标识符。
  • 客户端不允许绑定资源到流(例如,节点或用户达到了允许连接的资源数量的限度)。
  • 所提供的资源标识符已经在使用,但是服务器不允许用相同的标识符绑定多个连接的资源。

这些错误因素的协议展示如下:

处理不了资源标识符:

<iq type='error' id='bind_2'>
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>
<resource>someresource</resource>
</bind>
<error type='modify'>
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>

不允许客户端绑定资源:

<iq type='error' id='bind_2'>
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>
<resource>someresource</resource>
</bind>
<error type='cancel'>
<not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>

使用到了资源标识符:

<iq type='error' id='bind_2'>
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>
<resource>someresource</resource>
</bind>
<error type='cancel'>
<conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>

如果,在完成资源绑定步骤之前,可户端尝试发送一个不同于IQ节的,带有在‘urn:ietf:params:xml:ns:xmpp-bind’命名空间下的<bind/>子节点的XML节,服务器禁止(MUST NOT)处理这个节且应该(SHOULD)返回一个<not-authorized/>节错误到客户端。

 

XMPP翻译:RFC 3920[5]到此结束,请继续关注 XMPP翻译:RFC 3920[6]
posted on 2006-11-10 18:39  Hunts.C  阅读(2740)  评论(0编辑  收藏  举报