Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Default to re-authorizing scoped items (as documented), fix skipping for connections #4720

Merged
merged 1 commit into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/graphql/schema/member/scoped.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def reauthorize_scoped_objects(new_value = nil)
if @reauthorize_scoped_objects != nil
@reauthorize_scoped_objects
else
find_inherited_value(:reauthorize_scoped_objects, nil)
find_inherited_value(:reauthorize_scoped_objects, true)
end
else
@reauthorize_scoped_objects = new_value
Expand Down
13 changes: 13 additions & 0 deletions lib/graphql/types/relay/connection_behaviors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,19 @@ def scope_items(items, context)
node_type.scope_items(items, context)
end

# The connection will skip auth on its nodes if the node_type is configured for that
def reauthorize_scoped_objects(new_value = nil)
if new_value.nil?
if @reauthorize_scoped_objects != nil
@reauthorize_scoped_objects
else
node_type.reauthorize_scoped_objects
end
else
@reauthorize_scoped_objects = new_value
end
end

# Add the shortcut `nodes` field to this connection and its subclasses
def nodes_field(node_nullable: self.node_nullable, field_options: nil)
define_nodes_field(node_nullable, field_options: field_options)
Expand Down
87 changes: 87 additions & 0 deletions spec/graphql/schema/member/scoped_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ def self.resolve_type(item, ctx)
Item
end
end

reauthorize_scoped_objects(false)
end

class Query < BaseObject
Expand Down Expand Up @@ -294,4 +296,89 @@ def get_item_names_with_context(ctx, field_name: "items")
assert field.resolve(OpenStruct.new(object: { items: [] }), {}, ctx)
end
end


describe "skipping authorization on scoped lists" do
class SkipAuthSchema < GraphQL::Schema
class Book < GraphQL::Schema::Object
def self.authorized?(obj, ctx)
ctx[:auth_log] << [:authorized?, obj[:title]]
true
end

def self.scope_items(list, ctx)
ctx[:auth_log] << [:scope_items, list.map { |b| b[:title]}]
list.dup # Skipping authorized objects requires a new object to be returned
end

field :title, String
end

class SkipAuthorizationBook < Book
reauthorize_scoped_objects(false)
end

class ReauthorizedBook < Book
reauthorize_scoped_objects(true)
end

class Query < GraphQL::Schema::Object
field :book, Book

def book
{ title: "Nonsense Omnibus"}
end

field :books, [Book]

def books
[{ title: "Jayber Crow" }, { title: "Hannah Coulter" }]
end

field :skip_authorization_books, [SkipAuthorizationBook], resolver_method: :books

field :reauthorized_books, [ReauthorizedBook], resolver_method: :books

field :skip_authorization_books_connection, SkipAuthorizationBook.connection_type, resolver_method: :books
end

query(Query)
end

it "runs both authorizations by default" do
log = []
SkipAuthSchema.execute("{ book { title } books { title } }", context: { auth_log: log })
expected_log = [
[:authorized?, "Nonsense Omnibus"],
[:scope_items, ["Jayber Crow", "Hannah Coulter"]],
[:authorized?, "Jayber Crow"],
[:authorized?, "Hannah Coulter"],
]
assert_equal expected_log, log
end

it "skips self.authorized? when configured" do
log = []
SkipAuthSchema.execute("{ skipAuthorizationBooks { title } }", context: { auth_log: log })
assert_equal [[:scope_items, ["Jayber Crow", "Hannah Coulter"]]], log
end

it "can be re-enabled in subclasses" do
log = []
SkipAuthSchema.execute("{ reauthorizedBooks { title } }", context: { auth_log: log })
expected_log = [
[:scope_items, ["Jayber Crow", "Hannah Coulter"]],
[:authorized?, "Jayber Crow"],
[:authorized?, "Hannah Coulter"],
]

assert_equal expected_log, log
end

it "skips auth in connections" do
log = []
SkipAuthSchema.execute("{ skipAuthorizationBooksConnection(first: 10) { nodes { title } } }", context: { auth_log: log })
assert_equal [[:scope_items, ["Jayber Crow", "Hannah Coulter"]]], log
end
end
end