8000 🔒 Add SASL ANONYMOUS mechanism · ruby/net-imap@b6003f1 · GitHub
[go: up one dir, main page]

Skip to content

Commit b6003f1

Browse files
committed
🔒 Add SASL ANONYMOUS mechanism
See https://tools.ietf.org/html/rfc4505 for the specification.
1 parent 43a73ec commit b6003f1

File tree

5 files changed

+106
-0
lines changed

5 files changed

+106
-0
lines changed

lib/net/imap.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,6 +1002,12 @@ def starttls(options = {}, verify = true)
10021002
# Each mechanism has different properties and requirements. Please consult
10031003
# the documentation for the specific mechanisms you are using:
10041004
#
1005+
# +ANONYMOUS+::
1006+
# See AnonymousAuthenticator[Net::IMAP::SASL::AnonymousAuthenticator].
1007+
#
1008+
# Allows the user to gain access to public services or resources without
1009+
# authenticating or disclosing an identity.
1010+
#
10051011
# +OAUTHBEARER+::
10061012
# See OAuthBearerAuthenticator[rdoc-ref:Net::IMAP::SASL::OAuthBearerAuthenticator].
10071013
#

lib/net/imap/sasl.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ class IMAP
2727
# Each mechanism has different properties and requirements. Please consult
2828
# the documentation for the specific mechanisms you are using:
2929
#
30+
# +ANONYMOUS+::
31+
# See AnonymousAuthenticator[Net::IMAP::SASL::AnonymousAuthenticator].
32+
#
33+
# Allows the user to gain access to public services or resources without
34+
# authenticating or disclosing an identity.
35+
#
3036
# +OAUTHBEARER+::
3137
# See OAuthBearerAuthenticator.
3238
#
@@ -77,6 +83,8 @@ module SASL
7783
sasl_dir = File.expand_path("sasl", __dir__)
7884
autoload :Authenticators, "#{sasl_dir}/authenticators"
7985
autoload :GS2Header, "#{sasl_dir}/gs2_header"
86+
87+
autoload :AnonymousAuthenticator, "#{sasl_dir}/anonymous_authenticator"
8088
autoload :OAuthBearerAuthenticator, "#{sasl_dir}/oauthbearer_authenticator"
8189
autoload :PlainAuthenticator, "#{sasl_dir}/plain_authenticator"
8290
autoload :XOAuth2Authenticator, "#{sasl_dir}/xoauth2_authenticator"
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# frozen_string_literal: true
2+
3+
module Net
4+
class IMAP < Protocol
5+
module SASL
6+
7+
# Authenticator for the "+ANONYMOUS+" SASL mechanism, as specified by
8+
# RFC-4505[https://tools.ietf.org/html/rfc4505]. See
9+
# Net::IMAP#authenticate.
10+
class AnonymousAuthenticator
11+
12+
# :call-seq:
13+
# new(anonymous_message = "", **) -> authenticator
14+
# new(anonymous_message: "", **) -> authenticator
15+
#
16+
# Creates an Authenticator for the "+ANONYMOUS+" SASL mechanism, as
17+
# specified in RFC-4505[https://tools.ietf.org/html/rfc4505]. To use
18+
# this, see Net::IMAP#authenticate or your client's authentication
19+
# method.
20+
#
21+
# #anonymous_message is an optional message which is sent to the server.
22+
# It may be sent as a positional argument or as a keyword argument.
23+
#
24+
# Any other keyword parameters are quietly ignored.
25+
def initialize(anon_msg = nil, anonymous_message: nil, **)
26+
message = (anonymous_message || anon_msg || "").to_str
27+
@anonymous_message = StringPrep::Trace.stringprep_trace message
28+
if (size = @anonymous_message&.length)&.> 255
29+
raise ArgumentError,
30+
"anonymous_message is too long. (%d codepoints)" % [size]
31+
end
32+
end
33+
34+
# A token sent for the +ANONYMOUS+ mechanism.
35+
#
36+
# If it contains an "@" sign, the message must be a valid email address
37+
# (+addr-spec+ from RFC-2822[https://tools.ietf.org/html/rfc2822]).
38+
# Email syntax is _not_ validated by AnonymousAuthenticator.
39+
#
40+
# Otherwise, it can be any UTF8 string which is permitted by the
41+
# StringPrep::Trace profile, up to 255 UTF-8 characters in length.
42+
attr_reader :anonymous_message
43+
44+
# :call-seq:
45+
# initial_response? -> true
46+
#
47+
# +ANONYMOUS+ can send an initial client response.
48+
def initial_response?; true end
49+
50+
# Returns #anonymous_message.
51+
def process(_server_challenge_string) anonymous_message end
52+
53+
end
54+
end
55+
end
56+
end

lib/net/imap/sasl/authenticators.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class Authenticators
3333
def initialize(use_defaults: false)
3434
@authenticators = {}
3535
if use_defaults
36+
add_authenticator "Anonymous"
3637
add_authenticator "OAuthBearer"
3738
add_authenticator "Plain"
3839
add_authenticator "XOAuth2"

test/net/imap/test_imap_authenticators.rb

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,41 @@ def test_xoauth2_supports_initial_response
100100
assert Net::IMAP::SASL.initial_response?(xoauth2("foo", "bar"))
101101
end
102102

103+
# ----------------------
104+
# ANONYMOUS
105+
# ----------------------
106+
107+
def anonymous(*args, **kwargs, &block)
108+
Net::IMAP::SASL.authenticator("ANONYMOUS", *args, **kwargs, &block)
109+
end
110+
111+
def test_anonymous_matches_mechanism
112+
assert_kind_of(Net::IMAP::SASL::AnonymousAuthenticator, anonymous)
113+
end
114+
115+
def test_anonymous_response
116+
assert_equal("", anonymous.process(nil))
117+
assert_equal("hello world", anonymous("hello world").process(nil))
118+
assert_equal("kwargs",
119+
anonymous(anonymous_message: "kwargs").process(nil))
120+
end
121+
122+
def test_anonymous_stringprep
123+
assert_raise(Net::IMAP::SASL::ProhibitedCodepoint) {
124+
anonymous("no\ncontrol\rchars").process(nil)
125+
}
126+
assert_raise(Net::IMAP::SASL::ProhibitedCodepoint) {
127+
anonymous("regional flags use tagging chars: e.g." \
128+
"🏴󠁧󠁢󠁥󠁮󠁧󠁿 England, " \
129+
"🏴󠁧󠁢󠁳󠁣󠁴󠁿 Scotland, " \
130+
"🏴󠁧󠁢󠁷󠁬󠁳󠁿 Wales.").process(nil)
131+
}
132+
end
133+
134+
def test_anonymous_length_over_255
135+
assert_raise(ArgumentError) { anonymous("a" * 256).process(nil) }
136+
end
137+
103138
# ----------------------
104139
# LOGIN (obsolete)
105140
# ----------------------

0 commit comments

Comments
 (0)
0