改定履曆
2011-09-09---------------------建立文本文檔
引文:
調試GLOOX 1.0的注冊功能頗費了一些功夫。總體邏輯如GLOOX自帶的例子一樣是毫無疑問的,但是照搬例子又是不能完成注冊的,傳回錯誤碼為4------RegistrationBadRequest。筆者一開始在網上狂搜解決方案,資料少之又少,有建議重寫Client::handleNormalNode函數(目的是禁止SASL認證)的,有直接繼承Client重寫Client::handleNormalNode函數的,但都沒說到點子上。經過一段時間的研究,在GLOOX的maillist上得到啟發,順利完成注冊。現将解決方案記錄下來:
環境
用戶端:GLOOX1.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='[email protected]/447e0585' xmlns='jabber:client'><query xmlns='jabber:iq:register'><username>bbaxiao</username><password>123456</password><name>test2</name><email>[email protected]</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 <[email protected]> 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 <[email protected]/resource>. The service MUST perform the remove based on the bare JID <[email protected]> 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>[email protected]</email></query></iq>
---------------------------
綜上所述,解決方案如下:
一、關閉openFire的匿名登入功能。^_^……
二、禁止GLOOX匿名認證功能。
file:client.cpp
fun: int Client::getSaslMechs( Tag* tag )
line:355
将355行注釋掉即可。
354:if( tag->hasChildWithCData( mech, "ANONYMOUS" ) )
355 //mechs |= SaslMechAnonymous;
重新編譯生成DLL即可。
三、手動設定GLOOX用戶端SASL認證機制
在調用j->connect()之前設定SASL認證機制,比如設定為“DIGEST-MD5”
j->setSASLMechanisms(SaslMechDigestMd5);
這種方式的缺點是需要先确定伺服器支援的認證機制。
四、根據XEP-0077所述,即使其名登入,注冊流隻要不帶“from”屬性應該也可以。是以我們要處理發出的注冊流,去除“from”屬性重新發送注冊流即可。