引文:
调试GLOOX 1.0.10的注册功能颇费了一些功夫。总体逻辑如GLOOX自带的例子一样是毫无疑问的,但是照搬例子又是不能完成注册的,返回错误码为4------RegistrationBadRequest。笔者一开始在网上狂搜解决方案,资料少之又少,有建议重写Client::handleNormalNode函数(目的是禁止SASL认证)的,有直接继承Client重写Client::handleNormalNode函数的,但都没说到点子上。经过一段时间的研究,在GLOOX的maillist上得到启发,顺利完成注册。现将解决方案记录下来:
环境
客户端:GLOOX1.0.1.0 VS2008
服务器:OPENFIRE 默认安装
对于GLOOX自带的注册例子不能正常注册的问题有人在邮件列表里提出来。一个哥们这样回答:
Ok, I've found what the problem was
In openFire server parameters, Anonymous Login => Disabled !!!
意思是要禁用openFire服务器里的选项”注册和登录“的”匿名登录“项。笔者按此说明禁用该选项,果然注册成功。
这说明开始的注册失败是和匿名登录有关系的。我们来看一下引用registration_expmple例子登录失败时的XML流:
S->C:服务器返回给客户端支持的认证机制:
<stream:features xmlns:stream='http://etherx.jabber.org/streams'><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>DIGEST-MD5</mechanism><mechanism>PLAIN</mechanism><mechanism>ANONYMOUS</mechanism><mechanism>CRAM-MD5</mechanism></mechanisms><compression xmlns='http://jabber.org/features/compress'><method>zlib</method></compression><auth xmlns='http://jabber.org/features/iq-auth'/><register xmlns='http://jabber.org/features/iq-register'/></stream:features>
从上面XML流中我们可以看到,默认openFire支持四种认证机制,分别是:DIGEST-MD5、PLAIN、ANONYMOUS、CRAM-MD5。然后我们看GLOOX客户端的响应流:
C->S:客户端返回选择的认证方式:
<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='ANONYMOUS'/>
可以看出,客户端”无耻“的选择了”匿名“--'ANONYMOUS'方式接下来的流程就是客户端”无耻“的选择了以匿名的方式登录了服务器,然后再发送注册请求,请求如下:
<iq id='uid:4e69eccd:00006784' type='set' from='447e0585@zxl/447e0585' xmlns='jabber:client'><query xmlns='jabber:iq:register'><username>bbaxiao</username><password>123456</password><name>test2</name><email>163@gmail.com</email></query></iq>
我们看到,IQ节里包含“form”属性,即客户端匿名身份标识。
注意,一个客户端已经以一个身份(由服务器临时分配的一个JID)登录,建立了会话,在服务器上我们会看到这个会话,并且服务器发送心跳一直维护这个会话。这种情况下,这个客户端再发送注册请求(另一个身份)建立与服务器的连接是不被允许的。具体请参考XEP-0077(In-Band Registration):我们关注这两段:
If the entity cancels its registration with its "home" server (i.e., the server at which it has maintained its XMPP account), then the entity SHOULD NOT include a 'from' or 'to' address in the remove request the server SHOULD then return a <not-authorized/> stream error and terminate all active sessions for the entity. The server SHOULD perform the remove based on the bare JID <localpart@domain.tld> associated with the current session or connection over which it received the remove request. If the server is an instant messaging and presence server that conforms to XMPP IM [8], the server SHOULD also cancel all existing presence subscriptions related to that entity (as stored in the entity's roster).
If the entity cancels its registration with a service other than its home server, its home server MUST stamp a 'from' address on the remove request, which in accordance with XMPP Core will be the entity's full JID <localpart@domain.tld/resource>. The service MUST perform the remove based on the bare JID <localpart@domain.tld> portion of the 'from' address.
If the entity cancels its registration with its "home" server (i.e., the server at which it has maintained its XMPP account), then the entity SHOULD NOT include a 'from' or 'to' address in the remove request the server SHOULD then return a <not-authorized/> stream error and terminate all active sessions for the entity. The server SHOULD perform the remove based on the bare JID <localpart@domain.tld> associated with the current session or connection over which it received the remove request. If the server is an instant messaging and presence server that conforms to XMPP IM [8], the server SHOULD also cancel all existing presence subscriptions related to that entity (as stored in the entity's roster).
If the entity cancels its registration with a service other than its home server, its home server MUST stamp a 'from' address on the remove request, which in accordance with XMPP Core will be the entity's full JID <localpart@domain.tld/resource>. The service MUST perform the remove based on the bare JID <localpart@domain.tld> portion of the 'from' address.
意思是说注册请求不能包含“from”属性。正常的注册流如下:
<iq id='uid:4e69eccd:00003d6c' type='set' xmlns='jabber:client'><query xmlns='jabber:iq:register'><username>bbaxiao</username><password>123456</password><name>test2</name><email>163@gmail.com</email></query></iq>
---------------------------
综上所述,解决方案如下:
一、关闭openFire的匿名登录功能。^_^……
二、禁止GLOOX匿名认证功能。
file:client.cpp
fun: int Client::getSaslMechs( Tag* tag )
line:423
//将423行注释掉即可。
422:if( tag->hasChildWithCData( mech, "ANONYMOUS" ) )
423 //mechs |= SaslMechAnonymous;
重新编译生成DLL即可。三、手动设置GLOOX客户端SASL认证机制
在调用j->connect()之前设置SASL认证机制,比如设置为“DIGEST-MD5”
j->setSASLMechanisms(SaslMechDigestMd5);
这种方式的缺点是需要先确定服务器支持的认证机制。四、根据XEP-0077所述,即使其名登录,注册流只要不带“from”属性应该也可以。所以我们要处理发出的注册流,去除“from”属性重新发送注册流即可。
本文转自:http://blog.csdn.net/abcpanpeng/article/details/7370974
posted on 2014-08-28 17:59
王海光 阅读(1519)
评论(0) 编辑 收藏 引用 所属分类:
Openfire&Gloox