Step 1: Server1 initiates stream to Server2:
<
stream:stream
xmlns
='jabber:server'
xmlns:stream
='http://etherx.jabber.org/streams'
to
='example.com'
version
='1.0'
>
Step 2: Server2 responds with a stream tag sent to Server1:
<
stream:stream
xmlns
='jabber:server'
xmlns:stream
='http://etherx.jabber.org/streams'
from
='example.com'
id
='s2s_234'
version
='1.0'
>
Step 3: Server2 informs Server1 of available authentication mechanisms:
<
stream:features
>
<
mechanisms
xmlns
='urn:ietf:params:xml:ns:xmpp-sasl'
>
<
mechanism
>
DIGEST-MD5
</
mechanism
>
<
mechanism
>
KERBEROS_V4
</
mechanism
>
</
mechanisms
>
</
stream:features
>
Step 4: Server1 selects an authentication mechanism:
Step 5: Server2 sends a BASE64 encoded challenge to Server1:< auth xmlns ='urn:ietf:params:xml:ns:xmpp-sasl'
mechanism ='DIGEST-MD5' />
![]()
< challenge xmlns ='urn:ietf:params:xml:ns:xmpp-sasl' >
cmVhbG09InNvbWVyZWFsbSIsbm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixxb3A9
ImF1dGgiLGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz
</ challenge >
![]()
The decoded challenge is:
realm="somerealm",nonce="OA6MG9tEQGm2hh","
qop="auth",charset=utf-8,algorithm=md5-sess
Step 5 (alt): Server2 returns error to Server1:
<
failure
xmlns
='urn:ietf:params:xml:ns:xmpp-sasl'
>
<
incorrect-encoding
/>
</
failure
>
</
stream:stream
>
Step 6: Server1 sends a BASE64 encoded response to the challenge:
<
response
xmlns
='urn:ietf:params:xml:ns:xmpp-sasl'
>
dXNlcm5hbWU9ImV4YW1wbGUub3JnIixyZWFsbT0ic29tZXJlYWxtIixub25j
ZT0iT0E2TUc5dEVRR20yaGgiLGNub25jZT0iT0E2TUhYaDZWcVRyUmsiLG5j
PTAwMDAwMDAxLHFvcD1hdXRoLGRpZ2VzdC11cmk9InhtcHAvZXhhbXBsZS5v
cmciLHJlc3BvbnNlPWQzODhkYWQ5MGQ0YmJkNzYwYTE1MjMyMWYyMTQzYWY3
LGNoYXJzZXQ9dXRmLTgK
</
response
>
The decoded response is:
username="example.org",realm="somerealm","
nonce="OA6MG9tEQGm2hh",cnonce="OA6MHXh6VqTrRk","
nc=00000001,qop=auth,digest-uri="xmpp/example.org","
response=d388dad90d4bbd760a152321f2143af7,charset=utf-8
Step 7: Server2 sends another BASE64 encoded challenge to Server1:
<
challenge
xmlns
='urn:ietf:params:xml:ns:xmpp-sasl'
>
cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZAo=
</
challenge
>
The decoded challenge is:
rspauth=ea40f60335c427b5527b84dbabcdfffd
Step 7 (alt): Server2 returns error to Server1:
<
failure
xmlns
='urn:ietf:params:xml:ns:xmpp-sasl'
>
<
invalid-authzid
/>
</
failure
>
</
stream:stream
>
Step 8: Server1 responds to the challenge:
<
response
xmlns
='urn:ietf:params:xml:ns:xmpp-sasl'
/>
Step 8 (alt): Server1 aborts negotiation:
<
abort
xmlns
='urn:ietf:params:xml:ns:xmpp-sasl'
/>
Step 9: Server2 informs Server1 of successful authentication:
<
success
xmlns
='urn:ietf:params:xml:ns:xmpp-sasl'
/>
Step 9 (alt): Server2 informs Server1 of failed authentication:
<
failure
xmlns
='urn:ietf:params:xml:ns:xmpp-sasl'
>
<
aborted
/>
</
failure
>
</
stream:stream
>
Step 10: Server1 initiates a new stream to Server2:
<
stream:stream
xmlns
='jabber:server'
xmlns:stream
='http://etherx.jabber.org/streams'
to
='example.com'
version
='1.0'
>
Step 11: Server2 responds by sending a stream header to Server1 along with any additional features (or an empty features element):
<
stream:stream
xmlns
='jabber:server'
xmlns:stream
='http://etherx.jabber.org/streams'
from
='example.com'
id
='s2s_345'
version
='1.0'
>
<
stream:features
/>
服务器回拨
这是一种单向的,不安全的验证方式。
具体过程:
1, 服务器A发送流头部给服务器B:
< stream :stream
xmlns :stream = 'http: // etherx . jabber . org / streams'
xmlns = 'jabber :server '
xmlns :db = 'jabber :server:dialback ' >
![]()
2,服务器B回送一个应答给A,包含了此次交互的ID:
<stream:stream
xmlns:stream='http://etherx.jabber.org/streams'
xmlns='jabber:server'
xmlns:db='jabber:server:dialback'
id='457F9224A0...'>
3,服务器A发送一个回拨key给B
<db:result
to='Receiving Server'
from='Originating Server'>
98AF014EDC0...
</db:result>
4,服务器B同验证服务器C建立TCP连接,向C发送流头部:
<stream:stream
xmlns:stream='http://etherx.jabber.org/streams'
xmlns='jabber:server'
xmlns:db='jabber:server:dialback'>
5,C回送应答:
<stream:stream
xmlns:stream='http://etherx.jabber.org/streams'
xmlns='jabber:server'
xmlns:db='jabber:server:dialback'
id='1251A342B...'>
6,B发送验证key的请求
<db:verify
from='Receiving Server'
to='Originating Server'
id='457F9224A0...'>
98AF014EDC0...
</db:verify>
7,验证服务器验证key是否合法:
<db:verify
from='Originating Server'
to='Receiving Server'
type='valid'
id='457F9224A0...'/>
or
<db:verify
from='Originating Server'
to='Receiving Server'
type='invalid'
id='457F9224A0...'/>
8,B通知A结果:
<db:result
from='Receiving Server'
to='Originating Server'
type='valid'/>
上面这个示例只是验证了从A到B的流是否合法,但不能保证从B到A是否合法,因此需要在反方向再进行一次验证。