diff --git a/lib/galaxy/managers/history_contents.py b/lib/galaxy/managers/history_contents.py index 70fb896de19..2b51ea99647 100644 --- a/lib/galaxy/managers/history_contents.py +++ b/lib/galaxy/managers/history_contents.py @@ -267,7 +267,14 @@ class HistoryContentsManager(containers.ContainerManagerMixin): return False return True - def _union_of_contents_query(self, container, filters=None, limit=None, offset=None, order_by=None, **kwargs): + def _union_of_contents_query(self, + container, + filters=None, + limit=None, + offset=None, + order_by=None, + user_id=None, + **kwargs): """ Returns a query for a limited and offset list of both types of contents, filtered and in some order. @@ -285,8 +292,10 @@ class HistoryContentsManager(containers.ContainerManagerMixin): # note: I'm trying to keep these private functions as generic as possible in order to move them toward base later # query 1: create a union of common columns for which the component_classes can be filtered/limited - contained_query = self._contents_common_query_for_contained(container.id if container else None) - subcontainer_query = self._contents_common_query_for_subcontainer(container.id if container else None) + contained_query = self._contents_common_query_for_contained(history_id=container.id if container else None, + user_id=user_id) + subcontainer_query = self._contents_common_query_for_subcontainer(history_id=container.id if container else None, + user_id=user_id) filters = filters or [] # Apply filters that are specific to a model @@ -322,7 +331,7 @@ class HistoryContentsManager(containers.ContainerManagerMixin): columns.append(column) return columns - def _contents_common_query_for_contained(self, history_id=None): + def _contents_common_query_for_contained(self, history_id, user_id): component_class = self.contained_class # TODO: and now a join with Dataset - this is getting sad columns = self._contents_common_columns(component_class, @@ -336,9 +345,15 @@ class HistoryContentsManager(containers.ContainerManagerMixin): subquery = subquery.join(model.Dataset, model.Dataset.id == component_class.dataset_id) if history_id: subquery = subquery.filter(component_class.history_id == history_id) + else: + # Make sure we only return items that are user-accessible by checking that they are in a history + # owned by the current user. + # TODO: move into filter mixin, and implement accessible logic as SQL query + subquery = subquery.filter(component_class.history_id == model.History.table.c.id, + model.History.table.c.user_id == user_id) return subquery - def _contents_common_query_for_subcontainer(self, history_id): + def _contents_common_query_for_subcontainer(self, history_id, user_id): component_class = self.subcontainer_class columns = self._contents_common_columns(component_class, history_content_type=literal('dataset_collection'), @@ -358,6 +373,9 @@ class HistoryContentsManager(containers.ContainerManagerMixin): model.DatasetCollection.id == component_class.collection_id) if history_id: subquery = subquery.filter(component_class.history_id == history_id) + else: + subquery = subquery.filter(component_class.history_id == model.History.table.c.id, + model.History.table.c.user_id == user_id) return subquery def _get_union_type(self, union): diff --git a/lib/galaxy/webapps/galaxy/api/datasets.py b/lib/galaxy/webapps/galaxy/api/datasets.py index 28a70e76928..99eb617d768 100644 --- a/lib/galaxy/webapps/galaxy/api/datasets.py +++ b/lib/galaxy/webapps/galaxy/api/datasets.py @@ -115,7 +115,7 @@ class DatasetsController(BaseAPIController, UsesVisualizationMixin): if history_id: container = self.history_manager.get_accessible(self.decode_id(history_id), trans.user) contents = self.history_contents_manager.contents( - container=container, filters=filters, limit=limit, offset=offset, order_by=order_by + container=container, filters=filters, limit=limit, offset=offset, order_by=order_by, user_id=trans.user.id, ) return [self.serializer_by_type[content.history_content_type].serialize_to_view(content, user=trans.user, trans=trans, view='summary') for content in contents] diff --git a/test/api/test_datasets.py b/test/api/test_datasets.py index 58f3fcd3103..013fcf2d10b 100644 --- a/test/api/test_datasets.py +++ b/test/api/test_datasets.py @@ -88,6 +88,14 @@ class DatasetsApiTestCase(api.ApiTestCase): self._assert_status_code_is(index_response, 400) assert index_response.json()['err_msg'] == 'bad op in filter' + def test_search_returns_only_accessible(self): + hda_id = self.dataset_populator.new_dataset(self.history_id)['id'] + with self._different_user(): + payload = {'limit': 10, 'offset': 0, 'q': ['history_content_type'], 'qv': ['dataset']} + index_response = self._get("datasets", payload).json() + for item in index_response: + assert hda_id != item['id'] + def test_show(self): hda1 = self.dataset_populator.new_dataset(self.history_id) show_response = self._get("datasets/%s" % (hda1["id"]))