Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
# NEWS
## Unreleased

### Improvements

* Add XOAUTH2 authenticator <https://github.com/ruby/net-smtp/pull/47>

## Version 0.3.3 (2022-10-29)

Expand Down
30 changes: 30 additions & 0 deletions lib/net/smtp.rb
Original file line number Diff line number Diff line change
Expand Up @@ -857,6 +857,20 @@ def auth_login(user, secret)
res
end

def auth_xoauth2(user, oauth2_token)
check_auth_args user, oauth2_token

auth_string = build_oauth2_string(user, oauth2_token)
res = send_xoauth2(base64_encode(auth_string))

if res.continue?
res = get_final_status
end

check_auth_response res
res
end

def auth_cram_md5(user, secret)
check_auth_args user, secret
res = critical {
Expand Down Expand Up @@ -915,6 +929,22 @@ def cram_secret(secret, mask)
buf
end

def send_xoauth2(auth_token)
critical {
get_response("AUTH XOAUTH2 #{auth_token}")
}
end

def build_oauth2_string(user, oauth2_token)
format("user=%s\1auth=Bearer %s\1\1", user, oauth2_token)
end

def get_final_status
critical {
get_response("")
}
end

#
# SMTP command dispatcher
#
Expand Down
17 changes: 17 additions & 0 deletions test/net/smtp/test_smtp.rb
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,23 @@ def test_unsucessful_auth_plain
assert_equal "535", err.response.status
end

def test_auth_xoauth2
sock = FakeSocket.new("235 2.7.0 Authentication successful\r\n")
smtp = Net::SMTP.new 'localhost', 25
smtp.instance_variable_set :@socket, sock
assert smtp.auth_xoauth2("foo", "bar").success?
assert_equal "AUTH XOAUTH2 dXNlcj1mb28BYXV0aD1CZWFyZXIgYmFyAQE=\r\n", sock.write_io.string
end

def test_unsucessful_auth_xoauth2
sock = FakeSocket.new("535 5.7.8 BadCredentials\r\n")
smtp = Net::SMTP.new 'localhost', 25
smtp.instance_variable_set :@socket, sock
err = assert_raise(Net::SMTPAuthenticationError) { smtp.auth_xoauth2("foo", "bar") }
assert_equal "535 5.7.8 BadCredentials\n", err.message
assert_equal "535", err.response.status
end

def test_auth_login
sock = FakeSocket.new("334 VXNlcm5hbWU6\r\n334 UGFzc3dvcmQ6\r\n235 2.7.0 Authentication successful\r\n")
smtp = Net::SMTP.new 'localhost', 25
Expand Down