omniauth-google-oauth2 0.6.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 81997c7fd03317eea408408d6f18159972b8f3dc
4
- data.tar.gz: d16e88cdee0f4fd599d4b8d8c05ac40ebc761c07
2
+ SHA256:
3
+ metadata.gz: 278efb11e955abf864c2d163e1f1631a271ba34660fa166a4f65b56691ccab0d
4
+ data.tar.gz: 574e6d6b5f3dacfa271ba24a8999e104c74db64482860b6ba095938a6dc7c1b0
5
5
  SHA512:
6
- metadata.gz: eb2b1d82471d000a983728b92676e682d7006b0a3551bcb109cd9216a3114e6d78500bdd3d29ae71b55c95f4b7a2315f4d3930bf017edc7a2506641bb51cfc06
7
- data.tar.gz: 27605544db858360570a109a922689ec100bd70ff4ea63318a67f2ba6bc5a91c1f464e9110088addba9c83fc62a6fcae13ce54f22f53abcaf5933d04cb1538ff
6
+ metadata.gz: 22006de20bc8355329cdca2c9e41a15959e192dcd4c970d1ca6acc8dd149f0fb1eedc313351cc39072e51ea5b219ebb6968b2e178995397d14f58b5117b18c53
7
+ data.tar.gz: b54fe6ca226e39f05705837eb8a390247df3a4fc615c7aab798009b63fd830ad7c21df7536ffa9fefffc4ff6c3586c6067ba5d15ac4d192b88892b3080c753f6
data/.rubocop.yml CHANGED
@@ -1,11 +1,9 @@
1
- ClassLength:
2
- Enabled: false
3
- Layout/IndentHeredoc:
1
+ Metrics/ClassLength:
4
2
  Enabled: false
5
3
  Metrics/AbcSize:
6
4
  Enabled: false
7
5
  Metrics/BlockLength:
8
- ExcludedMethods: ['describe', 'context']
6
+ ExcludedMethods: ['describe', 'context', 'shared_examples']
9
7
  Metrics/CyclomaticComplexity:
10
8
  Enabled: false
11
9
  Metrics/LineLength:
@@ -20,4 +18,3 @@ Style/MutableConstant:
20
18
  Enabled: false
21
19
  Gemspec/RequiredRubyVersion:
22
20
  Enabled: false
23
-
data/.travis.yml CHANGED
@@ -1,7 +1,6 @@
1
1
  language: ruby
2
+ cache: bundler
2
3
  rvm:
3
- - '2.1.10'
4
- - '2.2.7'
5
4
  - '2.3.4'
6
5
  - '2.4.1'
7
6
  - '2.5.0'
data/CHANGELOG.md CHANGED
@@ -1,6 +1,91 @@
1
1
  # Changelog
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
+ ## 1.0.0 - 2021-03-14
5
+
6
+ ### Added
7
+ - Support for Omniauth 2.x!
8
+
9
+ ### Deprecated
10
+ - Nothing.
11
+
12
+ ### Removed
13
+ - Support for Omniauth 1.x
14
+
15
+ ### Fixed
16
+ - Nothing.
17
+
18
+ ## 0.8.2 - 2021-03-14
19
+
20
+ ### Added
21
+ - Constrains the version to Omniauth 1.x.
22
+
23
+ ### Deprecated
24
+ - Nothing.
25
+
26
+ ### Removed
27
+ - Nothing.
28
+
29
+ ### Fixed
30
+ - Nothing.
31
+
32
+ ## 0.8.1 - 2020-12-12
33
+
34
+ ### Added
35
+ - Support reading the access token from a json request body.
36
+
37
+ ### Deprecated
38
+ - Nothing.
39
+
40
+ ### Removed
41
+ - No longer verify the iat claim for JWT.
42
+
43
+ ### Fixed
44
+ - A few minor issues with .rubocop.yml.
45
+ - Issues with image resizing code when the image came with size information from Google.
46
+
47
+ ## 0.8.0 - 2019-08-21
48
+
49
+ ### Added
50
+ - Updated omniauth-oauth2 to v1.6.0 for security fixes.
51
+
52
+ ### Deprecated
53
+ - Nothing.
54
+
55
+ ### Removed
56
+ - Ruby 2.1 support.
57
+
58
+ ### Fixed
59
+ - Nothing.
60
+
61
+ ## 0.7.0 - 2019-06-03
62
+
63
+ ### Added
64
+ - Ensure `info[:email]` is always verified, and include `unverified_email`
65
+
66
+ ### Deprecated
67
+ - Nothing.
68
+
69
+ ### Removed
70
+ - Nothing.
71
+
72
+ ### Fixed
73
+ - Nothing.
74
+
75
+ ## 0.6.1 - 2019-03-07
76
+
77
+ ### Added
78
+ - Return `email` and `email_verified` keys in response.
79
+
80
+ ### Deprecated
81
+ - Nothing.
82
+
83
+ ### Removed
84
+ - Nothing.
85
+
86
+ ### Fixed
87
+ - Nothing.
88
+
4
89
  ## 0.6.0 - 2018-12-28
5
90
 
6
91
  ### Added
@@ -12,6 +97,7 @@ All notable changes to this project will be documented in this file.
12
97
  ### Removed
13
98
  - Support for JWT 1.x.
14
99
  - Support for `raw_friend_info` and `raw_image_info`.
100
+ - Stop using Google+ API endpoints.
15
101
 
16
102
  ### Fixed
17
103
  - Nothing.
data/README.md CHANGED
@@ -54,10 +54,10 @@ You can configure several options, which you pass in to the `provider` method vi
54
54
 
55
55
  * `prompt`: A space-delimited list of string values that determines whether the user is re-prompted for authentication and/or consent. Possible values are:
56
56
  * `none`: No authentication or consent pages will be displayed; it will return an error if the user is not already authenticated and has not pre-configured consent for the requested scopes. This can be used as a method to check for existing authentication and/or consent.
57
- * `consent`: The user will always be prompted for consent, even if he has previously allowed access a given set of scopes.
57
+ * `consent`: The user will always be prompted for consent, even if they have previously allowed access a given set of scopes.
58
58
  * `select_account`: The user will always be prompted to select a user account. This allows a user who has multiple current account sessions to select one amongst them.
59
59
 
60
- If no value is specified, the user only sees the authentication page if he is not logged in and only sees the consent page the first time he authorizes a given set of scopes.
60
+ If no value is specified, the user only sees the authentication page if they are not logged in and only sees the consent page the first time they authorize a given set of scopes.
61
61
 
62
62
  * `image_aspect_ratio`: The shape of the user's profile picture. Possible values are:
63
63
  * `original`: Picture maintains its original aspect ratio.
@@ -73,7 +73,7 @@ You can configure several options, which you pass in to the `provider` method vi
73
73
 
74
74
  * `hd`: (Optional) Limit sign-in to a particular Google Apps hosted domain. This can be simply string `'domain.com'` or an array `%w(domain.com domain.co)`. More information at: https://developers.google.com/accounts/docs/OpenIDConnect#hd-param
75
75
 
76
- * `jwt_leeway`: Number of seconds passed to the JWT library as leeway. Defaults to 60 seconds.
76
+ * `jwt_leeway`: Number of seconds passed to the JWT library as leeway. Defaults to 60 seconds. Note this only works if you use jwt 2.1, as the leeway option was removed in later versions.
77
77
 
78
78
  * `skip_jwt`: Skip JWT processing. This is for users who are seeing JWT decoding errors with the `iat` field. Always try adjusting the leeway before disabling JWT processing.
79
79
 
@@ -81,9 +81,11 @@ You can configure several options, which you pass in to the `provider` method vi
81
81
 
82
82
  * `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 Authorization](https://developers.google.com/accounts/docs/OAuth2WebServer#incrementalAuth) for additional details.
83
83
 
84
- * `openid_realm`: Set the OpenID realm value, to allow upgrading from OpenID based authentication to OAuth 2 based authentication. When this is set correctly an `openid_id` value will be set in `[:extra][:id_info]` in the authentication hash with the value of the user's OpenID ID URL.
84
+ * `openid_realm`: Set the OpenID realm value, to allow upgrading from OpenID based authentication to OAuth 2 based authentication. When this is set correctly an `openid_id` value will be set in `['extra']['id_info']` in the authentication hash with the value of the user's OpenID ID URL.
85
85
 
86
- 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:
86
+ * `provider_ignores_state`: You will need to set this to `true` when using the `One-time Code Flow` below. In this flow there is no server side redirect that would set the state.
87
+
88
+ 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 their account when logging in and the user's profile picture is returned as a thumbnail:
87
89
 
88
90
  ```ruby
89
91
  Rails.application.config.middleware.use OmniAuth::Builder do
@@ -176,6 +178,8 @@ devise :omniauthable, omniauth_providers: [:google_oauth2]
176
178
  Then make sure your callbacks controller is setup.
177
179
 
178
180
  ```ruby
181
+ # app/controllers/users/omniauth_callbacks_controller.rb:
182
+
179
183
  class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
180
184
  def google_oauth2
181
185
  # You need to implement the method below in your model (e.g. app/models/user.rb)
@@ -185,7 +189,7 @@ class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
185
189
  flash[:notice] = I18n.t 'devise.omniauth_callbacks.success', kind: 'Google'
186
190
  sign_in_and_redirect @user, event: :authentication
187
191
  else
188
- session['devise.google_data'] = request.env['omniauth.auth'].except(:extra) # Removing extra as it can overflow some session stores
192
+ session['devise.google_data'] = request.env['omniauth.auth'].except('extra') # Removing extra as it can overflow some session stores
189
193
  redirect_to new_user_registration_url, alert: @user.errors.full_messages.join("\n")
190
194
  end
191
195
  end
@@ -223,7 +227,7 @@ An overview is available at https://github.com/plataformatec/devise/wiki/OmniAut
223
227
 
224
228
  ### One-time Code Flow (Hybrid Authentication)
225
229
 
226
- 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:
230
+ Google describes the One-time Code Flow [here](https://developers.google.com/identity/sign-in/web/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:
227
231
 
228
232
  1. The client (web browser) authenticates the user directly via Google's JS API. During this process assorted modals may be rendered by Google.
229
233
  2. On successful authentication, Google returns a one-time use code, which requires the Google client secret (which is only available server-side).
@@ -232,7 +236,7 @@ Google describes the One-time Code Flow [here](https://developers.google.com/+/w
232
236
 
233
237
  This flow is immune to replay attacks, and conveys no useful information to a man in the middle.
234
238
 
235
- 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.
239
+ The omniauth-google-oauth2 gem supports this mode of operation when `provider_ignores_state` is set to `true`. 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.
236
240
 
237
241
  ```javascript
238
242
  // Basic hybrid auth example following the pattern at:
@@ -247,7 +251,7 @@ function init() {
247
251
  // Ready.
248
252
  $('.google-login-button').click(function(e) {
249
253
  e.preventDefault();
250
-
254
+
251
255
  gapi.auth2.authorize({
252
256
  client_id: 'YOUR_CLIENT_ID',
253
257
  cookie_policy: 'single_host_origin',
@@ -260,7 +264,7 @@ function init() {
260
264
  success: function(data) {
261
265
  // response from server
262
266
  }
263
- });
267
+ });
264
268
  } else {
265
269
  // google authentication failed
266
270
  }
@@ -280,6 +284,66 @@ In that case, ensure to send an additional parameter `redirect_uri=` (empty stri
280
284
 
281
285
  If you're making POST requests to `/auth/google_oauth2/callback` from another domain, then you need to make sure `'X-Requested-With': 'XMLHttpRequest'` header is included with your request, otherwise your server might respond with `OAuth2::Error, : Invalid Value` error.
282
286
 
287
+ #### Getting around the `redirect_uri_mismatch` error (See [Issue #365](https://github.com/zquestz/omniauth-google-oauth2/issues/365))
288
+
289
+ If you are struggling with a persistent `redirect_uri_mismatch`, you can instead pass the `access_token` from [`getAuthResponse`](https://developers.google.com/identity/sign-in/web/reference#googleusergetauthresponseincludeauthorizationdata) directly to the `auth/google_oauth2/callback` endpoint, like so:
290
+
291
+ ```javascript
292
+ // Initialize the GoogleAuth object
293
+ let googleAuth;
294
+ gapi.load('client:auth2', async () => {
295
+ await gapi.client.init({ scope: '...', client_id: '...' });
296
+ googleAuth = gapi.auth2.getAuthInstance();
297
+ });
298
+
299
+ // Call this when the Google Sign In button is clicked
300
+ async function signInGoogle() {
301
+ const googleUser = await googleAuth.signIn(); // wait for the user to authorize through the modal
302
+ const { access_token } = googleUser.getAuthResponse();
303
+
304
+ const data = new FormData();
305
+ data.append('access_token', access_token);
306
+
307
+ const response = await api.post('/auth/google_oauth2/callback', data)
308
+ console.log(response);
309
+ }
310
+ ```
311
+
312
+ #### Using Axios
313
+ If you're making a GET resquests from another domain using `access_token`.
314
+ ```
315
+ axios
316
+ .get(
317
+ 'url(path to your callback}',
318
+ { params: { access_token: 'token' } },
319
+ headers....
320
+ )
321
+ ```
322
+
323
+ If you're making a POST resquests from another domain using `access_token`.
324
+ ```
325
+ axios
326
+ .post(
327
+ 'url(path to your callback}',
328
+ { access_token: 'token' },
329
+ headers....
330
+ )
331
+
332
+ --OR--
333
+
334
+ axios
335
+ .post(
336
+ 'url(path to your callback}',
337
+ null,
338
+ {
339
+ params: {
340
+ access_token: 'token'
341
+ },
342
+ headers....
343
+ }
344
+ )
345
+ ```
346
+
283
347
  ## Fixing Protocol Mismatch for `redirect_uri` in Rails
284
348
 
285
349
  Just set the `full_host` in OmniAuth based on the Rails.env.
data/examples/Gemfile CHANGED
@@ -2,6 +2,6 @@
2
2
 
3
3
  source 'https://rubygems.org'
4
4
 
5
- gem 'omniauth-google-oauth2', '~> 0.5'
5
+ gem 'omniauth-google-oauth2', '~> 0.8.1'
6
6
  gem 'rubocop'
7
7
  gem 'sinatra', '~> 1.4'
@@ -10,6 +10,10 @@ Rails.application.config.middleware.use OmniAuth::Builder do
10
10
  #
11
11
  provider :google_oauth2, ENV['GOOGLE_KEY'], ENV['GOOGLE_SECRET'], scope: 'email,profile'
12
12
 
13
+ # Custom redirect_uri
14
+ #
15
+ # provider :google_oauth2, ENV['GOOGLE_KEY'], ENV['GOOGLE_SECRET'], scope: 'email,profile', redirect_uri: 'https://localhost:3000/redirect'
16
+
13
17
  # Manual setup for offline access with a refresh token.
14
18
  #
15
19
  # provider :google_oauth2, ENV['GOOGLE_KEY'], ENV['GOOGLE_SECRET'], access_type: 'offline'
@@ -2,6 +2,6 @@
2
2
 
3
3
  module OmniAuth
4
4
  module GoogleOauth2
5
- VERSION = '0.6.0'
5
+ VERSION = '1.0.0'
6
6
  end
7
7
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'jwt'
4
+ require 'oauth2'
4
5
  require 'omniauth/strategies/oauth2'
5
6
  require 'uri'
6
7
 
@@ -13,6 +14,7 @@ module OmniAuth
13
14
  BASE_SCOPES = %w[profile email openid].freeze
14
15
  DEFAULT_SCOPE = 'email,profile'
15
16
  USER_INFO_URL = 'https://www.googleapis.com/oauth2/v3/userinfo'
17
+ IMAGE_SIZE_REGEXP = /(s\d+(-c)?)|(w\d+-h\d+(-c)?)|(w\d+(-c)?)|(h\d+(-c)?)|c/
16
18
 
17
19
  option :name, 'google_oauth2'
18
20
  option :skip_friends, true
@@ -47,6 +49,8 @@ module OmniAuth
47
49
  prune!(
48
50
  name: raw_info['name'],
49
51
  email: verified_email,
52
+ unverified_email: raw_info['email'],
53
+ email_verified: raw_info['email_verified'],
50
54
  first_name: raw_info['given_name'],
51
55
  last_name: raw_info['family_name'],
52
56
  image: image_url,
@@ -72,7 +76,7 @@ module OmniAuth
72
76
  verify_sub: false,
73
77
  verify_expiration: true,
74
78
  verify_not_before: true,
75
- verify_iat: true,
79
+ verify_iat: false,
76
80
  verify_jti: false,
77
81
  leeway: options[:jwt_leeway])
78
82
 
@@ -92,31 +96,50 @@ module OmniAuth
92
96
  verify_hd(access_token)
93
97
  access_token
94
98
  end
99
+
95
100
  alias build_access_token custom_build_access_token
96
101
 
97
102
  private
98
103
 
99
104
  def callback_url
100
- options[:redirect_uri] || (full_host + script_name + callback_path)
105
+ options[:redirect_uri] || (full_host + callback_path)
101
106
  end
102
107
 
103
108
  def get_access_token(request)
104
- if request.xhr? && request.params['code']
105
- verifier = request.params['code']
106
- redirect_uri = request.params['redirect_uri'] || 'postmessage'
107
- client.auth_code.get_token(verifier, get_token_options(redirect_uri), deep_symbolize(options.auth_token_params || {}))
108
- elsif request.params['code'] && request.params['redirect_uri']
109
- verifier = request.params['code']
110
- redirect_uri = request.params['redirect_uri']
111
- client.auth_code.get_token(verifier, get_token_options(redirect_uri), deep_symbolize(options.auth_token_params || {}))
112
- elsif verify_token(request.params['access_token'])
109
+ verifier = request.params['code']
110
+ redirect_uri = request.params['redirect_uri']
111
+ access_token = request.params['access_token']
112
+ if verifier && request.xhr?
113
+ client_get_token(verifier, redirect_uri || 'postmessage')
114
+ elsif verifier
115
+ client_get_token(verifier, redirect_uri || callback_url)
116
+ elsif access_token && verify_token(access_token)
113
117
  ::OAuth2::AccessToken.from_hash(client, request.params.dup)
114
- else
115
- verifier = request.params['code']
116
- client.auth_code.get_token(verifier, get_token_options(callback_url), deep_symbolize(options.auth_token_params))
118
+ elsif request.content_type =~ /json/i
119
+ begin
120
+ body = JSON.parse(request.body.read)
121
+ request.body.rewind # rewind request body for downstream middlewares
122
+ verifier = body && body['code']
123
+ access_token = body && body['access_token']
124
+ if verifier
125
+ client_get_token(verifier, 'postmessage')
126
+ elsif verify_token(access_token)
127
+ ::OAuth2::AccessToken.from_hash(client, body.dup)
128
+ end
129
+ rescue JSON::ParserError => e
130
+ warn "[omniauth google-oauth2] JSON parse error=#{e}"
131
+ end
117
132
  end
118
133
  end
119
134
 
135
+ def client_get_token(verifier, redirect_uri)
136
+ client.auth_code.get_token(verifier, get_token_options(redirect_uri), get_token_params)
137
+ end
138
+
139
+ def get_token_params
140
+ deep_symbolize(options.auth_token_params || {})
141
+ end
142
+
120
143
  def get_scope(params)
121
144
  raw_scope = params[:scope] || DEFAULT_SCOPE
122
145
  scope_list = raw_scope.split(' ').map { |item| item.split(',') }.flatten
@@ -124,7 +147,11 @@ module OmniAuth
124
147
  scope_list.join(' ')
125
148
  end
126
149
 
127
- def get_token_options(redirect_uri)
150
+ def verified_email
151
+ raw_info['email_verified'] ? raw_info['email'] : nil
152
+ end
153
+
154
+ def get_token_options(redirect_uri = '')
128
155
  { redirect_uri: redirect_uri }.merge(token_params.to_hash(symbolize_keys: true))
129
156
  end
130
157
 
@@ -135,10 +162,6 @@ module OmniAuth
135
162
  end
136
163
  end
137
164
 
138
- def verified_email
139
- raw_info['email_verified'] ? raw_info['email'] : nil
140
- end
141
-
142
165
  def image_url
143
166
  return nil unless raw_info['picture']
144
167
 
@@ -149,6 +172,10 @@ module OmniAuth
149
172
  if path_index && image_size_opts_passed?
150
173
  u.path.insert(path_index, image_params)
151
174
  u.path = u.path.gsub('//', '/')
175
+
176
+ # Check if the image is already sized!
177
+ split_path = u.path.split('/')
178
+ u.path = u.path.sub("/#{split_path[-3]}", '') if split_path[-3] =~ IMAGE_SIZE_REGEXP
152
179
  end
153
180
 
154
181
  u.query = strip_unnecessary_query_parameters(u.query)
@@ -18,11 +18,12 @@ Gem::Specification.new do |gem|
18
18
  gem.files = `git ls-files`.split("\n")
19
19
  gem.require_paths = ['lib']
20
20
 
21
- gem.required_ruby_version = '>= 2.1'
21
+ gem.required_ruby_version = '>= 2.2'
22
22
 
23
23
  gem.add_runtime_dependency 'jwt', '>= 2.0'
24
- gem.add_runtime_dependency 'omniauth', '>= 1.1.1'
25
- gem.add_runtime_dependency 'omniauth-oauth2', '>= 1.5'
24
+ gem.add_runtime_dependency 'oauth2', '~> 1.1'
25
+ gem.add_runtime_dependency 'omniauth', '~> 2.0'
26
+ gem.add_runtime_dependency 'omniauth-oauth2', '~> 1.7.1'
26
27
 
27
28
  gem.add_development_dependency 'rake', '~> 12.0'
28
29
  gem.add_development_dependency 'rspec', '~> 3.6'
@@ -3,6 +3,7 @@
3
3
  require 'spec_helper'
4
4
  require 'json'
5
5
  require 'omniauth-google-oauth2'
6
+ require 'stringio'
6
7
 
7
8
  describe OmniAuth::Strategies::GoogleOauth2 do
8
9
  let(:request) { double('Request', params: {}, cookies: {}, env: {}) }
@@ -177,8 +178,8 @@ describe OmniAuth::Strategies::GoogleOauth2 do
177
178
 
178
179
  describe 'scope' do
179
180
  it 'should expand scope shortcuts' do
180
- @options = { scope: 'plus.me' }
181
- expect(subject.authorize_params['scope']).to eq('https://www.googleapis.com/auth/plus.me')
181
+ @options = { scope: 'calendar' }
182
+ expect(subject.authorize_params['scope']).to eq('https://www.googleapis.com/auth/calendar')
182
183
  end
183
184
 
184
185
  it 'should leave base scopes as is' do
@@ -288,14 +289,61 @@ describe OmniAuth::Strategies::GoogleOauth2 do
288
289
  end
289
290
  end
290
291
 
291
- describe '#callback_path' do
292
+ describe '#callback_url' do
293
+ let(:base_url) { 'https://example.com' }
294
+
292
295
  it 'has the correct default callback path' do
293
- expect(subject.callback_path).to eq('/auth/google_oauth2/callback')
296
+ allow(subject).to receive(:full_host) { base_url }
297
+ allow(subject).to receive(:script_name) { '' }
298
+ expect(subject.send(:callback_url)).to eq(base_url + '/auth/google_oauth2/callback')
299
+ end
300
+
301
+ it 'should set the callback path with script_name if present' do
302
+ allow(subject).to receive(:full_host) { base_url }
303
+ allow(subject).to receive(:script_name) { '/v1' }
304
+ expect(subject.send(:callback_url)).to eq(base_url + '/v1/auth/google_oauth2/callback')
294
305
  end
295
306
 
296
307
  it 'should set the callback_path parameter if present' do
297
308
  @options = { callback_path: '/auth/foo/callback' }
298
- expect(subject.callback_path).to eq('/auth/foo/callback')
309
+ allow(subject).to receive(:full_host) { base_url }
310
+ allow(subject).to receive(:script_name) { '' }
311
+ expect(subject.send(:callback_url)).to eq(base_url + '/auth/foo/callback')
312
+ end
313
+ end
314
+
315
+ describe '#info' do
316
+ let(:client) do
317
+ OAuth2::Client.new('abc', 'def') do |builder|
318
+ builder.request :url_encoded
319
+ builder.adapter :test do |stub|
320
+ stub.get('/oauth2/v3/userinfo') { [200, { 'content-type' => 'application/json' }, response_hash.to_json] }
321
+ end
322
+ end
323
+ end
324
+ let(:access_token) { OAuth2::AccessToken.from_hash(client, {}) }
325
+ before { allow(subject).to receive(:access_token).and_return(access_token) }
326
+
327
+ context 'with verified email' do
328
+ let(:response_hash) do
329
+ { email: 'something@domain.invalid', email_verified: true }
330
+ end
331
+
332
+ it 'should return equal email and unverified_email' do
333
+ expect(subject.info[:email]).to eq('something@domain.invalid')
334
+ expect(subject.info[:unverified_email]).to eq('something@domain.invalid')
335
+ end
336
+ end
337
+
338
+ context 'with unverified email' do
339
+ let(:response_hash) do
340
+ { email: 'something@domain.invalid', email_verified: false }
341
+ end
342
+
343
+ it 'should return nil email, and correct unverified email' do
344
+ expect(subject.info[:email]).to eq(nil)
345
+ expect(subject.info[:unverified_email]).to eq('something@domain.invalid')
346
+ end
299
347
  end
300
348
  end
301
349
 
@@ -313,7 +361,7 @@ describe OmniAuth::Strategies::GoogleOauth2 do
313
361
  before { allow(subject).to receive(:access_token).and_return(access_token) }
314
362
 
315
363
  describe 'id_token' do
316
- shared_examples 'id_token issued by valid issuer' do |issuer| # rubocop:disable Metrics/BlockLength
364
+ shared_examples 'id_token issued by valid issuer' do |issuer|
317
365
  context 'when the id_token is passed into the access token' do
318
366
  let(:token_info) do
319
367
  {
@@ -426,6 +474,12 @@ describe OmniAuth::Strategies::GoogleOauth2 do
426
474
  expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/s50/photo.jpg')
427
475
  end
428
476
 
477
+ it 'should return the image with size specified in the `image_size` option when sizing is in the picture' do
478
+ @options = { image_size: 50 }
479
+ allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh4.googleusercontent.com/url/s96-c/photo.jpg' } }
480
+ expect(subject.info[:image]).to eq('https://lh4.googleusercontent.com/url/s50/photo.jpg')
481
+ end
482
+
429
483
  it 'should handle a picture with too many slashes correctly' do
430
484
  @options = { image_size: 50 }
431
485
  allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url//photo.jpg' } }
@@ -456,24 +510,48 @@ describe OmniAuth::Strategies::GoogleOauth2 do
456
510
  expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/w50-h40/photo.jpg')
457
511
  end
458
512
 
513
+ it 'should return the image with width and height specified in the `image_size` option when sizing is in the picture' do
514
+ @options = { image_size: { width: 50, height: 40 } }
515
+ allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url/w100-h80-c/photo.jpg' } }
516
+ expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/w50-h40/photo.jpg')
517
+ end
518
+
459
519
  it 'should return square image when `image_aspect_ratio` is specified' do
460
520
  @options = { image_aspect_ratio: 'square' }
461
521
  allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url/photo.jpg' } }
462
522
  expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/c/photo.jpg')
463
523
  end
464
524
 
525
+ it 'should return square image when `image_aspect_ratio` is specified and sizing is in the picture' do
526
+ @options = { image_aspect_ratio: 'square' }
527
+ allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url/c/photo.jpg' } }
528
+ expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/c/photo.jpg')
529
+ end
530
+
465
531
  it 'should return square sized image when `image_aspect_ratio` and `image_size` is set' do
466
532
  @options = { image_aspect_ratio: 'square', image_size: 50 }
467
533
  allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url/photo.jpg' } }
468
534
  expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/s50-c/photo.jpg')
469
535
  end
470
536
 
537
+ it 'should return square sized image when `image_aspect_ratio` and `image_size` is set and sizing is in the picture' do
538
+ @options = { image_aspect_ratio: 'square', image_size: 50 }
539
+ allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url/s90/photo.jpg' } }
540
+ expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/s50-c/photo.jpg')
541
+ end
542
+
471
543
  it 'should return square sized image when `image_aspect_ratio` and `image_size` has height and width' do
472
544
  @options = { image_aspect_ratio: 'square', image_size: { width: 50, height: 40 } }
473
545
  allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url/photo.jpg' } }
474
546
  expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/w50-h40-c/photo.jpg')
475
547
  end
476
548
 
549
+ it 'should return square sized image when `image_aspect_ratio` and `image_size` has height and width and sizing is in the picture' do
550
+ @options = { image_aspect_ratio: 'square', image_size: { width: 50, height: 40 } }
551
+ allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url/w100-h80/photo.jpg' } }
552
+ expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/w50-h40-c/photo.jpg')
553
+ end
554
+
477
555
  it 'should return original image if image url does not end in `photo.jpg`' do
478
556
  @options = { image_size: 50 }
479
557
  allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url/photograph.jpg' } }
@@ -547,9 +625,42 @@ describe OmniAuth::Strategies::GoogleOauth2 do
547
625
  expect(token.client).to eq(:client)
548
626
  end
549
627
 
628
+ it 'reads the code from a json request body' do
629
+ body = StringIO.new(%({"code":"json_access_token"}))
630
+ client = double(:client)
631
+ auth_code = double(:auth_code)
632
+
633
+ allow(request).to receive(:xhr?).and_return(false)
634
+ allow(request).to receive(:content_type).and_return('application/json')
635
+ allow(request).to receive(:body).and_return(body)
636
+ allow(client).to receive(:auth_code).and_return(auth_code)
637
+ expect(subject).to receive(:client).and_return(client)
638
+
639
+ expect(auth_code).to receive(:get_token).with('json_access_token', { redirect_uri: 'postmessage' }, {})
640
+
641
+ subject.build_access_token
642
+ end
643
+
644
+ it 'reads the access token from a json request body' do
645
+ body = StringIO.new(%({"access_token":"valid_access_token"}))
646
+
647
+ allow(request).to receive(:xhr?).and_return(false)
648
+ allow(request).to receive(:content_type).and_return('application/json')
649
+ allow(request).to receive(:body).and_return(body)
650
+ expect(subject).to receive(:client).and_return(:client)
651
+
652
+ expect(subject).to receive(:verify_token).with('valid_access_token').and_return true
653
+
654
+ token = subject.build_access_token
655
+ expect(token).to be_instance_of(::OAuth2::AccessToken)
656
+ expect(token.token).to eq('valid_access_token')
657
+ expect(token.client).to eq(:client)
658
+ end
659
+
550
660
  it 'should use callback_url without query_string if this is not an AJAX request' do
551
661
  allow(request).to receive(:xhr?).and_return(false)
552
662
  allow(request).to receive(:params).and_return('code' => 'valid_code')
663
+ allow(request).to receive(:content_type).and_return('application/x-www-form-urlencoded')
553
664
 
554
665
  client = double(:client)
555
666
  auth_code = double(:auth_code)
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omniauth-google-oauth2
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josh Ellithorpe
8
8
  - Yury Korolev
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2018-12-29 00:00:00.000000000 Z
12
+ date: 2021-03-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: jwt
@@ -25,34 +25,48 @@ dependencies:
25
25
  - - ">="
26
26
  - !ruby/object:Gem::Version
27
27
  version: '2.0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: oauth2
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '1.1'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '1.1'
28
42
  - !ruby/object:Gem::Dependency
29
43
  name: omniauth
30
44
  requirement: !ruby/object:Gem::Requirement
31
45
  requirements:
32
- - - ">="
46
+ - - "~>"
33
47
  - !ruby/object:Gem::Version
34
- version: 1.1.1
48
+ version: '2.0'
35
49
  type: :runtime
36
50
  prerelease: false
37
51
  version_requirements: !ruby/object:Gem::Requirement
38
52
  requirements:
39
- - - ">="
53
+ - - "~>"
40
54
  - !ruby/object:Gem::Version
41
- version: 1.1.1
55
+ version: '2.0'
42
56
  - !ruby/object:Gem::Dependency
43
57
  name: omniauth-oauth2
44
58
  requirement: !ruby/object:Gem::Requirement
45
59
  requirements:
46
- - - ">="
60
+ - - "~>"
47
61
  - !ruby/object:Gem::Version
48
- version: '1.5'
62
+ version: 1.7.1
49
63
  type: :runtime
50
64
  prerelease: false
51
65
  version_requirements: !ruby/object:Gem::Requirement
52
66
  requirements:
53
- - - ">="
67
+ - - "~>"
54
68
  - !ruby/object:Gem::Version
55
- version: '1.5'
69
+ version: 1.7.1
56
70
  - !ruby/object:Gem::Dependency
57
71
  name: rake
58
72
  requirement: !ruby/object:Gem::Requirement
@@ -125,7 +139,7 @@ homepage: https://github.com/zquestz/omniauth-google-oauth2
125
139
  licenses:
126
140
  - MIT
127
141
  metadata: {}
128
- post_install_message:
142
+ post_install_message:
129
143
  rdoc_options: []
130
144
  require_paths:
131
145
  - lib
@@ -133,16 +147,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
133
147
  requirements:
134
148
  - - ">="
135
149
  - !ruby/object:Gem::Version
136
- version: '2.1'
150
+ version: '2.2'
137
151
  required_rubygems_version: !ruby/object:Gem::Requirement
138
152
  requirements:
139
153
  - - ">="
140
154
  - !ruby/object:Gem::Version
141
155
  version: '0'
142
156
  requirements: []
143
- rubyforge_project:
144
- rubygems_version: 2.6.11
145
- signing_key:
157
+ rubyforge_project:
158
+ rubygems_version: 2.7.9
159
+ signing_key:
146
160
  specification_version: 4
147
161
  summary: A Google OAuth2 strategy for OmniAuth 1.x
148
162
  test_files: []