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.
Used by UserDB to create a digest password entry
# File webrick/httpauth/digestauth.rb, line 69
def self.make_passwd(realm, user, pass)
pass ||= ""
Digest::MD5::hexdigest([user, realm, pass].join(":"))
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:
The name of the realm being protected.
A database of usernames and passwords. A WEBrick::HTTPAuth::Htdigest instance should be used.
# File 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
Authenticates a req and returns a 401 Unauthorized using res if the authentication was not correct.
# File 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
Returns a challenge response which asks for authentication information
# File 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