class RaptorIO::Protocol::HTTP::Request::Manipulators::Authenticators::Digest

Implements HTTP Digest authentication as per RFC2069.

@see tools.ietf.org/html/rfc2069 @see en.wikipedia.org/wiki/Digest_access_authentication

@author Tasos Laskos

Private Class Methods

nc() click to toggle source
# File lib/raptor-io/protocol/http/request/manipulators/authenticators/digest.rb, line 103
def self.nc
  @nc ||= 0
  @nc += 1
end

Public Instance Methods

run() click to toggle source
# File lib/raptor-io/protocol/http/request/manipulators/authenticators/digest.rb, line 20
def run
  request.headers['Authorization'] = {
      'Digest username' => username,
      realm:               challenge[:realm],
      nonce:               challenge[:nonce],
      uri:                 request.resource,
      qop:                 challenge[:qop],
      nc:                  nc,
      cnonce:              cnonce,
      response:            response,
      algorithm:           algorithm_name,
      opaque:              challenge[:opaque]
  }.map { |k, v| "#{k}=\"#{v}\"" }.join( ', ' )
end

Private Instance Methods

A1() click to toggle source
# File lib/raptor-io/protocol/http/request/manipulators/authenticators/digest.rb, line 66
def A1
  without_sess = [ username, challenge[:realm], password ] * ':'

  if sess?
    H( [without_sess, challenge[:nonce], cnonce ] * ':' )
  else
    without_sess
  end
end
A2() click to toggle source
# File lib/raptor-io/protocol/http/request/manipulators/authenticators/digest.rb, line 76
def A2
  [ request.http_method.to_s.upcase, request.resource ] * ':'
end
H( data ) click to toggle source
# File lib/raptor-io/protocol/http/request/manipulators/authenticators/digest.rb, line 62
def H( data )
  algorithm_klass.hexdigest( data )
end
H1() click to toggle source
# File lib/raptor-io/protocol/http/request/manipulators/authenticators/digest.rb, line 80
def H1
  H( A1() )
end
H2() click to toggle source
# File lib/raptor-io/protocol/http/request/manipulators/authenticators/digest.rb, line 84
def H2
  H( A2() )
end
algorithm_klass() click to toggle source
# File lib/raptor-io/protocol/http/request/manipulators/authenticators/digest.rb, line 37
def algorithm_klass
  if challenge[:algorithm].to_s =~ /(.+)(-sess)?$/
    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
  else
    ::Digest::MD5
  end
end
algorithm_name() click to toggle source
# File lib/raptor-io/protocol/http/request/manipulators/authenticators/digest.rb, line 54
def algorithm_name
  algorithm_klass.to_s.split( '::' ).last
end
challenge() click to toggle source
# File lib/raptor-io/protocol/http/request/manipulators/authenticators/digest.rb, line 108
def challenge
  return @challenge if @challenge

  challenge_options = {}
  options[:response].headers['www-authenticate'].split( ',' ).each do |pair|
    matches = pair.strip.match( /(.+)="(.*)"/ )
    challenge_options[matches[1].to_sym] = matches[2]
  end
  challenge_options[:realm] = challenge_options.delete( :'Digest realm' )

  @challenge = challenge_options
end
cnonce() click to toggle source
# File lib/raptor-io/protocol/http/request/manipulators/authenticators/digest.rb, line 96
def cnonce
  [Time.now.to_i.to_s].pack( 'm*' ).strip
end
nc() click to toggle source
# File lib/raptor-io/protocol/http/request/manipulators/authenticators/digest.rb, line 100
def nc
  @nc ||= self.class.nc
end
password() click to toggle source
# File lib/raptor-io/protocol/http/request/manipulators/authenticators/digest.rb, line 125
def password
  options[:password]
end
response() click to toggle source
# File lib/raptor-io/protocol/http/request/manipulators/authenticators/digest.rb, line 88
def response
  if ['auth', 'auth-int'].include? challenge[:qop]
    return H( [H1(), challenge[:nonce], nc, cnonce, challenge[:qop],  H2()] * ':' )
  end

  H( [H1(), challenge[:nonce], H2()] * ':' )
end
sess?() click to toggle source
# File lib/raptor-io/protocol/http/request/manipulators/authenticators/digest.rb, line 58
def sess?
  challenge[:algorithm].to_s.include? '-sess'
end
username() click to toggle source
# File lib/raptor-io/protocol/http/request/manipulators/authenticators/digest.rb, line 121
def username
  options[:username]
end