class Rack::Auth::Digest::MD5

Rack::Auth::Digest::MD5 implements the MD5 algorithm version of HTTP Digest Authentication, as per RFC 2617.

Initialize with the [Rack] application that you want protecting, and a block that looks up a plaintext password for a given username.

opaque needs to be set to a constant base64/hexadecimal string.

Constants

QOP

Attributes

opaque[RW]
passwords_hashed[W]

Public Class Methods

new(app, realm=nil, opaque=nil, &authenticator) click to toggle source
Calls superclass method Rack::Auth::AbstractHandler.new
# File lib/rack/auth/digest/md5.rb, line 24
def initialize(app, realm=nil, opaque=nil, &authenticator)
  @passwords_hashed = nil
  if opaque.nil? and realm.respond_to? :values_at
    realm, opaque, @passwords_hashed = realm.values_at :realm, :opaque, :passwords_hashed
  end
  super(app, realm, &authenticator)
  @opaque = opaque
end

Public Instance Methods

call(env) click to toggle source
# File lib/rack/auth/digest/md5.rb, line 37
def call(env)
  auth = Request.new(env)

  unless auth.provided?
    return unauthorized
  end

  if !auth.digest? || !auth.correct_uri? || !valid_qop?(auth)
    return bad_request
  end

  if valid?(auth)
    if auth.nonce.stale?
      return unauthorized(challenge(:stale => true))
    else
      env['REMOTE_USER'] = auth.username

      return @app.call(env)
    end
  end

  unauthorized
end
passwords_hashed?() click to toggle source
# File lib/rack/auth/digest/md5.rb, line 33
def passwords_hashed?
  !!@passwords_hashed
end

Private Instance Methods

A1(auth, password) click to toggle source
# File lib/rack/auth/digest/md5.rb, line 112
def A1(auth, password)
  [ auth.username, auth.realm, password ] * ':'
end
A2(auth) click to toggle source
# File lib/rack/auth/digest/md5.rb, line 116
def A2(auth)
  [ auth.method, auth.uri ] * ':'
end
H(data)
Alias for: md5
KD(secret, data) click to toggle source
# File lib/rack/auth/digest/md5.rb, line 108
def KD(secret, data)
  H([secret, data] * ':')
end
challenge(hash = {}) click to toggle source
# File lib/rack/auth/digest/md5.rb, line 77
def challenge(hash = {})
  "Digest #{params(hash)}"
end
digest(auth, password) click to toggle source
# File lib/rack/auth/digest/md5.rb, line 120
def digest(auth, password)
  password_hash = passwords_hashed? ? password : H(A1(auth, password))

  KD(password_hash, [ auth.nonce, auth.nc, auth.cnonce, QOP, H(A2(auth)) ] * ':')
end
md5(data) click to toggle source
# File lib/rack/auth/digest/md5.rb, line 102
def md5(data)
  ::Digest::MD5.hexdigest(data)
end
Also aliased as: H
params(hash = {}) click to toggle source
# File lib/rack/auth/digest/md5.rb, line 66
def params(hash = {})
  Params.new do |params|
    params['realm'] = realm
    params['nonce'] = Nonce.new.to_s
    params['opaque'] = H(opaque)
    params['qop'] = QOP

    hash.each { |k, v| params[k] = v }
  end
end
valid?(auth) click to toggle source
# File lib/rack/auth/digest/md5.rb, line 81
def valid?(auth)
  valid_opaque?(auth) && valid_nonce?(auth) && valid_digest?(auth)
end
valid_digest?(auth) click to toggle source
# File lib/rack/auth/digest/md5.rb, line 97
def valid_digest?(auth)
  pw = @authenticator.call(auth.username)
  pw && digest(auth, pw) == auth.response
end
valid_nonce?(auth) click to toggle source
# File lib/rack/auth/digest/md5.rb, line 93
def valid_nonce?(auth)
  auth.nonce.valid?
end
valid_opaque?(auth) click to toggle source
# File lib/rack/auth/digest/md5.rb, line 89
def valid_opaque?(auth)
  H(opaque) == auth.opaque
end
valid_qop?(auth) click to toggle source
# File lib/rack/auth/digest/md5.rb, line 85
def valid_qop?(auth)
  QOP == auth.qop
end