Skip to content

Commit f244f60

Browse files
committed
♻️ SASL CRAM-MD5: Add "#done?", moved to SASL
The protocol client is responsible for raising an error if the command completes successfully but "done?" returns false. Also moved to sasl dir and SASL module, and deprecated the old constant. Other than one or two minor stylistic changes, the code was left the same as before. This mechanism has not been updated to inherit from SASL::Authenticator.
1 parent 28b43c1 commit f244f60

File tree

6 files changed

+71
-55
lines changed

6 files changed

+71
-55
lines changed

lib/net/imap.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1000,7 +1000,7 @@ def starttls(options = {}, verify = true)
10001000
#
10011001
# For +LOGIN+, see LoginAuthenticator.
10021002
#
1003-
# For +CRAM-MD5+, see CramMD5Authenticator.
1003+
# For +CRAM-MD5+, see SASL::CramMD5Authenticator.
10041004
#
10051005
# <em>Using a deprecated mechanism will print a warning.</em>
10061006
#

lib/net/imap/authenticators.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,5 +72,5 @@ def authenticators
7272

7373
# deprecated
7474
require_relative "authenticators/login"
75-
require_relative "authenticators/cram_md5"
75+
require_relative "sasl/cram_md5_authenticator"
7676
require_relative "sasl/digest_md5_authenticator"

lib/net/imap/authenticators/cram_md5.rb

Lines changed: 0 additions & 51 deletions
This file was deleted.

lib/net/imap/sasl/authenticator.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ module SASL
3535
#
3636
# For +LOGIN+, see LoginAuthenticator.
3737
#
38-
# For +CRAM-MD5+, see CramMD5Authenticator.
38+
# For +CRAM-MD5+, see SASL::CramMD5Authenticator.
3939
#
4040
# <em>Using a deprecated mechanism will print a warning.</em>
4141
#
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# frozen_string_literal: true
2+
3+
module Net
4+
class IMAP < Protocol
5+
module SASL
6+
7+
# Authenticator for the "+CRAM-MD5+" SASL mechanism, specified in
8+
# RFC2195[https://tools.ietf.org/html/rfc2195]. See Net::IMAP#authenticate.
9+
#
10+
# == Deprecated
11+
#
12+
# +CRAM-MD5+ is obsolete and insecure. It is included for compatibility with
13+
# existing servers.
14+
# {draft-ietf-sasl-crammd5-to-historic}[https://tools.ietf.org/html/draft-ietf-sasl-crammd5-to-historic-00.html]
15+
# recommends using +SCRAM-*+ or +PLAIN+ protected by TLS instead.
16+
#
17+
# Additionally, RFC8314[https://tools.ietf.org/html/rfc8314] discourage the use
18+
# of cleartext and recommends TLS version 1.2 or greater be used for all
19+
# traffic. With TLS +CRAM-MD5+ is okay, but so is +PLAIN+
20+
class CramMD5Authenticator
21+
def process(challenge)
22+
digest = hmac_md5(challenge, @password)
23+
@user + " " + digest
24+
ensure
25+
@done = true
26+
end
27+
28+
def done?; @done end
29+
30+
private
31+
32+
def initialize(user, password, warn_deprecation: true, **_ignored)
33+
if warn_deprecation
34+
warn "WARNING: CRAM-MD5 mechanism is deprecated." # TODO: recommend SCRAM
35+
end
36+
require "digest/md5"
37+
@user = user
38+
@password = password
39+
@done = false
40+
end
41+
42+
def hmac_md5(text, key)
43+
if key.length > 64
44+
key = Digest::MD5.digest(key)
45+
end
46+
47+
k_ipad = key + "\0" * (64 - key.length)
48+
k_opad = key + "\0" * (64 - key.length)
49+
(0..63).each do |i|
50+
k_ipad[i] = (k_ipad[i].ord ^ 0x36).chr
51+
k_opad[i] = (k_opad[i].ord ^ 0x5c).chr
52+
end
53+
54+
digest = Digest::MD5.digest(k_ipad + text)
55+
56+
Digest::MD5.hexdigest(k_opad + digest)
57+
end
58+
59+
Net::IMAP.add_authenticator "CRAM-MD5", self
60+
end
61+
end
62+
63+
CramMD5Authenticator = SASL::CramMD5Authenticator # :nodoc:
64+
deprecate_constant :CramMD5Authenticator
65+
66+
end
67+
end

test/net/imap/sasl/test_authenticators.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ def cram_md5(*args, warn_deprecation: false, **kwargs, &block)
117117
end
118118

119119
def test_cram_md5_authenticator_matches_mechanism
120-
assert_kind_of(Net::IMAP::CramMD5Authenticator, cram_md5("n", "p"))
120+
assert_kind_of(Net::IMAP::SASL::CramMD5Authenticator, cram_md5("n", "p"))
121121
end
122122

123123
def test_cram_md5_authenticator_deprecated

0 commit comments

Comments
 (0)