Skip to content

Commit 510c293

Browse files
committed
Add #auth method for SASL authentication
Although `#authenticate` can be updated to make username and secret _both_ optional, by placing the mechanism last and making it optional, it's not possible to use an authenticator with a _single_ positional parameter or with more than two positional parameters. By placing `type` first among positional parameters or as a keyword argument, we avoid this problem.
1 parent a6280b6 commit 510c293

File tree

2 files changed

+41
-0
lines changed

2 files changed

+41
-0
lines changed

lib/net/smtp.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -898,6 +898,22 @@ def authenticate(*args, **kwargs, &block)
898898
raise ArgumentError, "wrong number of arguments " \
899899
"(given %d, expected 0..3)" % [args.length]
900900
end
901+
auth(authtype, *args, **kwargs, &block)
902+
end
903+
904+
# call-seq:
905+
# auth(type = DEFAULT_AUTH_TYPE, ...)
906+
# auth(type: DEFAULT_AUTH_TYPE, **kwargs, &block)
907+
#
908+
# All arguments besides +mechanism+ are forwarded directly to the
909+
# authenticator. Alternatively, +mechanism+ can be provided by the +type+
910+
# keyword parameter. Positional parameters cannot be used with +type+.
911+
#
912+
# Different authenticators take different options, but common options
913+
# include +authcid+ for authentication identity, +authzid+ for authorization
914+
# identity, +username+ for either "authentication identity" or
915+
# "authorization identity" depending on the +mechanism+, and +password+.
916+
def auth(authtype = DEFAULT_AUTH_TYPE, *args, **kwargs, &block)
901917
authtype, args, kwargs = check_auth_args authtype, *args, **kwargs
902918
authenticator = Authenticator.auth_class(authtype).new(self)
903919
authenticator.auth(*args, **kwargs, &block)

test/net/smtp/test_smtp.rb

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,21 @@ def test_auth_plain
110110
smtp = Net::SMTP.start 'localhost', server.port
111111
assert smtp.authenticate("account", "password", :plain).success?
112112
assert_equal "AUTH PLAIN AGFjY291bnQAcGFzc3dvcmQ=\r\n", server.commands.last
113+
114+
server = FakeServer.start(auth: 'plain')
115+
smtp = Net::SMTP.start 'localhost', server.port
116+
assert smtp.auth("PLAIN", "account", "password").success?
117+
assert_equal "AUTH PLAIN AGFjY291bnQAcGFzc3dvcmQ=\r\n", server.commands.last
118+
119+
server = FakeServer.start(auth: 'plain')
120+
smtp = Net::SMTP.start 'localhost', server.port
121+
assert smtp.auth(type: "PLAIN", username: "account", secret: "password").success?
122+
assert_equal "AUTH PLAIN AGFjY291bnQAcGFzc3dvcmQ=\r\n", server.commands.last
123+
124+
server = FakeServer.start(auth: 'plain')
125+
smtp = Net::SMTP.start 'localhost', server.port
126+
assert smtp.auth("PLAIN", username: "account", password: "password").success?
127+
assert_equal "AUTH PLAIN AGFjY291bnQAcGFzc3dvcmQ=\r\n", server.commands.last
113128
end
114129

115130
def test_unsucessful_auth_plain
@@ -120,10 +135,20 @@ def test_unsucessful_auth_plain
120135
assert_equal "535", err.response.status
121136
end
122137

138+
def test_auth_cram_md5
139+
server = FakeServer.start(auth: 'CRAM-MD5')
140+
smtp = Net::SMTP.start 'localhost', server.port
141+
assert smtp.auth(:cram_md5, "account", password: "password").success?
142+
end
143+
123144
def test_auth_login
124145
server = FakeServer.start(auth: 'login')
125146
smtp = Net::SMTP.start 'localhost', server.port
126147
assert smtp.authenticate("account", "password", :login).success?
148+
149+
server = FakeServer.start(auth: 'login')
150+
smtp = Net::SMTP.start 'localhost', server.port
151+
assert smtp.auth("LOGIN", username: "account", secret: "password").success?
127152
end
128153

129154
def test_unsucessful_auth_login

0 commit comments

Comments
 (0)