Specified by www.ietf.org/rfc/rfc2617.txt Inspired by segment7.net/projects/ruby/snippets/digest_auth.rb
The EndPoint classes mixes this in to support digest authentication.
Methods
public instance
protected instance
Classes and Modules
Class Rufus::Verbs::DigestAuthMixin::AuthInfoClass Rufus::Verbs::DigestAuthMixin::Challenge
Class Rufus::Verbs::DigestAuthMixin::ServerReply
Public instance methods
Interprets the information in the response’s ‘Authorization-Info’ header.
# File lib/rufus/verbs/digest.rb, line 74 74: def check_authentication_info (res, opts) 75: 76: return if no_digest_auth 77: # not using digest authentication 78: 79: return unless @challenge 80: # not yet authenticated 81: 82: authinfo = AuthInfo.new res 83: @challenge.nonce = authinfo.nextnonce 84: end
Makes sure digest_auth is on
# File lib/rufus/verbs/digest.rb, line 43 43: def digest_auth (req, opts) 44: 45: #return if no_digest_auth 46: # already done in add_authentication() 47: 48: @cnonce ||= generate_cnonce 49: @nonce_count ||= 0 50: 51: mention_digest_auth(req, opts) \ 52: and return 53: 54: mention_digest_auth(req, opts) \ 55: if request_challenge(req, opts) 56: end
Sets the ‘Authorization’ header with the appropriate info.
# File lib/rufus/verbs/digest.rb, line 61 61: def mention_digest_auth (req, opts) 62: 63: return false unless @challenge 64: 65: req['Authorization'] = generate_header req, opts 66: 67: true 68: end
Protected instance methods
To be enhanced.
(For example www.intertwingly.net/blog/1585.html)
# File lib/rufus/verbs/digest.rb, line 102 102: def generate_cnonce 103: 104: Digest::MD5.hexdigest("%x" % (Time.now.to_i + rand(65535))) 105: end
Generates the Authentication header that will be returned to the server.
# File lib/rufus/verbs/digest.rb, line 138 138: def generate_header (req, opts) 139: 140: @nonce_count += 1 141: 142: user, pass = o(opts, :digest_authentication) 143: realm = @challenge.realm || "" 144: method = req.class.const_get(:METHOD) 145: path = opts[:path] 146: 147: a1 = if @challenge.algorithm == 'MD5-sess' 148: h(h(user, realm, pass), @challenge.nonce, @cnonce) 149: else 150: h(user, realm, pass) 151: end 152: 153: a2, qop = if @challenge.qop.include?("auth-int") 154: [ h(method, path, h(req.body)), "auth-int" ] 155: else 156: [ h(method, path), "auth" ] 157: end 158: 159: nc = ('%08x' % @nonce_count) 160: 161: digest = h( 162: #a1, @challenge.nonce, nc, @cnonce, @challenge.qop, a2) 163: a1, @challenge.nonce, nc, @cnonce, "auth", a2) 164: 165: header = "" 166: header << "Digest username=\"#{user}\", " 167: header << "realm=\"#{realm}\", " 168: header << "qop=\"#{qop}\", " 169: header << "uri=\"#{path}\", " 170: header << "nonce=\"#{@challenge.nonce}\", " 171: #header << "nc=##{nc}, " 172: header << "nc=#{nc}, " 173: header << "cnonce=\"#{@cnonce}\", " 174: header << "algorithm=\"#{@challenge.algorithm}\", " 175: #header << "algorithm=\"MD5-sess\", " 176: header << "response=\"#{digest}\", " 177: header << "opaque=\"#{@challenge.opaque}\"" 178: 179: header 180: end
Generates an MD5 digest of the arguments (joined by “:”).
# File lib/rufus/verbs/digest.rb, line 129 129: def h (*args) 130: 131: Digest::MD5.hexdigest(args.join(":")) 132: end
Returns true if :digest_authentication is set at endpoint or request level.
# File lib/rufus/verbs/digest.rb, line 92 92: def no_digest_auth 93: 94: (not o(opts, :digest_authentication)) 95: end
# File lib/rufus/verbs/digest.rb, line 107 107: def request_challenge (req, opts) 108: 109: op = opts.dup 110: 111: op[:digest_authentication] = false 112: # preventing an infinite loop 113: 114: method = req.class.const_get(:METHOD).downcase.to_sym 115: #method = :get 116: 117: res = request(method, op) 118: 119: return false if res.code.to_i != 401 120: 121: @challenge = Challenge.new res 122: 123: true 124: end