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 25
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 38
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 34
def passwords_hashed?
  !!@passwords_hashed
end

Private Instance Methods

A1(auth, password) click to toggle source
# File lib/rack/auth/digest/md5.rb, line 113
def A1(auth, password)
  "#{auth.username}:#{auth.realm}:#{password}"
end
A2(auth) click to toggle source
# File lib/rack/auth/digest/md5.rb, line 117
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 109
def KD(secret, data)
  H "#{secret}:#{data}"
end
challenge(hash = {}) click to toggle source
# File lib/rack/auth/digest/md5.rb, line 78
def challenge(hash = {})
  "Digest #{params(hash)}"
end
digest(auth, password) click to toggle source
# File lib/rack/auth/digest/md5.rb, line 121
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 103
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 67
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 82
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 98
def valid_digest?(auth)
  pw = @authenticator.call(auth.username)
  pw && Rack::Utils.secure_compare(digest(auth, pw), auth.response)
end
valid_nonce?(auth) click to toggle source
# File lib/rack/auth/digest/md5.rb, line 94
def valid_nonce?(auth)
  auth.nonce.valid?
end
valid_opaque?(auth) click to toggle source
# File lib/rack/auth/digest/md5.rb, line 90
def valid_opaque?(auth)
  H(opaque) == auth.opaque
end
valid_qop?(auth) click to toggle source
# File lib/rack/auth/digest/md5.rb, line 86
def valid_qop?(auth)
  QOP == auth.qop
end