Class Jabber::SASL::DigestMD5
In: lib/xmpp4r/sasl.rb
Parent: Base

SASL DIGEST-MD5 authentication helper (RFC2831)

Methods

auth   decode_challenge   new  

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 165
165:       def auth(password)
166:         response = {}
167:         response['nonce'] = @nonce
168:         response['charset'] = 'utf-8'
169:         response['username'] = @stream.jid.node
170:         response['realm'] = @realm || @stream.jid.domain
171:         response['cnonce'] = generate_nonce
172:         response['nc'] = '00000001'
173:         response['qop'] = 'auth'
174:         response['digest-uri'] = "xmpp/#{@stream.jid.domain}"
175:         response['response'] = response_value(@stream.jid.node, @stream.jid.domain, response['digest-uri'], password, @nonce, response['cnonce'], response['qop'])
176:         response.each { |key,value|
177:           unless %w(nc qop response charset).include? key
178:             response[key] = "\"#{value}\""
179:           end
180:         }
181: 
182:         response_text = response.collect { |k,v| "#{k}=#{v}" }.join(',')
183:         Jabber::debuglog("SASL DIGEST-MD5 response:\n#{response_text}")
184: 
185:         r = REXML::Element.new('response')
186:         r.add_namespace NS_SASL
187:         r.text = Base64::encode64(response_text).gsub(/\s/, '')
188: 
189:         success_already = false
190:         error = nil
191:         @stream.send(r) { |reply|
192:           if reply.name == 'success'
193:             success_already = true
194:           elsif reply.name != 'challenge'
195:             error = reply.first_element(nil).name
196:           end
197:           true
198:         }
199: 
200:         return if success_already
201:         raise error if error
202: 
203:         # TODO: check the challenge from the server
204: 
205:         r.text = nil
206:         @stream.send(r) { |reply|
207:           if reply.name != 'success'
208:             error = reply.first_element(nil).name
209:           end
210:           true
211:         }
212: 
213:         raise error if error
214:       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: 
126:         text.scan(/./) do |ch|
127:           if state == :key
128:             if ch == '='
129:               state = :value
130:             else
131:               key += ch
132:             end
133: 
134:           elsif state == :value
135:             if ch == ','
136:               res[key] = value
137:               key = ''
138:               value = ''
139:               state = :key
140:             elsif ch == '"' and value == ''
141:               state = :quote
142:             else
143:               value += ch
144:             end
145: 
146:           elsif state == :quote
147:             if ch == '"'
148:               state = :value
149:             else
150:               value += ch
151:             end
152:           end
153:         end
154:         res[key] = value unless key == ''
155: 
156:         Jabber::debuglog("SASL DIGEST-MD5 challenge:\n#{text.inspect}\n#{res.inspect}")
157: 
158:         res
159:       end

[Validate]