# class WEBrick::HTTPAuth::DigestAuth

RFC 2617 Digest Access Authentication for WEBrick

Use this class to add digest authentication to a WEBrick servlet.

Here is an example of how to set up DigestAuth:

    config = { :Realm => 'DigestAuth example realm' }

    htdigest = WEBrick::HTTPAuth::Htdigest.new 'my_password_file'
    htdigest.set_passwd config[:Realm], 'username', 'password'
    htdigest.flush

    config[:UserDB] = htdigest

    digest_auth = WEBrick::HTTPAuth::DigestAuth.new config

When using this as with a servlet be sure not to create a new DigestAuth object in the servlet's initialize. By default WEBrick creates a new servlet instance for every request and the DigestAuth object must be used across requests.

### Attributes

algorithm[R]

Digest authentication algorithm

qop[R]

Quality of protection. RFC 2617 defines “auth” and “auth-int”

### Public Class Methods

make_passwd(realm, user, pass) click to toggle source

Used by UserDB to create a digest password entry

    # File lib/webrick/httpauth/digestauth.rb, line 68
    def self.make_passwd(realm, user, pass)
      pass ||= ""
      Digest::MD5::hexdigest([user, realm, pass].join(":"))
    end

new(config, default=Config::DigestAuth) click to toggle source

Creates a new DigestAuth instance. Be sure to use the same DigestAuth instance for multiple requests as it saves state between requests in order to perform authentication.

See WEBrick::Config::DigestAuth for default configuration entries

You must supply the following configuration entries:

:Realm

  The name of the realm being protected.

:UserDB

  A database of usernames and passwords. A WEBrick::HTTPAuth::Htdigest instance should be used.

    # File lib/webrick/httpauth/digestauth.rb, line 86
    def initialize(config, default=Config::DigestAuth)
      check_init(config)
      @config                 = default.dup.update(config)
      @algorithm              = @config[:Algorithm]
      @domain                 = @config[:Domain]
      @qop                    = @config[:Qop]
      @use_opaque             = @config[:UseOpaque]
      @use_next_nonce         = @config[:UseNextNonce]
      @check_nc               = @config[:CheckNc]
      @use_auth_info_header   = @config[:UseAuthenticationInfoHeader]
      @nonce_expire_period    = @config[:NonceExpirePeriod]
      @nonce_expire_delta     = @config[:NonceExpireDelta]
      @internet_explorer_hack = @config[:InternetExplorerHack]

      case @algorithm
      when 'MD5','MD5-sess'
        @h = Digest::MD5
      when 'SHA1','SHA1-sess'  # it is a bonus feature :-)
        @h = Digest::SHA1
      else
        msg = format('Algorithm "%s" is not supported.', @algorithm)
        raise ArgumentError.new(msg)
      end

      @instance_key = hexdigest(self.__id__, Time.now.to_i, Process.pid)
      @opaques = {}
      @last_nonce_expire = Time.now
      @mutex = Thread::Mutex.new
    end

### Public Instance Methods

authenticate(req, res) click to toggle source

Authenticates a `req` and returns a 401 Unauthorized using `res` if the authentication was not correct.

    # File lib/webrick/httpauth/digestauth.rb, line 120
    def authenticate(req, res)
      unless result = @mutex.synchronize{ _authenticate(req, res) }
        challenge(req, res)
      end
      if result == :nonce_is_stale
        challenge(req, res, true)
      end
      return true
    end

challenge(req, res, stale=false) click to toggle source

Returns a challenge response which asks for authentication information

    # File lib/webrick/httpauth/digestauth.rb, line 133
    def challenge(req, res, stale=false)
      nonce = generate_next_nonce(req)
      if @use_opaque
        opaque = generate_opaque(req)
        @opaques[opaque].nonce = nonce
      end

      param = Hash.new
      param["realm"]  = HTTPUtils::quote(@realm)
      param["domain"] = HTTPUtils::quote(@domain.to_a.join(" ")) if @domain
      param["nonce"]  = HTTPUtils::quote(nonce)
      param["opaque"] = HTTPUtils::quote(opaque) if opaque
      param["stale"]  = stale.to_s
      param["algorithm"] = @algorithm
      param["qop"]    = HTTPUtils::quote(@qop.to_a.join(",")) if @qop

      res[@response_field] =
        "#{@auth_scheme} " + param.map{|k,v| "#{k}=#{v}" }.join(", ")
      info("%s: %s", @response_field, res[@response_field]) if $DEBUG
      raise @auth_exception
    end