omniauth-shopify-oauth2 1.1.14 → 1.1.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e88a21bce303e6c6d637d58c50a2bfa7d75dfe86
4
- data.tar.gz: bced14c2fffa27c843425fe95dd088dbb5866c28
3
+ metadata.gz: 9fb79e1fb61eb4b740f0599821ce94f0d90bbf07
4
+ data.tar.gz: 5717243aa9a50abe95ce4b195d068a3b9e3605d1
5
5
  SHA512:
6
- metadata.gz: 575588b874c8c8d1774070ed66fbf55e8d70f9b82f9097c6f97e1ccb3423e792b82b400c2c3e481527eb60f5f54a69092aebd5715a5211845033bdc3a3be974c
7
- data.tar.gz: 3aa7bb0263d3c262f6c93aa39ce8729d92225fe712c9f0acc46560aed468f8c9dc125b4820a20273add6d4490b424215ba89565ac8c9fd8488d74dcc4dbe0f17
6
+ metadata.gz: 14c7013cd7138bb608422125897bec4662984b4080a7d13b479bb8fcdba8f838713ec8a0a7ef8eb7d8168b84532faec118b3a8f554d61df8e2bffa53ef542800
7
+ data.tar.gz: 2514636e95bf710c68545b420266e372ff9ad60df555c883df95bafa72a18125181473a29b5fdc1db0de68f6c38d82cec6c6752b54f46452db8858fad35bc24e
data/Gemfile CHANGED
@@ -1,3 +1,7 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
+
5
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.2")
6
+ gem 'rack', '~> 1.6'
7
+ end
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`:
@@ -1,5 +1,5 @@
1
1
  module OmniAuth
2
2
  module Shopify
3
- VERSION = "1.1.14"
3
+ VERSION = "1.1.15"
4
4
  end
5
5
  end
@@ -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 = ['denis.odorcic@shopify.com']
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'
@@ -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 /\A#{Regexp.quote("https://snowdevil.myshopify.com/admin/oauth/authorize?")}/, response.location
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 /\A#{Regexp.quote("https://snowdevil.myshopify.com/admin/oauth/authorize?")}/, response.location
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 /\A#{Regexp.quote("https://snowdevil.myshopify.dev:3000/admin/oauth/authorize?")}/, response.location
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 /\A#{Regexp.quote("/auth/failure?message=#{reason}")}/, response.location
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.14
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-02-25 00:00:00.000000000 Z
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
- - denis.odorcic@shopify.com
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.2.3
112
+ rubygems_version: 2.5.1
113
113
  signing_key:
114
114
  specification_version: 4
115
115
  summary: Shopify strategy for OmniAuth