| Class | Jabber::SASL::DigestMD5 |
| In: |
lib/xmpp4r/sasl.rb
|
| Parent: | Base |
SASL DIGEST-MD5 authentication helper (RFC2831)
Sends the wished auth mechanism and wait for a challenge
(proceed with DigestMD5#auth)
# 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
# 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
# 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