Class Jabber::SASL::DigestMD5
In: lib/xmpp4r/sasl.rb
Parent: Base
Message Presence XMPPStanza Iq XMPPElement ErrorResponse X IqQuery JabberError ComponentAuthenticationFailure ArgumentError InvalidChatState SOCKS5Error ServerError NoNameXmlnsRegistered ServerDisconnected ClientAuthenticationFailure Connection Client Component Connection Client Singleton IdGenerator Comparable JID Enumerable CallbackList Items Publish StandardError REXML::Element Stream XMPPElement Location IqFeature StreamHost IqSiFile IqSiFileRange IqSi StreamHostUsed XRosterItem RosterItem C Body HTML UserItem XMUCUserInvite Configuration Retract IqPubSub Item IqPubSubOwner Event Subscription Unsubscribe Tune XDataField XDataReported XDataTitle XDataInstructions Feature Item Identity IqVcard PubSub::ServiceHelper Helper Helper SOCKS5Bytestreams SOCKS5BytestreamsTarget SOCKS5BytestreamsInitiator SOCKS5BytestreamsServerStreamHost TCPSocket SOCKS5Socket IqQuery IqQueryBytestreams IqQueryRoster IqQueryVersion IqQueryRPC IqQueryMUCOwner IqQueryMUCAdmin IqQueryDiscoItems IqQueryDiscoInfo IqQueryLastActivity IBB IBBTarget IBBInitiator RosterXItem XRoster RosterX X XDelay XMUC XMUCUser XData Responder SimpleResponder Iq IqCommand XMLRPC::ParserWriterChooseMixin Client Server XMLRPC::ParseContentType XMLRPC::BasicServer MUCClient SimpleMUCClient MUC::UserItem XMUCUserItem IqQueryMUCAdminItem XParent SubscriptionConfig NodeConfig OwnerNodeConfig EventItems ServiceHelper OAuthServiceHelper NodeHelper EventItem Base Anonymous DigestMD5 Plain FileSource Base Bot Callback StreamParser Semaphore SOCKS5BytestreamsPeer SOCKS5BytestreamsServer IBBQueueItem Helper Responder Helper Listener MUCBrowser NodeBrowser ListenerMocker Helper Responder Helper Helper Helper lib/xmpp4r/message.rb lib/xmpp4r/connection.rb lib/xmpp4r/xmppstanza.rb lib/xmpp4r/iq.rb lib/xmpp4r/callbacks.rb lib/xmpp4r/idgenerator.rb lib/xmpp4r/stream.rb lib/xmpp4r/client.rb lib/xmpp4r/jid.rb lib/xmpp4r/x.rb lib/xmpp4r/streamparser.rb lib/xmpp4r/semaphore.rb lib/xmpp4r/errors.rb lib/xmpp4r/component.rb lib/xmpp4r/presence.rb lib/xmpp4r/xmppelement.rb lib/xmpp4r/query.rb XParent lib/xmpp4r/location/helper/helper.rb lib/xmpp4r/location/location.rb UserLocation lib/xmpp4r/feature_negotiation/iq/feature.rb FeatureNegotiation lib/xmpp4r/bytestreams/iq/si.rb lib/xmpp4r/bytestreams/helper/ibb/initiator.rb lib/xmpp4r/bytestreams/helper/socks5bytestreams/base.rb lib/xmpp4r/bytestreams/iq/bytestreams.rb lib/xmpp4r/bytestreams/helper/socks5bytestreams/initiator.rb lib/xmpp4r/bytestreams/helper/socks5bytestreams/target.rb lib/xmpp4r/bytestreams/helper/socks5bytestreams/socks5.rb lib/xmpp4r/bytestreams/helper/ibb/target.rb lib/xmpp4r/bytestreams/helper/socks5bytestreams/server.rb lib/xmpp4r/bytestreams/helper/ibb/base.rb Bytestreams lib/xmpp4r/roster/x/roster.rb lib/xmpp4r/roster/helper/roster.rb lib/xmpp4r/roster/iq/roster.rb Roster lib/xmpp4r/version/helper/responder.rb lib/xmpp4r/version/helper/simpleresponder.rb lib/xmpp4r/version/iq/version.rb Version lib/xmpp4r/command/iq/command.rb lib/xmpp4r/command/helper/responder.rb Command lib/xmpp4r/caps/helper/helper.rb lib/xmpp4r/caps/c.rb Caps lib/xmpp4r/reliable.rb Reliable lib/xmpp4r/delay/x/delay.rb Delay lib/xmpp4r/xhtml/html.rb XHTML lib/xmpp4r/rpc/helper/server.rb lib/xmpp4r/rpc/helper/client.rb lib/xmpp4r/rpc/iq/rpc.rb RPC lib/xmpp4r/muc/iq/mucadminitem.rb lib/xmpp4r/muc/x/muc.rb lib/xmpp4r/muc/item.rb lib/xmpp4r/muc/helper/simplemucclient.rb lib/xmpp4r/muc/iq/mucadmin.rb lib/xmpp4r/muc/helper/mucbrowser.rb lib/xmpp4r/muc/x/mucuseritem.rb lib/xmpp4r/muc/x/mucuserinvite.rb lib/xmpp4r/muc/iq/mucowner.rb lib/xmpp4r/muc/helper/mucclient.rb MUC lib/xmpp4r/pubsub/children/item.rb lib/xmpp4r/pubsub/children/configuration.rb lib/xmpp4r/pubsub/children/subscription.rb lib/xmpp4r/pubsub/helper/servicehelper.rb lib/xmpp4r/pubsub/children/unsubscribe.rb lib/xmpp4r/pubsub/children/publish.rb lib/xmpp4r/pubsub/helper/oauth_service_helper.rb lib/xmpp4r/pubsub/children/event.rb lib/xmpp4r/pubsub/iq/pubsub.rb lib/xmpp4r/pubsub/children/retract.rb lib/xmpp4r/pubsub/helper/nodebrowser.rb lib/xmpp4r/pubsub/helper/nodehelper.rb lib/xmpp4r/pubsub/children/items.rb lib/xmpp4r/pubsub/children/subscription_config.rb lib/xmpp4r/pubsub/children/node_config.rb OAuthPubSubStreamHelper PubSub lib/xmpp4r/httpbinding/client.rb HTTPBinding lib/xmpp4r/tune/helper/helper.rb lib/xmpp4r/tune/tune.rb UserTune lib/xmpp4r/sasl.rb SASL lib/xmpp4r/test/listener_mocker.rb Test lib/xmpp4r/dataforms/x/data.rb Dataforms lib/xmpp4r/discovery/helper/helper.rb lib/xmpp4r/discovery/iq/discoinfo.rb lib/xmpp4r/discovery/helper/responder.rb lib/xmpp4r/discovery/iq/discoitems.rb Discovery lib/xmpp4r/bytestreams/helper/filetransfer.rb TransferSource FileTransfer lib/xmpp4r/last/helper/helper.rb lib/xmpp4r/last/iq/last.rb LastActivity lib/xmpp4r/framework/base.rb lib/xmpp4r/framework/bot.rb Framework lib/xmpp4r/vcard/helper/vcard.rb lib/xmpp4r/vcard/iq/vcard.rb Vcard Jabber dot/m_110_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 99
 99:       def initialize(stream)
100:         super
101: 
102:         challenge = {}
103:         error = nil
104:         @stream.send(generate_auth('DIGEST-MD5')) { |reply|
105:           if reply.name == 'challenge' and reply.namespace == NS_SASL
106:             challenge = decode_challenge(reply.text)
107:           else
108:             error = reply.first_element(nil).name
109:           end
110:           true
111:         }
112:         raise error if error
113: 
114:         @nonce = challenge['nonce']
115:         @realm = challenge['realm']
116:       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 170
170:       def auth(password)
171:         response = {}
172:         response['nonce'] = @nonce
173:         response['charset'] = 'utf-8'
174:         response['username'] = @stream.jid.node
175:         response['realm'] = @realm || @stream.jid.domain
176:         response['cnonce'] = generate_nonce
177:         response['nc'] = '00000001'
178:         response['qop'] = 'auth'
179:         response['digest-uri'] = "xmpp/#{@stream.jid.domain}"
180:         response['response'] = response_value(@stream.jid.node, @stream.jid.domain, response['digest-uri'], password, @nonce, response['cnonce'], response['qop'], response['authzid'])
181:         response.each { |key,value|
182:           unless %w(nc qop response charset).include? key
183:             response[key] = "\"#{value}\""
184:           end
185:         }
186: 
187:         response_text = response.collect { |k,v| "#{k}=#{v}" }.join(',')
188:         Jabber::debuglog("SASL DIGEST-MD5 response:\n#{response_text}\n#{response.inspect}")
189: 
190:         r = REXML::Element.new('response')
191:         r.add_namespace NS_SASL
192:         r.text = Base64::encode64(response_text).gsub(/\s/, '')
193: 
194:         success_already = false
195:         error = nil
196:         @stream.send(r) { |reply|
197:           if reply.name == 'success'
198:             success_already = true
199:           elsif reply.name != 'challenge'
200:             error = reply.first_element(nil).name
201:           end
202:           true
203:         }
204: 
205:         return if success_already
206:         raise error if error
207: 
208:         # TODO: check the challenge from the server
209: 
210:         r.text = nil
211:         @stream.send(r) { |reply|
212:           if reply.name != 'success'
213:             error = reply.first_element(nil).name
214:           end
215:           true
216:         }
217: 
218:         raise error if error
219:       end

[Source]

     # File lib/xmpp4r/sasl.rb, line 118
118:       def decode_challenge(challenge)
119:         text = Base64::decode64(challenge)
120:         res = {}
121: 
122:         state = :key
123:         key = ''
124:         value = ''
125:         text.scan(/./) do |ch|
126:           if state == :key
127:             if ch == '='
128:               state = :value
129:             else
130:               key += ch
131:             end
132: 
133:           elsif state == :value
134:             if ch == ','
135:               # due to our home-made parsing of the challenge, the key could have
136:               # leading whitespace. strip it, or that would break jabberd2 support.
137:               key = key.strip
138:               res[key] = value
139:               key = ''
140:               value = ''
141:               state = :key
142:             elsif ch == '"' and value == ''
143:               state = :quote
144:             else
145:               value += ch
146:             end
147: 
148:           elsif state == :quote
149:             if ch == '"'
150:               state = :value
151:             else
152:               value += ch
153:             end
154:           end
155:         end
156:         # due to our home-made parsing of the challenge, the key could have
157:         # leading whitespace. strip it, or that would break jabberd2 support.
158:         key = key.strip
159:         res[key] = value unless key == ''
160: 
161:         Jabber::debuglog("SASL DIGEST-MD5 challenge:\n#{text}\n#{res.inspect}")
162: 
163:         res
164:       end

Private Instance methods

Function from RFC2831

[Source]

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

Function from RFC2831

[Source]

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

Calculate the value for the response field

[Source]

     # File lib/xmpp4r/sasl.rb, line 232
232:       def response_value(username, realm, digest_uri, passwd, nonce, cnonce, qop, authzid)
233:         a1_h = h("#{username}:#{realm}:#{passwd}")
234:         a1 = "#{a1_h}:#{nonce}:#{cnonce}"
235:         if authzid
236:           a1 += ":#{authzid}"
237:         end
238:         if qop == 'auth-int' || qop == 'auth-conf'
239:           a2 = "AUTHENTICATE:#{digest_uri}:00000000000000000000000000000000"
240:         else
241:           a2 = "AUTHENTICATE:#{digest_uri}"
242:         end
243:         hh("#{hh(a1)}:#{nonce}:00000001:#{cnonce}:#{qop}:#{hh(a2)}")
244:       end

[Validate]