Skip to content

Commit

Permalink
Merge pull request #3446 from rmosolgo/authorized-work-around
Browse files Browse the repository at this point in the history
Make it so you can opt out of object authorization
  • Loading branch information
Robert Mosolgo authored Apr 30, 2021
2 parents 289d17b + 62c8a1b commit 5ab3e5e
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 24 deletions.
24 changes: 5 additions & 19 deletions lib/graphql/execution/interpreter/runtime.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def run_eager
root_type = schema.root_type_for_operation(root_op_type)
path = []
set_all_interpreter_context(query.root_value, nil, nil, path)
object_proxy = authorized_new(root_type, query.root_value, context, path)
object_proxy = authorized_new(root_type, query.root_value, context)
object_proxy = schema.sync_lazy(object_proxy)
if object_proxy.nil?
# Root .authorized? returned false.
Expand Down Expand Up @@ -193,7 +193,7 @@ def evaluate_selection(path, result_name, field_ast_nodes_or_ast_node, scoped_co
object = owner_object

if is_introspection
object = authorized_new(field_defn.owner, object, context, next_path)
object = authorized_new(field_defn.owner, object, context)
end

total_args_count = field_defn.arguments.size
Expand Down Expand Up @@ -378,7 +378,7 @@ def continue_field(path, value, owner_type, field, current_type, ast_node, next_
end
when "OBJECT"
object_proxy = begin
authorized_new(current_type, value, context, path)
authorized_new(current_type, value, context)
rescue GraphQL::ExecutionError => err
err
end
Expand Down Expand Up @@ -641,22 +641,8 @@ def resolve_type(type, value, path)
end
end

def authorized_new(type, value, context, path)
trace_payload = { context: context, type: type, object: value, path: path }

auth_val = context.query.trace("authorized", trace_payload) do
type.authorized_new(value, context)
end

if context.schema.lazy?(auth_val)
GraphQL::Execution::Lazy.new do
context.query.trace("authorized_lazy", trace_payload) do
context.schema.sync_lazy(auth_val)
end
end
else
auth_val
end
def authorized_new(type, value, context)
type.authorized_new(value, context)
end
end
end
Expand Down
24 changes: 19 additions & 5 deletions lib/graphql/schema/object.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,26 @@ class << self
# @return [GraphQL::Schema::Object, GraphQL::Execution::Lazy]
# @raise [GraphQL::UnauthorizedError] if the user-provided hook returns `false`
def authorized_new(object, context)
auth_val = context.query.with_error_handling do
begin
authorized?(object, context)
rescue GraphQL::UnauthorizedError => err
context.schema.unauthorized_object(err)
trace_payload = { context: context, type: self, object: object, path: context[:current_path] }

maybe_lazy_auth_val = context.query.trace("authorized", trace_payload) do
context.query.with_error_handling do
begin
authorized?(object, context)
rescue GraphQL::UnauthorizedError => err
context.schema.unauthorized_object(err)
end
end
end

auth_val = if context.schema.lazy?(maybe_lazy_auth_val)
GraphQL::Execution::Lazy.new do
context.query.trace("authorized_lazy", trace_payload) do
context.schema.sync_lazy(maybe_lazy_auth_val)
end
end
else
maybe_lazy_auth_val
end

context.schema.after_lazy(auth_val) do |is_authorized|
Expand Down
50 changes: 50 additions & 0 deletions spec/graphql/authorization_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -966,4 +966,54 @@ def int
refute res.key?("errors")
end
end

describe "overriding authorized_new" do
class AuthorizedNewOverrideSchema < GraphQL::Schema
class LogTracer
def trace(key, data)
if (c = data[:context]) || ((q = data[:query]) && (c = q.context))
c[:log] << key
end
yield
end
end

module CustomIntrospection
class DynamicFields < GraphQL::Introspection::DynamicFields
def self.authorized_new(obj, ctx)
new(obj, ctx)
end
end
end

class Query < GraphQL::Schema::Object
def self.authorized_new(obj, ctx)
new(obj, ctx)
end
field :int, Integer, null: false
def int; 1; end
end

query(Query)
introspection(CustomIntrospection)
tracer(LogTracer.new)
end

it "avoids calls to Object.authorized?" do
log = []
res = AuthorizedNewOverrideSchema.execute("{ __typename int }", context: { log: log })
assert_equal "Query", res["data"]["__typename"]
assert_equal 1, res["data"]["int"]
expected_log = [
"validate",
"analyze_query",
"execute_query",
"execute_field",
"execute_field",
"execute_query_lazy"
]

assert_equal expected_log, log
end
end
end

0 comments on commit 5ab3e5e

Please sign in to comment.