class Rack::Auth::Digest::MD5
opaque
needs to be set to a constant base64/hexadecimal string.
and a block that looks up a plaintext password for a given username.
Initialize with the [Rack] application that you want protecting,
HTTP Digest Authentication, as per RFC 2617.
Rack::Auth::Digest::MD5 implements the MD5 algorithm version of
def A1(auth, password)
def A1(auth, password) "#{auth.username}:#{auth.realm}:#{password}" end
def A2(auth)
def A2(auth) "#{auth.method}:#{auth.uri}" end
def KD(secret, data)
def KD(secret, data) H "#{secret}:#{data}" end
def call(env)
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
def challenge(hash = {})
def challenge(hash = {}) "Digest #{params(hash)}" end
def digest(auth, password)
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
def initialize(app, realm = nil, opaque = nil, &authenticator)
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
def md5(data)
def md5(data) ::Digest::MD5.hexdigest(data) end
def params(hash = {})
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
def passwords_hashed?
def passwords_hashed? !!@passwords_hashed end
def valid?(auth)
def valid?(auth) valid_opaque?(auth) && valid_nonce?(auth) && valid_digest?(auth) end
def valid_digest?(auth)
def valid_digest?(auth) pw = @authenticator.call(auth.username) pw && Rack::Utils.secure_compare(digest(auth, pw), auth.response) end
def valid_nonce?(auth)
def valid_nonce?(auth) auth.nonce.valid? end
def valid_opaque?(auth)
def valid_opaque?(auth) H(opaque) == auth.opaque end
def valid_qop?(auth)
def valid_qop?(auth) QOP == auth.qop end