Jabberd/XMPP 学习之八:客户端-服务器示例

来源:互联网 发布:fm2017随机人头像优化 编辑:程序博客网 时间:2024/05/25 23:27

以下例子展示客户端和服务器协商XML流, 交换XML节, 和关闭已协商的流的XMPP数据流. 服务器是"im.example.com", 该服务器要求使用TLS, 客户端验证使用SASL SCRAM-SHA-1机制,客户端帐号是<juliet@im.example.com>而密码是"r0m30myr0m30", 并且客户端在这个流上提交了一个资源绑定请求. 我们假设在发送初始化流头之前, 客户端已经解析了_xmpp‑client._tcp.im.example.com的SRV记录并已经打开一个TCP连接到已解析的IP地址和声明的端口上.

TLS

第一步: 客户端初始化流到服务器:

C: <stream:stream     from='juliet@im.example.com'     to='im.example.com'     version='1.0'     xml:lang='en'     xmlns='jabber:client'     xmlns:stream='http://etherx.jabber.org/streams'>

第二步: 服务器发送一个应答流头给客户端来应答:

S: <stream:stream     from='im.example.com'     id='t7AMCin9zjMNwQKDnplntZPIDEI='     to='juliet@im.example.com'     version='1.0'     xml:lang='en'     xmlns='jabber:client'     xmlns:stream='http://etherx.jabber.org/streams'>

第三步: 服务器发送流特性给客户端(在这个点上只有STARTTLS扩展, 它是强制协商的):

S: <stream:features>     <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'>       <required/>     </starttls>   </stream:features>

第四步: 客户端发送STARTTLS命令给服务器:

C: <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>

第五步: 服务器通知客户端允许继续:

S: <proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>

第五步(替代): 服务器通知客户端STARTTLS协商失败, 关闭XML流, 并中止TCP连接(所以, 流协商处理以不成功而结束并且双方不再进入下一步):

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

第六步: 客户端和服务器尝试通过现有的TCP连接完成TLS协商(详见TLS).

第七步: 如果TLS协商成功, 客户端通过TLS保护的TCP连接初始化一个新的流到服务器:

C: <stream:stream     from='juliet@im.example.com'     to='im.example.com'     version='1.0'     xml:lang='en'     xmlns='jabber:client'     xmlns:stream='http://etherx.jabber.org/streams'>

第七步(替代): 如果TLS协商不成功, 服务器关闭TCP连接(所以, 流协商处理以不成功而结束并且双方不再进入下一步):

SASL

第八步: 服务器发送流头给客户端并带上任何可用的流特性来应答:

S: <stream:stream     from='im.example.com'     id='vgKi/bkYME8OAj4rlXMkpucAqe4='     to='juliet@im.example.com'     version='1.0'     xml:lang='en'     xmlns='jabber:client'     xmlns:stream='http://etherx.jabber.org/streams'> S: <stream:features>     <mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>       <mechanism>SCRAM-SHA-1-PLUS</mechanism>       <mechanism>SCRAM-SHA-1</mechanism>       <mechanism>PLAIN</mechanism>     </mechanisms>   </stream:features>

第九步: 客户端选择一个验证机制(在这个场景中, 是 SCRAM-SHA-1), 包含初始化应答数据:

C: <auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl"         mechanism="SCRAM-SHA-1">     biwsbj1qdWxpZXQscj1vTXNUQUF3QUFBQU1BQUFBTlAwVEFBQUFBQUJQVTBBQQ==   </auth>

解码之后的 base 64 数据是 "n,,n=juliet,r=oMsTAAwAAAAMAAAANP0TAAAAAABPU0AA".

第十步: 服务器发送挑战:

S: <challenge xmlns="urn:ietf:params:xml:ns:xmpp-sasl">     cj1vTXNUQUF3QUFBQU1BQUFBTlAwVEFBQUFBQUJQVTBBQWUxMjQ2OTViLTY5Y     TktNGRlNi05YzMwLWI1MWIzODA4YzU5ZSxzPU5qaGtZVE0wTURndE5HWTBaaT     AwTmpkbUxUa3hNbVV0TkRsbU5UTm1ORE5rTURNeixpPTQwOTY=   </challenge>

解码后的 base 64 数据是 "r=oMsTAAwAAAAMAAAANP0TAAAAAABPU0AAe124695b-69a9-4de6-9c30-b51b3808c59e,s=NjhkYTM0MDgtNGY0Zi00NjdmLTkxMmUtNDlmNTNmNDNkMDMz,i=4096" (实际数据中是没有换行的).

第十一步: 客户端发送一个应答:

C: <response xmlns="urn:ietf:params:xml:ns:xmpp-sasl">     Yz1iaXdzLHI9b01zVEFBd0FBQUFNQUFBQU5QMFRBQUFBQUFCUFUwQUFlMTI0N     jk1Yi02OWE5LTRkZTYtOWMzMC1iNTFiMzgwOGM1OWUscD1VQTU3dE0vU3ZwQV     RCa0gyRlhzMFdEWHZKWXc9   </response>

解码后的 base 64 数据是 "c=biws,r=oMsTAAwAAAAMAAAANP0TAAAAAABPU0 AAe124695b-69a9-4de6-9c30-b51b3808c59e,p=UA57tM/ SvpATBkH2FXs0WDXvJYw=" (实际数据中是没有换行的).

第十二步: 服务器通知客户端成功了, 并且包含了额外的数据:

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

解码后的 base 64 数据是 "v=pNNDFVEQxuXxCoSEiW8GEZ+1RSo=".

第十二步(替代): 服务器返回一个SASL错误给客户端(所以, 流协商处理以不成功结束并且双方不再进行下一步):

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

第十三步: 客户端初始化一个新的流到服务器:

C: <stream:stream     from='juliet@im.example.com'     to='im.example.com'     version='1.0'     xml:lang='en'     xmlns='jabber:client'     xmlns:stream='http://etherx.jabber.org/streams'>

资源绑定

第十四步: 服务器发送一个流头到客户端并带上支持的特性(在这个场景中, 是资源绑定)来应答:

S: <stream:stream     from='im.example.com'     id='gPybzaOzBmaADgxKXu9UClbprp0='     to='juliet@im.example.com'     version='1.0'     xml:lang='en'     xmlns='jabber:client'     xmlns:stream='http://etherx.jabber.org/streams'> S: <stream:features>     <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>   </stream:features>

在被通知资源绑定是强制协商之后, 客户端需要绑定一个资源到流; 这里我们假定客户端提交了一个自然人可读的文本字符串.

第十五步: 客户端绑定一个资源:

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

第十六步: 服务器接受提交的资源部分并通知客户端资源绑定成功:

S: <iq id='yhc13a95' type='result'>     <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>       <jid>         juliet@im.example.com/balcony       </jid>     </bind>   </iq>

第十六步(替代): 服务器返回错误给客户端(所以, 流协商处理以不成功结束并且双方不再进入下一步):

S: <iq id='yhc13a95' type='error'>     <error type='cancel'>       <conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>     </error>   </iq>

节交换

现在客户端被允许通过协商好的流发送XML节了.

C: <message from='juliet@im.example.com/balcony'            id='ju2ba41c'            to='romeo@example.net'            type='chat'            xml:lang='en'>     <body>Art thou not Romeo, and a Montague?</body>   </message>

如果必要, 发送者的服务器和预定的接收者的服务器协商XML流(见9.2).

预定的接收者应答, 并且消息被递送到客户端.

E: <message from='romeo@example.net/orchard'            id='ju2ba41c'            to='juliet@im.example.com/balcony'            type='chat'            xml:lang='en'>     <body>Neither, fair saint, if either thee dislike.</body>   </message>

客户端随后可以通过这个流继续发送和接收不限数量的XML节.

关闭

不想发送更多的消息, 客户端关闭它到服务器的流,不在等待来自服务器的入站数据了.

C: </stream:stream>

和4.4一致, 服务器可能发送额外的数据给客户端然后才关闭到该客户端的流.

S: </stream:stream>

客户端现在发送一个 TLS close_notify 警告, 从服务器接收到一个 close_notify 警告应答, 然后中止当前的TCP连接.


转自:http://wiki.jabbercn.org/RFC6120

0 0