Class: WEBrick::HTTPAuth::DigestAuth

Inherits:
Object
  • Object
show all
Includes:
Authenticator
Defined in:
lib/webrick/httpauth/digestauth.rb

Overview

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.

Direct Known Subclasses

ProxyDigestAuth

Defined Under Namespace

Classes: OpaqueInfo

Constant Summary collapse

AuthScheme =
"Digest"

Constants included from Authenticator

Authenticator::AuthException, Authenticator::RequestField, Authenticator::ResponseField, Authenticator::ResponseInfoField

Instance Attribute Summary collapse

Attributes included from Authenticator

#logger, #realm, #userdb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config, default = Config::DigestAuth) ⇒ DigestAuth

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.



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/webrick/httpauth/digestauth.rb', line 73

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 = Mutex.new
end

Instance Attribute Details

#algorithmObject (readonly)

Returns the value of attribute algorithm.



50
51
52
# File 'lib/webrick/httpauth/digestauth.rb', line 50

def algorithm
  @algorithm
end

#qopObject (readonly)

Returns the value of attribute qop.



50
51
52
# File 'lib/webrick/httpauth/digestauth.rb', line 50

def qop
  @qop
end

Class Method Details

.make_passwd(realm, user, pass) ⇒ Object

Used by UserDB to create a digest password entry



55
56
57
58
# File 'lib/webrick/httpauth/digestauth.rb', line 55

def self.make_passwd(realm, user, pass)
  pass ||= ""
  Digest::MD5::hexdigest([user, realm, pass].join(":"))
end

Instance Method Details

#authenticate(req, res) ⇒ Object

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



107
108
109
110
111
112
113
114
115
# File 'lib/webrick/httpauth/digestauth.rb', line 107

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) ⇒ Object

Returns a challenge response which asks for for authentication information

Raises:

  • (@auth_exception)


121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/webrick/httpauth/digestauth.rb', line 121

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