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

Fixed bug w/ not checking permissions in copy #174

Merged
merged 10 commits into from
Dec 21, 2023
2 changes: 1 addition & 1 deletion biblib/tests/unit_tests/test_webservices.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Copy link
Contributor

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?

Copy link
Contributor

@femalves femalves Dec 14, 2023

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.

response = self.client.post(
url,
data=json.dumps(post_data),
Expand Down
26 changes: 24 additions & 2 deletions biblib/views/base_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ class BaseView(Resource):
#default permissions for write_access()
write_allowed = ['write', 'admin', 'owner']

# default permissions for read_access()
read_allowed = ['read', 'write', 'admin', 'owner']

@staticmethod
def helper_uuid_to_slug(library_uuid):
"""
Expand Down Expand Up @@ -222,8 +225,27 @@ def delete_access(cls, service_uid, library_id):
delete_allowed = cls.helper_access_allowed(service_uid=service_uid,
library_id=library_id,
access_type='owner')
return delete_allowed

return delete_allowed

@classmethod
def read_access(cls, service_uid, library_id):
"""
Defines which type of user has read permissions to a library.

:param service_uid: the user ID within this microservice
:param library_id: the unique ID of the library

:return: boolean, access (True), no access (False)
"""

for access_type in cls.read_allowed:
if cls.helper_access_allowed(service_uid=service_uid,
library_id=library_id,
access_type=access_type):
return True

return False

@classmethod
def write_access(cls, service_uid, library_id):
"""
Expand Down
44 changes: 28 additions & 16 deletions biblib/views/operations_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ def post(self, library):
- admin
- write
"""

# Get the user requesting this from the header
try:
user_editing = self.helper_get_user_id()
Expand Down Expand Up @@ -203,22 +203,8 @@ def post(self, library):
current_app.logger.error('Wrong type passed for POST: {0} [{1}]'
.format(request.data, error))
return err(WRONG_TYPE_ERROR)

if data['action'] in ['union', 'intersection', 'difference']:
if 'libraries' not in data:
return err(NO_LIBRARY_SPECIFIED_ERROR)
if 'name' not in data:
data['name'] = 'Untitled {0}.'.format(get_date().isoformat())
if 'public' not in data:
data['public'] = False

if data['action'] == 'copy':
if 'libraries' not in data:
return err(NO_LIBRARY_SPECIFIED_ERROR)
if len(data['libraries']) > 1:
return err(TOO_MANY_LIBRARIES_SPECIFIED_ERROR)

lib_names = []
check_access = []
with current_app.session_scope() as session:
primary = session.query(Library).filter_by(id=library_uuid).one()
lib_names.append(primary.name)
Expand All @@ -230,6 +216,32 @@ def post(self, library):
return err(BAD_LIBRARY_ID_ERROR)
secondary = session.query(Library).filter_by(id=secondary_uuid).one()
lib_names.append(secondary.name)
check_access.append(secondary)

if data['action'] in ['union', 'intersection', 'difference']:
if 'libraries' not in data:
return err(NO_LIBRARY_SPECIFIED_ERROR)
for lib in check_access:
lib = session.merge(lib)
Copy link
Member Author

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?

Copy link
Contributor

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.

if lib.public or not self.read_access(service_uid=user_editing_uid,
Copy link
Member Author

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...

library_id=lib.id):
return err(NO_PERMISSION_ERROR)
if 'name' not in data:
data['name'] = 'Untitled {0}.'.format(get_date().isoformat())
if 'public' not in data:
data['public'] = False

if data['action'] == 'copy':
if 'libraries' not in data:
return err(NO_LIBRARY_SPECIFIED_ERROR)
if len(data['libraries']) > 1:
return err(TOO_MANY_LIBRARIES_SPECIFIED_ERROR)
# Check the permissions of the user
if not self.write_access(service_uid=user_editing_uid,
library_id=check_access[0].id):
return err(NO_PERMISSION_ERROR)



if data['action'] == 'union':
bib_union = self.setops_libraries(
Expand Down
Loading