Class: Net::SASL::DigestMD5Authenticator
- Inherits:
-
Authenticator
- Object
- Authenticator
- Net::SASL::DigestMD5Authenticator
- Defined in:
- lib/net/sasl/digest_md5_authenticator.rb
Overview
Authenticator for the “‘DIGEST-MD5`” SASL mechanism type, specified in RFC2831(tools.ietf.org/html/rfc2831).
Deprecated
“DIGEST-MD5
” has been deprecated by RFC6331 and should not be relied on for security. It is included for compatibility with existing servers.
Instance Attribute Summary collapse
-
#authzid ⇒ Object
readonly
Returns the value of attribute authzid.
-
#password ⇒ Object
readonly
Returns the value of attribute password.
-
#username ⇒ Object
readonly
Returns the value of attribute username.
Instance Method Summary collapse
-
#done? ⇒ Boolean
returns true after two challenge/response stages.
-
#initialize(username, password, authzid = nil, **_options) ⇒ DigestMD5Authenticator
constructor
Provide the
username
andpassword
credentials. -
#process(challenge) ⇒ Object
responds to the server’s DIGEST-MD5 challenges.
Methods inherited from Authenticator
Constructor Details
#initialize(username, password, authzid = nil, **_options) ⇒ DigestMD5Authenticator
Provide the username
and password
credentials. An optional authzid
is defined as: “The ”authorization ID“ as per RFC2222, encoded in UTF-8. optional. If present, and the authenticating user has sufficient privilege, and the server supports it, then after authentication the server will use this identity for making all accesses and access checks. If the client specifies it, and the server does not support it, then the response-value will be incorrect, and authentication will fail.”
This should generally be instantiated via Net::SASL.authenticator.
37 38 39 40 41 |
# File 'lib/net/sasl/digest_md5_authenticator.rb', line 37 def initialize(username, password, authzid = nil, **) super @username, @password, @authzid = username, password, authzid @nc, @stage = {}, STAGE_ONE end |
Instance Attribute Details
#authzid ⇒ Object (readonly)
Returns the value of attribute authzid.
24 25 26 |
# File 'lib/net/sasl/digest_md5_authenticator.rb', line 24 def authzid @authzid end |
#password ⇒ Object (readonly)
Returns the value of attribute password.
24 25 26 |
# File 'lib/net/sasl/digest_md5_authenticator.rb', line 24 def password @password end |
#username ⇒ Object (readonly)
Returns the value of attribute username.
24 25 26 |
# File 'lib/net/sasl/digest_md5_authenticator.rb', line 24 def username @username end |
Instance Method Details
#done? ⇒ Boolean
returns true after two challenge/response stages
121 122 123 |
# File 'lib/net/sasl/digest_md5_authenticator.rb', line 121 def done? @stage.nil? end |
#process(challenge) ⇒ Object
responds to the server’s DIGEST-MD5 challenges
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 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 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/net/sasl/digest_md5_authenticator.rb', line 46 def process(challenge) case @stage when STAGE_ONE @stage = STAGE_TWO sparams = {} c = StringScanner.new(challenge) while c.scan(/(?:\s*,)?\s*(\w+)=("(?:[^\\"]+|\\.)*"|[^,]+)\s*/) k, v = c[1], c[2] if v =~ /^"(.*)"$/ v = $1 if v =~ /,/ v = v.split(",") end end sparams[k] = v end raise DataFormatError, "Bad Challenge: '#{challenge}'" unless c.rest.empty? unless sparams["qop"].include?("auth") raise Error, "Server does not support auth (qop = #{sparams["qop"].join(",")})" end response = { nonce: sparams["nonce"], username: @username, realm: sparams["realm"], cnonce: Digest::MD5.hexdigest("%.15f:%.15f:%d" % [Time.now.to_f, rand, Process.pid.to_s,]), 'digest-uri': "imap/#{sparams["realm"]}", qop: "auth", maxbuf: 65_535, nc: "%08d" % nc(sparams["nonce"]), charset: sparams["charset"], } response[:authzid] = @authzid unless @authzid.nil? # now, the real thing a0 = Digest::MD5.digest([ response.values_at(:username, :realm), @password, ].join(":")) a1 = [ a0, response.values_at(:nonce, :cnonce) ].join(":") a1 << ":#{response[:authzid]}" unless response[:authzid].nil? a2 = "AUTHENTICATE:#{response[:'digest-uri']}" if response[:qop] && response[:qop] =~ (/^auth-(?:conf|int)$/) a2 << ":00000000000000000000000000000000" end response[:response] = Digest::MD5.hexdigest( [ Digest::MD5.hexdigest(a1), response.values_at(:nonce, :nc, :cnonce, :qop), Digest::MD5.hexdigest(a2), ].join(":") ) response.keys.map {|key| qdval(key.to_s, response[key]) }.join(",") when STAGE_TWO @stage = nil # if at the second stage, return an empty string if challenge =~ /rspauth=/ "" else raise ChallengeParseError, challenge end else raise ChallengeParseError, challenge end end |