omniauth-google-oauth2 0.6.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -5
- data/.travis.yml +1 -2
- data/CHANGELOG.md +71 -0
- data/README.md +74 -10
- data/examples/Gemfile +1 -1
- data/examples/omni_auth.rb +4 -0
- data/lib/omniauth/google_oauth2/version.rb +1 -1
- data/lib/omniauth/strategies/google_oauth2.rb +46 -16
- data/omniauth-google-oauth2.gemspec +4 -3
- data/spec/omniauth/strategies/google_oauth2_spec.rb +115 -4
- metadata +30 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 278efb11e955abf864c2d163e1f1631a271ba34660fa166a4f65b56691ccab0d
|
4
|
+
data.tar.gz: 574e6d6b5f3dacfa271ba24a8999e104c74db64482860b6ba095938a6dc7c1b0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,77 @@
|
|
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
|
+
|
4
75
|
## 0.6.1 - 2019-03-07
|
5
76
|
|
6
77
|
### Added
|
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
|
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
|
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 `[
|
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
|
-
|
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(
|
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
|
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
|
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
data/examples/omni_auth.rb
CHANGED
@@ -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'
|
@@ -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
|
@@ -46,7 +48,8 @@ module OmniAuth
|
|
46
48
|
info do
|
47
49
|
prune!(
|
48
50
|
name: raw_info['name'],
|
49
|
-
email:
|
51
|
+
email: verified_email,
|
52
|
+
unverified_email: raw_info['email'],
|
50
53
|
email_verified: raw_info['email_verified'],
|
51
54
|
first_name: raw_info['given_name'],
|
52
55
|
last_name: raw_info['family_name'],
|
@@ -73,7 +76,7 @@ module OmniAuth
|
|
73
76
|
verify_sub: false,
|
74
77
|
verify_expiration: true,
|
75
78
|
verify_not_before: true,
|
76
|
-
verify_iat:
|
79
|
+
verify_iat: false,
|
77
80
|
verify_jti: false,
|
78
81
|
leeway: options[:jwt_leeway])
|
79
82
|
|
@@ -93,31 +96,50 @@ module OmniAuth
|
|
93
96
|
verify_hd(access_token)
|
94
97
|
access_token
|
95
98
|
end
|
99
|
+
|
96
100
|
alias build_access_token custom_build_access_token
|
97
101
|
|
98
102
|
private
|
99
103
|
|
100
104
|
def callback_url
|
101
|
-
options[:redirect_uri] || (full_host +
|
105
|
+
options[:redirect_uri] || (full_host + callback_path)
|
102
106
|
end
|
103
107
|
|
104
108
|
def get_access_token(request)
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
redirect_uri
|
112
|
-
|
113
|
-
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)
|
114
117
|
::OAuth2::AccessToken.from_hash(client, request.params.dup)
|
115
|
-
|
116
|
-
|
117
|
-
|
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
|
118
132
|
end
|
119
133
|
end
|
120
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
|
+
|
121
143
|
def get_scope(params)
|
122
144
|
raw_scope = params[:scope] || DEFAULT_SCOPE
|
123
145
|
scope_list = raw_scope.split(' ').map { |item| item.split(',') }.flatten
|
@@ -125,7 +147,11 @@ module OmniAuth
|
|
125
147
|
scope_list.join(' ')
|
126
148
|
end
|
127
149
|
|
128
|
-
def
|
150
|
+
def verified_email
|
151
|
+
raw_info['email_verified'] ? raw_info['email'] : nil
|
152
|
+
end
|
153
|
+
|
154
|
+
def get_token_options(redirect_uri = '')
|
129
155
|
{ redirect_uri: redirect_uri }.merge(token_params.to_hash(symbolize_keys: true))
|
130
156
|
end
|
131
157
|
|
@@ -146,6 +172,10 @@ module OmniAuth
|
|
146
172
|
if path_index && image_size_opts_passed?
|
147
173
|
u.path.insert(path_index, image_params)
|
148
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
|
149
179
|
end
|
150
180
|
|
151
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.
|
21
|
+
gem.required_ruby_version = '>= 2.2'
|
22
22
|
|
23
23
|
gem.add_runtime_dependency 'jwt', '>= 2.0'
|
24
|
-
gem.add_runtime_dependency '
|
25
|
-
gem.add_runtime_dependency 'omniauth
|
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: {}) }
|
@@ -288,14 +289,61 @@ describe OmniAuth::Strategies::GoogleOauth2 do
|
|
288
289
|
end
|
289
290
|
end
|
290
291
|
|
291
|
-
describe '#
|
292
|
+
describe '#callback_url' do
|
293
|
+
let(:base_url) { 'https://example.com' }
|
294
|
+
|
292
295
|
it 'has the correct default callback path' do
|
293
|
-
|
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
|
-
|
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|
|
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.
|
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:
|
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:
|
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:
|
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:
|
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:
|
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,15 +147,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
133
147
|
requirements:
|
134
148
|
- - ">="
|
135
149
|
- !ruby/object:Gem::Version
|
136
|
-
version: '2.
|
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
|
-
|
144
|
-
|
157
|
+
rubyforge_project:
|
158
|
+
rubygems_version: 2.7.9
|
159
|
+
signing_key:
|
145
160
|
specification_version: 4
|
146
161
|
summary: A Google OAuth2 strategy for OmniAuth 1.x
|
147
162
|
test_files: []
|