action_policy-graphql 0.2.0 → 0.3.0

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