引文:
調(diào)試GLOOX 1.0的注冊(cè)功能頗費(fèi)了一些功夫??傮w邏輯如GLOOX自帶的例子一樣是毫無(wú)疑問(wèn)的,但是照搬例子又是不能完成注冊(cè)的,返回錯(cuò)誤碼為4------RegistrationBadRequest。筆者一開(kāi)始在網(wǎng)上狂搜解決方案,資料少之又少,有建議重寫(xiě)Client::handleNormalNode函數(shù)(目的是禁止SASL認(rèn)證)的,有直接繼承Client重寫(xiě)Client::handleNormalNode函數(shù)的,但都沒(méi)說(shuō)到點(diǎn)子上。經(jīng)過(guò)一段時(shí)間的研究,在GLOOX的maillist上得到啟發(fā),順利完成注冊(cè)?,F(xiàn)將解決方案記錄下來(lái):
環(huán)境
客戶端:GLOOX1.0 VS2008
服務(wù)器:OPENFIRE 默認(rèn)安裝
對(duì)于GLOOX自帶的注冊(cè)例子不能正常注冊(cè)的問(wèn)題有人在郵件列表里提出來(lái)。一個(gè)哥們這樣回答:
- Ok, I've found what the problem was
- In openFire server parameters, Anonymous Login => Disabled !!!
意思是要
禁用openFire服務(wù)器里的選項(xiàng)”注冊(cè)和登錄“的”匿名登錄“項(xiàng)。
筆者按此說(shuō)明禁用該選項(xiàng),果然注冊(cè)成功。
這說(shuō)明開(kāi)始的注冊(cè)失敗是和匿名登錄有關(guān)系的。我們來(lái)看一下引用registration_expmple例子登錄失敗時(shí)的XML流:
S->C:服務(wù)器返回給客戶端支持的認(rèn)證機(jī)制:
- <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流中我們可以看到,默認(rèn)openFire支持四種認(rèn)證機(jī)制,分別是:DIGEST-MD5、PLAIN、ANONYMOUS、CRAM-MD5。然后我們看GLOOX客戶端的響應(yīng)流:
C->S:客戶端返回選擇的認(rèn)證方式:
- <auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='ANONYMOUS'/>
可以看出,客戶端”無(wú)恥“的選擇了”匿名“--
'ANONYMOUS'方式接下來(lái)的流程就是客戶端”無(wú)恥“的選擇了以匿名的方式登錄了服務(wù)器,然后再發(fā)送注冊(cè)請(qǐng)求,請(qǐng)求如下:
- <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節(jié)里包含“form”屬性,即客戶端匿名身份標(biāo)識(shí)。
注意,一個(gè)客戶端已經(jīng)以一個(gè)身份(由服務(wù)器臨時(shí)分配的一個(gè)JID)登錄,建立了會(huì)話,在服務(wù)器上我們會(huì)看到這個(gè)會(huì)話,并且服務(wù)器發(fā)送心跳一直維護(hù)這個(gè)會(huì)話。這種情況下,這個(gè)客戶端再發(fā)送注冊(cè)請(qǐng)求(另一個(gè)身份)建立與服務(wù)器的連接是不被允許的。具體請(qǐng)參考XEP-0077(In-Band Registration):我們關(guān)注這兩段:
- 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.
意思是說(shuō)注冊(cè)請(qǐng)求不能包含“from”屬性。
正常的注冊(cè)流如下:
- <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>
---------------------------
綜上所述,解決方案如下:
一、關(guān)閉openFire的匿名登錄功能。^_^……
二、禁止GLOOX匿名認(rèn)證功能。
- file:client.cpp
-
- fun: int Client::getSaslMechs( Tag* tag )
-
- line:355
-
- 將355行注釋掉即可。
- 354:if( tag->hasChildWithCData( mech, "ANONYMOUS" ) )
- 355
重新編譯生成DLL即可。
三、手動(dòng)設(shè)置GLOOX客戶端SASL認(rèn)證機(jī)制
在調(diào)用j->connect()之前設(shè)置SASL認(rèn)證機(jī)制,比如設(shè)置為“DIGEST-MD5”
- j->setSASLMechanisms(SaslMechDigestMd5);
這種方式的缺點(diǎn)是需要先確定服務(wù)器支持的認(rèn)證機(jī)制。
四、根據(jù)XEP-0077所述,即使其名登錄,注冊(cè)流只要不帶“from”屬性應(yīng)該也可以。所以我們要處理發(fā)出的注冊(cè)流,去除“from”屬性重新發(fā)送注冊(cè)流即可。