omniauth-google-oauth2 0.8.0 → 0.8.1

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
2
  SHA256:
3
- metadata.gz: a035e3c9635a9e588b756e9b2dfe2004ea1b83c49f9860d68e8250e7d93e4459
4
- data.tar.gz: 20e8ba4d7f4b9fb20b139c8d4b9c51d8d1d598de1cada5d989640f01eee0df3a
3
+ metadata.gz: fcec58e2424446306a5ff766699234f2d6c171da2b709112769b99e72a203eaf
4
+ data.tar.gz: fcf68a4790a7309cd50d7c0b0e13bb53f0229fcc051fad60166d8d14b927d9f6
5
5
  SHA512:
6
- metadata.gz: 5b06e6a3ffd03ff81fe6e04bbc94c9154e26c59dc17a7c834361bf2fdd80197661434679e8174196f4dd8ed13e4b2b81ff4b223fb366238f48648ea452fcf1ce
7
- data.tar.gz: 4734f0d6f92b57cebfccbbd0b833a7da9674d04e9058b76ef43d96cd94520a48bd540f57c9f804f6b16f2bad76483aefb3ef7357a99186acfc4dcb1603fa3a28
6
+ metadata.gz: 99cd674b184a20ee2ff2c5da1a98e4a692aad4c0e739882da60338c9519d72828d440c0a375fd6c248651b7dd365f35800dabe3be28282e8e11ea425274dc0d1
7
+ data.tar.gz: d06b35c2f70c7680a9963edff13cc9e3e417ffca216dc7b46d6074ff01ec4207f41ae59b9251e5f91213ad39c0065b1f049450688b8cabdbc709acabc405090c
@@ -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
-
@@ -1,6 +1,5 @@
1
1
  language: ruby
2
2
  rvm:
3
- - '2.2.7'
4
3
  - '2.3.4'
5
4
  - '2.4.1'
6
5
  - '2.5.0'
@@ -1,6 +1,20 @@
1
1
  # Changelog
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
+ ## 0.8.1 - 2020-12-12
5
+
6
+ ### Added
7
+ - Support reading the access token from a json request body.
8
+
9
+ ### Deprecated
10
+ - Nothing.
11
+
12
+ ### Removed
13
+ - No longer verify the iat claim for JWT.
14
+
15
+ ### Fixed
16
+ - A few minor issues with .rubocop.yml.
17
+
4
18
  ## 0.8.0 - 2019-08-21
5
19
 
6
20
  ### Added
data/README.md CHANGED
@@ -81,7 +81,9 @@ 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
+
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.
85
87
 
86
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
 
@@ -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.
@@ -2,6 +2,6 @@
2
2
 
3
3
  source 'https://rubygems.org'
4
4
 
5
- gem 'omniauth-google-oauth2', '~> 0.8.0'
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.8.0'
5
+ VERSION = '0.8.1'
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
@@ -74,7 +76,7 @@ module OmniAuth
74
76
  verify_sub: false,
75
77
  verify_expiration: true,
76
78
  verify_not_before: true,
77
- verify_iat: true,
79
+ verify_iat: false,
78
80
  verify_jti: false,
79
81
  leeway: options[:jwt_leeway])
80
82
 
@@ -106,18 +108,24 @@ module OmniAuth
106
108
  def get_access_token(request)
107
109
  verifier = request.params['code']
108
110
  redirect_uri = request.params['redirect_uri']
111
+ access_token = request.params['access_token']
109
112
  if verifier && request.xhr?
110
113
  client_get_token(verifier, redirect_uri || 'postmessage')
111
114
  elsif verifier
112
115
  client_get_token(verifier, redirect_uri || callback_url)
113
- elsif verify_token(request.params['access_token'])
116
+ elsif access_token && verify_token(access_token)
114
117
  ::OAuth2::AccessToken.from_hash(client, request.params.dup)
115
118
  elsif request.content_type =~ /json/i
116
119
  begin
117
120
  body = JSON.parse(request.body.read)
118
121
  request.body.rewind # rewind request body for downstream middlewares
119
122
  verifier = body && body['code']
120
- client_get_token(verifier, 'postmessage') if verifier
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
121
129
  rescue JSON::ParserError => e
122
130
  warn "[omniauth google-oauth2] JSON parse error=#{e}"
123
131
  end
@@ -164,6 +172,10 @@ module OmniAuth
164
172
  if path_index && image_size_opts_passed?
165
173
  u.path.insert(path_index, image_params)
166
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
167
179
  end
168
180
 
169
181
  u.query = strip_unnecessary_query_parameters(u.query)
@@ -21,6 +21,7 @@ Gem::Specification.new do |gem|
21
21
  gem.required_ruby_version = '>= 2.2'
22
22
 
23
23
  gem.add_runtime_dependency 'jwt', '>= 2.0'
24
+ gem.add_runtime_dependency 'oauth2', '~> 1.1'
24
25
  gem.add_runtime_dependency 'omniauth', '>= 1.1.1'
25
26
  gem.add_runtime_dependency 'omniauth-oauth2', '>= 1.6'
26
27
 
@@ -349,7 +349,7 @@ describe OmniAuth::Strategies::GoogleOauth2 do
349
349
  before { allow(subject).to receive(:access_token).and_return(access_token) }
350
350
 
351
351
  describe 'id_token' do
352
- shared_examples 'id_token issued by valid issuer' do |issuer| # rubocop:disable Metrics/BlockLength
352
+ shared_examples 'id_token issued by valid issuer' do |issuer|
353
353
  context 'when the id_token is passed into the access token' do
354
354
  let(:token_info) do
355
355
  {
@@ -462,6 +462,12 @@ describe OmniAuth::Strategies::GoogleOauth2 do
462
462
  expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/s50/photo.jpg')
463
463
  end
464
464
 
465
+ it 'should return the image with size specified in the `image_size` option when sizing is in the picture' do
466
+ @options = { image_size: 50 }
467
+ allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh4.googleusercontent.com/url/s96-c/photo.jpg' } }
468
+ expect(subject.info[:image]).to eq('https://lh4.googleusercontent.com/url/s50/photo.jpg')
469
+ end
470
+
465
471
  it 'should handle a picture with too many slashes correctly' do
466
472
  @options = { image_size: 50 }
467
473
  allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url//photo.jpg' } }
@@ -492,24 +498,48 @@ describe OmniAuth::Strategies::GoogleOauth2 do
492
498
  expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/w50-h40/photo.jpg')
493
499
  end
494
500
 
501
+ it 'should return the image with width and height specified in the `image_size` option when sizing is in the picture' do
502
+ @options = { image_size: { width: 50, height: 40 } }
503
+ allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url/w100-h80-c/photo.jpg' } }
504
+ expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/w50-h40/photo.jpg')
505
+ end
506
+
495
507
  it 'should return square image when `image_aspect_ratio` is specified' do
496
508
  @options = { image_aspect_ratio: 'square' }
497
509
  allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url/photo.jpg' } }
498
510
  expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/c/photo.jpg')
499
511
  end
500
512
 
513
+ it 'should return square image when `image_aspect_ratio` is specified and sizing is in the picture' do
514
+ @options = { image_aspect_ratio: 'square' }
515
+ allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url/c/photo.jpg' } }
516
+ expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/c/photo.jpg')
517
+ end
518
+
501
519
  it 'should return square sized image when `image_aspect_ratio` and `image_size` is set' do
502
520
  @options = { image_aspect_ratio: 'square', image_size: 50 }
503
521
  allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url/photo.jpg' } }
504
522
  expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/s50-c/photo.jpg')
505
523
  end
506
524
 
525
+ it 'should return square sized image when `image_aspect_ratio` and `image_size` is set and sizing is in the picture' do
526
+ @options = { image_aspect_ratio: 'square', image_size: 50 }
527
+ allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url/s90/photo.jpg' } }
528
+ expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/s50-c/photo.jpg')
529
+ end
530
+
507
531
  it 'should return square sized image when `image_aspect_ratio` and `image_size` has height and width' do
508
532
  @options = { image_aspect_ratio: 'square', image_size: { width: 50, height: 40 } }
509
533
  allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url/photo.jpg' } }
510
534
  expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/w50-h40-c/photo.jpg')
511
535
  end
512
536
 
537
+ it 'should return square sized image when `image_aspect_ratio` and `image_size` has height and width and sizing is in the picture' do
538
+ @options = { image_aspect_ratio: 'square', image_size: { width: 50, height: 40 } }
539
+ allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url/w100-h80/photo.jpg' } }
540
+ expect(subject.info[:image]).to eq('https://lh3.googleusercontent.com/url/w50-h40-c/photo.jpg')
541
+ end
542
+
513
543
  it 'should return original image if image url does not end in `photo.jpg`' do
514
544
  @options = { image_size: 50 }
515
545
  allow(subject).to receive(:raw_info) { { 'picture' => 'https://lh3.googleusercontent.com/url/photograph.jpg' } }
@@ -599,6 +629,22 @@ describe OmniAuth::Strategies::GoogleOauth2 do
599
629
  subject.build_access_token
600
630
  end
601
631
 
632
+ it 'reads the access token from a json request body' do
633
+ body = StringIO.new(%({"access_token":"valid_access_token"}))
634
+
635
+ allow(request).to receive(:xhr?).and_return(false)
636
+ allow(request).to receive(:content_type).and_return('application/json')
637
+ allow(request).to receive(:body).and_return(body)
638
+ expect(subject).to receive(:client).and_return(:client)
639
+
640
+ expect(subject).to receive(:verify_token).with('valid_access_token').and_return true
641
+
642
+ token = subject.build_access_token
643
+ expect(token).to be_instance_of(::OAuth2::AccessToken)
644
+ expect(token.token).to eq('valid_access_token')
645
+ expect(token.client).to eq(:client)
646
+ end
647
+
602
648
  it 'should use callback_url without query_string if this is not an AJAX request' do
603
649
  allow(request).to receive(:xhr?).and_return(false)
604
650
  allow(request).to receive(:params).and_return('code' => 'valid_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.8.0
4
+ version: 0.8.1
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: 2019-08-22 00:00:00.000000000 Z
12
+ date: 2020-12-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: jwt
@@ -25,6 +25,20 @@ 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
@@ -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
@@ -140,9 +154,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
140
154
  - !ruby/object:Gem::Version
141
155
  version: '0'
142
156
  requirements: []
143
- rubyforge_project:
157
+ rubyforge_project:
144
158
  rubygems_version: 2.7.9
145
- signing_key:
159
+ signing_key:
146
160
  specification_version: 4
147
161
  summary: A Google OAuth2 strategy for OmniAuth 1.x
148
162
  test_files: []