天天看點

GLOOX 1.0---注冊子產品

改定履曆

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”屬性重新發送注冊流即可。

繼續閱讀