Class: Jabber::SASL::DigestMD5

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

new(stream)

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

auth(password)

- 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

decode_challenge(challenge)

[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]