An implementation of RFC 2617 Digest Access Authentication.
www.rfc-editor.org/rfc/rfc2617.txt
Here is a sample usage of DigestAuth on Net::HTTP:
require 'uri' require 'net/http' require 'net/http/digest_auth' digest_auth = Net::HTTP::DigestAuth.new uri = URI.parse 'http://localhost:8000/' uri.user = 'username' uri.password = 'password' h = Net::HTTP.new uri.host, uri.port req = Net::HTTP::Get.new uri.request_uri res = h.request req # res is a 401 response with a WWW-Authenticate header auth = digest_auth.auth_header uri, res['www-authenticate'], 'GET' # create a new request with the Authorization header req = Net::HTTP::Get.new uri.request_uri req.add_field 'Authorization', auth # re-issue request with Authorization res = h.request req
Version of Net::HTTP::DigestAuth you are using
Creates a new DigestAuth header creator.
# File lib/net/http/digest_auth.rb, line 57 def initialize ignored = :ignored mon_initialize @nonce_count = -1 end
Creates a digest auth header for uri
from the
www_authenticate
header for HTTP method method
.
The result of this method should be sent along with the HTTP request as the “Authorization” header. In Net::HTTP this will look like:
request.add_field 'Authorization', digest_auth.auth_header # ...
See Net::HTTP::DigestAuth for a complete example.
IIS servers handle the “qop” parameter of digest authentication differently
so you may need to set iis
to true for such servers.
# File lib/net/http/digest_auth.rb, line 76 def auth_header uri, www_authenticate, method, iis = false nonce_count = next_nonce user = CGI.unescape uri.user password = CGI.unescape uri.password www_authenticate =~ /^(\w+) (.*)/ challenge = $2 params = {} challenge.gsub(/(\w+)="(.*?)"/) { params[$1] = $2 } challenge =~ /algorithm="?(.*?)"?([, ]|$)/ params['algorithm'] = $1 || 'MD5' if params['algorithm'] =~ /(.*?)(-sess)?$/ algorithm = case $1 when 'MD5' then Digest::MD5 when 'SHA1' then Digest::SHA1 when 'SHA2' then Digest::SHA2 when 'SHA256' then Digest::SHA256 when 'SHA384' then Digest::SHA384 when 'SHA512' then Digest::SHA512 when 'RMD160' then Digest::RMD160 else raise Error, "unknown algorithm \"#{$1}\"" end sess = $2 end qop = params['qop'] cnonce = make_cnonce if qop or sess a1 = if sess then [ algorithm.hexdigest("#{user}:#{params['realm']}:#{password}"), params['nonce'], cnonce, ].join ':' else "#{user}:#{params['realm']}:#{password}" end ha1 = algorithm.hexdigest a1 ha2 = algorithm.hexdigest "#{method}:#{uri.request_uri}" request_digest = [ha1, params['nonce']] request_digest.push(('%08x' % nonce_count), cnonce, qop) if qop request_digest << ha2 request_digest = request_digest.join ':' header = [ "Digest username=\"#{user}\"", "realm=\"#{params['realm']}\"", "algorithm=#{params['algorithm']}", if qop.nil? then elsif iis then "qop=\"#{qop}\"" else "qop=#{qop}" end, "uri=\"#{uri.request_uri}\"", "nonce=\"#{params['nonce']}\"", if qop then [ "nc=#{'%08x' % @nonce_count}", "cnonce=\"#{cnonce}\"", ] end, "response=\"#{algorithm.hexdigest(request_digest)[0, 32]}\"", if params.key? 'opaque' then "opaque=\"#{params['opaque']}\"" end ].compact header.join ', ' end
Creates a client nonce value that is used across all requests based on the current time, process id and a random number
# File lib/net/http/digest_auth.rb, line 158 def make_cnonce Digest::MD5.hexdigest [ Time.now.to_i, $$, SecureRandom.random_number(2**32), ].join ':' end
# File lib/net/http/digest_auth.rb, line 166 def next_nonce synchronize do @nonce_count += 1 end end