diff --git a/lib/net/imap/authenticators/plain.rb b/lib/net/imap/authenticators/plain.rb index 0829476c..2b6051c0 100644 --- a/lib/net/imap/authenticators/plain.rb +++ b/lib/net/imap/authenticators/plain.rb @@ -4,15 +4,30 @@ # # See RFC4616[https://tools.ietf.org/html/rfc4616] for the specification. class Net::IMAP::PlainAuthenticator + def process(data) - return "\0#{@user}\0#{@password}" + return "#@authzid\0#@username\0#@password" end + NULL = -"\0".b + private - def initialize(user, password) - @user = user + # +username+ is the authentication identity, the identity whose +password+ is + # used. +username+ is referred to as +authcid+ by + # RFC4616[https://tools.ietf.org/html/rfc4616]. + # + # +authzid+ is the authorization identity (identity to act as). It can + # usually be left blank. When +authzid+ is left blank (nil or empty string) + # the server will derive an identity from the credentials and use that as the + # authorization identity. + def initialize(username, password, authzid: nil) + raise ArgumentError, "username contains NULL" if username&.include?(NULL) + raise ArgumentError, "password contains NULL" if password&.include?(NULL) + raise ArgumentError, "authzid contains NULL" if authzid&.include?(NULL) + @username = username @password = password + @authzid = authzid end Net::IMAP.add_authenticator "PLAIN", self diff --git a/test/net/imap/test_imap_authenticators.rb b/test/net/imap/test_imap_authenticators.rb new file mode 100644 index 00000000..0c7a0a32 --- /dev/null +++ b/test/net/imap/test_imap_authenticators.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require "net/imap" +require "test/unit" + +class IMAPAuthenticatorsTest < Test::Unit::TestCase + + PLAIN = Net::IMAP::PlainAuthenticator + + def test_plain + assert_equal("\0authc\0passwd", + PLAIN.new("authc", "passwd").process(nil)) + assert_equal("authz\0user\0pass", + PLAIN.new("user", "pass", authzid: "authz").process(nil)) + end + + def test_plain_no_null_chars + assert_raise(ArgumentError) { PLAIN.new("bad\0user", "pass") } + assert_raise(ArgumentError) { PLAIN.new("user", "bad\0pass") } + assert_raise(ArgumentError) { PLAIN.new("u", "p", authzid: "bad\0authz") } + end + +end