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 +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +38 -2
- data/lib/action_policy/graphql.rb +12 -0
- data/lib/action_policy/graphql/authorized_field.rb +50 -15
- data/lib/action_policy/graphql/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: af986a07ebe7dbdfa82c22e7c5977562fe950297e9d7a1a73f3b3350df2985e7
|
4
|
+
data.tar.gz: 1c9f5b334f632827e9221b327fe622d91be5f92c871f6fb4807a397a73984735
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7d98d44c4c349789b58d463dc1b447e9181f6fadcdd5a3e09b7c47835b4b9a154b000e5c39ac96cce98a8e09e91e1560a4bb8a6d3263753a59362bd352102692
|
7
|
+
data.tar.gz: 6aad6769bbea6aae1137b158a6c54d6f12742a443227f43de6ad28471ce2add320349a671c196dada9d304238f2bdaa8ab201437b526e8cb6a51d9ccc31fbf4c
|
data/CHANGELOG.md
CHANGED
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://
|
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.
|
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
|
-
|
75
|
+
if authorize && preauthorize
|
76
|
+
raise ArgumentError, "Only one of `authorize` and `preauthorize` " \
|
77
|
+
"options could be specified."
|
78
|
+
end
|
50
79
|
|
51
|
-
|
52
|
-
options = {} if options == true
|
80
|
+
extensions = (kwargs[:extensions] ||= [])
|
53
81
|
|
54
|
-
|
82
|
+
add_extension! extensions, AuthorizeExtension, authorize
|
83
|
+
add_extension! extensions, ScopeExtension, authorized_scope
|
84
|
+
add_extension! extensions, PreauthorizeExtension, preauthorize
|
55
85
|
|
56
|
-
|
86
|
+
super(*args, **kwargs, &block)
|
87
|
+
end
|
57
88
|
|
58
|
-
|
89
|
+
private
|
59
90
|
|
60
|
-
|
61
|
-
|
62
|
-
else
|
63
|
-
extensions << extension
|
64
|
-
end
|
65
|
-
end
|
91
|
+
def add_extension!(extensions, extension_class, options)
|
92
|
+
return unless options
|
66
93
|
|
67
|
-
|
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
|
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.
|
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-
|
11
|
+
date: 2019-10-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: action_policy
|