lib/rack/auth/digest/md5.rb in rack-2.2.10 vs lib/rack/auth/digest/md5.rb in rack-3.0.0.beta1

- old
+ new

@@ -1,131 +2 @@ -# frozen_string_literal: true - -require_relative '../abstract/handler' -require_relative 'request' -require_relative 'params' -require_relative 'nonce' -require 'digest/md5' - -module Rack - module Auth - module Digest - # 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. - # - class MD5 < AbstractHandler - - attr_accessor :opaque - - attr_writer :passwords_hashed - - 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 passwords_hashed? - !!@passwords_hashed - end - - 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 - - - private - - QOP = 'auth' - - 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 challenge(hash = {}) - "Digest #{params(hash)}" - end - - def valid?(auth) - valid_opaque?(auth) && valid_nonce?(auth) && valid_digest?(auth) - end - - def valid_qop?(auth) - QOP == auth.qop - end - - def valid_opaque?(auth) - H(opaque) == auth.opaque - end - - def valid_nonce?(auth) - auth.nonce.valid? - end - - def valid_digest?(auth) - pw = @authenticator.call(auth.username) - pw && Rack::Utils.secure_compare(digest(auth, pw), auth.response) - end - - def md5(data) - ::Digest::MD5.hexdigest(data) - end - - alias :H :md5 - - def KD(secret, data) - H "#{secret}:#{data}" - end - - def A1(auth, password) - "#{auth.username}:#{auth.realm}:#{password}" - end - - def A2(auth) - "#{auth.method}:#{auth.uri}" - end - - 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 - - end - end - end -end +require_relative '../digest'