Module: Ramaze::Helper::HttpDigest

Defined in:
lib/ramaze/helper/httpdigest.rb

Overview

Authorization using HTTP Digest.

For custom authorization failure handling add an #httpdigest_failure method in your controller.

Constant Summary collapse

SESSION_NONCE =
'httpdigest_authentication_nonce'
SESSION_OPAQUE =
'httpdigest_authentication_opaque'
DIGEST_HEADER =
%|Digest realm="%s", qop="auth,auth-int", nonce="%s", opaque="%s"|

Instance Method Summary collapse

Instance Method Details

#httpdigest(uid, realm, &block) ⇒ Object



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
94
# File 'lib/ramaze/helper/httpdigest.rb', line 66

def httpdigest(uid, realm, &block)
  session[SESSION_OPAQUE] ||= {}
  session[SESSION_OPAQUE][realm] ||= {}

  http_authorization = httpdigest_http_authorization(uid, realm)

  httpdigest_failure unless session_nonce = session[SESSION_NONCE]
  httpdigest_failure unless session_opaque = session[SESSION_OPAQUE][realm][uid]

  auth_type, auth_raw = http_authorization.split(' ', 2)
  httpdigest_failure unless auth_type == 'Digest'

  authorization = Rack::Auth::Digest::Params.parse(auth_raw)

  digest_response, username, nonce, nc, cnonce, qop, opaque =
    authorization.values_at(*%w[response username nonce nc cnonce qop opaque])

  httpdigest_failure unless nonce == session_nonce and opaque == session_opaque

  ha1 = httpdigest_lookup(username, realm, &block)
  a2 = [request.request_method,request.request_uri]
  a2 << Digest::MD5.hexdigest(request.body.read) if qop == "auth-int"
  ha2 = Digest::MD5.hexdigest( a2.join(':') )
  md5 = Digest::MD5.hexdigest([ha1, nonce, nc, cnonce, qop, ha2].join(':'))

  httpdigest_failure unless digest_response == md5

  return username
end

#httpdigest_failureObject



41
42
43
# File 'lib/ramaze/helper/httpdigest.rb', line 41

def httpdigest_failure
  respond 'Unauthorized', 401
end

#httpdigest_headers(uid, realm) ⇒ Object

Set the WWW-Authenticate header and store relevant data in the session.

Parameters:



35
36
37
38
39
# File 'lib/ramaze/helper/httpdigest.rb', line 35

def httpdigest_headers(uid, realm)
  nonce = session[SESSION_NONCE] = httpdigest_uuid
  opaque = session[SESSION_OPAQUE][realm][uid] = httpdigest_uuid
  response['WWW-Authenticate'] = DIGEST_HEADER % [realm, nonce, opaque]
end

#httpdigest_http_authorization(uid, realm) ⇒ Object



45
46
47
48
49
50
51
# File 'lib/ramaze/helper/httpdigest.rb', line 45

def httpdigest_http_authorization(uid, realm)
  http_authorization = request.env['HTTP_AUTHORIZATION']
  return http_authorization if http_authorization

  httpdigest_headers(uid, realm)
  httpdigest_failure
end

#httpdigest_logoutObject

Delete the nonce and opaque from session to log out.



22
23
24
25
# File 'lib/ramaze/helper/httpdigest.rb', line 22

def httpdigest_logout
  session.delete(SESSION_NONCE)
  session.delete(SESSION_OPAQUE)
end

#httpdigest_lookup(username, realm) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/ramaze/helper/httpdigest.rb', line 53

def httpdigest_lookup(username, realm)
  if block_given?
    yield(username)
  elsif respond_to?(:httpdigest_lookup_password)
    httpdigest_lookup_password(username)
  elsif respond_to?(:httpdigest_lookup_plaintext_password)
    plain = httpdigest_lookup_plaintext_password(username)
    Digest::MD5.hexdigest([username, realm, plain].join(':'))
  else
    raise "No password lookup handler found"
  end
end

#httpdigest_uuidObject



27
28
29
# File 'lib/ramaze/helper/httpdigest.rb', line 27

def httpdigest_uuid
  ::SecureRandom.hex(32)
end