Skip to content

Commit

Permalink
Add #auth method for SASL authentication
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
nevans committed Oct 15, 2023
1 parent 3d14232 commit 4efd8a4
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 0 deletions.
16 changes: 16 additions & 0 deletions lib/net/smtp.rb
Original file line number Diff line number Diff line change
Expand Up @@ -897,6 +897,22 @@ def authenticate(*args, **kwargs, &block)
raise ArgumentError, "wrong number of arguments " \
"(given %d, expected 0..3)" % [args.length]
end
auth(authtype, *args, **kwargs, &block)
end

# call-seq:
# auth(type = DEFAULT_AUTH_TYPE, ...)
# auth(type: DEFAULT_AUTH_TYPE, **kwargs, &block)
#
# All arguments besides +mechanism+ are forwarded directly to the
# authenticator. Alternatively, +mechanism+ can be provided by the +type+
# keyword parameter. Positional parameters cannot be used with +type+.
#
# Different authenticators take different options, but common options
# include +authcid+ for authentication identity, +authzid+ for authorization
# identity, +username+ for either "authentication identity" or
# "authorization identity" depending on the +mechanism+, and +password+.
def auth(authtype = DEFAULT_AUTH_TYPE, *args, **kwargs, &block)
authtype, args, kwargs = check_auth_args authtype, *args, **kwargs
authenticator = Authenticator.auth_class(authtype).new(self)
critical { authenticator.auth(*args, **kwargs, &block) }
Expand Down
25 changes: 25 additions & 0 deletions test/net/smtp/test_smtp.rb
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,21 @@ def test_auth_plain
smtp = Net::SMTP.start 'localhost', server.port
assert smtp.authenticate("account", "password", :plain).success?
assert_equal "AUTH PLAIN AGFjY291bnQAcGFzc3dvcmQ=\r\n", server.commands.last

server = FakeServer.start(auth: 'plain')
smtp = Net::SMTP.start 'localhost', server.port
assert smtp.auth("PLAIN", "account", "password").success?
assert_equal "AUTH PLAIN AGFjY291bnQAcGFzc3dvcmQ=\r\n", server.commands.last

server = FakeServer.start(auth: 'plain')
smtp = Net::SMTP.start 'localhost', server.port
assert smtp.auth(type: "PLAIN", username: "account", secret: "password").success?
assert_equal "AUTH PLAIN AGFjY291bnQAcGFzc3dvcmQ=\r\n", server.commands.last

server = FakeServer.start(auth: 'plain')
smtp = Net::SMTP.start 'localhost', server.port
assert smtp.auth("PLAIN", username: "account", password: "password").success?
assert_equal "AUTH PLAIN AGFjY291bnQAcGFzc3dvcmQ=\r\n", server.commands.last
end

def test_unsucessful_auth_plain
Expand All @@ -120,10 +135,20 @@ def test_unsucessful_auth_plain
assert_equal "535", err.response.status
end

def test_auth_cram_md5
server = FakeServer.start(auth: 'CRAM-MD5')
smtp = Net::SMTP.start 'localhost', server.port
assert smtp.auth(:cram_md5, "account", password: "password").success?
end

def test_auth_login
server = FakeServer.start(auth: 'login')
smtp = Net::SMTP.start 'localhost', server.port
assert smtp.authenticate("account", "password", :login).success?

server = FakeServer.start(auth: 'login')
smtp = Net::SMTP.start 'localhost', server.port
assert smtp.auth("LOGIN", username: "account", secret: "password").success?
end

def test_unsucessful_auth_login
Expand Down

0 comments on commit 4efd8a4

Please sign in to comment.