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

Skip authorization for included resources #141

Closed
ahmadabdelhalim opened this issue Feb 25, 2021 · 5 comments
Closed

Skip authorization for included resources #141

ahmadabdelhalim opened this issue Feb 25, 2021 · 5 comments

Comments

@ahmadabdelhalim
Copy link

Hey!

I'm trying to skip authorization for the included resources, but still, I want each resource to be authorized separately. Does that make sense? and is that even possible?

@valscion
Copy link
Member

Sorry, I don't really understand what you mean by "still want each resource to be authorized separately". Can you give some examples of what you'd like to authorize in some scenarios?

@ahmadabdelhalim
Copy link
Author

ahmadabdelhalim commented Feb 26, 2021

@valscion for example when I do the following "/trips?include=driver" I don't want the driver resource to be authorized. However; if I did "/drivers" I want it to be authorized. So basically I want to skip authorization for relationships when I include them

@valscion
Copy link
Member

valscion commented Mar 1, 2021

Not that I really understand why you'd want to do it, it's still possible 😄.

You can implement a custom authorizer class that subclasses from the JSONAPI::Authorization::DefaultPunditAuthorizer and then override the include_has_many_resource or include_has_one_resource depending on which one you'd need to act differently:

# Any request including <tt>?include=other-resources</tt>
#
# This will be called for each has_many relationship if the include goes
# deeper than one level until some authorization fails or the include
# directive has been travelled completely.
#
# We can't pass all the records of a +has_many+ association here due to
# performance reasons, so the class is passed instead.
#
# ==== Parameters
#
# * +source_record+ — The source relationship record, e.g. an Article in
# article.comments check
# * +record_class+ - The underlying record class for the relationships
# resource.
# rubocop:disable Lint/UnusedMethodArgument
def include_has_many_resource(source_record:, record_class:)
::Pundit.authorize(user, record_class, 'index?')
end
# rubocop:enable Lint/UnusedMethodArgument
# Any request including <tt>?include=another-resource</tt>
#
# This will be called for each has_one relationship if the include goes
# deeper than one level until some authorization fails or the include
# directive has been travelled completely.
#
# ==== Parameters
#
# * +source_record+ — The source relationship record, e.g. an Article in
# article.author check
# * +related_record+ - The associated record to return
# rubocop:disable Lint/UnusedMethodArgument
def include_has_one_resource(source_record:, related_record:)
::Pundit.authorize(user, related_record, 'show?')
end
# rubocop:enable Lint/UnusedMethodArgument

Then configure JSONAPI::Authorization to use your custom authorizer class as documented in the readme: https://github.com/venuu/jsonapi-authorization#configuration

That will not stop the AuthorizingProcessor from running authorization codepath, so models will still be loaded for authorization purposes. You might want to consider the #83 issue if that's a concern for you. If it is, you can use your own processor in favor of the built-in one to skip this code:

def authorize_include_directive
return if result.is_a?(::JSONAPI::ErrorsOperationResult)
resources = Array.wrap(
if result.respond_to?(:resources)
result.resources
elsif result.respond_to?(:resource)
result.resource
end
)
resources.each do |resource|
authorize_model_includes(resource._model)
end
end

Note that these approaches will require careful review if we at some point get to do a new release of jsonapi-authorization to maintain compatibility.

@ahmadabdelhalim
Copy link
Author

@valscion I want some fields from the relationships just for displaying information on a certain page, but I want to restrict the resource itself. Thank you so much, will try it out.

@valscion
Copy link
Member

valscion commented Mar 1, 2021

👍 I'll close this issue now as the discussion seems settled to me.

@valscion valscion closed this as completed Mar 1, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

2 participants