omniauth-google-oauth2 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- Nzk0NDc2ZmZhYjJiOTI1OWI5NDY1NDcwZTNlNWE2NTI0OTk1OWQwNQ==
4
+ NTE1ZjFkZmYyYTNlM2I4MTI5NmM2MmZlMWFlYjZmNjQ2YjNhNDU1MA==
5
5
  data.tar.gz: !binary |-
6
- NmMzNzgxNzg3NDAxYTE5NGI1ODc5MzA1MDY3YmI1MGNlZjc5ODlkYQ==
6
+ OTNiNzQ4MGVhMmFkODVhZGU3Yjk0ZTFjNmY1ZDlkNjM5ZTUwMTFkOA==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- NWEzNjllMDY0ODRkMTY1ZTljMGYwOGQzZWI4YjE3ZWUxMGY1YWUwMjQxMjVh
10
- NDhjNTRlYzVlOWFiYWU2ZjZhYWQwMThlNzU0NmI1NzE0MTc1NGRlOTYwMjk2
11
- NTY5ZWE0Mjk4MjNiZTNkN2NmYWQ5ZmJlOWRhYWE2YjUxZDA3YWY=
9
+ ZGI2YjNkMWU5MzRjNzcyYjIxZTE1NGJhMTFkNWNmZDZmMGU1NjczODAwZjUz
10
+ Y2U5YWE5ZjU3ZDY4NTc5YTVhMmUyZmNhOTk0M2VjZmY3MTc5YzI4MzRiOWEw
11
+ MDZmY2YwNTE2YmQ1MGRiNDg5ZTBlNzI3OWU5ZDBkNmQ1NjNjOWM=
12
12
  data.tar.gz: !binary |-
13
- NTFhODFlZDlkZDVmMTY4NzJkMzc4YzJmZGMzZjc4NTA2ZGE0Y2NhMDY0MTEx
14
- YTg5ZmU5NGZhOWFjNWIzOThiNjMxMzlkMzljMjFlZTFlNDVhYTY5NzZhY2Iz
15
- YWU5YzA4MDFiOWY5NDEyNWUxMDQxZWEzNDAzOTYwM2RlMDkzMjM=
13
+ YTViOTc3NTgwMTJjYjg0NjhhZDJhYzRlM2E4MmMyZjA2NWQ4YWQ1NWRmODAy
14
+ YjZlYjQ3OTkxYjRjNTAxNWQwMTVkN2E5ZDhlZDI1ZTg4Y2ZkNTBjYmRiYTYx
15
+ MjU2N2Q5ZGQxNzVjZWViNDQ4YjM3ZjQ1OGZkMGY3YTk5N2RiNDk=
data/.gitignore CHANGED
@@ -3,6 +3,9 @@
3
3
  .bundle
4
4
  .config
5
5
  .yardoc
6
+ .ruby-gemset
7
+ .ruby-version
8
+ .rvmrc
6
9
  Gemfile.lock
7
10
  InstalledFiles
8
11
  _yardoc
data/.travis.yml CHANGED
@@ -6,3 +6,10 @@ rvm:
6
6
  - "1.9.2"
7
7
  - "1.9.3"
8
8
  - "2.0.0"
9
+ - "2.1.0"
10
+ - "rbx"
11
+ - "jruby"
12
+ matrix:
13
+ allow_failures:
14
+ - rvm: "rbx"
15
+ - rvm: "jruby"
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Strategy to authenticate with Google via OAuth2 in OmniAuth.
4
4
 
5
- Get your API key at: https://code.google.com/apis/console/
5
+ Get your API key at: https://code.google.com/apis/console/ Note the Client ID and the Client Secret.
6
6
 
7
7
  For more details, read the Google docs: https://developers.google.com/accounts/docs/OAuth2
8
8
 
@@ -22,7 +22,7 @@ Here's an example for adding the middleware to a Rails app in `config/initialize
22
22
 
23
23
  ```ruby
24
24
  Rails.application.config.middleware.use OmniAuth::Builder do
25
- provider :google_oauth2, ENV["GOOGLE_KEY"], ENV["GOOGLE_SECRET"]
25
+ provider :google_oauth2, ENV["GOOGLE_CLIENT_ID"], ENV["GOOGLE_CLIENT_SECRET"]
26
26
  end
27
27
  ```
28
28
 
@@ -30,6 +30,8 @@ You can now access the OmniAuth Google OAuth2 URL: `/auth/google_oauth2`
30
30
 
31
31
  For more examples please check out `examples/omni_auth.rb`
32
32
 
33
+ NOTE: While developing your application, if you change the scope in the initializer you will need to restart your app server.
34
+
33
35
  ## Configuration
34
36
 
35
37
  You can configure several options, which you pass in to the `provider` method via a hash:
@@ -56,11 +58,15 @@ You can configure several options, which you pass in to the `provider` method vi
56
58
 
57
59
  * `access_type`: Defaults to `offline`, so a refresh token is sent to be used when the user is not present at the browser. Can be set to `online`. Note that if you need a refresh token, google requires you to also to specify the option `prompt: 'consent'`, which is not a default.
58
60
 
61
+ * `login_hint`: When your app knows which user it is trying to authenticate, it can provide this parameter as a hint to the authentication server. Passing this hint suppresses the account chooser and either pre-fill the email box on the sign-in form, or select the proper session (if the user is using multiple sign-in), which can help you avoid problems that occur if your app logs in the wrong user account. The value can be either an email address or the sub string, which is equivalent to the user's Google+ ID.
62
+
63
+ * `include_granted_scopes`: If this is provided with the value true, and the authorization request is granted, the authorization will include any previous authorizations granted to this user/application combination for other scopes. See Google's [Incremental Autorization](https://developers.google.com/accounts/docs/OAuth2WebServer#incrementalAuth) for additional details.
64
+
59
65
  Here's an example of a possible configuration where the strategy name is changed, the user is asked for extra permissions, the user is always prompted to select his account when logging in and the user's profile picture is returned as a thumbnail:
60
66
 
61
67
  ```ruby
62
68
  Rails.application.config.middleware.use OmniAuth::Builder do
63
- provider :google_oauth2, ENV["GOOGLE_KEY"], ENV["GOOGLE_SECRET"],
69
+ provider :google_oauth2, ENV["GOOGLE_CLIENT_ID"], ENV["GOOGLE_CLIENT_SECRET"],
64
70
  {
65
71
  :name => "google",
66
72
  :scope => "userinfo.email, userinfo.profile, plus.me, http://gdata.youtube.com",
@@ -150,6 +156,53 @@ end
150
156
  ```
151
157
  Detailed example at https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview#google-oauth2-example
152
158
 
159
+ ### One-time Code Flow (Hybrid Authentication)
160
+
161
+ Google describes the One-time Code Flow [here](https://developers.google.com/+/web/signin/server-side-flow). This hybrid authentication flow has significant functional and security advantages over a pure server-side or pure client-side flow. The following steps occur in this flow:
162
+
163
+ 1. The client (web browser) authenticates the user directly via Google's JS API. During this process assorted modals may be rendered by Google.
164
+ 2. On successful authentication, Google returns a one-time use code, which requires the Google client secret (which is only available server-side).
165
+ 3. Using a AJAX request, the code is POSTed to the Omniauth Google OAuth2 callback.
166
+ 4. The Omniauth Google OAuth2 gem will validate the code via a server-side request to Google. If the code is valid, then Google will return an access token and, if this is the first time this user is authenticating against this application, a refresh token. Both of these should be stored on the server. The response to the AJAX request indicates the success or failure of this process.
167
+
168
+ This flow is immune to replay attacks, and conveys no useful information to a man in the middle.
169
+
170
+ The omniauth-google-oauth2 gem supports this mode of operation out of the box. Implementors simply need to add the appropriate JavaScript to their web page, and they can take advantage of this flow. An example JavaScript snippet follows.
171
+
172
+ ```javascript
173
+ jQuery(function() {
174
+ return $.ajax({
175
+ url: 'https://apis.google.com/js/client:plus.js?onload=gpAsyncInit',
176
+ dataType: 'script',
177
+ cache: true
178
+ });
179
+ });
180
+
181
+ window.gpAsyncInit = function() {
182
+ $('.googleplus-login').click(function(e) {
183
+ e.preventDefault();
184
+ gapi.auth.authorize({
185
+ immediate: true,
186
+ response_type: 'code',
187
+ cookie_policy: 'single_host_origin',
188
+ client_id: '000000000000.apps.googleusercontent.com',
189
+ scope: 'email profile'
190
+ }, function(response) {
191
+ if (response && !response.error) {
192
+ // google authentication succeed, now post data to server and handle data securely
193
+ jQuery.ajax({type: 'POST', url: "/auth/google_oauth2/callback", dataType: 'json', data: response,
194
+ success: function(json) {
195
+ // response from server
196
+ });
197
+ } else {
198
+ // google authentication failed
199
+ }
200
+ });
201
+ });
202
+ };
203
+ ```
204
+
205
+
153
206
  ## Build Status
154
207
  [![Build Status](https://travis-ci.org/zquestz/omniauth-google-oauth2.png)](https://travis-ci.org/zquestz/omniauth-google-oauth2)
155
208
 
@@ -4,9 +4,11 @@
4
4
 
5
5
  Rails.application.config.middleware.use OmniAuth::Builder do
6
6
  # Default usage, this will give you offline access and a refresh token
7
- # using default scopes 'userinfo.email' and 'userinfo.profile'
7
+ # using default scopes 'email' and 'profile'
8
8
  #
9
- provider :google_oauth2, ENV['GOOGLE_KEY'], ENV['GOOGLE_SECRET'], {}
9
+ provider :google_oauth2, ENV['GOOGLE_KEY'], ENV['GOOGLE_SECRET'], {
10
+ :scope => 'email,profile'
11
+ }
10
12
 
11
13
  # Manual setup for offline access with a refresh token.
12
14
  # The prompt must be set to 'consent'
@@ -17,10 +19,10 @@ Rails.application.config.middleware.use OmniAuth::Builder do
17
19
  # }
18
20
 
19
21
  # Custom scope supporting youtube. If you are customizing scopes, remember
20
- # to include the default scopes 'userinfo.email' and 'userinfo.profile'
22
+ # to include the default scopes 'email' and 'profile'
21
23
  #
22
24
  # provider :google_oauth2, ENV['GOOGLE_KEY'], ENV['GOOGLE_SECRET'], {
23
- # :scope => 'http://gdata.youtube.com,userinfo.email,userinfo.profile,plus.me'
25
+ # :scope => 'http://gdata.youtube.com,email,profile,plus.me'
24
26
  # }
25
27
 
26
28
  # Custom scope for users only using Google for account creation/auth and do not require a refresh token.
@@ -29,4 +31,11 @@ Rails.application.config.middleware.use OmniAuth::Builder do
29
31
  # :access_type => 'online',
30
32
  # :prompt => ''
31
33
  # }
34
+
35
+ # To include information about people in your circles you must include the 'plus.login' scope.
36
+ #
37
+ # provider :google_oauth2, ENV['GOOGLE_KEY'], ENV['GOOGLE_SECRET'], {
38
+ # :skip_friends => false,
39
+ # :scope => "email,profile,plus.login"
40
+ # }
32
41
  end
@@ -1,5 +1,5 @@
1
1
  module OmniAuth
2
2
  module GoogleOauth2
3
- VERSION = "0.2.2"
3
+ VERSION = "0.2.3"
4
4
  end
5
5
  end
@@ -4,13 +4,14 @@ module OmniAuth
4
4
  module Strategies
5
5
  class GoogleOauth2 < OmniAuth::Strategies::OAuth2
6
6
  BASE_SCOPE_URL = "https://www.googleapis.com/auth/"
7
- DEFAULT_SCOPE = "userinfo.email,userinfo.profile"
7
+ BASE_SCOPES = %w[profile email openid]
8
+ DEFAULT_SCOPE = "email,profile"
8
9
 
9
10
  option :name, 'google_oauth2'
10
11
 
11
12
  option :skip_friends, true
12
13
 
13
- option :authorize_options, [:access_type, :hd, :login_hint, :prompt, :request_visible_actions, :scope, :state, :redirect_uri]
14
+ option :authorize_options, [:access_type, :hd, :login_hint, :prompt, :request_visible_actions, :scope, :state, :redirect_uri, :include_granted_scopes]
14
15
 
15
16
  option :client_options, {
16
17
  :site => 'https://accounts.google.com',
@@ -26,7 +27,7 @@ module OmniAuth
26
27
 
27
28
  raw_scope = params[:scope] || DEFAULT_SCOPE
28
29
  scope_list = raw_scope.split(" ").map {|item| item.split(",")}.flatten
29
- scope_list.map! { |s| s =~ /^https?:\/\// ? s : "#{BASE_SCOPE_URL}#{s}" }
30
+ scope_list.map! { |s| s =~ /^https?:\/\// || BASE_SCOPES.include?(s) ? s : "#{BASE_SCOPE_URL}#{s}" }
30
31
  params[:scope] = scope_list.join(" ")
31
32
  params[:access_type] = 'offline' if params[:access_type].nil?
32
33
 
@@ -34,7 +35,7 @@ module OmniAuth
34
35
  end
35
36
  end
36
37
 
37
- uid { raw_info['id'] || verified_email }
38
+ uid { raw_info['sub'] || verified_email }
38
39
 
39
40
  info do
40
41
  prune!({
@@ -42,9 +43,9 @@ module OmniAuth
42
43
  :email => verified_email,
43
44
  :first_name => raw_info['given_name'],
44
45
  :last_name => raw_info['family_name'],
45
- :image => image_url(options),
46
+ :image => image_url,
46
47
  :urls => {
47
- 'Google' => raw_info['link']
48
+ 'Google' => raw_info['profile']
48
49
  }
49
50
  })
50
51
  end
@@ -53,12 +54,12 @@ module OmniAuth
53
54
  hash = {}
54
55
  hash[:id_token] = access_token['id_token']
55
56
  hash[:raw_info] = raw_info unless skip_info?
56
- hash[:raw_friend_info] = raw_friend_info(raw_info['id']) unless skip_info? || options[:skip_friends]
57
+ hash[:raw_friend_info] = raw_friend_info(raw_info['sub']) unless skip_info? || options[:skip_friends]
57
58
  prune! hash
58
59
  end
59
60
 
60
61
  def raw_info
61
- @raw_info ||= access_token.get('https://www.googleapis.com/oauth2/v1/userinfo').parsed
62
+ @raw_info ||= access_token.get('https://www.googleapis.com/plus/v1/people/me/openIdConnect').parsed
62
63
  end
63
64
 
64
65
  def raw_friend_info(id)
@@ -66,7 +67,11 @@ module OmniAuth
66
67
  end
67
68
 
68
69
  def custom_build_access_token
69
- if verify_token(request.params['id_token'], request.params['access_token'])
70
+ if request.xhr? && request.params['code']
71
+ verifier = request.params['code']
72
+ client.auth_code.get_token(verifier, { :redirect_uri => 'postmessage'}.merge(token_params.to_hash(:symbolize_keys => true)),
73
+ deep_symbolize(options.auth_token_params || {}))
74
+ elsif verify_token(request.params['id_token'], request.params['access_token'])
70
75
  ::OAuth2::AccessToken.from_hash(client, request.params.dup)
71
76
  else
72
77
  orig_build_access_token
@@ -85,13 +90,25 @@ module OmniAuth
85
90
  end
86
91
 
87
92
  def verified_email
88
- raw_info['verified_email'] ? raw_info['email'] : nil
93
+ raw_info['email_verified'] ? raw_info['email'] : nil
89
94
  end
90
95
 
91
- def image_url(options)
96
+ def image_url
92
97
  original_url = raw_info['picture']
93
- return original_url if original_url.nil? || (!options[:image_size] && !options[:image_aspect_ratio])
98
+ params_index = original_url.index('/photo.jpg') if original_url
94
99
 
100
+ if params_index && image_size_opts_passed?
101
+ original_url.insert(params_index, image_params)
102
+ else
103
+ original_url
104
+ end
105
+ end
106
+
107
+ def image_size_opts_passed?
108
+ !!(options[:image_size] || options[:image_aspect_ratio])
109
+ end
110
+
111
+ def image_params
95
112
  image_params = []
96
113
  if options[:image_size].is_a?(Integer)
97
114
  image_params << "s#{options[:image_size]}"
@@ -101,8 +118,7 @@ module OmniAuth
101
118
  end
102
119
  image_params << 'c' if options[:image_aspect_ratio] == 'square'
103
120
 
104
- params_index = original_url.index('/photo.jpg')
105
- original_url.insert(params_index, ('/' + image_params.join('-')))
121
+ '/' + image_params.join('-')
106
122
  end
107
123
 
108
124
  def verify_token(id_token, access_token)
@@ -17,8 +17,8 @@ Gem::Specification.new do |gem|
17
17
  gem.require_paths = ["lib"]
18
18
  gem.version = OmniAuth::GoogleOauth2::VERSION
19
19
 
20
- gem.add_runtime_dependency 'omniauth-oauth2'
20
+ gem.add_runtime_dependency 'omniauth-oauth2', '~> 1.1'
21
21
 
22
- gem.add_development_dependency 'rspec', '~> 2.6.0'
22
+ gem.add_development_dependency 'rspec', '>= 2.14.0'
23
23
  gem.add_development_dependency 'rake'
24
24
  end
@@ -11,7 +11,7 @@ describe OmniAuth::Strategies::GoogleOauth2 do
11
11
 
12
12
  subject do
13
13
  OmniAuth::Strategies::GoogleOauth2.new(app, 'appid', 'secret', @options || {}).tap do |strategy|
14
- strategy.stub(:request) {
14
+ allow(strategy).to receive(:request) {
15
15
  request
16
16
  }
17
17
  end
@@ -27,31 +27,31 @@ describe OmniAuth::Strategies::GoogleOauth2 do
27
27
 
28
28
  describe '#client_options' do
29
29
  it 'has correct site' do
30
- subject.client.site.should eq('https://accounts.google.com')
30
+ expect(subject.client.site).to eq('https://accounts.google.com')
31
31
  end
32
32
 
33
33
  it 'has correct authorize_url' do
34
- subject.client.options[:authorize_url].should eq('/o/oauth2/auth')
34
+ expect(subject.client.options[:authorize_url]).to eq('/o/oauth2/auth')
35
35
  end
36
36
 
37
37
  it 'has correct token_url' do
38
- subject.client.options[:token_url].should eq('/o/oauth2/token')
38
+ expect(subject.client.options[:token_url]).to eq('/o/oauth2/token')
39
39
  end
40
40
 
41
41
  describe "overrides" do
42
42
  it 'should allow overriding the site' do
43
43
  @options = {:client_options => {'site' => 'https://example.com'}}
44
- subject.client.site.should == 'https://example.com'
44
+ expect(subject.client.site).to eq('https://example.com')
45
45
  end
46
46
 
47
47
  it 'should allow overriding the authorize_url' do
48
48
  @options = {:client_options => {'authorize_url' => 'https://example.com'}}
49
- subject.client.options[:authorize_url].should == 'https://example.com'
49
+ expect(subject.client.options[:authorize_url]).to eq('https://example.com')
50
50
  end
51
51
 
52
52
  it 'should allow overriding the token_url' do
53
53
  @options = {:client_options => {'token_url' => 'https://example.com'}}
54
- subject.client.options[:token_url].should == 'https://example.com'
54
+ expect(subject.client.options[:token_url]).to eq('https://example.com')
55
55
  end
56
56
  end
57
57
  end
@@ -60,135 +60,146 @@ describe OmniAuth::Strategies::GoogleOauth2 do
60
60
  [:access_type, :hd, :login_hint, :prompt, :scope, :state].each do |k|
61
61
  it "should support #{k}" do
62
62
  @options = {k => 'http://someval'}
63
- subject.authorize_params[k.to_s].should eq('http://someval')
63
+ expect(subject.authorize_params[k.to_s]).to eq('http://someval')
64
64
  end
65
65
  end
66
66
 
67
67
  describe "redirect_uri" do
68
68
  it 'should default to nil' do
69
69
  @options = {}
70
- subject.authorize_params['redirect_uri'].should eq(nil)
70
+ expect(subject.authorize_params['redirect_uri']).to eq(nil)
71
71
  end
72
72
 
73
73
  it 'should set the redirect_uri parameter if present' do
74
74
  @options = {:redirect_uri => 'https://example.com'}
75
- subject.authorize_params['redirect_uri'].should eq('https://example.com')
75
+ expect(subject.authorize_params['redirect_uri']).to eq('https://example.com')
76
76
  end
77
77
  end
78
78
 
79
79
  describe 'access_type' do
80
80
  it 'should default to "offline"' do
81
81
  @options = {}
82
- subject.authorize_params['access_type'].should eq('offline')
82
+ expect(subject.authorize_params['access_type']).to eq('offline')
83
83
  end
84
84
 
85
85
  it 'should set the access_type parameter if present' do
86
86
  @options = {:access_type => 'online'}
87
- subject.authorize_params['access_type'].should eq('online')
87
+ expect(subject.authorize_params['access_type']).to eq('online')
88
88
  end
89
89
  end
90
90
 
91
91
  describe 'hd' do
92
92
  it "should default to nil" do
93
- subject.authorize_params['hd'].should eq(nil)
93
+ expect(subject.authorize_params['hd']).to eq(nil)
94
94
  end
95
95
 
96
96
  it 'should set the hd (hosted domain) parameter if present' do
97
97
  @options = {:hd => 'example.com'}
98
- subject.authorize_params['hd'].should eq('example.com')
98
+ expect(subject.authorize_params['hd']).to eq('example.com')
99
99
  end
100
100
  end
101
101
 
102
102
  describe 'login_hint' do
103
103
  it "should default to nil" do
104
- subject.authorize_params['login_hint'].should eq(nil)
104
+ expect(subject.authorize_params['login_hint']).to eq(nil)
105
105
  end
106
106
 
107
107
  it 'should set the login_hint parameter if present' do
108
108
  @options = {:login_hint => 'john@example.com'}
109
- subject.authorize_params['login_hint'].should eq('john@example.com')
109
+ expect(subject.authorize_params['login_hint']).to eq('john@example.com')
110
110
  end
111
111
  end
112
112
 
113
113
  describe 'prompt' do
114
114
  it "should default to nil" do
115
- subject.authorize_params['prompt'].should eq(nil)
115
+ expect(subject.authorize_params['prompt']).to eq(nil)
116
116
  end
117
117
 
118
118
  it 'should set the prompt parameter if present' do
119
119
  @options = {:prompt => 'consent select_account'}
120
- subject.authorize_params['prompt'].should eq('consent select_account')
120
+ expect(subject.authorize_params['prompt']).to eq('consent select_account')
121
121
  end
122
122
  end
123
123
 
124
124
  describe 'request_visible_actions' do
125
125
  it "should default to nil" do
126
- subject.authorize_params['request_visible_actions'].should eq(nil)
126
+ expect(subject.authorize_params['request_visible_actions']).to eq(nil)
127
127
  end
128
128
 
129
129
  it 'should set the request_visible_actions parameter if present' do
130
130
  @options = {:request_visible_actions => 'something'}
131
- subject.authorize_params['request_visible_actions'].should eq('something')
131
+ expect(subject.authorize_params['request_visible_actions']).to eq('something')
132
+ end
133
+ end
134
+
135
+ describe 'include_granted_scopes' do
136
+ it 'should default to nil' do
137
+ expect(subject.authorize_params['include_granted_scopes']).to eq(nil)
138
+ end
139
+
140
+ it 'should set the include_granted_scopes parameter if present' do
141
+ @options = {:include_granted_scopes => 'true'}
142
+ expect(subject.authorize_params['include_granted_scopes']).to eq('true')
132
143
  end
133
144
  end
134
145
 
135
146
  describe 'scope' do
136
147
  it 'should expand scope shortcuts' do
137
- @options = {:scope => 'userinfo.email'}
138
- subject.authorize_params['scope'].should eq('https://www.googleapis.com/auth/userinfo.email')
148
+ @options = {:scope => 'plus.me'}
149
+ expect(subject.authorize_params['scope']).to eq('https://www.googleapis.com/auth/plus.me')
139
150
  end
140
151
 
141
- it 'should leave full scopes as is' do
142
- @options = {:scope => 'https://www.googleapis.com/auth/userinfo.profile'}
143
- subject.authorize_params['scope'].should eq('https://www.googleapis.com/auth/userinfo.profile')
152
+ it 'should leave base scopes as is' do
153
+ @options = {:scope => 'profile'}
154
+ expect(subject.authorize_params['scope']).to eq('profile')
144
155
  end
145
156
 
146
157
  it 'should join scopes' do
147
- @options = {:scope => 'userinfo.profile,userinfo.email'}
148
- subject.authorize_params['scope'].should eq('https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email')
158
+ @options = {:scope => 'profile,email'}
159
+ expect(subject.authorize_params['scope']).to eq('profile email')
149
160
  end
150
161
 
151
162
  it 'should deal with whitespace when joining scopes' do
152
- @options = {:scope => 'userinfo.profile, userinfo.email'}
153
- subject.authorize_params['scope'].should eq('https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email')
163
+ @options = {:scope => 'profile, email'}
164
+ expect(subject.authorize_params['scope']).to eq('profile email')
154
165
  end
155
166
 
156
- it 'should set default scope to userinfo.email,userinfo.profile' do
157
- subject.authorize_params['scope'].should eq('https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile')
167
+ it 'should set default scope to email,profile' do
168
+ expect(subject.authorize_params['scope']).to eq('email profile')
158
169
  end
159
170
 
160
171
  it 'should support space delimited scopes' do
161
- @options = {:scope => 'userinfo.profile userinfo.email'}
162
- subject.authorize_params['scope'].should eq('https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email')
172
+ @options = {:scope => 'profile email'}
173
+ expect(subject.authorize_params['scope']).to eq('profile email')
163
174
  end
164
175
 
165
176
  it "should support extremely badly formed scopes" do
166
- @options = {:scope => 'userinfo.profile userinfo.email,foo,steve yeah http://example.com'}
167
- subject.authorize_params['scope'].should eq('https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/foo https://www.googleapis.com/auth/steve https://www.googleapis.com/auth/yeah http://example.com')
177
+ @options = {:scope => 'profile email,foo,steve yeah http://example.com'}
178
+ expect(subject.authorize_params['scope']).to eq('profile email https://www.googleapis.com/auth/foo https://www.googleapis.com/auth/steve https://www.googleapis.com/auth/yeah http://example.com')
168
179
  end
169
180
  end
170
181
 
171
182
  describe 'state' do
172
183
  it 'should set the state parameter' do
173
184
  @options = {:state => 'some_state'}
174
- subject.authorize_params['state'].should eq('some_state')
175
- subject.session['omniauth.state'].should eq('some_state')
185
+ expect(subject.authorize_params['state']).to eq('some_state')
186
+ expect(subject.session['omniauth.state']).to eq('some_state')
176
187
  end
177
188
 
178
189
  it 'should set the omniauth.state dynamically' do
179
- subject.stub(:request) { double('Request', {:params => {'state' => 'some_state'}, :env => {}}) }
180
- subject.authorize_params['state'].should eq('some_state')
181
- subject.session['omniauth.state'].should eq('some_state')
190
+ allow(subject).to receive(:request) { double('Request', {:params => {'state' => 'some_state'}, :env => {}}) }
191
+ expect(subject.authorize_params['state']).to eq('some_state')
192
+ expect(subject.session['omniauth.state']).to eq('some_state')
182
193
  end
183
194
  end
184
195
 
185
196
  describe "overrides" do
186
197
  it 'should include top-level options that are marked as :authorize_options' do
187
198
  @options = {:authorize_options => [:scope, :foo, :request_visible_actions], :scope => 'http://bar', :foo => 'baz', :hd => "wow", :request_visible_actions => "something"}
188
- subject.authorize_params['scope'].should eq('http://bar')
189
- subject.authorize_params['foo'].should eq('baz')
190
- subject.authorize_params['hd'].should eq(nil)
191
- subject.authorize_params['request_visible_actions'].should eq('something')
199
+ expect(subject.authorize_params['scope']).to eq('http://bar')
200
+ expect(subject.authorize_params['foo']).to eq('baz')
201
+ expect(subject.authorize_params['hd']).to eq(nil)
202
+ expect(subject.authorize_params['request_visible_actions']).to eq('something')
192
203
  end
193
204
 
194
205
  describe "request overrides" do
@@ -198,7 +209,7 @@ describe OmniAuth::Strategies::GoogleOauth2 do
198
209
 
199
210
  it "should set the #{k} authorize option dynamically in the request" do
200
211
  @options = {k => ''}
201
- subject.authorize_params[k.to_s].should eq('http://example.com')
212
+ expect(subject.authorize_params[k.to_s]).to eq('http://example.com')
202
213
  end
203
214
  end
204
215
  end
@@ -208,7 +219,7 @@ describe OmniAuth::Strategies::GoogleOauth2 do
208
219
 
209
220
  it "should support request overrides from custom authorize_options" do
210
221
  @options = {:authorize_options => [:foo], :foo => ''}
211
- subject.authorize_params['foo'].should eq('something')
222
+ expect(subject.authorize_params['foo']).to eq('something')
212
223
  end
213
224
  end
214
225
  end
@@ -218,34 +229,34 @@ describe OmniAuth::Strategies::GoogleOauth2 do
218
229
  describe '#authorize_params' do
219
230
  it 'should include any authorize params passed in the :authorize_params option' do
220
231
  @options = {:authorize_params => {:request_visible_actions => 'something', :foo => 'bar', :baz => 'zip'}, :hd => 'wow', :bad => 'not_included'}
221
- subject.authorize_params['request_visible_actions'].should eq('something')
222
- subject.authorize_params['foo'].should eq('bar')
223
- subject.authorize_params['baz'].should eq('zip')
224
- subject.authorize_params['hd'].should eq('wow')
225
- subject.authorize_params['bad'].should eq(nil)
232
+ expect(subject.authorize_params['request_visible_actions']).to eq('something')
233
+ expect(subject.authorize_params['foo']).to eq('bar')
234
+ expect(subject.authorize_params['baz']).to eq('zip')
235
+ expect(subject.authorize_params['hd']).to eq('wow')
236
+ expect(subject.authorize_params['bad']).to eq(nil)
226
237
  end
227
238
  end
228
239
 
229
240
  describe '#token_params' do
230
241
  it 'should include any token params passed in the :token_params option' do
231
242
  @options = {:token_params => {:foo => 'bar', :baz => 'zip'}}
232
- subject.token_params['foo'].should eq('bar')
233
- subject.token_params['baz'].should eq('zip')
243
+ expect(subject.token_params['foo']).to eq('bar')
244
+ expect(subject.token_params['baz']).to eq('zip')
234
245
  end
235
246
  end
236
247
 
237
248
  describe "#token_options" do
238
249
  it 'should include top-level options that are marked as :token_options' do
239
250
  @options = {:token_options => [:scope, :foo], :scope => 'bar', :foo => 'baz', :bad => 'not_included'}
240
- subject.token_params['scope'].should eq('bar')
241
- subject.token_params['foo'].should eq('baz')
242
- subject.token_params['bad'].should eq(nil)
251
+ expect(subject.token_params['scope']).to eq('bar')
252
+ expect(subject.token_params['foo']).to eq('baz')
253
+ expect(subject.token_params['bad']).to eq(nil)
243
254
  end
244
255
  end
245
256
 
246
257
  describe '#callback_path' do
247
258
  it 'has the correct callback path' do
248
- subject.callback_path.should eq('/auth/google_oauth2/callback')
259
+ expect(subject.callback_path).to eq('/auth/google_oauth2/callback')
249
260
  end
250
261
  end
251
262
 
@@ -254,7 +265,7 @@ describe OmniAuth::Strategies::GoogleOauth2 do
254
265
  OAuth2::Client.new('abc', 'def') do |builder|
255
266
  builder.request :url_encoded
256
267
  builder.adapter :test do |stub|
257
- stub.get('/oauth2/v1/userinfo') {|env| [200, {'content-type' => 'application/json'}, '{"id": "12345"}']}
268
+ stub.get('/plus/v1/people/me/openIdConnect') {|env| [200, {'content-type' => 'application/json'}, '{"sub": "12345"}']}
258
269
  stub.get('/plus/v1/people/12345/people/visible') {|env| [200, {'content-type' => 'application/json'}, '[{"foo":"bar"}]']}
259
270
  end
260
271
  end
@@ -268,13 +279,13 @@ describe OmniAuth::Strategies::GoogleOauth2 do
268
279
  let(:access_token) { OAuth2::AccessToken.from_hash(client, {'id_token' => 'xyz'}) }
269
280
 
270
281
  it 'should include id_token when set on the access_token' do
271
- subject.extra.should include(:id_token => 'xyz')
282
+ expect(subject.extra).to include(:id_token => 'xyz')
272
283
  end
273
284
  end
274
285
 
275
286
  context 'when the id_token is missing' do
276
287
  it 'should not include id_token' do
277
- subject.extra.should_not have_key(:id_token)
288
+ expect(subject.extra).not_to have_key(:id_token)
278
289
  end
279
290
  end
280
291
  end
@@ -284,7 +295,7 @@ describe OmniAuth::Strategies::GoogleOauth2 do
284
295
  before { subject.options[:skip_info] = true }
285
296
 
286
297
  it 'should not include raw_info' do
287
- subject.extra.should_not have_key(:raw_info)
298
+ expect(subject.extra).not_to have_key(:raw_info)
288
299
  end
289
300
  end
290
301
 
@@ -292,7 +303,7 @@ describe OmniAuth::Strategies::GoogleOauth2 do
292
303
  before { subject.options[:skip_info] = false }
293
304
 
294
305
  it 'should include raw_info' do
295
- subject.extra[:raw_info].should eq('id' => '12345')
306
+ expect(subject.extra[:raw_info]).to eq('sub' => '12345')
296
307
  end
297
308
  end
298
309
  end
@@ -302,7 +313,7 @@ describe OmniAuth::Strategies::GoogleOauth2 do
302
313
  before { subject.options[:skip_info] = true }
303
314
 
304
315
  it 'should not include raw_friend_info' do
305
- subject.extra.should_not have_key(:raw_friend_info)
316
+ expect(subject.extra).not_to have_key(:raw_friend_info)
306
317
  end
307
318
  end
308
319
 
@@ -313,7 +324,7 @@ describe OmniAuth::Strategies::GoogleOauth2 do
313
324
  before { subject.options[:skip_friends] = true }
314
325
 
315
326
  it 'should not include raw_friend_info' do
316
- subject.extra.should_not have_key(:raw_friend_info)
327
+ expect(subject.extra).not_to have_key(:raw_friend_info)
317
328
  end
318
329
  end
319
330
 
@@ -321,7 +332,7 @@ describe OmniAuth::Strategies::GoogleOauth2 do
321
332
  before { subject.options[:skip_friends] = false }
322
333
 
323
334
  it 'should not include raw_friend_info' do
324
- subject.extra[:raw_friend_info].should eq([{'foo' => 'bar'}])
335
+ expect(subject.extra[:raw_friend_info]).to eq([{'foo' => 'bar'}])
325
336
  end
326
337
  end
327
338
  end
@@ -330,75 +341,98 @@ describe OmniAuth::Strategies::GoogleOauth2 do
330
341
 
331
342
  describe 'populate auth hash urls' do
332
343
  it 'should populate url map in auth hash if link present in raw_info' do
333
- subject.stub(:raw_info) { {'name' => 'Foo', 'link' => 'https://plus.google.com/123456'} }
334
- subject.info[:urls]['Google'].should eq('https://plus.google.com/123456')
344
+ allow(subject).to receive(:raw_info) { {'name' => 'Foo', 'profile' => 'https://plus.google.com/123456'} }
345
+ expect(subject.info[:urls]['Google']).to eq('https://plus.google.com/123456')
335
346
  end
336
347
 
337
348
  it 'should not populate url map in auth hash if no link present in raw_info' do
338
- subject.stub(:raw_info) { {'name' => 'Foo'} }
339
- subject.info.should_not have_key(:urls)
349
+ allow(subject).to receive(:raw_info) { {'name' => 'Foo'} }
350
+ expect(subject.info).not_to have_key(:urls)
340
351
  end
341
352
  end
342
353
 
343
354
  describe 'image options' do
344
355
  it "should have no image if a picture isn't present" do
345
356
  @options = {:image_aspect_ratio => 'square'}
346
- subject.stub(:raw_info) { {'name' => 'User Without Pic'} }
347
- subject.info[:image].should be_nil
357
+ allow(subject).to receive(:raw_info) { {'name' => 'User Without Pic'} }
358
+ expect(subject.info[:image]).to be_nil
348
359
  end
349
360
 
350
361
  describe "when a picture is returned from google" do
351
362
  it 'should return the image with size specified in the `image_size` option' do
352
363
  @options = {:image_size => 50}
353
- subject.stub(:raw_info) { {'picture' => 'https://lh3.googleusercontent.com/url/photo.jpg'} }
354
- subject.info[:image].should eq('https://lh3.googleusercontent.com/url/s50/photo.jpg')
364
+ allow(subject).to receive(:raw_info) { {'picture' => 'https://lh3.googleusercontent.com/url/photo.jpg'} }
365
+ expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/s50/photo.jpg')
355
366
  end
356
367
 
357
368
  it 'should return the image with width and height specified in the `image_size` option' do
358
369
  @options = {:image_size => {:width => 50, :height => 40}}
359
- subject.stub(:raw_info) { {'picture' => 'https://lh3.googleusercontent.com/url/photo.jpg'} }
360
- subject.info[:image].should eq('https://lh3.googleusercontent.com/url/w50-h40/photo.jpg')
370
+ allow(subject).to receive(:raw_info) { {'picture' => 'https://lh3.googleusercontent.com/url/photo.jpg'} }
371
+ expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/w50-h40/photo.jpg')
361
372
  end
362
373
 
363
374
  it 'should return square image when `image_aspect_ratio` is specified' do
364
375
  @options = {:image_aspect_ratio => 'square'}
365
- subject.stub(:raw_info) { {'picture' => 'https://lh3.googleusercontent.com/url/photo.jpg'} }
366
- subject.info[:image].should eq('https://lh3.googleusercontent.com/url/c/photo.jpg')
376
+ allow(subject).to receive(:raw_info) { {'picture' => 'https://lh3.googleusercontent.com/url/photo.jpg'} }
377
+ expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/c/photo.jpg')
367
378
  end
368
379
 
369
380
  it 'should return square sized image when `image_aspect_ratio` and `image_size` is set' do
370
381
  @options = {:image_aspect_ratio => 'square', :image_size => 50}
371
- subject.stub(:raw_info) { {'picture' => 'https://lh3.googleusercontent.com/url/photo.jpg'} }
372
- subject.info[:image].should eq('https://lh3.googleusercontent.com/url/s50-c/photo.jpg')
382
+ allow(subject).to receive(:raw_info) { {'picture' => 'https://lh3.googleusercontent.com/url/photo.jpg'} }
383
+ expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/s50-c/photo.jpg')
373
384
  end
374
385
 
375
386
  it 'should return square sized image when `image_aspect_ratio` and `image_size` has height and width' do
376
387
  @options = {:image_aspect_ratio => 'square', :image_size => {:width => 50, :height => 40}}
377
- subject.stub(:raw_info) { {'picture' => 'https://lh3.googleusercontent.com/url/photo.jpg'} }
378
- subject.info[:image].should eq('https://lh3.googleusercontent.com/url/w50-h40-c/photo.jpg')
388
+ allow(subject).to receive(:raw_info) { {'picture' => 'https://lh3.googleusercontent.com/url/photo.jpg'} }
389
+ expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/w50-h40-c/photo.jpg')
390
+ end
391
+
392
+ it 'should return original image if image url does not end in `photo.jpg`' do
393
+ @options = {:image_size => 50}
394
+ subject.stub(:raw_info) { {'picture' => 'https://lh3.googleusercontent.com/url/photograph.jpg'} }
395
+ subject.info[:image].should eq('https://lh3.googleusercontent.com/url/photograph.jpg')
379
396
  end
380
397
  end
381
398
 
382
399
  it 'should return original image if no options are provided' do
383
- subject.stub(:raw_info) { {'picture' => 'https://lh3.googleusercontent.com/url/photo.jpg'} }
384
- subject.info[:image].should eq('https://lh3.googleusercontent.com/url/photo.jpg')
400
+ allow(subject).to receive(:raw_info) { {'picture' => 'https://lh3.googleusercontent.com/url/photo.jpg'} }
401
+ expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/photo.jpg')
385
402
  end
386
403
  end
387
404
 
388
405
  describe 'build_access_token' do
389
- it 'should read access_token from hash' do
390
- request.stub(:params).and_return('id_token' => 'valid_id_token', 'access_token' => 'valid_access_token')
391
- subject.should_receive(:verify_token).with('valid_id_token', 'valid_access_token').and_return true
392
- subject.should_receive(:client).and_return(:client)
406
+ it 'should use a hybrid authorization request_uri if this is an AJAX request with a code parameter' do
407
+ allow(request).to receive(:xhr?).and_return(true)
408
+ allow(request).to receive(:params).and_return('code' => 'valid_code')
409
+
410
+ client = double(:client)
411
+ auth_code = double(:auth_code)
412
+ allow(client).to receive(:auth_code).and_return(auth_code)
413
+ expect(subject).to receive(:client).and_return(client)
414
+ expect(auth_code).to receive(:get_token).with('valid_code', { :redirect_uri => 'postmessage'}, {})
415
+
416
+ expect(subject).not_to receive(:orig_build_access_token)
417
+ subject.build_access_token
418
+ end
419
+
420
+ it 'should read access_token from hash if this is not an AJAX request with a code parameter' do
421
+ allow(request).to receive(:xhr?).and_return(false)
422
+ allow(request).to receive(:params).and_return('id_token' => 'valid_id_token', 'access_token' => 'valid_access_token')
423
+ expect(subject).to receive(:verify_token).with('valid_id_token', 'valid_access_token').and_return true
424
+ expect(subject).to receive(:client).and_return(:client)
393
425
 
394
426
  token = subject.build_access_token
395
- token.should be_instance_of(::OAuth2::AccessToken)
396
- token.token.should eq('valid_access_token')
397
- token.client.should eq(:client)
427
+ expect(token).to be_instance_of(::OAuth2::AccessToken)
428
+ expect(token.token).to eq('valid_access_token')
429
+ expect(token.client).to eq(:client)
398
430
  end
399
431
 
400
- it 'should call super' do
401
- subject.should_receive(:orig_build_access_token)
432
+ it 'should call super if this is not an AJAX request' do
433
+ allow(request).to receive(:xhr?).and_return(false)
434
+ allow(request).to receive(:params).and_return('code' => 'valid_code')
435
+ expect(subject).to receive(:orig_build_access_token)
402
436
  subject.build_access_token
403
437
  end
404
438
  end
@@ -413,7 +447,7 @@ describe OmniAuth::Strategies::GoogleOauth2 do
413
447
  :issued_to => '000000000000.apps.googleusercontent.com',
414
448
  :audience => '000000000000.apps.googleusercontent.com',
415
449
  :user_id => '000000000000000000000',
416
- :scope => 'https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email',
450
+ :scope => 'profile email',
417
451
  :expires_in => 3514,
418
452
  :email => 'me@example.com',
419
453
  :verified_email => true,
@@ -429,11 +463,11 @@ describe OmniAuth::Strategies::GoogleOauth2 do
429
463
 
430
464
  it 'should verify token if access_token and id_token are valid and app_id equals' do
431
465
  subject.options.client_id = '000000000000.apps.googleusercontent.com'
432
- subject.send(:verify_token, 'valid_id_token', 'valid_access_token').should == true
466
+ expect(subject.send(:verify_token, 'valid_id_token', 'valid_access_token')).to eq(true)
433
467
  end
434
468
 
435
469
  it 'should not verify token if access_token and id_token are valid but app_id is false' do
436
- subject.send(:verify_token, 'valid_id_token', 'valid_access_token').should == false
470
+ expect(subject.send(:verify_token, 'valid_id_token', 'valid_access_token')).to eq(false)
437
471
  end
438
472
 
439
473
  it 'should raise error if access_token or id_token is invalid' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omniauth-google-oauth2
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josh Ellithorpe
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-12-31 00:00:00.000000000 Z
12
+ date: 2014-04-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: omniauth
@@ -29,30 +29,30 @@ dependencies:
29
29
  name: omniauth-oauth2
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - ! '>='
32
+ - - ~>
33
33
  - !ruby/object:Gem::Version
34
- version: '0'
34
+ version: '1.1'
35
35
  type: :runtime
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
- - - ! '>='
39
+ - - ~>
40
40
  - !ruby/object:Gem::Version
41
- version: '0'
41
+ version: '1.1'
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: rspec
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
- - - ~>
46
+ - - ! '>='
47
47
  - !ruby/object:Gem::Version
48
- version: 2.6.0
48
+ version: 2.14.0
49
49
  type: :development
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
- - - ~>
53
+ - - ! '>='
54
54
  - !ruby/object:Gem::Version
55
- version: 2.6.0
55
+ version: 2.14.0
56
56
  - !ruby/object:Gem::Dependency
57
57
  name: rake
58
58
  requirement: !ruby/object:Gem::Requirement
@@ -75,9 +75,6 @@ extensions: []
75
75
  extra_rdoc_files: []
76
76
  files:
77
77
  - .gitignore
78
- - .ruby-gemset
79
- - .ruby-version
80
- - .rvmrc
81
78
  - .travis.yml
82
79
  - Gemfile
83
80
  - README.md
data/.ruby-gemset DELETED
@@ -1 +0,0 @@
1
- omniauth-google-oauth2
data/.ruby-version DELETED
@@ -1 +0,0 @@
1
- 1.9.3-p484
data/.rvmrc DELETED
@@ -1 +0,0 @@
1
- rvm use 1.9.3@omniauth-google-oauth2 --create