Skip to content

Commit 5ab3e5e

Browse files
author
Robert Mosolgo
authored
Merge pull request rmosolgo#3446 from rmosolgo/authorized-work-around
Make it so you can opt out of object authorization
2 parents 289d17b + 62c8a1b commit 5ab3e5e

File tree

3 files changed

+74
-24
lines changed

3 files changed

+74
-24
lines changed

lib/graphql/execution/interpreter/runtime.rb

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def run_eager
5050
root_type = schema.root_type_for_operation(root_op_type)
5151
path = []
5252
set_all_interpreter_context(query.root_value, nil, nil, path)
53-
object_proxy = authorized_new(root_type, query.root_value, context, path)
53+
object_proxy = authorized_new(root_type, query.root_value, context)
5454
object_proxy = schema.sync_lazy(object_proxy)
5555
if object_proxy.nil?
5656
# Root .authorized? returned false.
@@ -193,7 +193,7 @@ def evaluate_selection(path, result_name, field_ast_nodes_or_ast_node, scoped_co
193193
object = owner_object
194194

195195
if is_introspection
196-
object = authorized_new(field_defn.owner, object, context, next_path)
196+
object = authorized_new(field_defn.owner, object, context)
197197
end
198198

199199
total_args_count = field_defn.arguments.size
@@ -378,7 +378,7 @@ def continue_field(path, value, owner_type, field, current_type, ast_node, next_
378378
end
379379
when "OBJECT"
380380
object_proxy = begin
381-
authorized_new(current_type, value, context, path)
381+
authorized_new(current_type, value, context)
382382
rescue GraphQL::ExecutionError => err
383383
err
384384
end
@@ -641,22 +641,8 @@ def resolve_type(type, value, path)
641641
end
642642
end
643643

644-
def authorized_new(type, value, context, path)
645-
trace_payload = { context: context, type: type, object: value, path: path }
646-
647-
auth_val = context.query.trace("authorized", trace_payload) do
648-
type.authorized_new(value, context)
649-
end
650-
651-
if context.schema.lazy?(auth_val)
652-
GraphQL::Execution::Lazy.new do
653-
context.query.trace("authorized_lazy", trace_payload) do
654-
context.schema.sync_lazy(auth_val)
655-
end
656-
end
657-
else
658-
auth_val
659-
end
644+
def authorized_new(type, value, context)
645+
type.authorized_new(value, context)
660646
end
661647
end
662648
end

lib/graphql/schema/object.rb

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,26 @@ class << self
4848
# @return [GraphQL::Schema::Object, GraphQL::Execution::Lazy]
4949
# @raise [GraphQL::UnauthorizedError] if the user-provided hook returns `false`
5050
def authorized_new(object, context)
51-
auth_val = context.query.with_error_handling do
52-
begin
53-
authorized?(object, context)
54-
rescue GraphQL::UnauthorizedError => err
55-
context.schema.unauthorized_object(err)
51+
trace_payload = { context: context, type: self, object: object, path: context[:current_path] }
52+
53+
maybe_lazy_auth_val = context.query.trace("authorized", trace_payload) do
54+
context.query.with_error_handling do
55+
begin
56+
authorized?(object, context)
57+
rescue GraphQL::UnauthorizedError => err
58+
context.schema.unauthorized_object(err)
59+
end
60+
end
61+
end
62+
63+
auth_val = if context.schema.lazy?(maybe_lazy_auth_val)
64+
GraphQL::Execution::Lazy.new do
65+
context.query.trace("authorized_lazy", trace_payload) do
66+
context.schema.sync_lazy(maybe_lazy_auth_val)
67+
end
5668
end
69+
else
70+
maybe_lazy_auth_val
5771
end
5872

5973
context.schema.after_lazy(auth_val) do |is_authorized|

spec/graphql/authorization_spec.rb

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -966,4 +966,54 @@ def int
966966
refute res.key?("errors")
967967
end
968968
end
969+
970+
describe "overriding authorized_new" do
971+
class AuthorizedNewOverrideSchema < GraphQL::Schema
972+
class LogTracer
973+
def trace(key, data)
974+
if (c = data[:context]) || ((q = data[:query]) && (c = q.context))
975+
c[:log] << key
976+
end
977+
yield
978+
end
979+
end
980+
981+
module CustomIntrospection
982+
class DynamicFields < GraphQL::Introspection::DynamicFields
983+
def self.authorized_new(obj, ctx)
984+
new(obj, ctx)
985+
end
986+
end
987+
end
988+
989+
class Query < GraphQL::Schema::Object
990+
def self.authorized_new(obj, ctx)
991+
new(obj, ctx)
992+
end
993+
field :int, Integer, null: false
994+
def int; 1; end
995+
end
996+
997+
query(Query)
998+
introspection(CustomIntrospection)
999+
tracer(LogTracer.new)
1000+
end
1001+
1002+
it "avoids calls to Object.authorized?" do
1003+
log = []
1004+
res = AuthorizedNewOverrideSchema.execute("{ __typename int }", context: { log: log })
1005+
assert_equal "Query", res["data"]["__typename"]
1006+
assert_equal 1, res["data"]["int"]
1007+
expected_log = [
1008+
"validate",
1009+
"analyze_query",
1010+
"execute_query",
1011+
"execute_field",
1012+
"execute_field",
1013+
"execute_query_lazy"
1014+
]
1015+
1016+
assert_equal expected_log, log
1017+
end
1018+
end
9691019
end

0 commit comments

Comments
 (0)