Class: HTTPAuth::Digest::Credentials

Inherits:
AbstractHeader show all
Defined in:
lib/httpauth/digest.rb

Overview

The Credentials class handlers the Authorize header. The Authorize header is sent by a client who wants to let the server know he has the credentials needed to access a resource.

See the Digest module for examples

Instance Attribute Summary collapse

Attributes inherited from AbstractHeader

#h

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from AbstractHeader

#method_missing

Constructor Details

#initialize(h, options = {}) ⇒ Credentials

Create a new instance.

  • h: A Hash with directives, normally this is filled with the directives coming from a Challenge instance.

  • options: Used to set or override data from the Authorize header and add additional parameters.

    • :username: Mostly set by a client to send the username

    • :password: Mostly set by a client to send the password, set either this or the digest

    • :digest: Mostly set by a client to send a digest, set either this or the digest. For more information about digests see Digest.

    • :uri: Mostly set by the client to send the uri

    • :method: The HTTP Method used by the client to send the request, this should be an uppercase string with the name of the verb.



323
324
325
326
327
328
329
# File 'lib/httpauth/digest.rb', line 323

def initialize(h, options = {})
  @h = h
  @h.merge! options
  session = Session.new h[:opaque], :tmpdir => options[:tmpdir]
  @s = session.load
  @reason = 'There has been no validation yet'
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class HTTPAuth::Digest::AbstractHeader

Instance Attribute Details

#reasonObject (readonly)

Holds an explanation why validate returned false.



283
284
285
# File 'lib/httpauth/digest.rb', line 283

def reason
  @reason
end

Class Method Details

.from_challenge(challenge, options = {}) ⇒ Object

Creates a new Credential instance based on a Challenge instance.

  • challenge: A Challenge instance

See initialize for valid options.



298
299
300
301
302
# File 'lib/httpauth/digest.rb', line 298

def self.from_challenge(challenge, options = {})
  credentials = new challenge.h
  credentials.update_from_challenge! options
  credentials
end

.from_header(authorization, options = {}) ⇒ Object

Parses the information from an Authorize header and creates a new Credentials instance with the information. The options hash allows you to specify additional information.

  • authorization: The contents of the Authorize header

See initialize for valid options.



290
291
292
# File 'lib/httpauth/digest.rb', line 290

def self.from_header(authorization, options = {})
  new Utils.decode_directives(authorization, :credentials), options
end

.load(filename, options = {}) ⇒ Object



304
305
306
307
308
309
310
# File 'lib/httpauth/digest.rb', line 304

def self.load(filename, options = {})
  h = nil
  File.open(filename, 'r') do |f|
    h = Marshal.load f
  end
  new h, options
end

Instance Method Details

#dump_sans_creds(filename) ⇒ Object



403
404
405
406
407
# File 'lib/httpauth/digest.rb', line 403

def dump_sans_creds(filename)
  File.open(filename, 'w') do |f|
    Marshal.dump(Utils.filter_h_on(@h, [:username, :realm, :nonce, :algorithm, :cnonce, :opaque, :qop, :nc]), f)
  end
end

#to_headerObject

Encodeds directives and returns a string that can be used in the Authorize header



369
370
371
372
# File 'lib/httpauth/digest.rb', line 369

def to_header
  Utils.encode_directives Utils.filter_h_on(@h,
                                            [:username, :realm, :nonce, :uri, :response, :algorithm, :cnonce, :opaque, :qop, :nc]), :credentials
end

#update_from_challenge!(options) ⇒ Object

Updates @h from options, generally called after an instance was created with from_challenge.



375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
# File 'lib/httpauth/digest.rb', line 375

def update_from_challenge!(options)
  # TODO: integrity checks
  @h[:username] = options[:username]
  @h[:password] = options[:password]
  @h[:digest] = options[:digest]
  @h[:uri] = options[:uri]
  @h[:method] = options[:method]
  @h[:request_body] = options[:request_body]
  unless @h[:qop].nil?
    # Determine the QOP
    if !options[:qop].nil? && @h[:qop].include?(options[:qop])
      @h[:qop] = options[:qop]
    elsif @h[:qop].include?(HTTPAuth::PREFERRED_QOP)
      @h[:qop] = HTTPAuth::PREFERRED_QOP
    else
      qop = @h[:qop].detect { |qop_field| HTTPAuth::SUPPORTED_QOPS.include? qop_field }
      if qop.nil?
        fail(UnsupportedError, "HTTPAuth doesn't support any of the proposed qop values: #{@h[:qop].inspect}")
      else
        @h[:qop] = qop
      end
    end
    @h[:cnonce] ||= Utils.create_nonce options[:salt]
    @h[:nc] ||= 1 unless @h[:qop].nil?
  end
  @h[:response] = Utils.calculate_digest(@h, @s, :request)
end

#validate(options) ⇒ Object

Validates the credential information stored in the Credentials instance. Returns true or false. You can read the ue

  • options: The extra options needed to validate the credentials. A server implementation should provide the :method and a :password or :digest.

    • :method: The HTTP Verb in uppercase, ie. GET or POST.

    • :password: The password for the sent username and realm, either a password or digest should be provided.

    • :digest: The digest for the specified username and realm, either a digest or password should be provided.



353
354
355
356
357
358
359
360
361
362
363
364
365
366
# File 'lib/httpauth/digest.rb', line 353

def validate(options)
  ho = @h.merge(options)
  fail(ArgumentError, "You have to set the :request_body value if you want to use :qop => 'auth-int'") if @h[:qop] == 'auth-int' && ho[:request_body].nil?
  fail(ArgumentError, 'Please specify the request method :method (ie. GET)') if ho[:method].nil?

  calculated_response = Utils.calculate_digest(ho, @s, :request)
  if ho[:response] == calculated_response
    @reason = ''
    return true
  else
    @reason = "Response isn't the same as computed response #{ho[:response]} != #{calculated_response} for #{ho.inspect}"
  end
  false
end

#validate_digest(digest, options = {}) ⇒ Object

Convenience method, basically an alias for validate(options.merge(:digest => digest))



338
339
340
341
# File 'lib/httpauth/digest.rb', line 338

def validate_digest(digest, options = {})
  options[:digest] = digest
  validate(options)
end

#validate_password(password, options = {}) ⇒ Object

Convenience method, basically an alias for validate(options.merge(:password => password))



332
333
334
335
# File 'lib/httpauth/digest.rb', line 332

def validate_password(password, options = {})
  options[:password] = password
  validate(options)
end