class Net::HTTP::DigestAuth

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

Constants

VERSION

Version of Net::HTTP::DigestAuth you are using

Public Class Methods

new(ignored = :ignored) click to toggle source

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

Public Instance Methods

auth_header(uri, www_authenticate, method, iis = false) click to toggle source

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
make_cnonce() click to toggle source

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
next_nonce() click to toggle source
# File lib/net/http/digest_auth.rb, line 166
def next_nonce
  synchronize do
    @nonce_count += 1
  end
end