Skip to content

Commit 0918094

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 f004977 commit 0918094

File tree

4 files changed

+69
-53
lines changed

4 files changed

+69
-53
lines changed

lib/net/imap/authenticators/cram_md5.rb

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

lib/net/imap/sasl.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ module SASL
6565
autoload :PlainAuthenticator, "#{sasl_dir}/plain_authenticator"
6666
autoload :XOAuth2Authenticator, "#{sasl_dir}/xoauth2_authenticator"
6767

68+
autoload :CramMD5Authenticator, "#{sasl_dir}/cram_md5_authenticator"
6869
autoload :DigestMD5Authenticator, "#{sasl_dir}/digest_md5_authenticator"
6970

7071
# Authenticators are all lazy loaded
@@ -73,7 +74,7 @@ def self.authenticators
7374
registry.add_authenticator "Plain"
7475
registry.add_authenticator "XOAuth2"
7576
registry.add_authenticator "Login", LoginAuthenticator # deprecated
76-
registry.add_authenticator "Cram-MD5", CramMD5Authenticator # deprecated
77+
registry.add_authenticator "Cram-MD5" # deprecated
7778
registry.add_authenticator "Digest-MD5" # deprecated
7879
end
7980
end
@@ -106,4 +107,3 @@ def saslprep(string, **opts)
106107
end
107108

108109
require_relative "authenticators/login"
109-
require_relative "authenticators/cram_md5"
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
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+
end
60+
end
61+
62+
CramMD5Authenticator = SASL::CramMD5Authenticator # :nodoc:
63+
deprecate_constant :CramMD5Authenticator
64+
65+
end
66+
end

test/net/imap/test_imap_authenticators.rb

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

125125
def test_cram_md5_authenticator_matches_mechanism
126-
assert_kind_of(Net::IMAP::CramMD5Authenticator, cram_md5("n", "p"))
126+
assert_kind_of(Net::IMAP::SASL::CramMD5Authenticator, cram_md5("n", "p"))
127127
end
128128

129129
def test_cram_md5_authenticator_deprecated

0 commit comments

Comments
 (0)