gmail_xoauth 0.3.2 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +1 -1
- data/README.markdown +95 -56
- data/lib/gmail_xoauth.rb +2 -0
- data/lib/gmail_xoauth/imap_xoauth2_authenticator.rb +24 -0
- data/lib/gmail_xoauth/oauth_string.rb +11 -2
- data/lib/gmail_xoauth/smtp_xoauth2_authenticator.rb +25 -0
- data/lib/gmail_xoauth/version.rb +1 -1
- data/test/helper.rb +3 -1
- data/test/test_imap_xoauth2_authenticator.rb +32 -0
- data/test/test_smtp_xoauth2_authenticator.rb +32 -0
- data/test/test_smtp_xoauth_authenticator.rb +2 -2
- metadata +7 -3
data/LICENSE
CHANGED
data/README.markdown
CHANGED
@@ -1,18 +1,48 @@
|
|
1
1
|
# gmail_xoauth [](https://gemnasium.com/nfo/gmail_xoauth)
|
2
2
|
|
3
|
-
Get access to [Gmail IMAP and STMP via OAuth](
|
3
|
+
Get access to [Gmail IMAP and STMP via OAuth2](https://developers.google.com/google-apps/gmail/xoauth2_protocol) and [OAuth 1.0a](https://developers.google.com/google-apps/gmail/oauth_protocol), using the standard Ruby Net libraries.
|
4
4
|
|
5
5
|
The gem supports 3-legged OAuth, and 2-legged OAuth for Google Apps Business or Education account owners.
|
6
6
|
|
7
|
-
Note: 2-legged OAuth support was added by [Wojciech Kruszewski](https://github.com/wojciech).
|
8
|
-
|
9
7
|
## Install
|
10
8
|
|
11
9
|
$ gem install gmail_xoauth
|
12
10
|
|
13
|
-
## Usage
|
11
|
+
## Usage for OAuth 2.0
|
12
|
+
|
13
|
+
### Get your OAuth 2.0 tokens
|
14
|
+
|
15
|
+
You can generate and validate your OAuth 2.0 tokens thanks to the [oauth2.py tool](http://code.google.com/p/google-mail-oauth2-tools/wiki/OAuth2DotPyRunThrough).
|
16
|
+
|
17
|
+
Create your API project in the [Google APIs console](https://code.google.com/apis/console/), from the "API Access" tab.
|
18
|
+
|
19
|
+
$ python oauth2.py --generate_oauth2_token --client_id=364545978226.apps.googleusercontent.com --client_secret=zNrNsBzOOnQy8_O-8LkofeTR
|
20
|
+
|
21
|
+
### IMAP OAuth 2.0
|
14
22
|
|
15
|
-
|
23
|
+
```ruby
|
24
|
+
require 'gmail_xoauth'
|
25
|
+
imap = Net::IMAP.new('imap.gmail.com', 993, usessl = true, certs = nil, verify = false)
|
26
|
+
imap.authenticate('XOAUTH2', 'myemail@gmail.com', my_oauth2_token)
|
27
|
+
messages_count = imap.status('INBOX', ['MESSAGES'])['MESSAGES']
|
28
|
+
puts "Seeing #{messages_count} messages in INBOX"
|
29
|
+
```
|
30
|
+
|
31
|
+
### SMTP OAuth 2.0
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
require 'gmail_xoauth'
|
35
|
+
smtp = Net::SMTP.new('smtp.gmail.com', 587)
|
36
|
+
smtp.enable_starttls_auto
|
37
|
+
smtp.start('gmail.com', 'myemail@gmail.com', my_oauth2_token, :xoauth2)
|
38
|
+
smtp.finish
|
39
|
+
```
|
40
|
+
|
41
|
+
## Usage for OAuth 1.0a
|
42
|
+
|
43
|
+
== *[OAuth 1.0 has been officially deprecated as of April 20, 2012](https://developers.google.com/google-apps/gmail/oauth_protocol)*. ==
|
44
|
+
|
45
|
+
### Get your OAuth 1.0a tokens
|
16
46
|
|
17
47
|
For testing, you can generate and validate your OAuth tokens thanks to the awesome [xoauth.py tool](http://code.google.com/p/google-mail-xoauth-tools/wiki/XoauthDotPyRunThrough).
|
18
48
|
|
@@ -20,76 +50,85 @@ For testing, you can generate and validate your OAuth tokens thanks to the aweso
|
|
20
50
|
|
21
51
|
Or if you want some webapp code, check the [gmail-oauth-sinatra](https://github.com/nfo/gmail-oauth-sinatra) project.
|
22
52
|
|
23
|
-
### IMAP
|
53
|
+
### IMAP 3-legged OAuth 1.0a
|
24
54
|
|
25
55
|
For your tests, Gmail allows to set 'anonymous' as the consumer key and secret.
|
26
56
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
57
|
+
```ruby
|
58
|
+
require 'gmail_xoauth'
|
59
|
+
imap = Net::IMAP.new('imap.gmail.com', 993, usessl = true, certs = nil, verify = false)
|
60
|
+
imap.authenticate('XOAUTH', 'myemail@gmail.com',
|
61
|
+
:consumer_key => 'anonymous',
|
62
|
+
:consumer_secret => 'anonymous',
|
63
|
+
:token => '4/nM2QAaunKUINb4RrXPC55F-mix_k',
|
64
|
+
:token_secret => '41r18IyXjIvuyabS/NDyW6+m'
|
65
|
+
)
|
66
|
+
messages_count = imap.status('INBOX', ['MESSAGES'])['MESSAGES']
|
67
|
+
puts "Seeing #{messages_count} messages in INBOX"
|
68
|
+
```
|
37
69
|
|
38
70
|
Note that the [Net::IMAP#login](http://www.ruby-doc.org/core/classes/Net/IMAP.html#M004191) method does not use support custom authenticators, so you have to use the [Net::IMAP#authenticate](http://www.ruby-doc.org/core/classes/Net/IMAP.html#M004190) method.
|
39
71
|
|
40
|
-
|
72
|
+
### IMAP 2-legged OAuth 1.0a
|
41
73
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
74
|
+
```ruby
|
75
|
+
require 'gmail_xoauth'
|
76
|
+
imap = Net::IMAP.new('imap.gmail.com', 993, usessl = true, certs = nil, verify = false)
|
77
|
+
imap.authenticate('XOAUTH', 'myemail@mydomain.com',
|
78
|
+
:two_legged => true,
|
79
|
+
:consumer_key => 'a',
|
80
|
+
:consumer_secret => 'b'
|
81
|
+
)
|
82
|
+
```
|
49
83
|
|
50
|
-
### SMTP
|
84
|
+
### SMTP 3-legged OAuth 1.0a
|
51
85
|
|
52
86
|
For your tests, Gmail allows to set 'anonymous' as the consumer key and secret.
|
53
87
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
88
|
+
```ruby
|
89
|
+
require 'gmail_xoauth'
|
90
|
+
smtp = Net::SMTP.new('smtp.gmail.com', 587)
|
91
|
+
smtp.enable_starttls_auto
|
92
|
+
secret = {
|
93
|
+
:consumer_key => 'anonymous',
|
94
|
+
:consumer_secret => 'anonymous',
|
95
|
+
:token => '4/nM2QAaunKUINb4RrXPC55F-mix_k',
|
96
|
+
:token_secret => '41r18IyXjIvuyabS/NDyW6+m'
|
97
|
+
}
|
98
|
+
smtp.start('gmail.com', 'myemail@gmail.com', secret, :xoauth)
|
99
|
+
smtp.finish
|
100
|
+
```
|
101
|
+
|
102
|
+
Note that `Net::SMTP#enable_starttls_auto` is not defined in Ruby 1.8.6.
|
103
|
+
|
104
|
+
### SMTP 2-legged OAuth 1.0a
|
105
|
+
|
106
|
+
```ruby
|
107
|
+
require 'gmail_xoauth'
|
108
|
+
smtp = Net::SMTP.new('smtp.gmail.com', 587)
|
109
|
+
smtp.enable_starttls_auto
|
110
|
+
secret = {
|
111
|
+
:two_legged => true,
|
112
|
+
:consumer_key => 'a',
|
113
|
+
:consumer_secret => 'b'
|
114
|
+
}
|
115
|
+
smtp.start('gmail.com', 'myemail@mydomain.com', secret, :xoauth)
|
116
|
+
smtp.finish
|
117
|
+
```
|
81
118
|
|
82
119
|
## Compatibility
|
83
120
|
|
84
|
-
Tested on Ruby MRI 1.8.6, 1.8.7, 1.9.1 and 1.9.
|
121
|
+
Tested on Ruby MRI 1.8.6, 1.8.7, 1.9.1, 1.9.2 and 1.9.3. Feel free to send me a message if you tested this code with other implementations of Ruby.
|
85
122
|
|
86
123
|
The only external dependency is the [oauth gem](http://rubygems.org/gems/oauth).
|
87
124
|
|
88
125
|
## History
|
89
126
|
|
127
|
+
* 0.4.1 Changed to way to give the OAuth 2.0 token, see https://github.com/nfo/gmail_xoauth/commit/b7b936cfb094c2fc9b8e9e48526906191423cb88
|
128
|
+
* 0.4.0 [XOAUTH2](https://developers.google.com/google-apps/gmail/xoauth2_protocol) support, thanks to [glongman](https://github.com/glongman)
|
90
129
|
* 0.3.2 New email for the maintainer
|
91
130
|
* 0.3.1 2-legged OAuth support confirmed by [BobDohnal](https://github.com/BobDohnal)
|
92
|
-
* 0.3.0 Experimental 2-legged OAuth support
|
131
|
+
* 0.3.0 Experimental 2-legged OAuth support, thanks to [wojciech](https://github.com/wojciech)
|
93
132
|
* 0.2.0 SMTP support
|
94
133
|
* 0.1.0 Initial release with IMAP support and 3-legged OAuth
|
95
134
|
|
@@ -107,6 +146,6 @@ The only external dependency is the [oauth gem](http://rubygems.org/gems/oauth).
|
|
107
146
|
|
108
147
|
http://about.me/nfo
|
109
148
|
|
110
|
-
##
|
149
|
+
## License
|
111
150
|
|
112
|
-
|
151
|
+
See LICENSE for details.
|
data/lib/gmail_xoauth.rb
CHANGED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'net/imap'
|
2
|
+
|
3
|
+
module GmailXoauth
|
4
|
+
class ImapXoauth2Authenticator
|
5
|
+
|
6
|
+
def process(data)
|
7
|
+
build_oauth2_string(@user, @oauth2_token)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
# +user+ is an email address: roger@gmail.com
|
13
|
+
# +oauth2_token+ is the OAuth2 token
|
14
|
+
def initialize(user, oauth2_token)
|
15
|
+
@user = user
|
16
|
+
@oauth2_token = oauth2_token
|
17
|
+
end
|
18
|
+
|
19
|
+
include OauthString
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
Net::IMAP.add_authenticator('XOAUTH2', GmailXoauth::ImapXoauth2Authenticator)
|
@@ -4,7 +4,7 @@ module GmailXoauth
|
|
4
4
|
private
|
5
5
|
|
6
6
|
#
|
7
|
-
# Builds the "oauth protocol parameter string". See
|
7
|
+
# Builds the "oauth protocol parameter string". See https://developers.google.com/google-apps/gmail/oauth_protocol#sasl_initial_client_request
|
8
8
|
#
|
9
9
|
# +request_url+ https://mail.google.com/mail/b/user_name@gmail.com/{imap|smtp}/
|
10
10
|
# +oauth_params+ contains the following keys:
|
@@ -45,10 +45,19 @@ module GmailXoauth
|
|
45
45
|
oauth_request_params.map { |k,v| "#{k}=\"#{OAuth::Helper.escape(v)}\"" }.sort.join(',')
|
46
46
|
end
|
47
47
|
|
48
|
-
# See
|
48
|
+
# See https://developers.google.com/google-apps/gmail/oauth_protocol#sasl_initial_client_request
|
49
49
|
def build_sasl_client_request(request_url, oauth_string)
|
50
50
|
'GET ' + request_url + ' ' + oauth_string
|
51
51
|
end
|
52
|
+
|
53
|
+
#
|
54
|
+
# Builds the "oauth2 protocol authentication string". See https://developers.google.com/google-apps/gmail/xoauth2_protocol
|
55
|
+
#
|
56
|
+
# +user+ is an email address: roger@gmail.com
|
57
|
+
# +oauth2_token+ is the oauth2 token
|
58
|
+
def build_oauth2_string(user, oauth2_token)
|
59
|
+
"user=%s\1auth=Bearer %s\1\1".encode("us-ascii") % [user, oauth2_token]
|
60
|
+
end
|
52
61
|
|
53
62
|
end
|
54
63
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'net/smtp'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
module GmailXoauth
|
5
|
+
module SmtpXoauth2Authenticator
|
6
|
+
|
7
|
+
def auth_xoauth2(user, oauth2_token)
|
8
|
+
check_auth_args user, oauth2_token
|
9
|
+
|
10
|
+
auth_string = build_oauth2_string(user, oauth2_token)
|
11
|
+
res = critical {
|
12
|
+
get_response("AUTH XOAUTH2 #{base64_encode(auth_string)}")
|
13
|
+
}
|
14
|
+
|
15
|
+
check_auth_response res
|
16
|
+
res
|
17
|
+
end
|
18
|
+
|
19
|
+
include OauthString
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Not pretty, right ?
|
25
|
+
Net::SMTP.__send__('include', GmailXoauth::SmtpXoauth2Authenticator)
|
data/lib/gmail_xoauth/version.rb
CHANGED
data/test/helper.rb
CHANGED
@@ -26,7 +26,8 @@ VALID_CREDENTIALS = begin
|
|
26
26
|
rescue Errno::ENOENT
|
27
27
|
STDERR.puts %(
|
28
28
|
Warning: some tests are disabled because they require valid credentials. To enable them, create a file \"test/valid_credentials.yml\".
|
29
|
-
It should contain valid OAuth tokens. Valid tokens can be generated thanks to \"xoauth.py\":http://code.google.com/p/google-mail-xoauth-tools/.
|
29
|
+
It should contain valid OAuth tokens. Valid tokens oauth tokens can be generated thanks to \"xoauth.py\":http://code.google.com/p/google-mail-xoauth-tools/.
|
30
|
+
It should also ontain a valid OAuth2 access token. Valid tokens oauth2 tokens can be generated thanks to \"oauth2.py\":http://code.google.com/p/google-mail-oauth2-tools//. Note that oauth2 access tokens are time limited (an hour in my experience).
|
30
31
|
Of course, this file is .gitignored. Template:
|
31
32
|
|
32
33
|
---
|
@@ -35,6 +36,7 @@ Of course, this file is .gitignored. Template:
|
|
35
36
|
:consumer_secret: anonymous # "anonymous" is a valid value for testing
|
36
37
|
:token: 1/nE2xBCDOU0429bTeJySE11kRE95qzKQNlfTaaBcDeFg
|
37
38
|
:token_secret: 123Z/bMsi9fFhN6qHFWOabcd
|
39
|
+
:oauth2_token: ya29.AHES6ZTIpsLuSyMwnh-3C40WWcuiOe4N7he0a8xnkvDk_6Q_6yUg7E
|
38
40
|
|
39
41
|
)
|
40
42
|
false
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestImapXoauth2Authenticator < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_xoauth2_authenticator_is_enabled
|
9
|
+
authenticators = Net::IMAP.__send__('class_variable_get', '@@authenticators')
|
10
|
+
assert_not_nil authenticators['XOAUTH2']
|
11
|
+
assert_equal authenticators['XOAUTH2'], GmailXoauth::ImapXoauth2Authenticator
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_authenticate_with_invalid_credentials
|
15
|
+
imap = Net::IMAP.new('imap.gmail.com', 993, usessl = true, certs = nil, verify = false)
|
16
|
+
assert_raise(Net::IMAP::NoResponseError) do
|
17
|
+
imap.authenticate('XOAUTH2', 'roger@moore.com', 'a')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_authenticate_with_valid_credentials
|
22
|
+
return unless VALID_CREDENTIALS
|
23
|
+
|
24
|
+
imap = Net::IMAP.new('imap.gmail.com', 993, usessl = true, certs = nil, verify = false)
|
25
|
+
imap.authenticate('XOAUTH2', VALID_CREDENTIALS[:email], VALID_CREDENTIALS[:oauth2_token])
|
26
|
+
mailboxes = imap.list('', '*')
|
27
|
+
assert_instance_of Array, mailboxes
|
28
|
+
assert_instance_of Net::IMAP::MailboxList, mailboxes.first
|
29
|
+
ensure
|
30
|
+
imap.disconnect if imap
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestSmtpXoauthAuthenticator < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_smtp_authenticator_is_enabled
|
9
|
+
assert Net::SMTP.new(nil).respond_to?(:auth_xoauth2), 'The Net::SMTP class should define the method :auth_xoauth2'
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_authenticate_with_invalid_credentials
|
13
|
+
smtp = Net::SMTP.new('smtp.gmail.com', 587)
|
14
|
+
smtp.enable_starttls_auto
|
15
|
+
assert_raise(Net::SMTPAuthenticationError) do
|
16
|
+
smtp.start('gmail.com', 'roger@moore.com', 'a', :xoauth2)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_authenticate_with_valid_credentials
|
21
|
+
return unless VALID_CREDENTIALS
|
22
|
+
|
23
|
+
smtp = Net::SMTP.new('smtp.gmail.com', 587)
|
24
|
+
smtp.enable_starttls_auto
|
25
|
+
|
26
|
+
assert_nothing_raised do
|
27
|
+
smtp.start('gmail.com', VALID_CREDENTIALS[:email], VALID_CREDENTIALS[:oauth2_token], :xoauth2)
|
28
|
+
end
|
29
|
+
ensure
|
30
|
+
smtp.finish if smtp && smtp.started?
|
31
|
+
end
|
32
|
+
end
|
@@ -34,7 +34,7 @@ class TestSmtpXoauthAuthenticator < Test::Unit::TestCase
|
|
34
34
|
smtp.start('gmail.com', VALID_CREDENTIALS[:email], secret, :xoauth)
|
35
35
|
end
|
36
36
|
ensure
|
37
|
-
smtp.finish if smtp.started?
|
37
|
+
smtp.finish if smtp && smtp.started?
|
38
38
|
end
|
39
39
|
|
40
40
|
def test_2_legged_authenticate_with_invalid_credentials
|
@@ -61,6 +61,6 @@ class TestSmtpXoauthAuthenticator < Test::Unit::TestCase
|
|
61
61
|
smtp.start('gmail.com', VALID_CREDENTIALS[:email], secret, :xoauth)
|
62
62
|
end
|
63
63
|
ensure
|
64
|
-
smtp.finish if smtp.started?
|
64
|
+
smtp.finish if smtp && smtp.started?
|
65
65
|
end
|
66
66
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gmail_xoauth
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-09-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: oauth
|
@@ -51,14 +51,18 @@ executables: []
|
|
51
51
|
extensions: []
|
52
52
|
extra_rdoc_files: []
|
53
53
|
files:
|
54
|
+
- lib/gmail_xoauth/imap_xoauth2_authenticator.rb
|
54
55
|
- lib/gmail_xoauth/imap_xoauth_authenticator.rb
|
55
56
|
- lib/gmail_xoauth/oauth_string.rb
|
57
|
+
- lib/gmail_xoauth/smtp_xoauth2_authenticator.rb
|
56
58
|
- lib/gmail_xoauth/smtp_xoauth_authenticator.rb
|
57
59
|
- lib/gmail_xoauth/version.rb
|
58
60
|
- lib/gmail_xoauth.rb
|
59
61
|
- test/helper.rb
|
62
|
+
- test/test_imap_xoauth2_authenticator.rb
|
60
63
|
- test/test_imap_xoauth_authenticator.rb
|
61
64
|
- test/test_oauth_string.rb
|
65
|
+
- test/test_smtp_xoauth2_authenticator.rb
|
62
66
|
- test/test_smtp_xoauth_authenticator.rb
|
63
67
|
- LICENSE
|
64
68
|
- README.markdown
|
@@ -83,7 +87,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
83
87
|
version: 1.3.6
|
84
88
|
requirements: []
|
85
89
|
rubyforge_project:
|
86
|
-
rubygems_version: 1.8.
|
90
|
+
rubygems_version: 1.8.23
|
87
91
|
signing_key:
|
88
92
|
specification_version: 3
|
89
93
|
summary: Get access to Gmail IMAP and STMP via OAuth, using the standard Ruby Net
|