-
Notifications
You must be signed in to change notification settings - Fork 8
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
Fixed bug w/ not checking permissions in copy #174
Conversation
biblib/views/operations_view.py
Outdated
@@ -207,6 +207,10 @@ def post(self, library): | |||
if data['action'] in ['union', 'intersection', 'difference']: | |||
if 'libraries' not in data: | |||
return err(NO_LIBRARY_SPECIFIED_ERROR) | |||
for lib in data['libraries']: | |||
if not self.read_access(service_uid=user_editing_uid, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be a check on if the user has read access, or if the library is public
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just added the access check when library is public. A slug is passed for each library, so we have to convert it to UUID and then get the library to check if it's public. I noticed there was code right below that sort of did that, so I moved some things around.
biblib/views/operations_view.py
Outdated
return err(NO_LIBRARY_SPECIFIED_ERROR) | ||
for lib in check_access: | ||
lib = session.merge(lib) | ||
if lib.public or not self.read_access(service_uid=user_editing_uid, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whoops my comment wasn't very clear - this should be if not lib.public or not self.read_access...
biblib/views/operations_view.py
Outdated
if 'libraries' not in data: | ||
return err(NO_LIBRARY_SPECIFIED_ERROR) | ||
for lib in check_access: | ||
lib = session.merge(lib) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't used merge
before - lib
is the same as secondary
, as returned by the query in line 217. Do you need to do the merge into the session, even though this should already be a sqlalchemy object?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Totally get it! The reason I used merge was because the libraries were getting detached from the session. I'm sure there's some other way around it, but I couldn't think of any off the top of my head. If you're okay with holding off on this until tomorrow, I can try to come up with something else.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall I think we are nearly there. One quick question on a test and a modification of the logic for checking if we have permissions for the secondary libraries.
@@ -718,7 +718,7 @@ def test_operations_view_post_types(self): | |||
self.assertEqual(response.json['error'], NO_LIBRARY_SPECIFIED_ERROR['body']) | |||
|
|||
post_data['action'] = 'copy' | |||
post_data['libraries'] = ['lib1', 'lib2'] | |||
post_data['libraries'] = [library_id_2, library_id_2] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it matters for the test, but did you mean for these to both be the same library?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it wasn't relevant so I added lib2. But I changed it now to lib1, just because that's more consistent with how it was before.
biblib/views/operations_view.py
Outdated
library_id=library_uuid): | ||
has_read_access_primary = True | ||
|
||
for lib in data.get('libraries', []): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this might miss a corner case where if someone specifies a mix of libraries with various access types. This isn't an issue for the copy
method because we limit the number of secondary libraries to 1, but for other methods, they could potentially acquire access to a secondary library they are not supposed to have (ie. a user could compute the union with three libraries where they only have access to two of them and gain access to the documents stored in the third library.) I have to double-check all the methods but a simple first past fix might be to raise an exception immediately if a user has no permissions on a private secondary library.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for catching that. I had changed the logic a little bit and forgot to account for the implications here. Good one. I'll fix it right away.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this PR is basically there. The logic is all sound, I just had one comment on the handling of the primary library in the permissions check.
biblib/views/operations_view.py
Outdated
) | ||
|
||
if action in ["union", "intersection", "difference"]: | ||
if not has_read_access_primary or not ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! The only comment I have, and I might be misunderstanding this, is that we can also perform union
, intersection
, and difference
actions with a public primary library. In that case, you might be able to move the logical check for the primary out of the loop and immediately exit if the primary permissions aren't set and then have checks only on the secondary in the loop. Would potentially save some postgres
queries.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the union
, intersection
, and difference
we need a public secondary
library, so I think it makes sense as it is right now. Feel free to correct me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you are entirely correct on that point. I'm wondering if has_read_access_primary
should be (primary_is_public or has_read_access_primary)
as it is in the check for copy
. If that is the case we may be able to keep the checks in the loop to only looking at the secondary because the requirements for the primary are the same.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's the thing. For copy
we need (primary_is_public or has_read_access_primary)
but for union, intersection, difference
we need has_read_access_primary
.
At least that is my understanding.
Here's my notes:
copy
:
- primary: has_read_access or is_public
- secondary: has_write_access
union, intersection, difference
:
- primary: has_read_access
- secondary: has_read_access or is_public
Does that make sense to you?
I talked to Kelly and checked a couple of times, but we might have missed something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! I think this is ready.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. Looks ready to me.
|
||
if data['action'] == 'union': | ||
|
||
if action == "empty": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really like this change to use permission_check_<>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. It was pretty readable in the end.
Bug fix: users were erroneously able to copy their own library into a library they did not have permissions to edit