graphql-guard 0.2.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5870b2ab41869305af964ae8412f7b7628328272
4
- data.tar.gz: 35db74d61a58b98c041a6f31a3fe05f1fd2183e2
3
+ metadata.gz: 33482164f7f2f2a17ba43bc1219975ee6de6ea19
4
+ data.tar.gz: fade6ad6159072a1f3609cbc4e43b5fba2ce100b
5
5
  SHA512:
6
- metadata.gz: 984a157c13ca13f6d49b6b2c770f51d8898b573ac58b8bf9c927b7c63b38e0a9cc6a1e731a621546a1fa875aef9b0c3489323aa8f7605b503ed91bfc02fcf279
7
- data.tar.gz: 15f06cd5cfe6d2e5fad01258010c10b4a9203fa4427344e5007107decc9583b3b4d215073acf9c1e887cdca405c55f5d3507612359b3caa81152a5820c7a34fe
6
+ metadata.gz: e198c43bd8b1a4e9ce8de01db82605f1d937efbbd8f6f509e89ae1363e253ec43a70251584fa6f7ef7a44d7b89a4029322be4b93ad9e43b4d8e04a6f3a26bea1
7
+ data.tar.gz: f465007bb574373cb6d220aea2b6361d828055a69bf57e91ed5e12a6f6fb31d64043b7636e15763eaac922926618ab1e01c280456dd91b022094df6d9e300bb7
data/CHANGELOG.md CHANGED
@@ -12,7 +12,11 @@ that you can set version constraints properly.
12
12
 
13
13
  * WIP
14
14
 
15
- #### [v0.2.0](https://github.com/exAspArk/graphql-guard/compare/v0.1.0...v0.2.0)
15
+ #### [v0.3.0](https://github.com/exAspArk/graphql-guard/compare/v0.2.0...v0.3.0) – 2017-07-19
16
+
17
+ * `Added`: ability to use custom error handlers.
18
+
19
+ #### [v0.2.0](https://github.com/exAspArk/graphql-guard/compare/v0.1.0...v0.2.0) – 2017-07-19
16
20
 
17
21
  * `Added`: support for object policies.
18
22
 
data/README.md CHANGED
@@ -4,19 +4,35 @@
4
4
 
5
5
  This tiny gem provides a field-level authorization for [graphql-ruby](https://github.com/rmosolgo/graphql-ruby).
6
6
 
7
+ ## Contents
8
+
9
+ * [Usage](#usage)
10
+ * [Inline policies](#inline-policies)
11
+ * [Policy object](#policy-object)
12
+ * [Priority order](#priority-order)
13
+ * [Error handling](#error-handling)
14
+ * [Integration](#integration)
15
+ * [CanCanCan](#cancancan)
16
+ * [Pundit](#pundit)
17
+ * [Installation](#installation)
18
+ * [Development](#development)
19
+ * [Contributing](#contributing)
20
+ * [License](#license)
21
+ * [Code of Conduct](#code-of-conduct)
22
+
7
23
  ## Usage
8
24
 
9
25
  Define a GraphQL schema:
10
26
 
11
27
  ```ruby
12
- # define type
28
+ # define a type
13
29
  PostType = GraphQL::ObjectType.define do
14
30
  name "Post"
15
31
  field :id, !types.ID
16
32
  field :title, !types.String
17
33
  end
18
34
 
19
- # define query
35
+ # define a query
20
36
  QueryType = GraphQL::ObjectType.define do
21
37
  name "Query"
22
38
  field :posts, !types[PostType] do
@@ -25,17 +41,13 @@ QueryType = GraphQL::ObjectType.define do
25
41
  end
26
42
  end
27
43
 
28
- # define schema
44
+ # define a schema
29
45
  Schema = GraphQL::Schema.define do
30
46
  query QueryType
31
47
  end
32
48
 
33
49
  # execute query
34
- GraphSchema.execute(
35
- query,
36
- variables: { user_id: 1 },
37
- context: { current_user: current_user }
38
- )
50
+ GraphSchema.execute(query, variables: { user_id: 1 }, context: { current_user: current_user })
39
51
  ```
40
52
 
41
53
  ### Inline policies
@@ -85,7 +97,7 @@ class GraphqlPolicy
85
97
  posts: ->(_obj, args, ctx) { args[:user_id] == ctx[:current_user].id }
86
98
  },
87
99
  PostType => {
88
- '*': ->(post, ctx) { ctx[:current_user].admin? }
100
+ '*': ->(_post, ctx) { ctx[:current_user].admin? }
89
101
  }
90
102
  }
91
103
 
@@ -95,7 +107,7 @@ class GraphqlPolicy
95
107
  end
96
108
  ```
97
109
 
98
- Use pass this object to `GraphQL::Guard`:
110
+ Pass this object to `GraphQL::Guard`:
99
111
 
100
112
  ```ruby
101
113
  Schema = GraphQL::Schema.define do
@@ -104,7 +116,7 @@ Schema = GraphQL::Schema.define do
104
116
  end
105
117
  ```
106
118
 
107
- ## Order of priority
119
+ ## Priority order
108
120
 
109
121
  `GraphQL::Guard` will use the policy in the following order of priority:
110
122
 
@@ -139,6 +151,96 @@ Schema = GraphQL::Schema.define do
139
151
  end
140
152
  ```
141
153
 
154
+ ## Error handling
155
+
156
+ By default `GraphQL::Guard` raises a `GraphQL::Guard::NotAuthorizedError` exception if access to field is not authorized.
157
+ You can change this behavior, by passing custom `not_authorized` lambda. For example:
158
+
159
+ ```ruby
160
+ SchemaWithoutExceptions = GraphQL::Schema.define do
161
+ query QueryType
162
+ use GraphQL::Guard.new(
163
+ # by default it raises an error
164
+ # not_authorized: ->(type, field) { raise GraphQL::Guard::NotAuthorizedError.new("#{type}.#{field}") }
165
+
166
+ # returns an error in the response
167
+ not_authorized: ->(type, field) { GraphQL::ExecutionError.new("Not authorized to access #{type}.#{field}") }
168
+ )
169
+ end
170
+ ```
171
+
172
+ In this case executing a query will continue, but return `nil` for not authorized field and also an array of `errors`:
173
+
174
+ ```ruby
175
+ SchemaWithoutExceptions.execute("query { posts(user_id: 1) { id title } }")
176
+ # => {
177
+ # "data" => nil,
178
+ # "errors" => [{ "messages" => "Not authorized to access Query.posts", "locations": { ... }, "path" => ["posts"] }]
179
+ # }
180
+ ```
181
+
182
+ ## Integration
183
+
184
+ You can simply reuse your existing policies if you really want. You don't need any monkey patches or magic for it ;)
185
+
186
+ ### CanCanCan
187
+
188
+ ```ruby
189
+ # define an ability
190
+ class Ability
191
+ include CanCan::Ability
192
+
193
+ def initialize(user)
194
+ user ||= User.new # guest user if not logged in
195
+ if user.admin?
196
+ can :manage, :all
197
+ else
198
+ can :read, Post, author_id: user.id
199
+ end
200
+ end
201
+ end
202
+
203
+ # use the ability in your guard policy object
204
+ class GraphqlPolicy
205
+ RULES = {
206
+ PostType => {
207
+ '*': ->(post, ctx) { ctx[:current_ability].can?(:read, post) },
208
+ }
209
+ }
210
+
211
+ def self.guard(type, field)
212
+ RULES.dig(type, field)
213
+ end
214
+ end
215
+
216
+ # pass the ability
217
+ GraphSchema.execute(query, context: { current_ability: Ability.new(current_user) })
218
+ ```
219
+
220
+ ### Pundit
221
+
222
+ ```ruby
223
+ # define a policy
224
+ class PostPolicy < ApplicationPolicy
225
+ def show?
226
+ user.admin? || record.author_id == user.id
227
+ end
228
+ end
229
+
230
+ # use the policy in your guard policy object
231
+ class GraphqlPolicy
232
+ RULES = {
233
+ PostType => {
234
+ '*': ->(post, ctx) { PostPolicy.new(ctx[:current_user], post).show? },
235
+ }
236
+ }
237
+
238
+ def self.guard(type, field)
239
+ RULES.dig(type, field)
240
+ end
241
+ end
242
+ ```
243
+
142
244
  ## Installation
143
245
 
144
246
  Add this line to your application's Gemfile:
data/lib/graphql/guard.rb CHANGED
@@ -9,13 +9,15 @@ GraphQL::Field.accepts_definitions(guard: GraphQL::Define.assign_metadata_key(:g
9
9
  module GraphQL
10
10
  class Guard
11
11
  ANY_FIELD_NAME = :'*'
12
+ DEFAULT_NOT_AUTHORIZED = ->(type, field) { raise NotAuthorizedError.new("#{type}.#{field}") }
12
13
 
13
14
  NotAuthorizedError = Class.new(StandardError)
14
15
 
15
- attr_reader :policy_object
16
+ attr_reader :policy_object, :not_authorized
16
17
 
17
- def initialize(policy_object: nil)
18
+ def initialize(policy_object: nil, not_authorized: DEFAULT_NOT_AUTHORIZED)
18
19
  @policy_object = policy_object
20
+ @not_authorized = not_authorized
19
21
  end
20
22
 
21
23
  def use(schema_definition)
@@ -35,9 +37,12 @@ module GraphQL
35
37
  elsif type_guard_proc
36
38
  type_guard_proc.call(object, context)
37
39
  end
38
- raise NotAuthorizedError.new("#{type}.#{field.name}") unless authorized
39
40
 
40
- old_resolve_proc.call(object, arguments, context)
41
+ if authorized
42
+ old_resolve_proc.call(object, arguments, context)
43
+ else
44
+ not_authorized.call(type, field.name.to_sym)
45
+ end
41
46
  end
42
47
 
43
48
  field.redefine { resolve(new_resolve_proc) }
@@ -2,6 +2,6 @@
2
2
 
3
3
  module GraphQL
4
4
  class Guard
5
- VERSION = "0.2.0"
5
+ VERSION = "0.3.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql-guard
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - exAspArk