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 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