graphql_devise 0.15.0 → 0.16.0
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 +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +21 -7
- data/lib/graphql_devise/schema_plugin.rb +6 -2
- data/lib/graphql_devise/version.rb +1 -1
- data/spec/dummy/app/graphql/types/query_type.rb +5 -0
- data/spec/dummy/db/migrate/20210516211417_add_vip_to_users.rb +5 -0
- data/spec/dummy/db/schema.rb +4 -3
- data/spec/requests/user_controller_spec.rb +71 -30
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 12c52068c8c538bc35dc67deb2d697101e1fa001419ccdbff23183e854f5f404
|
4
|
+
data.tar.gz: 65afe18384fb742e8dbc300d19b227815ebe166997147031bbabd63742738205
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fcf10385aeb27e02f283fa5b5d140f51352508d4a9973dd374edfe78b67a64cfa9b4183e39a8065af5a9697569fac4ed9c21aa007df26fd271b6739c2f9cd5a9
|
7
|
+
data.tar.gz: d3f45d87972e29a325375c1868fced4ef377effcfba6be182c7d8c0b34bdfd6032db66097f0304416ff5966b532fea994d135be0ee48a070c2369668acc3beb2
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [v0.16.0](https://github.com/graphql-devise/graphql_devise/tree/v0.16.0) (2021-05-20)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/graphql-devise/graphql_devise/compare/v0.15.0...v0.16.0)
|
6
|
+
|
7
|
+
**Implemented enhancements:**
|
8
|
+
|
9
|
+
- Allow checking of authenticaded resource via callable object [\#180](https://github.com/graphql-devise/graphql_devise/pull/180) ([mcelicalderon](https://github.com/mcelicalderon))
|
10
|
+
|
11
|
+
**Merged pull requests:**
|
12
|
+
|
13
|
+
- Document authenticate with callable [\#181](https://github.com/graphql-devise/graphql_devise/pull/181) ([mcelicalderon](https://github.com/mcelicalderon))
|
14
|
+
|
3
15
|
## [v0.15.0](https://github.com/graphql-devise/graphql_devise/tree/v0.15.0) (2021-05-09)
|
4
16
|
|
5
17
|
[Full Changelog](https://github.com/graphql-devise/graphql_devise/compare/v0.14.3...v0.15.0)
|
data/README.md
CHANGED
@@ -28,8 +28,10 @@ GraphQL interface on top of the [Devise Token Auth](https://github.com/lynndylan
|
|
28
28
|
* [I18n](#i18n)
|
29
29
|
* [Authenticating Controller Actions](#authenticating-controller-actions)
|
30
30
|
* [Authenticate Resource in the Controller (>= v0.15.0)](#authenticate-resource-in-the-controller--v0150)
|
31
|
+
* [Authentication Options](#authentication-options)
|
31
32
|
* [Authenticate Before Reaching Your GQL Schema (Deprecated)](#authenticate-before-reaching-your-gql-schema-deprecated)
|
32
33
|
* [Authenticate in Your GQL Schema (Deprecated)](#authenticate-in-your-gql-schema-deprecated)
|
34
|
+
* [Authentication Options](#authentication-options-1)
|
33
35
|
* [Important](#important-2)
|
34
36
|
* [Making Requests](#making-requests)
|
35
37
|
* [Introspection query](#introspection-query)
|
@@ -45,7 +47,7 @@ GraphQL interface on top of the [Devise Token Auth](https://github.com/lynndylan
|
|
45
47
|
* [Contributing](#contributing)
|
46
48
|
* [License](#license)
|
47
49
|
|
48
|
-
<!-- Added by: mcelicalderon, at:
|
50
|
+
<!-- Added by: mcelicalderon, at: Wed May 19 21:25:22 -05 2021 -->
|
49
51
|
|
50
52
|
<!--te-->
|
51
53
|
|
@@ -432,7 +434,13 @@ restricted to authenticated users and you can only do this at the root level fie
|
|
432
434
|
schema. Configure the plugin as explained [here](#mounting-operations-into-your-own-schema)
|
433
435
|
so this can work.
|
434
436
|
|
435
|
-
|
437
|
+
##### Authentication Options
|
438
|
+
Wether you setup authentications as a default in the plugin, or you do it at the field level,
|
439
|
+
these are the options you can use:
|
440
|
+
1. **Any truthy value:** If `current_resource` is not `.present?`, query will return an authentication error.
|
441
|
+
1. **A callable object:** Provided object will be called with `current_resource` as the only argument if `current_resource` is `.present?`. If return value of the callable object is false, query will return an authentication error.
|
442
|
+
|
443
|
+
In your main app's schema this is how you might specify if a field needs to be authenticated or not:
|
436
444
|
```ruby
|
437
445
|
module Types
|
438
446
|
class QueryType < Types::BaseObject
|
@@ -442,13 +450,11 @@ module Types
|
|
442
450
|
field :public_field, String, null: false, authenticate: false
|
443
451
|
# this field requires authentication
|
444
452
|
field :private_field, String, null: false, authenticate: true
|
453
|
+
# this field requires authenticated users to also be admins
|
454
|
+
field :admin_field, String, null: false, authenticate: ->(user) { user.admin? }
|
445
455
|
end
|
446
456
|
end
|
447
457
|
```
|
448
|
-
**Important:** Currently, the only check the plugin does to see if the user is authenticated or not when executing
|
449
|
-
the query, is verifying that `context[:current_resource].present?` in the GraphQL context.
|
450
|
-
So, be careful not to populate that key of the context with values other than what `gql_devise_context`
|
451
|
-
returns. The option to do more complex verifications will be added in the future.
|
452
458
|
|
453
459
|
#### Authenticate Before Reaching Your GQL Schema (Deprecated)
|
454
460
|
For this you will need to call `authenticate_<model>!` in a `before_action` controller hook.
|
@@ -506,7 +512,13 @@ restricted to authenticated users and you can only do this at the root level fie
|
|
506
512
|
schema. Configure the plugin as explained [here](#mounting-operations-into-your-own-schema)
|
507
513
|
so this can work.
|
508
514
|
|
509
|
-
|
515
|
+
##### Authentication Options
|
516
|
+
Wether you setup authentications as a default in the plugin, or you do it at the field level,
|
517
|
+
these are the options you can use:
|
518
|
+
1. **Any truthy value:** If `current_resource` is not `.present?`, query will return an authentication error.
|
519
|
+
1. **A callable object:** Provided object will be called with `current_resource` as the only argument if `current_resource` is `.present?`. If return value of the callable object is false, query will return an authentication error.
|
520
|
+
|
521
|
+
In your main app's schema this is how you might specify if a field needs to be authenticated or not:
|
510
522
|
```ruby
|
511
523
|
module Types
|
512
524
|
class QueryType < Types::BaseObject
|
@@ -516,6 +528,8 @@ module Types
|
|
516
528
|
field :public_field, String, null: false, authenticate: false
|
517
529
|
# this field requires authentication
|
518
530
|
field :private_field, String, null: false, authenticate: true
|
531
|
+
# this field requires authenticated users to also be admins
|
532
|
+
field :admin_field, String, null: false, authenticate: ->(user) { user.admin? }
|
519
533
|
end
|
520
534
|
end
|
521
535
|
```
|
@@ -46,7 +46,7 @@ module GraphqlDevise
|
|
46
46
|
|
47
47
|
if auth_required && !(public_introspection && introspection_field?(field))
|
48
48
|
context = set_current_resource(context)
|
49
|
-
raise_on_missing_resource(context, field)
|
49
|
+
raise_on_missing_resource(context, field, auth_required)
|
50
50
|
end
|
51
51
|
|
52
52
|
yield
|
@@ -75,8 +75,12 @@ module GraphqlDevise
|
|
75
75
|
context
|
76
76
|
end
|
77
77
|
|
78
|
-
def raise_on_missing_resource(context, field)
|
78
|
+
def raise_on_missing_resource(context, field, auth_required)
|
79
79
|
@unauthenticated_proc.call(field.name) if context[:current_resource].blank?
|
80
|
+
|
81
|
+
if auth_required.respond_to?(:call) && !auth_required.call(context[:current_resource])
|
82
|
+
@unauthenticated_proc.call(field.name)
|
83
|
+
end
|
80
84
|
end
|
81
85
|
|
82
86
|
def context_from_data(trace_data)
|
@@ -5,6 +5,7 @@ module Types
|
|
5
5
|
field :user, resolver: Resolvers::UserShow
|
6
6
|
field :public_field, String, null: false, authenticate: false
|
7
7
|
field :private_field, String, null: false, authenticate: true
|
8
|
+
field :vip_field, String, null: false, authenticate: ->(user) { user.is_a?(User) && user.vip? }
|
8
9
|
|
9
10
|
def public_field
|
10
11
|
'Field does not require authentication'
|
@@ -13,5 +14,9 @@ module Types
|
|
13
14
|
def private_field
|
14
15
|
'Field will always require authentication'
|
15
16
|
end
|
17
|
+
|
18
|
+
def vip_field
|
19
|
+
'Field available only for VIP Users'
|
20
|
+
end
|
16
21
|
end
|
17
22
|
end
|
data/spec/dummy/db/schema.rb
CHANGED
@@ -2,15 +2,15 @@
|
|
2
2
|
# of editing this file, please use the migrations feature of Active Record to
|
3
3
|
# incrementally modify your database, and then regenerate this schema definition.
|
4
4
|
#
|
5
|
-
# This file is the source Rails uses to define your schema when running `rails
|
6
|
-
# db:schema:load`. When creating a new database, `rails db:schema:load` tends to
|
5
|
+
# This file is the source Rails uses to define your schema when running `bin/rails
|
6
|
+
# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
|
7
7
|
# be faster and is potentially less error prone than running all of your
|
8
8
|
# migrations from scratch. Old migrations may fail to apply correctly if those
|
9
9
|
# migrations use external dependencies or application code.
|
10
10
|
#
|
11
11
|
# It's strongly recommended that you check this file into your version control system.
|
12
12
|
|
13
|
-
ActiveRecord::Schema.define(version:
|
13
|
+
ActiveRecord::Schema.define(version: 2021_05_16_211417) do
|
14
14
|
|
15
15
|
create_table "admins", force: :cascade do |t|
|
16
16
|
t.string "provider", default: "email", null: false
|
@@ -105,6 +105,7 @@ ActiveRecord::Schema.define(version: 2020_06_23_003142) do
|
|
105
105
|
t.datetime "created_at", null: false
|
106
106
|
t.datetime "updated_at", null: false
|
107
107
|
t.boolean "auth_available", default: true, null: false
|
108
|
+
t.boolean "vip", default: false, null: false
|
108
109
|
t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
|
109
110
|
t.index ["email"], name: "index_users_on_email", unique: true
|
110
111
|
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
|
@@ -5,6 +5,14 @@ require 'rails_helper'
|
|
5
5
|
RSpec.describe "Integrations with the user's controller" do
|
6
6
|
include_context 'with graphql query request'
|
7
7
|
|
8
|
+
shared_examples 'returns a must authenticate error' do |field|
|
9
|
+
it 'returns a must sign in error' do
|
10
|
+
expect(json_response[:errors]).to contain_exactly(
|
11
|
+
hash_including(message: "#{field} field requires authentication", extensions: { code: 'AUTHENTICATION_ERROR' })
|
12
|
+
)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
8
16
|
let(:user) { create(:user, :confirmed) }
|
9
17
|
|
10
18
|
describe 'publicField' do
|
@@ -54,11 +62,7 @@ RSpec.describe "Integrations with the user's controller" do
|
|
54
62
|
end
|
55
63
|
|
56
64
|
context 'when user is not authenticated' do
|
57
|
-
|
58
|
-
expect(json_response[:errors]).to contain_exactly(
|
59
|
-
hash_including(message: 'privateField field requires authentication', extensions: { code: 'AUTHENTICATION_ERROR' })
|
60
|
-
)
|
61
|
-
end
|
65
|
+
it_behaves_like 'returns a must authenticate error', 'privateField'
|
62
66
|
end
|
63
67
|
end
|
64
68
|
|
@@ -82,11 +86,7 @@ RSpec.describe "Integrations with the user's controller" do
|
|
82
86
|
end
|
83
87
|
|
84
88
|
context 'when user is not authenticated' do
|
85
|
-
|
86
|
-
expect(json_response[:errors]).to contain_exactly(
|
87
|
-
hash_including(message: 'privateField field requires authentication', extensions: { code: 'AUTHENTICATION_ERROR' })
|
88
|
-
)
|
89
|
-
end
|
89
|
+
it_behaves_like 'returns a must authenticate error', 'privateField'
|
90
90
|
end
|
91
91
|
|
92
92
|
context 'when using the failing route' do
|
@@ -111,11 +111,7 @@ RSpec.describe "Integrations with the user's controller" do
|
|
111
111
|
end
|
112
112
|
|
113
113
|
context 'when user is not authenticated' do
|
114
|
-
|
115
|
-
expect(json_response[:errors]).to contain_exactly(
|
116
|
-
hash_including(message: 'privateField field requires authentication', extensions: { code: 'AUTHENTICATION_ERROR' })
|
117
|
-
)
|
118
|
-
end
|
114
|
+
it_behaves_like 'returns a must authenticate error', 'privateField'
|
119
115
|
end
|
120
116
|
end
|
121
117
|
end
|
@@ -141,11 +137,7 @@ RSpec.describe "Integrations with the user's controller" do
|
|
141
137
|
end
|
142
138
|
|
143
139
|
context 'when user is not authenticated' do
|
144
|
-
|
145
|
-
expect(json_response[:errors]).to contain_exactly(
|
146
|
-
hash_including(message: 'dummyMutation field requires authentication', extensions: { code: 'AUTHENTICATION_ERROR' })
|
147
|
-
)
|
148
|
-
end
|
140
|
+
it_behaves_like 'returns a must authenticate error', 'dummyMutation'
|
149
141
|
end
|
150
142
|
end
|
151
143
|
|
@@ -161,11 +153,7 @@ RSpec.describe "Integrations with the user's controller" do
|
|
161
153
|
end
|
162
154
|
|
163
155
|
context 'when user is not authenticated' do
|
164
|
-
|
165
|
-
expect(json_response[:errors]).to contain_exactly(
|
166
|
-
hash_including(message: 'dummyMutation field requires authentication', extensions: { code: 'AUTHENTICATION_ERROR' })
|
167
|
-
)
|
168
|
-
end
|
156
|
+
it_behaves_like 'returns a must authenticate error', 'dummyMutation'
|
169
157
|
end
|
170
158
|
end
|
171
159
|
end
|
@@ -199,11 +187,7 @@ RSpec.describe "Integrations with the user's controller" do
|
|
199
187
|
end
|
200
188
|
|
201
189
|
context 'when user is not authenticated' do
|
202
|
-
|
203
|
-
expect(json_response[:errors]).to contain_exactly(
|
204
|
-
hash_including(message: 'user field requires authentication', extensions: { code: 'AUTHENTICATION_ERROR' })
|
205
|
-
)
|
206
|
-
end
|
190
|
+
it_behaves_like 'returns a must authenticate error', 'user'
|
207
191
|
end
|
208
192
|
end
|
209
193
|
|
@@ -271,4 +255,61 @@ RSpec.describe "Integrations with the user's controller" do
|
|
271
255
|
)
|
272
256
|
end
|
273
257
|
end
|
258
|
+
|
259
|
+
describe 'vipField' do
|
260
|
+
let(:error_message) { 'Field available only for VIP Users' }
|
261
|
+
let(:query) do
|
262
|
+
<<-GRAPHQL
|
263
|
+
query { vipField }
|
264
|
+
GRAPHQL
|
265
|
+
end
|
266
|
+
|
267
|
+
context 'when using a regular schema' do
|
268
|
+
before { post_request('/api/v1/graphql') }
|
269
|
+
|
270
|
+
context 'when user is authenticated' do
|
271
|
+
let(:headers) { user.create_new_auth_token }
|
272
|
+
|
273
|
+
context 'when schema user is VIP' do
|
274
|
+
let(:user) { create(:user, :confirmed, vip: true) }
|
275
|
+
|
276
|
+
it 'allows to perform the query' do
|
277
|
+
expect(json_response[:data][:vipField]).to eq(error_message)
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
context 'when schema user is not VIP' do
|
282
|
+
it_behaves_like 'returns a must authenticate error', 'vipField'
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
context 'when user is not authenticated' do
|
287
|
+
it_behaves_like 'returns a must authenticate error', 'vipField'
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
context 'when using the interpreter schema' do
|
292
|
+
before { post_request('/api/v1/interpreter') }
|
293
|
+
|
294
|
+
context 'when user is authenticated' do
|
295
|
+
let(:headers) { user.create_new_auth_token }
|
296
|
+
|
297
|
+
context 'when schema user is VIP' do
|
298
|
+
let(:user) { create(:user, :confirmed, vip: true) }
|
299
|
+
|
300
|
+
it 'allows to perform the query' do
|
301
|
+
expect(json_response[:data][:vipField]).to eq(error_message)
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
context 'when schema user is not VIP' do
|
306
|
+
it_behaves_like 'returns a must authenticate error', 'vipField'
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
context 'when user is not authenticated' do
|
311
|
+
it_behaves_like 'returns a must authenticate error', 'vipField'
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
274
315
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql_devise
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.16.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mario Celi
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2021-05-
|
12
|
+
date: 2021-05-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: devise_token_auth
|
@@ -425,6 +425,7 @@ files:
|
|
425
425
|
- spec/dummy/db/migrate/20200321121807_create_users_customers.rb
|
426
426
|
- spec/dummy/db/migrate/20200621182414_remove_uncofirmed_email_from_admins.rb
|
427
427
|
- spec/dummy/db/migrate/20200623003142_create_schema_users.rb
|
428
|
+
- spec/dummy/db/migrate/20210516211417_add_vip_to_users.rb
|
428
429
|
- spec/dummy/db/schema.rb
|
429
430
|
- spec/dummy/db/seeds.rb
|
430
431
|
- spec/dummy/public/robots.txt
|
@@ -502,7 +503,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
502
503
|
- !ruby/object:Gem::Version
|
503
504
|
version: '0'
|
504
505
|
requirements: []
|
505
|
-
rubygems_version: 3.
|
506
|
+
rubygems_version: 3.0.3
|
506
507
|
signing_key:
|
507
508
|
specification_version: 4
|
508
509
|
summary: GraphQL queries and mutations on top of devise_token_auth
|
@@ -574,6 +575,7 @@ test_files:
|
|
574
575
|
- spec/dummy/db/migrate/20200321121807_create_users_customers.rb
|
575
576
|
- spec/dummy/db/migrate/20200621182414_remove_uncofirmed_email_from_admins.rb
|
576
577
|
- spec/dummy/db/migrate/20200623003142_create_schema_users.rb
|
578
|
+
- spec/dummy/db/migrate/20210516211417_add_vip_to_users.rb
|
577
579
|
- spec/dummy/db/schema.rb
|
578
580
|
- spec/dummy/db/seeds.rb
|
579
581
|
- spec/dummy/public/robots.txt
|