Module: Atom::DigestAuth

Included in:
HTTP
Defined in:
lib/atom/http.rb

Constant Summary collapse

CNONCE =
Digest::MD5.new("%x" % (Time.now.to_i + rand(65535))).hexdigest
@@nonce_count =
-1

Instance Method Summary collapse

Instance Method Details

#digest_authenticate(req, url, param_string = "") ⇒ Object

HTTP Digest authentication (RFC 2617)



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/atom/http.rb', line 43

def digest_authenticate(req, url, param_string = "")
  raise "Digest authentication requires a WWW-Authenticate header" if param_string.empty?

  params = parse_wwwauth_digest(param_string)
  qop = params[:qop]

  user, pass = username_and_password_for_realm(url, params[:realm])

  if params[:algorithm] == "MD5"
    a1 = user + ":" + params[:realm] + ":" + pass
  else
    # XXX MD5-sess
    raise "I only support MD5 digest authentication (not #{params[:algorithm].inspect})"
  end

  if qop.nil? or qop.member? "auth"
    a2 = req.method + ":" + req.path
  else
    # XXX auth-int
    raise "only 'auth' qop supported (none of: #{qop.inspect})"
  end

  if qop.nil?
    response = kd(h(a1), params[:nonce] + ":" + h(a2))
  else
    @@nonce_count += 1
    nc = ('%08x' % @@nonce_count) 
   
    # XXX auth-int
    data = "#{params[:nonce]}:#{nc}:#{CNONCE}:#{"auth"}:#{h(a2)}"

    response = kd(h(a1), data)
  end

  header = %Q<Digest username="#{user}", uri="#{req.path}", realm="#{params[:realm]}", response="#{response}", nonce="#{params[:nonce]}">
   
  if params[:opaque]
    header += %Q<, opaque="#{params[:opaque]}">
  end

  if params[:algorithm] != "MD5"
    header += ", algorithm=#{algo}"
  end

  if qop
    # XXX auth-int
    header += %Q<, nc=#{nc}, cnonce="#{CNONCE}", qop=auth>
  end

  req["Authorization"] = header
end

#h(data) ⇒ Object



39
# File 'lib/atom/http.rb', line 39

def h(data); Digest::MD5.hexdigest(data); end

#kd(secret, data) ⇒ Object



40
# File 'lib/atom/http.rb', line 40

def kd(secret, data); h(secret + ":" + data); end

#parse_wwwauth_digest(param_string) ⇒ Object

quoted-strings plus a few special cases for Digest



25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/atom/http.rb', line 25

def parse_wwwauth_digest param_string
  params = parse_quoted_wwwauth param_string
  qop = params[:qop] ? params[:qop].split(",") : nil

  param_string.gsub(/stale=([^,]*)/) do
    params[:stale] = ($1.downcase == "true")
  end

  params[:algorithm] = "MD5"
  param_string.gsub(/algorithm=([^,]*)/) { params[:algorithm] = $1 }

  params
end