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.
Struct
containing the opaque portion of the digest authentication
Quality of protection. RFC 2617 defines “auth” and “auth-int”
# File tmp/rubies/ruby-2.6.10/lib/webrick/httpauth/digestauth.rb, line 69
def self.make_passwd(realm, user, pass)
pass ||= ""
Digest::MD5::hexdigest([user, realm, pass].join(":"))
end
Used by UserDB
to create a digest password entry
# File tmp/rubies/ruby-2.6.10/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
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 tmp/rubies/ruby-2.6.10/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
Authenticates a req
and returns a 401 Unauthorized using res
if the authentication was not correct.
# File tmp/rubies/ruby-2.6.10/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
Returns a challenge response which asks for authentication information