Class: Net::IMAP::SASL::DigestMD5Authenticator
- Inherits:
-
Object
- Object
- Net::IMAP::SASL::DigestMD5Authenticator
- Defined in:
- lib/net/imap/sasl/digest_md5_authenticator.rb
Overview
Instance Attribute Summary collapse
-
#authzid ⇒ Object
readonly
Authorization identity: an identity to act as or on behalf of.
-
#password ⇒ Object
readonly
A password or passphrase that matches the #username.
-
#username ⇒ Object
(also: #authcid)
readonly
Authentication identity: the identity that matches the #password.
Instance Method Summary collapse
- #done? ⇒ Boolean
- #initial_response? ⇒ Boolean
-
#initialize(user = nil, pass = nil, authz = nil, username: nil, password: nil, authzid: nil, authcid: nil, secret: nil, warn_deprecation: true) ⇒ DigestMD5Authenticator
constructor
:call-seq: new(username, password, authzid = nil, **options) -> authenticator new(username:, password:, authzid: nil, **options) -> authenticator new(authcid:, password:, authzid: nil, **options) -> authenticator.
-
#process(challenge) ⇒ Object
Responds to server challenge in two stages.
Constructor Details
#initialize(user = nil, pass = nil, authz = nil, username: nil, password: nil, authzid: nil, authcid: nil, secret: nil, warn_deprecation: true) ⇒ DigestMD5Authenticator
:call-seq:
new(username, password, authzid = nil, **options) -> authenticator
new(username:, password:, authzid: nil, **options) -> authenticator
new(authcid:, password:, authzid: nil, **options) -> authenticator
Creates an Authenticator for the “DIGEST-MD5
” SASL mechanism.
Called by Net::IMAP#authenticate and similar methods on other clients.
Parameters
-
#authcid ― Authentication identity that is associated with #password.
#username ― An alias for
authcid
. -
#password ― A password or passphrase associated with this #authcid.
-
optional #authzid ― Authorization identity to act as or on behalf of.
When
authzid
is not set, the server should derive the authorization identity from the authentication identity. -
optional
warn_deprecation
— Set tofalse
to silence the warning.
Any other keyword arguments are silently ignored.
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/net/imap/sasl/digest_md5_authenticator.rb', line 70 def initialize(user = nil, pass = nil, authz = nil, username: nil, password: nil, authzid: nil, authcid: nil, secret: nil, warn_deprecation: true, **) username = authcid || username || user or raise ArgumentError, "missing username (authcid)" password ||= secret || pass or raise ArgumentError, "missing password" authzid ||= authz if warn_deprecation warn "WARNING: DIGEST-MD5 SASL mechanism was deprecated by RFC6331." # TODO: recommend SCRAM instead. end require "digest/md5" require "strscan" @username, @password, @authzid = username, password, authzid @nc, @stage = {}, STAGE_ONE end |
Instance Attribute Details
#authzid ⇒ Object (readonly)
Authorization identity: an identity to act as or on behalf of. The identity form is application protocol specific. If not provided or left blank, the server derives an authorization identity from the authentication identity. The server is responsible for verifying the client’s credentials and verifying that the identity it associates with the client’s authentication identity is allowed to act as (or on behalf of) the authorization identity.
For example, an administrator or superuser might take on another role:
imap.authenticate "DIGEST-MD5", "root", ->{passwd}, authzid: "user"
43 44 45 |
# File 'lib/net/imap/sasl/digest_md5_authenticator.rb', line 43 def authzid @authzid end |
#password ⇒ Object (readonly)
A password or passphrase that matches the #username.
The password
will be used to create the response digest.
30 31 32 |
# File 'lib/net/imap/sasl/digest_md5_authenticator.rb', line 30 def password @password end |
#username ⇒ Object (readonly) Also known as: authcid
24 25 26 |
# File 'lib/net/imap/sasl/digest_md5_authenticator.rb', line 24 def username @username end |
Instance Method Details
#done? ⇒ Boolean
156 |
# File 'lib/net/imap/sasl/digest_md5_authenticator.rb', line 156 def done?; @stage == STAGE_DONE end |
#initial_response? ⇒ Boolean
88 |
# File 'lib/net/imap/sasl/digest_md5_authenticator.rb', line 88 def initial_response?; false end |
#process(challenge) ⇒ Object
Responds to server challenge in two stages.
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 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/net/imap/sasl/digest_md5_authenticator.rb', line 91 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 Net::IMAP::DataFormatError, "Bad Challenge: '#{challenge}'" unless c.eos? and sparams['qop'] raise Net::IMAP::Error, "Server does not support auth (qop = #{sparams['qop'].join(',')})" unless sparams['qop'].include?("auth") 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 => 65535, :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'] a2 << ":00000000000000000000000000000000" if response[:qop] and response[:qop] =~ /^auth-(?:conf|int)$/ response[:response] = Digest::MD5.hexdigest( [ Digest::MD5.hexdigest(a1), response.values_at(:nonce, :nc, :cnonce, :qop), Digest::MD5.hexdigest(a2) ].join(':') ) return response.keys.map {|key| qdval(key.to_s, response[key]) }.join(',') when STAGE_TWO @stage = STAGE_DONE # if at the second stage, return an empty string if challenge =~ /rspauth=/ return '' else raise ResponseParseError, challenge end else raise ResponseParseError, challenge end end |