action_policy-graphql 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
  SHA256:
3
- metadata.gz: da60e0290bedb6652f75804bf0b54eb995c1a85708d35ec486b46022604c13d2
4
- data.tar.gz: c996102f26404ba808fd0a6b5d927f3509c45ba799acc5c1147e20f7e62bb76d
3
+ metadata.gz: af986a07ebe7dbdfa82c22e7c5977562fe950297e9d7a1a73f3b3350df2985e7
4
+ data.tar.gz: 1c9f5b334f632827e9221b327fe622d91be5f92c871f6fb4807a397a73984735
5
5
  SHA512:
6
- metadata.gz: c344fff8978dc691b1c820e01790234ef472779592bc70b20b5ef9fa0dbac9cc3075893ad299270396b4be69ed7a7c3c54dc502dde39e3c6fedd11049f2007d7
7
- data.tar.gz: 667b4957e8400858eaff8544508cc04482ad90ada14d5f2839910a1ecc29ca6987f3906cf1a111222d81f0d06cc0475884115ddbbac564a554c17200f5bf60cf
6
+ metadata.gz: 7d98d44c4c349789b58d463dc1b447e9181f6fadcdd5a3e09b7c47835b4b9a154b000e5c39ac96cce98a8e09e91e1560a4bb8a6d3263753a59362bd352102692
7
+ data.tar.gz: 6aad6769bbea6aae1137b158a6c54d6f12742a443227f43de6ad28471ce2add320349a671c196dada9d304238f2bdaa8ab201437b526e8cb6a51d9ccc31fbf4c
@@ -2,6 +2,10 @@
2
2
 
3
3
  ## master (unreleased)
4
4
 
5
+ ## 0.3.0 (2019-10-21)
6
+
7
+ - Add `preauthorize: *` option to perform authorization prior to resolving fields. ([@palkan][])
8
+
5
9
  ## 0.2.0 (2019-08-15)
6
10
 
7
11
  - Add ability to specify a field name explicitly. ([@palkan][])
data/README.md CHANGED
@@ -9,7 +9,7 @@ This gem provides an integration for using [Action Policy](https://github.com/pa
9
9
  This integration includes the following features:
10
10
  - Fields & mutations authorization
11
11
  - List and connections scoping
12
- - [**Exposing permissions/authorization rules in the API**](https://dev.to/evilmartians/exposing-permissions-in-graphql-apis-with-action-policy-1mfh).
12
+ - [**Exposing permissions/authorization rules in the API**](https://evilmartians.com/chronicles/exposing-permissions-in-graphql-apis-with-action-policy).
13
13
 
14
14
  📑 [Documentation](https://actionpolicy.evilmartians.io/#/graphql)
15
15
 
@@ -21,7 +21,7 @@ This integration includes the following features:
21
21
  Add this line to your application's Gemfile:
22
22
 
23
23
  ```ruby
24
- gem "action_policy-graphql", "~> 0.1"
24
+ gem "action_policy-graphql", "~> 0.3"
25
25
  ```
26
26
 
27
27
  And then execute:
@@ -96,6 +96,42 @@ class CityType < ::Common::Graphql::Type
96
96
  end
97
97
  ```
98
98
 
99
+ **NOTE:** you cannot use `authorize: *` and `authorized_scope: *` at the same time but you can combine `preauthorize: *` with `authorized_scope: *`.
100
+
101
+ ### `preauthorize: *`
102
+
103
+ If you want to perform authorization before resolving the field value, you can use `preauthorize: *` option:
104
+
105
+ ```ruby
106
+ field :homes, [Home], null: false, preauthorize: {with: HomePolicy}
107
+
108
+ def homes
109
+ Home.all
110
+ end
111
+ ```
112
+
113
+ The code above is equal to:
114
+
115
+ ```ruby
116
+ field :homes, [Home], null: false
117
+
118
+ def homes
119
+ authorize! "homes", to: :index?, with: HomePolicy
120
+ Home.all
121
+ end
122
+ ```
123
+
124
+ **NOTE:** we pass the field's name as the `record` to the policy rule. We assume that preauthorization rules do not depend on
125
+ the record itself and pass the field's name for debugging purposes only.
126
+
127
+ You can customize the authorization options, e.g. `authorize: {to: :preview?, with: CustomPolicy}`.
128
+
129
+ **NOTE:** unlike `authorize: *` you MUST specify the `with: SomePolicy` option.
130
+ The default authorization rule depends on the type of the field:
131
+
132
+ - for lists we use `index?` (configured by `ActionPolicy::GraphQL.default_preauthorize_list_rule` parameter)
133
+ - for _singleton_ fields we use `show?` (configured by `ActionPolicy::GraphQL.default_preauthorize_node_rule` parameter)
134
+
99
135
  ### `expose_authorization_rules`
100
136
 
101
137
  You can add permissions/authorization exposing fields to "tell" clients which actions could be performed against the object or not (and why).
@@ -12,6 +12,16 @@ module ActionPolicy
12
12
  # Defaults to `:show?`
13
13
  attr_accessor :default_authorize_rule
14
14
 
15
+ # Which rule to use when no specified for preauthorization (e.g. `preauthorize: true`)
16
+ # of a list-like field.
17
+ # Defaults to `:index?`
18
+ attr_accessor :default_preauthorize_list_rule
19
+
20
+ # Which rule to use when no specified for preauthorization (e.g. `preauthorize: true`)
21
+ # of a singleton-like field.
22
+ # Defaults to `:show?`
23
+ attr_accessor :default_preauthorize_node_rule
24
+
15
25
  # Whether to raise an exeption if field is not authorized
16
26
  # or return `nil`.
17
27
  # Defaults to `true`.
@@ -23,6 +33,8 @@ module ActionPolicy
23
33
  end
24
34
 
25
35
  self.default_authorize_rule = :show?
36
+ self.default_preauthorize_list_rule = :index?
37
+ self.default_preauthorize_node_rule = :show?
26
38
  self.authorize_raise_exception = true
27
39
  self.default_authorization_field_prefix = "can_"
28
40
  end
@@ -32,6 +32,32 @@ module ActionPolicy
32
32
  end
33
33
  end
34
34
 
35
+ class PreauthorizeExtension < ::GraphQL::Schema::FieldExtension
36
+ def initialize(*)
37
+ super
38
+ if options[:with].nil?
39
+ raise ArgumentError, "You must specify the policy for preauthorization: " \
40
+ "`field :#{field.name}, preauthorize: {with: SomePolicy}`"
41
+ end
42
+ options[:to] ||=
43
+ if field.type.list?
44
+ ::ActionPolicy::GraphQL.default_preauthorize_list_rule
45
+ else
46
+ ::ActionPolicy::GraphQL.default_preauthorize_node_rule
47
+ end
48
+ options[:raise] = ::ActionPolicy::GraphQL.authorize_raise_exception unless options.key?(:raise)
49
+ end
50
+
51
+ def resolve(context:, object:, arguments:, **_rest)
52
+ if options[:raise]
53
+ object.authorize! field.name, **options
54
+ yield object, arguments
55
+ elsif object.allowed_to?(options[:to], field.name, options)
56
+ yield object, arguments
57
+ end
58
+ end
59
+ end
60
+
35
61
  class ScopeExtension < ::GraphQL::Schema::FieldExtension
36
62
  def after_resolve(value:, context:, object:, **_rest)
37
63
  return value if value.nil?
@@ -40,31 +66,40 @@ module ActionPolicy
40
66
  end
41
67
  end
42
68
 
43
- def initialize(*args, authorize: nil, authorized_scope: nil, **kwargs, &block)
69
+ def initialize(*args, preauthorize: nil, authorize: nil, authorized_scope: nil, **kwargs, &block)
44
70
  if authorize && authorized_scope
45
71
  raise ArgumentError, "Only one of `authorize` and `authorized_scope` " \
46
- "options could be specified"
72
+ "options could be specified. You can use `preauthorize` along with scoping"
47
73
  end
48
74
 
49
- options = authorize || authorized_scope
75
+ if authorize && preauthorize
76
+ raise ArgumentError, "Only one of `authorize` and `preauthorize` " \
77
+ "options could be specified."
78
+ end
50
79
 
51
- if options
52
- options = {} if options == true
80
+ extensions = (kwargs[:extensions] ||= [])
53
81
 
54
- extension_class = authorized_scope ? ScopeExtension : AuthorizeExtension
82
+ add_extension! extensions, AuthorizeExtension, authorize
83
+ add_extension! extensions, ScopeExtension, authorized_scope
84
+ add_extension! extensions, PreauthorizeExtension, preauthorize
55
85
 
56
- extension = {extension_class => options}
86
+ super(*args, **kwargs, &block)
87
+ end
57
88
 
58
- extensions = (kwargs[:extensions] ||= [])
89
+ private
59
90
 
60
- if extensions.is_a?(Hash)
61
- extensions.merge!(extension)
62
- else
63
- extensions << extension
64
- end
65
- end
91
+ def add_extension!(extensions, extension_class, options)
92
+ return unless options
66
93
 
67
- super(*args, **kwargs, &block)
94
+ options = {} if options == true
95
+
96
+ extension = {extension_class => options}
97
+
98
+ if extensions.is_a?(Hash)
99
+ extensions.merge!(extension)
100
+ else
101
+ extensions << extension
102
+ end
68
103
  end
69
104
  end
70
105
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ActionPolicy
4
4
  module GraphQL
5
- VERSION = "0.2.0"
5
+ VERSION = "0.3.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: action_policy-graphql
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
  - Vladimir Dementyev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-08-15 00:00:00.000000000 Z
11
+ date: 2019-10-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: action_policy