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 =

:nodoc:

"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.



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/webrick/httpauth/digestauth.rb', line 87

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

Instance Attribute Details

#algorithmObject (readonly)

Digest authentication algorithm



59
60
61
# File 'lib/webrick/httpauth/digestauth.rb', line 59

def algorithm
  @algorithm
end

#qopObject (readonly)

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



64
65
66
# File 'lib/webrick/httpauth/digestauth.rb', line 64

def qop
  @qop
end

Class Method Details

.make_passwd(realm, user, pass) ⇒ Object

Used by UserDB to create a digest password entry



69
70
71
72
# File 'lib/webrick/httpauth/digestauth.rb', line 69

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.



121
122
123
124
125
126
127
128
129
# File 'lib/webrick/httpauth/digestauth.rb', line 121

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 authentication information

Raises:

  • (@auth_exception)


134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/webrick/httpauth/digestauth.rb', line 134

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