Skip to content

API proposal for authorizing relationships #30

@valscion

Description

@valscion

UPDATE on 2016-10-29:

The approach I want to take on authorizing relationships relies on always using a whitelist instead of blacklist. This means that:

  • There won't be a generic allow_relationship? method that would handle all relationships.
  • Using update? after trying to set a foreign key won't work, as it is a blacklist approach.

So even at the cost of some policies becoming huge, I want to keep each method as small and unambiguous as possible. That means methods named like this:

class CommentPolicy
  def allow_relationship_article?(article)
    # ...
  end
end

I haven't yet made up my mind on which side of the association the authorization should happen, but I'd like that choice to be abstracted away from the AuthorizingProcessor. It could live inside DefaultPunditAuthorizer, if it would make sense, or we could come up with a new place for that logic to live in.

See my comment about this for more details, and to continue the discussion.

Open this to read the old proposal that kicked off the conversation

For a create request that looks like this:

{
  "data": {
    "id": "post-1",
    "type": "posts",
    "relationships": {
      "author": {
        "data": {
          "id": "user-1", "type": "user"
        }
      },
      "comments": {
        "data": [
          { "id": "comment-1", "type": "comments" },
          { "id": "comment-2", "type": "comments" }
        ]
      },
      "tags": {
        "data": [
          { "id": "tag-1", "type": "tags" },
          { "id": "tag-2", "type": "tags" }
        ]
      }
    }
  }
}

We authorize with these methods:

  1. PostPolicy.new(post_1, current_user).create?
  2. PostPolicy.new(post_1, current_user).associate_with_author(user_1)?
  3. PostPolicy.new(post_1, current_user).associate_with_comments([comment_1, comment_2])?
  4. PostPolicy.new(post_1, current_user).associate_with_tags([tag_1, tag_2])?

For this request, no matter if it's an update or a create call, we are able to only use PostPolicy to authorize for every association.

I can't see there being any other way as we ​_cannot_​ change the UserPolicy#associate_with_comments call to these without a huge scope creep:

  1. CommentPolicy.new(comment_1, user).associate_with_post(post_1)?
  2. CommentPolicy.new(comment_2, user).associate_with_post(post_1)?

Who knows, the Comment resource might even call that association with a completely different name than post underneath!

If that request would be an update request, it would only change the PostPolicy#create? call to be PostPolicy#update? and the association checks would remain the same.

I know this goes against Pundit architecture, but I can't really see there being any other way because we aren't able to call post_1.author = author_1 nor post_1.comments = [comment_1, comment_2] before authorizing as it would implicitly save the association immediately. So we aren't able to just use the post_1.author value in PostPolicy#update? to check for authorization, as it isn't set yet.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions