Class Jabber::SASL::DigestMD5
In: lib/xmpp4r/sasl.rb
Parent: Base
Message Presence XMPPStanza Iq XMPPElement X IqQuery Error Singleton IdGenerator Connection Client Component Client Comparable JID RuntimeError ErrorException AuthenticationFailure NoNameXmlnsRegistered SOCKS5Error REXML::Element Stream SOCKS5Bytestreams SOCKS5BytestreamsTarget SOCKS5BytestreamsInitiator XMPPElement StreamHost IqSiFileRange IqSiFile StreamHostUsed IqSi IqFeature XRosterItem RosterItem XMUCUserItem XMUCUserInvite IqPubSub Items Subscription IqPubSubOwner Item Event Feature Identity Item XDataField XDataReported XDataTitle XDataInstructions IqVcard SOCKS5BytestreamsServerStreamHost TCPSocket SOCKS5Socket IqQuery IqQueryBytestreams IqQueryVersion IqQueryRoster IqQueryRPC IqQueryMUCOwner IqQueryDiscoItems IqQueryDiscoInfo IBB IBBTarget IBBInitiator Responder SimpleResponder Iq IqCommand RosterXItem XRoster RosterX X XMUCUser XMUC XDelay XData XMLRPC::ParserWriterChooseMixin Client Server XMLRPC::ParseContentType XMLRPC::BasicServer XParent MUCClient SimpleMUCClient Base DigestMD5 Plain FileSource ServiceHelper NodeHelper CallbackList Callback Semaphore StreamParser SOCKS5BytestreamsPeer SOCKS5BytestreamsServer IBBQueueItem Responder Helper MUCBrowser Helper NodeBrowser Helper lib/xmpp4r/authenticationfailure.rb lib/xmpp4r/xmppstanza.rb lib/xmpp4r/callbacks.rb lib/xmpp4r/idgenerator.rb lib/xmpp4r/connection.rb lib/xmpp4r/iq.rb lib/xmpp4r/jid.rb lib/xmpp4r/errorexception.rb lib/xmpp4r/semaphore.rb lib/xmpp4r/client.rb lib/xmpp4r/stream.rb lib/xmpp4r/x.rb lib/xmpp4r/streamparser.rb lib/xmpp4r/error.rb lib/xmpp4r/component.rb lib/xmpp4r/query.rb lib/xmpp4r/xmppelement.rb lib/xmpp4r/message.rb lib/xmpp4r/presence.rb lib/xmpp4r/bytestreams/helper/ibb/initiator.rb lib/xmpp4r/bytestreams/iq/si.rb lib/xmpp4r/bytestreams/iq/bytestreams.rb lib/xmpp4r/bytestreams/helper/socks5bytestreams/base.rb lib/xmpp4r/bytestreams/helper/socks5bytestreams/server.rb lib/xmpp4r/bytestreams/helper/socks5bytestreams/target.rb lib/xmpp4r/bytestreams/helper/socks5bytestreams/socks5.rb lib/xmpp4r/bytestreams/helper/socks5bytestreams/initiator.rb lib/xmpp4r/bytestreams/helper/ibb/base.rb lib/xmpp4r/bytestreams/helper/ibb/target.rb Bytestreams XParent lib/xmpp4r/version/iq/version.rb lib/xmpp4r/version/helper/responder.rb lib/xmpp4r/version/helper/simpleresponder.rb Version lib/xmpp4r/command/iq/command.rb lib/xmpp4r/command/helper/responder.rb Command lib/xmpp4r/feature_negotiation/iq/feature.rb FeatureNegotiation lib/xmpp4r/roster/helper/roster.rb lib/xmpp4r/roster/iq/roster.rb lib/xmpp4r/roster/x/roster.rb Roster lib/xmpp4r/rpc/helper/server.rb lib/xmpp4r/rpc/helper/client.rb lib/xmpp4r/rpc/iq/rpc.rb RPC lib/xmpp4r/muc/x/muc.rb lib/xmpp4r/muc/helper/mucclient.rb lib/xmpp4r/muc/x/mucuseritem.rb lib/xmpp4r/muc/helper/mucbrowser.rb lib/xmpp4r/muc/x/mucuserinvite.rb lib/xmpp4r/muc/iq/mucowner.rb lib/xmpp4r/muc/helper/simplemucclient.rb MUC lib/xmpp4r/sasl.rb SASL lib/xmpp4r/bytestreams/helper/filetransfer.rb TransferSource FileTransfer lib/xmpp4r/delay/x/delay.rb Delay lib/xmpp4r/pubsub/stanzas/subscription.rb lib/xmpp4r/pubsub/helper/servicehelper.rb lib/xmpp4r/pubsub/stanzas/item.rb lib/xmpp4r/pubsub/helper/nodehelper.rb lib/xmpp4r/pubsub/iq/pubsub.rb lib/xmpp4r/pubsub/stanzas/event.rb lib/xmpp4r/pubsub/helper/nodebrowser.rb lib/xmpp4r/pubsub/stanzas/items.rb PubSub lib/xmpp4r/httpbinding/client.rb HTTPBinding lib/xmpp4r/discovery/iq/discoinfo.rb lib/xmpp4r/discovery/iq/discoitems.rb Discovery lib/xmpp4r/dataforms/x/data.rb Dataforms lib/xmpp4r/vcard/helper/vcard.rb lib/xmpp4r/vcard/iq/vcard.rb Vcard Jabber dot/m_81_0.png

SASL DIGEST-MD5 authentication helper (RFC2831)

Methods

auth   decode_challenge   h   hh   new   response_value  

Public Class methods

Sends the wished auth mechanism and wait for a challenge

(proceed with DigestMD5#auth)

[Source]

    # File lib/xmpp4r/sasl.rb, line 78
78:       def initialize(stream)
79:         super
80: 
81:         challenge = {}
82:         error = nil
83:         @stream.send(generate_auth('DIGEST-MD5')) { |reply|
84:           if reply.name == 'challenge' and reply.namespace == NS_SASL
85:             challenge = decode_challenge(reply.text)
86:           else
87:             error = reply.first_element(nil).name
88:           end
89:           true
90:         }
91:         raise error if error
92: 
93:         @nonce = challenge['nonce']
94:         @realm = challenge['realm']
95:       end

Public Instance methods

  • Send a response
  • Wait for the server‘s challenge (which aren‘t checked)
  • Send a blind response to the server‘s challenge

[Source]

     # File lib/xmpp4r/sasl.rb, line 144
144:       def auth(password)
145:         response = {}
146:         response['nonce'] = @nonce
147:         response['charset'] = 'utf-8'
148:         response['username'] = @stream.jid.node
149:         response['realm'] = @realm || @stream.jid.domain
150:         response['cnonce'] = generate_nonce
151:         response['nc'] = '00000001'
152:         response['qop'] = 'auth'
153:         response['digest-uri'] = "xmpp/#{@stream.jid.domain}"
154:         response['response'] = response_value(@stream.jid.node, @stream.jid.domain, response['digest-uri'], password, @nonce, response['cnonce'], response['qop'])
155:         response.each { |key,value|
156:           unless %w(nc qop response charset).include? key
157:             response[key] = "\"#{value}\""
158:           end
159:         }
160: 
161:         response_text = response.collect { |k,v| "#{k}=#{v}" }.join(',')
162:         Jabber::debuglog("SASL DIGEST-MD5 response:\n#{response_text}")
163: 
164:         r = REXML::Element.new('response')
165:         r.add_namespace NS_SASL
166:         r.text = Base64::encode64(response_text).gsub(/\s/, '')
167: 
168:         success_already = false
169:         error = nil
170:         @stream.send(r) { |reply|
171:           if reply.name == 'success'
172:             success_already = true
173:           elsif reply.name != 'challenge'
174:             error = reply.first_element(nil).name
175:           end
176:           true
177:         }
178:         
179:         return if success_already
180:         raise error if error
181: 
182:         # TODO: check the challenge from the server
183: 
184:         r.text = nil
185:         @stream.send(r) { |reply|
186:           if reply.name != 'success'
187:             error = reply.first_element(nil).name
188:           end
189:           true
190:         }
191:         
192:         raise error if error
193:       end

[Source]

     # File lib/xmpp4r/sasl.rb, line 97
 97:       def decode_challenge(challenge)
 98:         text = Base64::decode64(challenge)
 99:         res = {}
100: 
101:         state = :key
102:         key = ''
103:         value = ''
104: 
105:         text.scan(/./) do |ch|
106:           if state == :key
107:             if ch == '='
108:               state = :value
109:             else
110:               key += ch
111:             end
112: 
113:           elsif state == :value
114:             if ch == ','
115:               res[key] = value
116:               key = ''
117:               value = ''
118:               state = :key
119:             elsif ch == '"' and value == ''
120:               state = :quote
121:             else
122:               value += ch
123:             end
124: 
125:           elsif state == :quote
126:             if ch == '"'
127:               state = :value
128:             else
129:               value += ch
130:             end
131:           end
132:         end
133:         res[key] = value unless key == ''
134: 
135:         Jabber::debuglog("SASL DIGEST-MD5 challenge:\n#{text.inspect}\n#{res.inspect}")
136: 
137:         res
138:       end

Private Instance methods

Function from RFC2831

[Source]

     # File lib/xmpp4r/sasl.rb, line 199
199:       def h(s); Digest::MD5.digest(s); end

Function from RFC2831

[Source]

     # File lib/xmpp4r/sasl.rb, line 202
202:       def hh(s); Digest::MD5.hexdigest(s); end

Calculate the value for the response field

[Source]

     # File lib/xmpp4r/sasl.rb, line 206
206:       def response_value(username, realm, digest_uri, passwd, nonce, cnonce, qop)
207:         a1_h = h("#{username}:#{realm}:#{passwd}")
208:         a1 = "#{a1_h}:#{nonce}:#{cnonce}"
209:         #a2 = "AUTHENTICATE:#{digest_uri}#{(qop == 'auth') ? '' : ':00000000000000000000000000000000'}"
210:         a2 = "AUTHENTICATE:#{digest_uri}"
211: 
212:         hh("#{hh(a1)}:#{nonce}:00000001:#{cnonce}:#{qop}:#{hh(a2)}")
213:       end

[Validate]