Skip to content

Commit 62c8a1b

Browse files
committed
Move authorization logic and tracing into authorized_new; test that it can be overridden
1 parent 1f386e2 commit 62c8a1b

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
@@ -372,7 +372,7 @@ def continue_field(path, value, owner_type, field, current_type, ast_node, next_
372372
end
373373
when "OBJECT"
374374
object_proxy = begin
375-
authorized_new(current_type, value, context, path)
375+
authorized_new(current_type, value, context)
376376
rescue GraphQL::ExecutionError => err
377377
err
378378
end
@@ -635,22 +635,8 @@ def resolve_type(type, value, path)
635635
end
636636
end
637637

638-
def authorized_new(type, value, context, path)
639-
trace_payload = { context: context, type: type, object: value, path: path }
640-
641-
auth_val = context.query.trace("authorized", trace_payload) do
642-
type.authorized_new(value, context)
643-
end
644-
645-
if context.schema.lazy?(auth_val)
646-
GraphQL::Execution::Lazy.new do
647-
context.query.trace("authorized_lazy", trace_payload) do
648-
context.schema.sync_lazy(auth_val)
649-
end
650-
end
651-
else
652-
auth_val
653-
end
638+
def authorized_new(type, value, context)
639+
type.authorized_new(value, context)
654640
end
655641
end
656642
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
@@ -950,4 +950,54 @@ def int
950950
refute res.key?("errors")
951951
end
952952
end
953+
954+
describe "overriding authorized_new" do
955+
class AuthorizedNewOverrideSchema < GraphQL::Schema
956+
class LogTracer
957+
def trace(key, data)
958+
if (c = data[:context]) || ((q = data[:query]) && (c = q.context))
959+
c[:log] << key
960+
end
961+
yield
962+
end
963+
end
964+
965+
module CustomIntrospection
966+
class DynamicFields < GraphQL::Introspection::DynamicFields
967+
def self.authorized_new(obj, ctx)
968+
new(obj, ctx)
969+
end
970+
end
971+
end
972+
973+
class Query < GraphQL::Schema::Object
974+
def self.authorized_new(obj, ctx)
975+
new(obj, ctx)
976+
end
977+
field :int, Integer, null: false
978+
def int; 1; end
979+
end
980+
981+
query(Query)
982+
introspection(CustomIntrospection)
983+
tracer(LogTracer.new)
984+
end
985+
986+
it "avoids calls to Object.authorized?" do
987+
log = []
988+
res = AuthorizedNewOverrideSchema.execute("{ __typename int }", context: { log: log })
989+
assert_equal "Query", res["data"]["__typename"]
990+
assert_equal 1, res["data"]["int"]
991+
expected_log = [
992+
"validate",
993+
"analyze_query",
994+
"execute_query",
995+
"execute_field",
996+
"execute_field",
997+
"execute_query_lazy"
998+
]
999+
1000+
assert_equal expected_log, log
1001+
end
1002+
end
9531003
end

0 commit comments

Comments
 (0)