omniauth-shopify-oauth2 1.1.14 → 1.1.15
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +4 -0
- data/README.md +10 -0
- data/lib/omniauth/shopify/version.rb +1 -1
- data/lib/omniauth/strategies/shopify.rb +22 -0
- data/omniauth-shopify-oauth2.gemspec +1 -1
- data/test/integration_test.rb +57 -7
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9fb79e1fb61eb4b740f0599821ce94f0d90bbf07
|
4
|
+
data.tar.gz: 5717243aa9a50abe95ce4b195d068a3b9e3605d1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 14c7013cd7138bb608422125897bec4662984b4080a7d13b479bb8fcdba8f838713ec8a0a7ef8eb7d8168b84532faec118b3a8f554d61df8e2bffa53ef542800
|
7
|
+
data.tar.gz: 2514636e95bf710c68545b420266e372ff9ad60df555c883df95bafa72a18125181473a29b5fdc1db0de68f6c38d82cec6c6752b54f46452db8858fad35bc24e
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -26,6 +26,16 @@ Rails.application.config.middleware.use OmniAuth::Builder do
|
|
26
26
|
end
|
27
27
|
```
|
28
28
|
|
29
|
+
Authenticate the user by having them visit /auth/shopify with a `shop` query parameter of their shop's myshopify.com domain. For example, the following form could be used
|
30
|
+
|
31
|
+
```html
|
32
|
+
<form action="/auth/shopify" method="get">
|
33
|
+
<label for="shop">Enter your store's URL:</label>
|
34
|
+
<input type="text" name="shop" placeholder="your-shop-url.myshopify.com">
|
35
|
+
<button type="submit">Log In</button>
|
36
|
+
</form>
|
37
|
+
```
|
38
|
+
|
29
39
|
## Configuring
|
30
40
|
|
31
41
|
You can configure the scope, which you pass in to the `provider` method via a `Hash`:
|
@@ -18,6 +18,10 @@ module OmniAuth
|
|
18
18
|
option :callback_url
|
19
19
|
option :myshopify_domain, 'myshopify.com'
|
20
20
|
|
21
|
+
# When `true`, the user's permission level will apply (in addition to
|
22
|
+
# the requested access scope) when making API requests to Shopify.
|
23
|
+
option :per_user_permissions, false
|
24
|
+
|
21
25
|
# When `true`, the authorization phase will fail if the granted scopes
|
22
26
|
# mismatch the requested scopes.
|
23
27
|
option :validate_granted_scopes, true
|
@@ -29,6 +33,16 @@ module OmniAuth
|
|
29
33
|
|
30
34
|
uid { URI.parse(options[:client_options][:site]).host }
|
31
35
|
|
36
|
+
extra do
|
37
|
+
if access_token
|
38
|
+
{
|
39
|
+
'associated_user' => access_token['associated_user'],
|
40
|
+
'associated_user_scope' => access_token['associated_user_scope'],
|
41
|
+
'scope' => access_token['scope'],
|
42
|
+
}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
32
46
|
def valid_site?
|
33
47
|
!!(/\A(https|http)\:\/\/[a-zA-Z0-9][a-zA-Z0-9\-]*\.#{Regexp.quote(options[:myshopify_domain])}[\/]?\z/ =~ options[:client_options][:site])
|
34
48
|
end
|
@@ -71,6 +85,10 @@ module OmniAuth
|
|
71
85
|
OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA256.new, secret, encoded_params)
|
72
86
|
end
|
73
87
|
|
88
|
+
def valid_permissions?(token)
|
89
|
+
token && (options[:per_user_permissions] == !token['associated_user'].nil?)
|
90
|
+
end
|
91
|
+
|
74
92
|
def fix_https
|
75
93
|
options[:client_options][:site].gsub!(/\Ahttp\:/, 'https:')
|
76
94
|
end
|
@@ -96,6 +114,9 @@ module OmniAuth
|
|
96
114
|
unless valid_scope?(token)
|
97
115
|
return fail!(:invalid_scope, CallbackError.new(:invalid_scope, "Scope does not match, it may have been tampered with."))
|
98
116
|
end
|
117
|
+
unless valid_permissions?(token)
|
118
|
+
return fail!(:invalid_permissions, CallbackError.new(:invalid_permissions, "Requested API access mode does not match."))
|
119
|
+
end
|
99
120
|
|
100
121
|
super
|
101
122
|
end
|
@@ -107,6 +128,7 @@ module OmniAuth
|
|
107
128
|
def authorize_params
|
108
129
|
super.tap do |params|
|
109
130
|
params[:scope] = normalized_scopes(params[:scope] || DEFAULT_SCOPE).join(SCOPE_DELIMITER)
|
131
|
+
params[:grant_options] = ['per-user'] if options[:per_user_permissions]
|
110
132
|
end
|
111
133
|
end
|
112
134
|
|
@@ -6,7 +6,7 @@ Gem::Specification.new do |s|
|
|
6
6
|
s.name = 'omniauth-shopify-oauth2'
|
7
7
|
s.version = OmniAuth::Shopify::VERSION
|
8
8
|
s.authors = ['Denis Odorcic']
|
9
|
-
s.email = ['
|
9
|
+
s.email = ['gems@shopify.com']
|
10
10
|
s.summary = 'Shopify strategy for OmniAuth'
|
11
11
|
s.homepage = 'https://github.com/Shopify/omniauth-shopify-oauth2'
|
12
12
|
s.license = 'MIT'
|
data/test/integration_test.rb
CHANGED
@@ -13,11 +13,19 @@ class IntegrationTest < Minitest::Test
|
|
13
13
|
def test_authorize
|
14
14
|
response = authorize('snowdevil.myshopify.com')
|
15
15
|
assert_equal 302, response.status
|
16
|
-
assert_match
|
16
|
+
assert_match %r{\A#{Regexp.quote(shopify_authorize_url)}}, response.location
|
17
17
|
redirect_params = Rack::Utils.parse_query(URI(response.location).query)
|
18
18
|
assert_equal "123", redirect_params['client_id']
|
19
19
|
assert_equal "https://app.example.com/auth/shopify/callback", redirect_params['redirect_uri']
|
20
20
|
assert_equal "read_products", redirect_params['scope']
|
21
|
+
assert_nil redirect_params['grant_options']
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_authorize_includes_auth_type_when_per_user_permissions_are_requested
|
25
|
+
build_app(per_user_permissions: true)
|
26
|
+
response = authorize('snowdevil.myshopify.com')
|
27
|
+
redirect_params = Rack::Utils.parse_query(URI(response.location).query)
|
28
|
+
assert_equal 'per-user', redirect_params['grant_options[]']
|
21
29
|
end
|
22
30
|
|
23
31
|
def test_authorize_overrides_site_with_https_scheme
|
@@ -27,7 +35,7 @@ class IntegrationTest < Minitest::Test
|
|
27
35
|
}
|
28
36
|
|
29
37
|
response = authorize('snowdevil.myshopify.com')
|
30
|
-
assert_match
|
38
|
+
assert_match %r{\A#{Regexp.quote(shopify_authorize_url)}}, response.location
|
31
39
|
end
|
32
40
|
|
33
41
|
def test_site_validation
|
@@ -142,7 +150,7 @@ class IntegrationTest < Minitest::Test
|
|
142
150
|
|
143
151
|
response = authorize('snowdevil')
|
144
152
|
assert_equal 302, response.status
|
145
|
-
assert_match
|
153
|
+
assert_match %r{\A#{Regexp.quote("https://snowdevil.myshopify.dev:3000/admin/oauth/authorize?")}}, response.location
|
146
154
|
redirect_params = Rack::Utils.parse_query(URI(response.location).query)
|
147
155
|
assert_equal 'read_products,read_orders,write_content', redirect_params['scope']
|
148
156
|
assert_equal 'https://app.example.com/admin/auth/legacy/callback', redirect_params['redirect_uri']
|
@@ -178,7 +186,7 @@ class IntegrationTest < Minitest::Test
|
|
178
186
|
def test_callback_with_mismatching_scope_fails
|
179
187
|
access_token = SecureRandom.hex(16)
|
180
188
|
code = SecureRandom.hex(16)
|
181
|
-
expect_access_token_request(access_token, 'some_invalid_scope')
|
189
|
+
expect_access_token_request(access_token, 'some_invalid_scope', nil)
|
182
190
|
|
183
191
|
response = callback(sign_params(shop: 'snowdevil.myshopify.com', code: code, state: opts["rack.session"]["omniauth.state"]))
|
184
192
|
|
@@ -247,6 +255,44 @@ class IntegrationTest < Minitest::Test
|
|
247
255
|
assert_callback_success(response, access_token, code)
|
248
256
|
end
|
249
257
|
|
258
|
+
def test_callback_when_per_user_permissions_are_present_but_not_requested
|
259
|
+
build_app(scope: 'scope', per_user_permissions: false)
|
260
|
+
|
261
|
+
access_token = SecureRandom.hex(16)
|
262
|
+
code = SecureRandom.hex(16)
|
263
|
+
expect_access_token_request(access_token, 'scope', { id: 1, email: 'bob@bobsen.com'})
|
264
|
+
|
265
|
+
response = callback(sign_params(shop: 'snowdevil.myshopify.com', code: code, state: opts["rack.session"]["omniauth.state"]))
|
266
|
+
|
267
|
+
assert_equal 302, response.status
|
268
|
+
assert_equal '/auth/failure?message=invalid_permissions&strategy=shopify', response.location
|
269
|
+
end
|
270
|
+
|
271
|
+
def test_callback_when_per_user_permissions_are_not_present_but_requested
|
272
|
+
build_app(scope: 'scope', per_user_permissions: true)
|
273
|
+
|
274
|
+
access_token = SecureRandom.hex(16)
|
275
|
+
code = SecureRandom.hex(16)
|
276
|
+
expect_access_token_request(access_token, 'scope', nil)
|
277
|
+
|
278
|
+
response = callback(sign_params(shop: 'snowdevil.myshopify.com', code: code, state: opts["rack.session"]["omniauth.state"]))
|
279
|
+
|
280
|
+
assert_equal 302, response.status
|
281
|
+
assert_equal '/auth/failure?message=invalid_permissions&strategy=shopify', response.location
|
282
|
+
end
|
283
|
+
|
284
|
+
def test_callback_works_when_per_user_permissions_are_present_and_requested
|
285
|
+
build_app(scope: 'scope', per_user_permissions: true)
|
286
|
+
|
287
|
+
access_token = SecureRandom.hex(16)
|
288
|
+
code = SecureRandom.hex(16)
|
289
|
+
expect_access_token_request(access_token, 'scope', { id: 1, email: 'bob@bobsen.com'})
|
290
|
+
|
291
|
+
response = callback(sign_params(shop: 'snowdevil.myshopify.com', code: code, state: opts["rack.session"]["omniauth.state"]))
|
292
|
+
|
293
|
+
assert_equal 200, response.status
|
294
|
+
end
|
295
|
+
|
250
296
|
private
|
251
297
|
|
252
298
|
def sign_params(params)
|
@@ -259,9 +305,9 @@ class IntegrationTest < Minitest::Test
|
|
259
305
|
params
|
260
306
|
end
|
261
307
|
|
262
|
-
def expect_access_token_request(access_token, scope)
|
308
|
+
def expect_access_token_request(access_token, scope, associated_user=nil)
|
263
309
|
FakeWeb.register_uri(:post, "https://snowdevil.myshopify.com/admin/oauth/access_token",
|
264
|
-
body: JSON.dump(access_token: access_token, scope: scope),
|
310
|
+
body: JSON.dump(access_token: access_token, scope: scope, associated_user: associated_user),
|
265
311
|
content_type: 'application/json')
|
266
312
|
end
|
267
313
|
|
@@ -282,7 +328,7 @@ class IntegrationTest < Minitest::Test
|
|
282
328
|
def assert_auth_failure(response, reason)
|
283
329
|
assert_nil FakeWeb.last_request
|
284
330
|
assert_equal 302, response.status
|
285
|
-
assert_match
|
331
|
+
assert_match %r{\A#{Regexp.quote("/auth/failure?message=#{reason}")}}, response.location
|
286
332
|
end
|
287
333
|
|
288
334
|
def build_app(options={})
|
@@ -314,4 +360,8 @@ class IntegrationTest < Minitest::Test
|
|
314
360
|
def request
|
315
361
|
Rack::MockRequest.new(@app)
|
316
362
|
end
|
363
|
+
|
364
|
+
def shopify_authorize_url
|
365
|
+
"https://snowdevil.myshopify.com/admin/oauth/authorize?"
|
366
|
+
end
|
317
367
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: omniauth-shopify-oauth2
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.15
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Denis Odorcic
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-10-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: omniauth-oauth2
|
@@ -68,7 +68,7 @@ dependencies:
|
|
68
68
|
version: '0'
|
69
69
|
description:
|
70
70
|
email:
|
71
|
-
-
|
71
|
+
- gems@shopify.com
|
72
72
|
executables: []
|
73
73
|
extensions: []
|
74
74
|
extra_rdoc_files: []
|
@@ -109,7 +109,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
109
109
|
version: '0'
|
110
110
|
requirements: []
|
111
111
|
rubyforge_project:
|
112
|
-
rubygems_version: 2.
|
112
|
+
rubygems_version: 2.5.1
|
113
113
|
signing_key:
|
114
114
|
specification_version: 4
|
115
115
|
summary: Shopify strategy for OmniAuth
|