Check for authorization against related records#119
Conversation
|
Sorry about Travis CI failing ...again... we've fixed the errors caused by bundler upgrade several times now but it seems they keep on failing. |
|
I fixed the CI in #120 and merged |
|
CI seems to be happy. And so am I This seems like it's ready to go, right? How would we describe this change, similarly to how we've done change docs in the past? https://github.com/venuu/jsonapi-authorization/releases |
|
@all-contributors please add @brianswko for bug, test and code Let me know if you'd rather not be listed in the README. I'll wait for your confirmaton before merging the README.md update by the bot. |
|
I've put up a pull request to add @brianswko! 🎉 |
| context 'which is out of scope' do | ||
| let(:policy_scope) { Article.none } | ||
|
|
||
| it { is_expected.to be_forbidden } |
There was a problem hiding this comment.
@valscion I just realized while testing that instead of being forbidden this should probably be a not found response. I'm going to rework the processor a bit.
|
Proposed description: Fixes PATCH and POST requests to check if the user has the correct permissions for every given object in a has-many relationship For example: Previously: Would return a 20x and update the book to include author 2 In some scenarios, this will cause a 404 to be returned where a 403 used to be returned. |
|
@valscion I've simplified the change in the processor, but ended up having to make a decent amount of changes to the specs. Hoping those all make sense to you. I'm conflicted as to whether this should be a major or minor version change, as there will almost certainly be a not-insignificant number of projects that will start seeing specs fail as bugs in specs are exposed and formerly incorrect 403s start returning 404s. Will leave that decision in your hands. |
| end | ||
| allow_any_instance_of(UserPolicy::Scope).to receive(:resolve) do |policy_scope| | ||
| user_policy_scope.merge(policy_scope.scope.all) | ||
| end |
There was a problem hiding this comment.
I'm having a bit of a hard time figuring out what these policy scope changes do. It seems like it's overriding the policy scope stubbing to always return all results?
Maybe there could be some sort of a documentation comment here to tell why this is necessary.
There was a problem hiding this comment.
I wanted to get rid of these entirely, but that required a much larger overhaul of the tests than I wanted to take on.
As previously written, this spec never checked which has_many records were returned except in situations where the spec stubbed the comments_policy_scope to be Comment.limit(1), and it masked a fundamental problem with the mock when I added additional scenarios to test.
The value of
policy_scope! is supposed to be the records that the user has access to, further restricted by the specific record_or_records in the association. A simple and_return like what was here before would return all records in the user's scope, even if it had nothing to do with the @model under test. For example, a user who has access to all articles and looked up the articles written by a single user would get a list of all articles instead of just the articles written by that user.
merge acts like a sql AND, so this change allows the stubbed scope to return something more similar to how it should actually behave outside of tests.
Will add a comment for this.
There was a problem hiding this comment.
Perfect, thanks for clarifying!
| expect(json_included.length).to eq(1) | ||
| expect(json_included.first["id"]).to eq(comments_policy_scope.first.id.to_s) | ||
| it 'includes only comments allowed by policy scope and associated with the article' do | ||
| expect(json_included.length).to eq(article.comments.count) |
There was a problem hiding this comment.
Hmm so does this now test that there are more records than were allowed? I.e. do we lose test coverage on the pundit policy scope being applied?
There was a problem hiding this comment.
I moved the specs specifically testing for limited scopes to https://github.com/venuu/jsonapi-authorization/pull/119/files#diff-f3a557fdd906ce389d7b5d190c721b99R220. I had to move them out of this shared spec since the behavior is different for GET (which returns the relationships but limited by the scope) vs POST (which should return a 404).
Nice. This entire change description is great.
Given we only recently upgraded to 2.0.0 to fix an authorization bug, and only less than 1000 downloads as of this date have been done against v2.0.0, we could do this change and just bump to 3.0.0. I'd rather signal a potentially backwards incompatible change with more major versions than to squint my eyes and think this could be a backwards-compatible change. So once this is ready to be merged, let's punt this to 3.0.0. |
|
This looks like it's ready to go for me! What do you think? Is it ready? I'll update the README to clarify what's the intent on version numbering here: #123. I think it's likely to be helpful given how this change will be shipped as v3.0.0 once we merge it. I'll copy the text of #119 (comment) for the release notes. Let me know if there's any changes you'd like there to be. |
|
Yes it's ready to go, and that comment works for the changelog. |
|
Thank you! This has now been released as v3.0.0 🎉 |
* AuthorizingProcessor#related_models_with_context should not use the scope * Remove unused AuthorizingProcessor#related_models * Check all related records in authorize_remove_to_many_relationships * Return 404 instead of 403 for records out of scope * Style fixes * Optimization for Array#size * Comment to clarify changes to mocks * Better array matching in specs
This reverts commit 065a623.
Fixes #118
This PR fixes a bug where related resources are not checked for authorization if they are not in the user's scope.
Also fixes inconsistencies between the behavior of has-one, has-many, and polymorphic relationships to always return a 404 instead of sometimes returning a 403 when the user should not be able to see that a given record exists.