改定履歷
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='447e0585@zxl/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”屬性重新發送註冊流即可。