Skip to content

Commit a94b045

Browse files
committed
Fix when a root type returns nil because unauthorized
1 parent df0e6b3 commit a94b045

File tree

4 files changed

+51
-9
lines changed

4 files changed

+51
-9
lines changed

lib/graphql/execution/execute.rb

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,16 @@ def resolve_root_selection(query)
5050
operation = query.selected_operation
5151
op_type = operation.operation_type
5252
root_type = query.root_type_for_operation(op_type)
53-
resolve_selection(
54-
query.root_value,
55-
root_type,
56-
query.context,
57-
mutation: query.mutation?
58-
)
53+
if query.context[:__root_unauthorized]
54+
# This was set by member/instrumentation.rb so that we wouldn't continue.
55+
else
56+
resolve_selection(
57+
query.root_value,
58+
root_type,
59+
query.context,
60+
mutation: query.mutation?
61+
)
62+
end
5963
end
6064
end
6165

lib/graphql/execution/interpreter/runtime.rb

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,15 @@ def run_eager
4949
root_type = legacy_root_type.metadata[:type_class] || raise("Invariant: type must be class-based: #{legacy_root_type}")
5050
object_proxy = root_type.authorized_new(query.root_value, context)
5151
object_proxy = schema.sync_lazy(object_proxy)
52-
path = []
53-
evaluate_selections(path, object_proxy, root_type, root_operation.selections, root_operation_type: root_op_type)
54-
nil
52+
if object_proxy.nil?
53+
# Root .authorized? returned false.
54+
write_in_response([], nil)
55+
nil
56+
else
57+
path = []
58+
evaluate_selections(path, object_proxy, root_type, root_operation.selections, root_operation_type: root_op_type)
59+
nil
60+
end
5561
end
5662

5763
def gather_selections(owner_object, owner_type, selections, selections_by_name)

lib/graphql/schema/member/instrumentation.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ def before_query(query)
2828
wrapper_class = root_type.metadata[:type_class]
2929
if wrapper_class
3030
new_root_value = wrapper_class.authorized_new(query.root_value, query.context)
31+
new_root_value = query.schema.sync_lazy(new_root_value)
32+
if new_root_value.nil?
33+
# This is definitely a hack,
34+
# but we need some way to tell execute.rb not to run.
35+
query.context[:__root_unauthorized] = true
36+
end
3137
query.root_value = new_root_value
3238
end
3339
end

spec/graphql/authorization_spec.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -912,4 +912,30 @@ def auth_execute(*args)
912912
assert_equal [{"message"=>"Unauthorized Query: nil"}], unauth_res["errors"]
913913
end
914914
end
915+
916+
describe "returning false" do
917+
class FalseSchema < GraphQL::Schema
918+
class Query < GraphQL::Schema::Object
919+
def self.authorized?(obj, ctx)
920+
false
921+
end
922+
923+
field :int, Integer, null: false
924+
925+
def int
926+
1
927+
end
928+
end
929+
query(Query)
930+
if TESTING_INTERPRETER
931+
use GraphQL::Execution::Interpreter
932+
end
933+
end
934+
935+
it "works out-of-the-box" do
936+
res = FalseSchema.execute("{ int }")
937+
assert_nil res.fetch("data")
938+
refute res.key?("errors")
939+
end
940+
end
915941
end

0 commit comments

Comments
 (0)