Class | HTTPAuth::Digest::Utils |
In: |
lib/httpauth/digest.rb
|
Parent: | Object |
Calculate the digest value for the directives as explained in the RFC.
# File lib/httpauth/digest.rb, line 190 190: def calculate_digest(h, s, variant) 191: raise ArgumentError.new("Variant should be either :request or :response, not #{variant}") unless [:request, :response].include?(variant) 192: # Compatability with RFC 2069 193: if h[:qop].nil? 194: digest_kd digest_a1(h, s), digest_concat( 195: h[:nonce], 196: send("#{variant}_digest_a2".intern, h) 197: ) 198: else 199: digest_kd digest_a1(h, s), digest_concat( 200: h[:nonce], 201: Conversions.int_to_hex(h[:nc]), 202: h[:cnonce], 203: h[:qop], 204: send("#{variant}_digest_a2".intern, h) 205: ) 206: end 207: end
Create a nonce value of the time and a salt. The nonce is created in such a way that the issuer can check the age of the nonce.
# File lib/httpauth/digest.rb, line 223 223: def create_nonce(salt) 224: now = Time.now 225: time = now.strftime("%Y-%m-%d %H:%M:%S").to_s + ':' + now.usec.to_s 226: Base64.encode64( 227: digest_concat( 228: time, 229: digest_h(digest_concat(time, salt)) 230: ) 231: ).gsub("\n", '')[0..-3] 232: end
Create a 32 character long opaque string with a ‘random’ value
# File lib/httpauth/digest.rb, line 235 235: def create_opaque 236: s = []; 16.times { s << rand(127).chr } 237: digest_h s.join 238: end
Decodes digest directives from a header. Returns a hash with directives.
# File lib/httpauth/digest.rb, line 90 90: def decode_directives(directives, variant) 91: raise HTTPAuth::UnwellformedHeader.new("Can't decode directives which are nil") if directives.nil? 92: decode = {:domain => :split, :algorithm => false, :stale => :bool_to_str, :nc => :hex_to_int, 93: :nextnonce => :hex_to_int} 94: if [:credentials, :auth].include? variant 95: decode.merge! :qop => false 96: elsif variant == :challenge 97: decode.merge! :qop => :quoted_string_to_list 98: else 99: raise ArgumentError.new("#{variant} is not a valid value for `variant' use :auth, :credentials or :challenge") 100: end 101: 102: start = 0 103: unless variant == :auth 104: # The first six characters are 'Digest ' 105: start = 6 106: scheme = directives[0..6].strip 107: raise HTTPAuth::UnwellformedHeader.new("Scheme should be Digest, server responded with `#{directives}'") unless scheme == 'Digest' 108: end 109: 110: # The rest are the directives 111: # TODO: split is ugly, I want a real parser (: 112: directives[start..-1].split(',').inject({}) do |h,part| 113: parts = part.split('=') 114: name = parts[0].strip.intern 115: value = parts[1..-1].join('=').strip 116: 117: # --- HACK 118: # IE and Safari qoute qop values 119: # IE also quotes algorithm values 120: if variant != :challenge and [:qop, :algorithm].include?(name) and value =~ /^\"[^\"]+\"$/ 121: value = Conversions.unquote_string(value) 122: end 123: # --- END HACK 124: 125: if decode[name] 126: h[name] = Conversions.send decode[name], value 127: elsif decode[name].nil? 128: h[name] = Conversions.unquote_string value 129: else 130: h[name] = value 131: end 132: h 133: end 134: end
Calculate the H(A1) as explain in the RFC. If h[:digest] is set, it‘s used instead of calculating H(username ":" realm ":" password).
# File lib/httpauth/digest.rb, line 155 155: def digest_a1(h, s) 156: # TODO: check for known algorithm values (look out for the IE algorithm quote bug) 157: if h[:algorithm] == 'MD5-sess' 158: digest_h digest_concat( 159: h[:digest] || htdigest(h[:username], h[:realm], h[:password]), 160: h[:nonce], 161: h[:cnonce] 162: ) 163: else 164: h[:digest] || htdigest(h[:username], h[:realm], h[:password]) 165: end 166: end
Calculate the MD5 hexdigest for the string data
# File lib/httpauth/digest.rb, line 143 143: def digest_h(data); ::Digest::MD5.hexdigest data; end
Calculate the KD value of a secret and data as explained in the RFC.
# File lib/httpauth/digest.rb, line 146 146: def digest_kd(secret, data); digest_h digest_concat(secret, data); end
Encodes a hash with digest directives to send in a header.
# File lib/httpauth/digest.rb, line 56 56: def encode_directives(h, variant) 57: encode = {:domain => :join, :algorithm => false, :stale => :str_to_bool, :nc => :int_to_hex, 58: :nextnonce => :int_to_hex} 59: if [:credentials, :auth].include? variant 60: encode.merge! :qop => false 61: elsif variant == :challenge 62: encode.merge! :qop => :list_to_quoted_string 63: else 64: raise ArgumentError.new("#{variant} is not a valid value for `variant' use :auth, :credentials or :challenge") 65: end 66: (variant == :auth ? '' : 'Digest ') + h.collect do |directive, value| 67: '' << directive.to_s << '=' << if encode[directive] 68: begin 69: Conversions.send encode[directive], value 70: rescue NoMethodError, ArgumentError 71: raise ArgumentError.new("Can't encode #{directive}(#{value.inspect}) with #{encode[directive]}") 72: end 73: elsif encode[directive].nil? 74: begin 75: Conversions.quote_string value 76: rescue NoMethodError, ArgumentError 77: raise ArgumentError.new("Can't encode #{directive}(#{value.inspect}) with quote_string") 78: end 79: else 80: value 81: end 82: end.join(", ") 83: end
Return a hash with the keys in keys found in h.
Example
filter_h_on({1=>1,2=>2}, [1]) #=> {1=>1} filter_h_on({1=>1,2=>2}, [1, 2]) #=> {1=>1,2=>2}
# File lib/httpauth/digest.rb, line 215 215: def filter_h_on(h, keys) 216: h.inject({}) { |r,l| keys.include?(l[0]) ? r.merge({l[0]=>l[1]}) : r } 217: end
Calculate the H(A2) for the Authorize header as explained in the RFC.
# File lib/httpauth/digest.rb, line 169 169: def request_digest_a2(h) 170: # TODO: check for known qop values (look out for the safari qop quote bug) 171: if h[:qop] == 'auth-int' 172: digest_h digest_concat(h[:method], h[:uri], digest_h(h[:request_body])) 173: else 174: digest_h digest_concat(h[:method], h[:uri]) 175: end 176: end
Calculate the H(A2) for the Authentication-Info header as explained in the RFC.
# File lib/httpauth/digest.rb, line 179 179: def response_digest_a2(h) 180: if h[:qop] == 'auth-int' 181: digest_h ':' + digest_concat(h[:uri], digest_h(h[:response_body])) 182: else 183: digest_h ':' + h[:uri] 184: end 185: end