diff --git a/lib/galaxy/security/__init__.py b/lib/galaxy/security/__init__.py index 1520d74b2b3..e82e5b4eba0 100644 --- a/lib/galaxy/security/__init__.py +++ b/lib/galaxy/security/__init__.py @@ -68,16 +68,20 @@ class RBACAgent: raise "Unimplemented Method" def set_dataset_permission( self, dataset, permission ): raise "Unimplemented Method" - def dataset_is_public( self, dataset ): - raise "Unimplemented Method" - def make_dataset_public( self, dataset ): - raise "Unimplemented Method" def set_all_library_permissions( self, dataset, permissions ): raise "Unimplemented Method" def library_is_public( self, library ): raise "Unimplemented Method" def make_library_public( self, library ): raise "Unimplemented Method" + def folder_is_public( self, library ): + raise "Unimplemented Method" + def make_folder_public( self, folder, count=0 ): + raise "Unimplemented Method" + def dataset_is_public( self, dataset ): + raise "Unimplemented Method" + def make_dataset_public( self, dataset ): + raise "Unimplemented Method" def get_permissions( self, library_dataset ): raise "Unimplemented Method" def get_legitimate_roles( self, trans, item, cntrller ): @@ -343,6 +347,7 @@ class GalaxyRBACAgent( RBACAgent ): self.model.Role.table.c.type == self.model.Role.types.SHARING ) ) def user_set_default_permissions( self, user, permissions={}, history=False, dataset=False, bypass_manage_permission=False, default_access_private = False ): # bypass_manage_permission is used to change permissions of datasets in a userless history when logging in + flush_needed = False if user is None: return None if not permissions: @@ -354,13 +359,16 @@ class GalaxyRBACAgent( RBACAgent ): # Delete all of the current default permissions for the user for dup in user.default_permissions: self.sa_session.delete( dup ) + flush_needed = True # Add the new default permissions for the user for action, roles in permissions.items(): if isinstance( action, Action ): action = action.action for dup in [ self.model.DefaultUserPermissions( user, action, role ) for role in roles ]: self.sa_session.add( dup ) - self.sa_session.flush() + flush_needed = True + if flush_needed: + self.sa_session.flush() if history: for history in user.active_histories: self.history_set_default_permissions( history, permissions=permissions, dataset=dataset, bypass_manage_permission=bypass_manage_permission ) @@ -375,6 +383,7 @@ class GalaxyRBACAgent( RBACAgent ): return permissions def history_set_default_permissions( self, history, permissions={}, dataset=False, bypass_manage_permission=False ): # bypass_manage_permission is used to change permissions of datasets in a user-less history when logging in + flush_needed = False user = history.user if not user: # default permissions on a user-less history are None @@ -384,13 +393,16 @@ class GalaxyRBACAgent( RBACAgent ): # Delete all of the current default permission for the history for dhp in history.default_permissions: self.sa_session.delete( dhp ) + flush_needed = True # Add the new default permissions for the history for action, roles in permissions.items(): if isinstance( action, Action ): action = action.action for dhp in [ self.model.DefaultHistoryPermissions( history, action, role ) for role in roles ]: self.sa_session.add( dhp ) - self.sa_session.flush() + flush_needed = True + if flush_needed: + self.sa_session.flush() if dataset: # Only deal with datasets that are not purged for hda in history.activatable_datasets: @@ -417,21 +429,26 @@ class GalaxyRBACAgent( RBACAgent ): Set new permissions on a dataset, eliminating all current permissions permissions looks like: { Action : [ Role, Role ] } """ + flush_needed = False # Delete all of the current permissions on the dataset for dp in dataset.actions: self.sa_session.delete( dp ) + flush_needed = True # Add the new permissions on the dataset for action, roles in permissions.items(): if isinstance( action, Action ): action = action.action for dp in [ self.model.DatasetPermissions( action, dataset, role ) for role in roles ]: self.sa_session.add( dp ) - self.sa_session.flush() + flush_needed = True + if flush_needed: + self.sa_session.flush() def set_dataset_permission( self, dataset, permission={} ): """ Set a specific permission on a dataset, leaving all other current permissions on the dataset alone permissions looks like: { Action : [ Role, Role ] } """ + flush_needed = False for action, roles in permission.items(): if isinstance( action, Action ): action = action.action @@ -439,21 +456,13 @@ class GalaxyRBACAgent( RBACAgent ): for dp in dataset.actions: if dp.action == action: self.sa_session.delete( dp ) + flush_needed = True # Add the new specific permission on the dataset for dp in [ self.model.DatasetPermissions( action, dataset, role ) for role in roles ]: self.sa_session.add( dp ) - self.sa_session.flush() - def dataset_is_public( self, dataset ): - # A dataset is considered public if there are no "access" actions associated with it. Any - # other actions ( 'manage permissions', 'edit metadata' ) are irrelevant. - return self.permitted_actions.DATASET_ACCESS.action not in [ a.action for a in dataset.actions ] - def make_dataset_public( self, dataset ): - # A dataset is considered public if there are no "access" actions associated with it. Any - # other actions ( 'manage permissions', 'edit metadata' ) are irrelevant. - for dp in dataset.actions: - if dp.action == self.permitted_actions.DATASET_ACCESS.action: - self.sa_session.delete( dp ) - self.sa_session.flush() + flush_needed = True + if flush_needed: + self.sa_session.flush() def get_permissions( self, item ): """ Return a dictionary containing the actions and associated roles on item @@ -503,8 +512,10 @@ class GalaxyRBACAgent( RBACAgent ): self.set_dataset_permission( dataset, { self.permitted_actions.DATASET_ACCESS : [ sharing_role ] } ) def set_all_library_permissions( self, library_item, permissions={} ): # Set new permissions on library_item, eliminating all current permissions + flush_needed = False for role_assoc in library_item.actions: self.sa_session.delete( role_assoc ) + flush_needed = True # Add the new permissions on library_item for item_class, permission_class in self.library_item_assocs: if isinstance( library_item, item_class ): @@ -513,6 +524,7 @@ class GalaxyRBACAgent( RBACAgent ): action = action.action for role_assoc in [ permission_class( action, library_item, role ) for role in roles ]: self.sa_session.add( role_assoc ) + flush_needed = True if isinstance( library_item, self.model.LibraryDatasetDatasetAssociation ) and \ action == self.permitted_actions.LIBRARY_MANAGE.action: # Handle the special case when we are setting the LIBRARY_MANAGE_PERMISSION on a @@ -521,16 +533,58 @@ class GalaxyRBACAgent( RBACAgent ): permissions = {} permissions[ self.permitted_actions.DATASET_MANAGE_PERMISSIONS ] = roles self.set_dataset_permission( library_item.dataset, permissions ) - self.sa_session.flush() - def library_is_public( self, library ): + if flush_needed: + self.sa_session.flush() + def library_is_public( self, library, contents=False ): + if contents: + # Check all contained folders and datasets to find any that are not public + if not self.folder_is_public( library.root_folder ): + return False # A library is considered public if there are no "access" actions associated with it. return self.permitted_actions.LIBRARY_ACCESS.action not in [ a.action for a in library.actions ] - def make_library_public( self, library ): - # A library is considered public if there are no "access" actions associated with it. + def make_library_public( self, library, contents=False ): + flush_needed = False + if contents: + # Make all contained folders (include deleted folders, but not purged folders), public + self.make_folder_public( library.root_folder ) + # A library is considered public if there are no LIBRARY_ACCESS actions associated with it. for lp in library.actions: if lp.action == self.permitted_actions.LIBRARY_ACCESS.action: self.sa_session.delete( lp ) - self.sa_session.flush() + flush_needed = True + if flush_needed: + self.sa_session.flush() + def folder_is_public( self, folder ): + for sub_folder in folder.folders: + if not self.folder_is_public( sub_folder ): + return False + for library_dataset in folder.datasets: + if not self.dataset_is_public( library_dataset.library_dataset_dataset_association.dataset ): + return False + return True + def make_folder_public( self, folder ): + # Make all of the contents (include deleted contents, but not purged contents) of folder public + for sub_folder in folder.folders: + if not sub_folder.purged: + self.make_folder_public( sub_folder ) + for library_dataset in folder.datasets: + dataset = library_dataset.library_dataset_dataset_association.dataset + if not dataset.purged and not self.dataset_is_public( dataset ): + self.make_dataset_public( dataset ) + def dataset_is_public( self, dataset ): + # A dataset is considered public if there are no "access" actions associated with it. Any + # other actions ( 'manage permissions', 'edit metadata' ) are irrelevant. + return self.permitted_actions.DATASET_ACCESS.action not in [ a.action for a in dataset.actions ] + def make_dataset_public( self, dataset ): + # A dataset is considered public if there are no "access" actions associated with it. Any + # other actions ( 'manage permissions', 'edit metadata' ) are irrelevant. + flush_needed = False + for dp in dataset.actions: + if dp.action == self.permitted_actions.DATASET_ACCESS.action: + self.sa_session.delete( dp ) + flush_needed = True + if flush_needed: + self.sa_session.flush() def derive_roles_from_access( self, trans, item_id, cntrller, library=False, **kwd ): # Check the access permission on a dataset. If library is true, item_id refers to a library. If library # is False, item_id refers to a dataset ( item_id must currently be decoded before being sent ). The @@ -700,8 +754,11 @@ class GalaxyRBACAgent( RBACAgent ): def set_entity_user_associations( self, users=[], roles=[], groups=[], delete_existing_assocs=True ): for user in users: if delete_existing_assocs: + flush_needed = False for a in user.non_private_roles + user.groups: self.sa_session.delete( a ) + flush_needed = True + if flush_needed: self.sa_session.flush() self.sa_session.refresh( user ) for role in roles: @@ -713,8 +770,11 @@ class GalaxyRBACAgent( RBACAgent ): def set_entity_group_associations( self, groups=[], users=[], roles=[], delete_existing_assocs=True ): for group in groups: if delete_existing_assocs: + flush_needed = False for a in group.roles + group.users: self.sa_session.delete( a ) + flush_needed = True + if flush_needed: self.sa_session.flush() for role in roles: self.associate_components( group=group, role=role ) @@ -723,8 +783,11 @@ class GalaxyRBACAgent( RBACAgent ): def set_entity_role_associations( self, roles=[], users=[], groups=[], delete_existing_assocs=True ): for role in roles: if delete_existing_assocs: + flush_needed = False for a in role.users + role.groups: self.sa_session.delete( a ) + flush_needed = True + if flush_needed: self.sa_session.flush() for user in users: self.associate_components( user=user, role=role ) @@ -805,15 +868,15 @@ class GalaxyRBACAgent( RBACAgent ): # Add the new permissions on request_type item_class = self.model.RequestType permission_class = self.model.RequestTypePermissions + flush_needed = False for action, roles in permissions.items(): if isinstance( action, Action ): action = action.action for role_assoc in [ permission_class( action, request_type, role ) for role in roles ]: self.sa_session.add( role_assoc ) - self.sa_session.flush() - - - + flush_needed = True + if flush_needed: + self.sa_session.flush() class HostAgent( RBACAgent ): """ diff --git a/lib/galaxy/web/controllers/library_common.py b/lib/galaxy/web/controllers/library_common.py index db8a20baac2..26bb37b65d0 100644 --- a/lib/galaxy/web/controllers/library_common.py +++ b/lib/galaxy/web/controllers/library_common.py @@ -151,25 +151,9 @@ class LibraryCommon( BaseController, UsesFormDefinitionWidgets ): library = trans.sa_session.query( trans.app.model.Library ).get( trans.security.decode_id( library_id ) ) except: library = None - # Deny that the library exists if the user does not have the LIBRARY_ACCESS permission. - if not library or not ( is_admin or trans.app.security_agent.can_access_library( current_user_roles, library ) ): - message = "Invalid library id ( %s ) specified." % str( library_id ) - return trans.response.send_redirect( web.url_for( controller=cntrller, - action='browse_libraries', - use_panels=use_panels, - message=util.sanitize_text( message ), - status='error' ) ) + self._check_access( trans, cntrller, is_admin, library, current_user_roles, use_panels, library_id, show_deleted ) if params.get( 'library_info_button', False ): - # Deny modification if the user is not an admin and does not have the LIBRARY_MODIFY permission. - if not ( is_admin or trans.app.security_agent.can_modify_library_item( current_user_roles, library ) ): - message = "You are not authorized to modify library '%s'." % library.name - return trans.response.send_redirect( web.url_for( controller='library_common', - action='browse_library', - cntrller=cntrller, - id=library_id, - use_panels=use_panels, - message=util.sanitize_text( message ), - status='error' ) ) + self._check_modify( trans, cntrller, is_admin, library, current_user_roles, use_panels, library_id, show_deleted ) old_name = library.name new_name = util.restore_text( params.get( 'name', 'No name' ) ) if not new_name: @@ -227,24 +211,8 @@ class LibraryCommon( BaseController, UsesFormDefinitionWidgets ): library = trans.sa_session.query( trans.app.model.Library ).get( trans.security.decode_id( library_id ) ) except: library = None - # Deny that the library exists if the user does not have the LIBRARY_ACCESS permission. - if not library or not ( is_admin or trans.app.security_agent.can_access_library( current_user_roles, library ) ): - message = "Invalid library id ( %s ) specified." % str( library_id ) - return trans.response.send_redirect( web.url_for( controller=cntrller, - action='browse_libraries', - use_panels=use_panels, - message=util.sanitize_text( message ), - status='error' ) ) - # Deny access (even to view) if the user is not an admin and does not have the LIBRARY_MANAGE permission. - if not ( is_admin or trans.app.security_agent.can_manage_library_item( current_user_roles, library ) ): - message = "You are not authorized to manage permissions on library '%s'." % library.name - return trans.response.send_redirect( web.url_for( controller='library_common', - action='browse_library', - id=library_id, - cntrller=cntrller, - use_panels=use_panels, - message=util.sanitize_text( message ), - status='error' ) ) + self._check_access( trans, cntrller, is_admin, library, current_user_roles, use_panels, library_id, show_deleted ) + self._check_manage( trans, cntrller, is_admin, library, current_user_roles, use_panels, library_id, show_deleted ) if params.get( 'update_roles_button', False ): # The user clicked the Save button on the 'Associate With Roles' form permissions = {} @@ -291,37 +259,8 @@ class LibraryCommon( BaseController, UsesFormDefinitionWidgets ): # library, which could be anything. if parent_folder: parent_library = parent_folder.parent_library - # Deny that the parent folder exists if the user does not have the LIBRARY_ACCESS permission on - # its parent library, or if they are not able to see the folder's contents. - if not parent_folder or ( not is_admin and not trans.app.security_agent.can_access_library_item( current_user_roles, parent_folder, trans.user ) ): - message = "Invalid parent folder id ( %s ) specified." % str( parent_id ) - if cntrller == 'api': - return 400, message - # This doesn't give away the library's existence since - # browse_library will simply punt to browse_libraries if the - # user-supplied id is invalid or inaccessible. - return trans.response.send_redirect( web.url_for( controller='library_common', - action='browse_library', - cntrller=cntrller, - use_panels=use_panels, - id=library_id, - show_deleted=show_deleted, - message=util.sanitize_text( message ), - status='error' ) ) - # Deny access (even to view) if the user is not an admin and does not have the LIBRARY_ADD permission. - if not ( is_admin or trans.app.security_agent.can_add_library_item( current_user_roles, parent_folder ) ): - message = "You are not authorized to create a folder in parent folder '%s'." % parent_folder.name - # Redirect to the real parent library since we know we have access to it. - if cntrller == 'api': - return 403, message - return trans.response.send_redirect( web.url_for( controller='library_common', - action='browse_library', - cntrller=cntrller, - use_panels=use_panels, - id=library_id, - show_deleted=show_deleted, - message=util.sanitize_text( message ), - status='error' ) ) + self._check_access( trans, cntrller, is_admin, parent_folder, current_user_roles, use_panels, library_id, show_deleted ) + self._check_add( trans, cntrller, is_admin, parent_folder, current_user_roles, use_panels, library_id, show_deleted ) if params.get( 'new_folder_button', False ) or cntrller == 'api': new_folder = trans.app.model.LibraryFolder( name=util.restore_text( params.name ), description=util.restore_text( params.description ) ) @@ -391,29 +330,9 @@ class LibraryCommon( BaseController, UsesFormDefinitionWidgets ): folder = trans.sa_session.query( trans.app.model.LibraryFolder ).get( trans.security.decode_id( id ) ) except: folder = None - # Deny that the parent folder exists if the user does not have the LIBRARY_ACCESS permission on - # its parent library, or if they are not able to see the folder's contents. - if not folder or ( not is_admin and not trans.app.security_agent.can_access_library_item( current_user_roles, folder, trans.user ) ): - message = "Invalid folder id ( %s ) specified." % str( id ) - return trans.response.send_redirect( web.url_for( controller='library_common', - action='browse_library', - cntrller=cntrller, - use_panels=use_panels, - id=library_id, - show_deleted=show_deleted, - message=util.sanitize_text( message ), - status='error' ) ) + self._check_access( trans, cntrller, is_admin, folder, current_user_roles, use_panels, library_id, show_deleted ) if params.get( 'rename_folder_button', False ): - # Deny modification if the user is not an admin and does not have the LIBRARY_MODIFY permission - if not ( is_admin or trans.app.security_agent.can_modify_library_item( current_user_roles, folder ) ): - message = "You are not authorized to modify folder '%s'." % folder.name - return trans.response.send_redirect( web.url_for( controller='library_common', - action='browse_library', - cntrller=cntrller, - id=library_id, - use_panels=use_panels, - message=util.sanitize_text( message ), - status='error' ) ) + self._check_modify( trans, cntrller, is_admin, folder, current_user_roles, use_panels, library_id, show_deleted ) old_name = folder.name new_name = util.restore_text( params.name ) new_description = util.restore_text( params.description ) @@ -468,28 +387,8 @@ class LibraryCommon( BaseController, UsesFormDefinitionWidgets ): folder = trans.sa_session.query( trans.app.model.LibraryFolder ).get( trans.security.decode_id( id ) ) except: folder = None - # Deny that the parent folder exists if the user does not have the LIBRARY_ACCESS permission on - # its parent library, or if they are not able to see the folder's contents. - if not folder or ( not is_admin and not trans.app.security_agent.can_access_library_item( current_user_roles, folder, trans.user ) ): - message = "Invalid folder id ( %s ) specified." % str( id ) - return trans.response.send_redirect( web.url_for( controller='library_common', - action='browse_library', - cntrller=cntrller, - use_panels=use_panels, - id=library_id, - show_deleted=show_deleted, - message=util.sanitize_text( message ), - status='error' ) ) - # Deny access (even to view) if the user is not an admin and does not have the LIBRARY_MANAGE permission. - if not ( is_admin or trans.app.security_agent.can_manage_library_item( current_user_roles, folder ) ): - message = "You are not authorized to manage permissions on folder id ( %s )." % str( id ) - return trans.response.send_redirect( web.url_for( controller='library_common', - action='browse_library', - id=library_id, - cntrller=cntrller, - use_panels=use_panels, - message=util.sanitize_text( message ), - status='error' ) ) + self._check_access( trans, cntrller, is_admin, folder, current_user_roles, use_panels, library_id, show_deleted ) + self._check_manage( trans, cntrller, is_admin, folder, current_user_roles, use_panels, library_id, show_deleted ) if params.get( 'update_roles_button', False ): # The user clicked the Save button on the 'Associate With Roles' form permissions = {} @@ -538,28 +437,8 @@ class LibraryCommon( BaseController, UsesFormDefinitionWidgets ): ldda = trans.sa_session.query( trans.app.model.LibraryDatasetDatasetAssociation ).get( trans.security.decode_id( id ) ) except: ldda = None - # Deny that the dataset exists if the user does not have the LIBRARY_ACCESS permission on - # its parent library, or if they are not able to view the dataset itself. - if not ldda or ( not is_admin and not trans.app.security_agent.can_access_library_item( current_user_roles, ldda, trans.user ) ): - message = "Invalid library dataset id ( %s ) specified." % str( id ) - return trans.response.send_redirect( web.url_for( controller='library_common', - action='browse_library', - cntrller=cntrller, - use_panels=use_panels, - id=library_id, - show_deleted=show_deleted, - message=util.sanitize_text( message ), - status='error' ) ) - # Deny access (even to view) if the user is not an admin and does not have the LIBRARY_MODIFY permission. - if not ( is_admin or trans.app.security_agent.can_modify_library_item( current_user_roles, ldda ) ): - message = "You are not authorized to modify library dataset '%s'." % ldda.name - return trans.response.send_redirect( web.url_for( controller='library_common', - action='browse_library', - id=library_id, - cntrller=cntrller, - use_panels=use_panels, - message=util.sanitize_text( message ), - status='error' ) ) + self._check_access( trans, cntrller, is_admin, ldda, current_user_roles, use_panels, library_id, show_deleted ) + self._check_modify( trans, cntrller, is_admin, ldda, current_user_roles, use_panels, library_id, show_deleted ) dbkey = params.get( 'dbkey', '?' ) if isinstance( dbkey, list ): dbkey = dbkey[0] @@ -653,18 +532,7 @@ class LibraryCommon( BaseController, UsesFormDefinitionWidgets ): ldda = trans.sa_session.query( trans.app.model.LibraryDatasetDatasetAssociation ).get( trans.security.decode_id( id ) ) except: ldda = None - # Deny that the dataset exists if the user does not have the LIBRARY_ACCESS permission on - # its parent library, or if they are not able to view the dataset itself. - if not ldda or ( not is_admin and not trans.app.security_agent.can_access_library_item( current_user_roles, ldda, trans.user ) ): - message = "Invalid library dataset id ( %s ) specified." % str( id ) - return trans.response.send_redirect( web.url_for( controller='library_common', - action='browse_library', - cntrller=cntrller, - use_panels=use_panels, - id=library_id, - show_deleted=show_deleted, - message=util.sanitize_text( message ), - status='error' ) ) + self._check_access( trans, cntrller, is_admin, ldda, current_user_roles, use_panels, library_id, show_deleted ) if is_admin: # Get all associated hdas and lddas that use the same disk file. associated_hdas = trans.sa_session.query( trans.model.HistoryDatasetAssociation ) \ @@ -720,31 +588,7 @@ class LibraryCommon( BaseController, UsesFormDefinitionWidgets ): ldda = None if ldda: library = ldda.library_dataset.folder.parent_library - # Deny that the dataset exists if the user does not have the LIBRARY_ACCESS permission on - # its parent library, or if they are not able to view the dataset itself. - if not ldda or ( not is_admin and not trans.app.security_agent.can_access_library_item( current_user_roles, ldda, trans.user ) ): - message = "Invalid library dataset id ( %s ) specified." % str( id ) - return trans.response.send_redirect( web.url_for( controller='library_common', - action='browse_library', - cntrller=cntrller, - use_panels=use_panels, - id=library_id, - show_deleted=show_deleted, - message=util.sanitize_text( message ), - status='error' ) ) - # Deny access (even to view) if the user is not an admin and does not - # have the LIBRARY_MANAGE and DATASET_MANAGE_PERMISSIONS permissions. - if not ( is_admin or \ - ( trans.app.security_agent.can_manage_library_item( current_user_roles, ldda ) and - trans.app.security_agent.can_manage_dataset( current_user_roles, ldda.dataset ) ) ): - message = "You are not authorized to manage permissions on library dataset '%s'." % ldda.name - return trans.response.send_redirect( web.url_for( controller='library_common', - action='browse_library', - id=library_id, - cntrller=cntrller, - use_panels=use_panels, - message=util.sanitize_text( message ), - status='error' ) ) + self._check_access( trans, cntrller, is_admin, ldda, current_user_roles, use_panels, library_id, show_deleted ) lddas.append( ldda ) libraries.append( library ) library = libraries[0] @@ -869,33 +713,8 @@ class LibraryCommon( BaseController, UsesFormDefinitionWidgets ): replace_dataset = trans.sa_session.query( trans.app.model.LibraryDataset ).get( trans.security.decode_id( replace_id ) ) except: replace_dataset = None - # Deny that the dataset exists if the user does not have the LIBRARY_ACCESS permission on - # its parent library, or if they are not able to view the dataset itself. - if not replace_dataset or ( not is_admin and not trans.app.security_agent.can_access_library_item( current_user_roles, replace_dataset, trans.user ) ): - message = "Invalid library dataset id ( %s ) to replace specified." % replace_id - if cntrller == 'api': - return 400, message - return trans.response.send_redirect( web.url_for( controller='library_common', - action='browse_library', - cntrller=cntrller, - use_panels=use_panels, - id=library_id, - show_deleted=show_deleted, - message=util.sanitize_text( message ), - status='error' ) ) - # Deny access if the user is not an admin and does not have the LIBRARY_MODIFY permission. - if not ( is_admin or trans.app.security_agent.can_modify_library_item( current_user_roles, replace_dataset ) ): - message = "You are not authorized to replace library dataset '%s'." % replace_dataset.name - if cntrller == 'api': - return 403, message - return trans.response.send_redirect( web.url_for( controller='library_common', - action='browse_library', - cntrller=cntrller, - use_panels=use_panels, - id=library_id, - show_deleted=show_deleted, - message=util.sanitize_text( message ), - status='error' ) ) + self._check_access( trans, cntrller, is_admin, replace_dataset, current_user_roles, use_panels, library_id, show_deleted ) + self._check_modify( trans, cntrller, is_admin, replace_dataset, current_user_roles, use_panels, library_id, show_deleted ) library = replace_dataset.folder.parent_library folder = replace_dataset.folder # The name is stored - by the time the new ldda is created, replace_dataset.name @@ -910,33 +729,8 @@ class LibraryCommon( BaseController, UsesFormDefinitionWidgets ): folder = trans.sa_session.query( trans.app.model.LibraryFolder ).get( trans.security.decode_id( folder_id ) ) except: folder = None - # Deny that the dataset exists if the user does not have the LIBRARY_ACCESS permission on - # its parent library, or if they are not able to see the folder's contents. - if not folder or ( not is_admin and not trans.app.security_agent.can_access_library_item( current_user_roles, folder, trans.user ) ): - message = "Invalid parent folder id ( %s ) specified." % str( folder_id ) - if cntrller == 'api': - return 400, message - return trans.response.send_redirect( web.url_for( controller='library_common', - action='browse_library', - cntrller=cntrller, - use_panels=use_panels, - id=library_id, - show_deleted=show_deleted, - message=util.sanitize_text( message ), - status='error' ) ) - # Deny access if the user is not an admin and does not have the LIBRARY_ADD permission. - if not ( is_admin or trans.app.security_agent.can_add_library_item( current_user_roles, folder ) ): - message = "You are not authorized to create a library dataset in parent folder '%s'." % folder.name - if cntrller == 'api': - return 403, message - return trans.response.send_redirect( web.url_for( controller='library_common', - action='browse_library', - cntrller=cntrller, - use_panels=use_panels, - id=library_id, - show_deleted=show_deleted, - message=util.sanitize_text( message ), - status='error' ) ) + self._check_access( trans, cntrller, is_admin, folder, current_user_roles, use_panels, library_id, show_deleted ) + self._check_add( trans, cntrller, is_admin, folder, current_user_roles, use_panels, library_id, show_deleted ) library = folder.parent_library if folder and last_used_build in [ 'None', None, '?' ]: last_used_build = folder.genome_build @@ -1356,29 +1150,8 @@ class LibraryCommon( BaseController, UsesFormDefinitionWidgets ): replace_dataset = trans.sa_session.query( trans.app.model.LibraryDataset ).get( trans.security.decode_id( replace_id ) ) except: replace_dataset = None - # Deny that the dataset exists if the user does not have the LIBRARY_ACCESS permission on - # its parent library, or if they are not able to view the dataset itself. - if not replace_dataset or ( not is_admin and not trans.app.security_agent.can_access_library_item( current_user_roles, replace_dataset, trans.user ) ): - message = "Invalid library dataset id ( %s ) to replace specified." % replace_id - return trans.response.send_redirect( web.url_for( controller='library_common', - action='browse_library', - cntrller=cntrller, - use_panels=use_panels, - id=library_id, - show_deleted=show_deleted, - message=util.sanitize_text( message ), - status='error' ) ) - # Deny access if the user is not an admin and does not have the LIBRARY_MODIFY permission. - if not ( is_admin or trans.app.security_agent.can_modify_library_item( current_user_roles, replace_dataset ) ): - message = "You are not authorized to replace library dataset '%s'." % replace_dataset.name - return trans.response.send_redirect( web.url_for( controller='library_common', - action='browse_library', - cntrller=cntrller, - use_panels=use_panels, - id=library_id, - show_deleted=show_deleted, - message=util.sanitize_text( message ), - status='error' ) ) + self._check_access( trans, cntrller, is_admin, replace_dataset, current_user_roles, use_panels, library_id, show_deleted ) + self._check_modify( trans, cntrller, is_admin, replace_dataset, current_user_roles, use_panels, library_id, show_deleted ) library = replace_dataset.folder.parent_library folder = replace_dataset.folder last_used_build = replace_dataset.library_dataset_dataset_association.dbkey @@ -1387,29 +1160,8 @@ class LibraryCommon( BaseController, UsesFormDefinitionWidgets ): folder = trans.sa_session.query( trans.app.model.LibraryFolder ).get( trans.security.decode_id( folder_id ) ) except: folder = None - # Deny that the dataset exists if the user does not have the LIBRARY_ACCESS permission on - # its parent library, or if they are not able to see the folder's contents. - if not folder or ( not is_admin and not trans.app.security_agent.can_access_library_item( current_user_roles, folder, trans.user ) ): - message = "Invalid parent folder id ( %s ) specified." % str( folder_id ) - return trans.response.send_redirect( web.url_for( controller='library_common', - action='browse_library', - cntrller=cntrller, - use_panels=use_panels, - id=library_id, - show_deleted=show_deleted, - message=util.sanitize_text( message ), - status='error' ) ) - # Deny access if the user is not an admin and does not have the LIBRARY_ADD permission. - if not ( is_admin or trans.app.security_agent.can_add_library_item( current_user_roles, folder ) ): - message = "You are not authorized to create a library dataset in parent folder '%s'." % folder.name - return trans.response.send_redirect( web.url_for( controller='library_common', - action='browse_library', - cntrller=cntrller, - use_panels=use_panels, - id=library_id, - show_deleted=show_deleted, - message=util.sanitize_text( message ), - status='error' ) ) + self._check_access( trans, cntrller, is_admin, folder, current_user_roles, use_panels, library_id, show_deleted ) + self._check_add( trans, cntrller, is_admin, folder, current_user_roles, use_panels, library_id, show_deleted ) library = folder.parent_library last_used_build = folder.genome_build # See if the current history is empty @@ -1434,18 +1186,7 @@ class LibraryCommon( BaseController, UsesFormDefinitionWidgets ): hda = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( trans.security.decode_id( hda_id ) ) except: hda = None - # Deny that the dataset exists if the user does not have the DATASET_ACCESS permission. - if not hda or \ - not ( trans.app.security_agent.can_access_dataset( current_user_roles, hda.dataset ) and \ - hda.history.user == trans.user ): - message = "Invalid history dataset id ( %s ) specified." % hda_id - return trans.response.send_redirect( web.url_for( controller='library_common', - action='browse_library', - cntrller=cntrller, - id=library_id, - show_deleted=show_deleted, - message=util.sanitize_text( message ), - status='error' ) ) + self._check_access( trans, cntrller, is_admin, hda, current_user_roles, use_panels, library_id, show_deleted ) ldda = hda.to_library_dataset_dataset_association( target_folder=folder, replace_dataset=replace_dataset ) created_ldda_ids = '%s,%s' % ( created_ldda_ids, str( ldda.id ) ) dataset_names.append( ldda.name ) @@ -1531,18 +1272,7 @@ class LibraryCommon( BaseController, UsesFormDefinitionWidgets ): ldda = trans.sa_session.query( trans.app.model.LibraryDatasetDatasetAssociation ).get( trans.security.decode_id( id ) ) except: ldda = None - # Deny that the dataset exists if the user does not have the LIBRARY_ACCESS permission on - # its parent library, or if they are not able to view the dataset itself. - if not ldda or ( not is_admin and not trans.app.security_agent.can_access_library_item( current_user_roles, ldda, trans.user ) ): - message = "Invalid library dataset id ( %s ) specified." % str( id ) - return trans.response.send_redirect( web.url_for( controller='library_common', - action='browse_library', - cntrller=cntrller, - use_panels=use_panels, - id=library_id, - show_deleted=show_deleted, - message=util.sanitize_text( message ), - status='error' ) ) + self._check_access( trans, cntrller, is_admin, ldda, current_user_roles, use_panels, library_id, show_deleted ) composite_extensions = trans.app.datatypes_registry.get_composite_extensions( ) ext = ldda.extension if ext in composite_extensions: @@ -1584,29 +1314,9 @@ class LibraryCommon( BaseController, UsesFormDefinitionWidgets ): library_dataset = trans.sa_session.query( trans.app.model.LibraryDataset ).get( trans.security.decode_id( id ) ) except: library_dataset = None - # Deny that the dataset exists if the user does not have the LIBRARY_ACCESS permission on - # its parent library, or if they are not able to view the dataset itself. - if not library_dataset or ( not is_admin and not trans.app.security_agent.can_access_library_item( current_user_roles, library_dataset, trans.user ) ): - message = "Invalid library dataset id ( %s ) specified." % str( id ) - return trans.response.send_redirect( web.url_for( controller='library_common', - action='browse_library', - cntrller=cntrller, - use_panels=use_panels, - id=library_id, - show_deleted=show_deleted, - message=util.sanitize_text( message ), - status='error' ) ) + self._check_access( trans, cntrller, is_admin, library_dataset, current_user_roles, use_panels, library_id, show_deleted ) if params.get( 'edit_attributes_button', False ): - # Deny access if the user is not an admin and does not have the LIBRARY_MODIFY permission. - if not ( is_admin or trans.app.security_agent.can_modify_library_item( current_user_roles, library_dataset ) ): - message = "You are not authorized to modify library dataset '%s'." % library_dataset.name - return trans.response.send_redirect( web.url_for( controller='library_common', - action='browse_library', - id=library_id, - cntrller=cntrller, - use_panels=use_panels, - message=util.sanitize_text( message ), - status = 'error' ) ) + self._check_modify( trans, cntrller, is_admin, library_dataset, current_user_roles, use_panels, library_id, show_deleted ) old_name = library_dataset.name new_name = util.restore_text( params.get( 'name', '' ) ) new_info = util.restore_text( params.get( 'info', '' ) ) @@ -1653,31 +1363,8 @@ class LibraryCommon( BaseController, UsesFormDefinitionWidgets ): library_dataset = trans.sa_session.query( trans.app.model.LibraryDataset ).get( trans.security.decode_id( id ) ) except: library_dataset = None - # Deny that the dataset exists if the user does not have the LIBRARY_ACCESS permission on - # its parent library, or if they are not able to view the dataset itself. - if not library_dataset or ( not is_admin and not trans.app.security_agent.can_access_library_item( current_user_roles, library_dataset, trans.user ) ): - message = "Invalid library dataset id ( %s ) specified." % str( id ) - return trans.response.send_redirect( web.url_for( controller='library_common', - action='browse_library', - cntrller=cntrller, - use_panels=use_panels, - id=library_id, - show_deleted=show_deleted, - message=util.sanitize_text( message ), - status='error' ) ) - # Deny access (even to view) if the user is not an admin and does not - # have the LIBRARY_MANAGE and DATASET_MANAGE_PERMISSIONS permissions. - if not ( is_admin or \ - ( trans.app.security_agent.can_manage_library_item( current_user_roles, library_dataset ) and - trans.app.security_agent.can_manage_dataset( current_user_roles, library_dataset.library_dataset_dataset_association.dataset ) ) ): - message = "You are not authorized to manage permissions on library dataset '%s'." % library_dataset.name - return trans.response.send_redirect( web.url_for( controller='library_common', - action='browse_library', - id=library_id, - cntrller=cntrller, - use_panels=use_panels, - message=util.sanitize_text( message ), - status='error' ) ) + self._check_access( trans, cntrller, is_admin, library_dataset, current_user_roles, use_panels, library_id, show_deleted ) + self._check_manage( trans, cntrller, is_admin, library_dataset, current_user_roles, use_panels, library_id, show_deleted ) if params.get( 'update_roles_button', False ): # The user clicked the Save button on the 'Associate With Roles' form permissions = {} @@ -1708,6 +1395,48 @@ class LibraryCommon( BaseController, UsesFormDefinitionWidgets ): message=message, status=status ) @web.expose + def make_library_item_public( self, trans, cntrller, library_id, item_type, id, **kwd ): + params = util.Params( kwd ) + message = util.restore_text( params.get( 'message', '' ) ) + status = params.get( 'status', 'done' ) + show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) ) + use_panels = util.string_as_bool( params.get( 'use_panels', False ) ) + current_user_roles = trans.get_current_user_roles() + is_admin = trans.user_is_admin() and cntrller == 'library_admin' + if item_type == 'library': + library = trans.sa_session.query( trans.model.Library ).get( trans.security.decode_id( id ) ) + self._check_access( trans, cntrller, is_admin, library, current_user_roles, use_panels, library_id, show_deleted ) + self._check_manage( trans, cntrller, is_admin, library, current_user_roles, use_panels, library_id, show_deleted ) + contents = util.string_as_bool( params.get( 'contents', 'False' ) ) + trans.app.security_agent.make_library_public( library, contents=contents ) + if contents: + message = "The data library (%s) and all it's contents have been made publicly accessible." % library.name + else: + message = "The data library (%s) has been made publicly accessible, but access to it's contents has been left unchanged." % library.name + elif item_type == 'folder': + folder = trans.sa_session.query( trans.model.LibraryFolder ).get( trans.security.decode_id( id ) ) + self._check_access( trans, cntrller, is_admin, folder, current_user_roles, use_panels, library_id, show_deleted ) + self._check_manage( trans, cntrller, is_admin, folder, current_user_roles, use_panels, library_id, show_deleted ) + trans.app.security_agent.make_folder_public( folder ) + message = "All of the contents of folder (%s) have been made publicly accessible." % folder.name + elif item_type == 'ldda': + ldda = trans.sa_session.query( trans.model.LibraryDatasetDatasetAssociation ).get( trans.security.decode_id( id ) ) + self._check_access( trans, cntrller, is_admin, ldda.library_dataset, current_user_roles, use_panels, library_id, show_deleted ) + self._check_manage( trans, cntrller, is_admin, ldda.library_dataset, current_user_roles, use_panels, library_id, show_deleted ) + trans.app.security_agent.make_dataset_public( ldda.dataset ) + message = "The libary dataset (%s) has been made publicly accessible." % ldda.name + else: + message = "Invalid item_type (%s) received." % str( item_type ) + status = 'error' + return trans.response.send_redirect( web.url_for( controller='library_common', + action='browse_library', + cntrller=cntrller, + use_panels=use_panels, + id=library_id, + show_deleted=show_deleted, + message=util.sanitize_text( message ), + status=status ) ) + @web.expose def act_on_multiple_datasets( self, trans, cntrller, library_id, ldda_ids='', **kwd ): class NgxZip( object ): def __init__( self, url_base ): @@ -2462,6 +2191,97 @@ class LibraryCommon( BaseController, UsesFormDefinitionWidgets ): show_deleted=show_deleted, message=message, status=status ) ) + def _check_access( self, trans, cntrller, is_admin, item, current_user_roles, use_panels, library_id, show_deleted ): + if isinstance( item, trans.model.HistoryDatasetAssociation ): + # Deny that the dataset exists if the user does not have the DATASET_ACCESS permission. + if not item or \ + not ( trans.app.security_agent.can_access_dataset( current_user_roles, item.dataset ) and item.history.user==trans.user ): + message = "Invalid history dataset id (%s) specified." % str( item.id ) + return trans.response.send_redirect( web.url_for( controller='library_common', + action='browse_library', + cntrller=cntrller, + id=library_id, + show_deleted=show_deleted, + message=util.sanitize_text( message ), + status='error' ) ) + # Deny that the item exists if the user does not have the LIBRARY_ACCESS permission on its parent library, + # or if they are not able to access the item itself. + if not item or ( not is_admin and not trans.app.security_agent.can_access_library_item( current_user_roles, item, trans.user ) ): + message = "Invalid item id (%s) specified." % str( item.id ) + if cntrller == 'api': + return 400, message + if isinstance( item, trans.model.Library ): + return trans.response.send_redirect( web.url_for( controller=cntrller, + action='browse_libraries', + cntrller=cntrller, + use_panels=use_panels, + message=util.sanitize_text( message ), + status='error' ) ) + return trans.response.send_redirect( web.url_for( controller='library_common', + action='browse_library', + cntrller=cntrller, + use_panels=use_panels, + id=library_id, + show_deleted=show_deleted, + message=util.sanitize_text( message ), + status='error' ) ) + def _check_add( self, trans, cntrller, is_admin, item, current_user_roles, use_panels, library_id, show_deleted ): + # Deny access if the user is not an admin and does not have the LIBRARY_ADD permission. + if not ( is_admin or trans.app.security_agent.can_add_library_item( current_user_roles, item ) ): + message = "You are not authorized to add an item to '%s'." % item.name + # Redirect to the real parent library since we know we have access to it. + if cntrller == 'api': + return 403, message + return trans.response.send_redirect( web.url_for( controller='library_common', + action='browse_library', + cntrller=cntrller, + use_panels=use_panels, + id=library_id, + show_deleted=show_deleted, + message=util.sanitize_text( message ), + status='error' ) ) + def _check_manage( self, trans, cntrller, is_admin, item, current_user_roles, use_panels, library_id, show_deleted ): + if isinstance( item, trans.model.LibraryDataset ): + # Deny access if the user is not an admin and does not have the LIBRARY_MANAGE and DATASET_MANAGE_PERMISSIONS permissions. + if not ( is_admin or \ + ( trans.app.security_agent.can_manage_library_item( current_user_roles, item ) and + trans.app.security_agent.can_manage_dataset( current_user_roles, library_dataset.library_dataset_dataset_association.dataset ) ) ): + message = "You are not authorized to manage permissions on library dataset '%s'." % library_dataset.name + if cntrller == 'api': + return 403, message + return trans.response.send_redirect( web.url_for( controller='library_common', + action='browse_library', + id=library_id, + cntrller=cntrller, + use_panels=use_panels, + message=util.sanitize_text( message ), + status='error' ) ) + # Deny access if the user is not an admin and does not have the LIBRARY_MANAGE permission. + if not ( is_admin or trans.app.security_agent.can_manage_library_item( current_user_roles, item ) ): + message = "You are not authorized to manage permissions on '%s'." % item.name + if cntrller == 'api': + return 403, message + return trans.response.send_redirect( web.url_for( controller='library_common', + action='browse_library', + id=library_id, + cntrller=cntrller, + use_panels=use_panels, + message=util.sanitize_text( message ), + status='error' ) ) + def _check_modify( self, trans, cntrller, is_admin, item, current_user_roles, use_panels, library_id, show_deleted ): + # Deny modification if the user is not an admin and does not have the LIBRARY_MODIFY permission. + if not ( is_admin or trans.app.security_agent.can_modify_library_item( current_user_roles, item ) ): + message = "You are not authorized to modify '%s'." % item.name + if cntrller == 'api': + return 403, message + return trans.response.send_redirect( web.url_for( controller='library_common', + action='browse_library', + cntrller=cntrller, + id=library_id, + use_panels=use_panels, + show_deleted=show_deleted, + message=util.sanitize_text( message ), + status='error' ) ) # ---- Utility methods ------------------------------------------------------- diff --git a/templates/library/common/browse_library.mako b/templates/library/common/browse_library.mako index 7af5197f231..7d457e56e25 100644 --- a/templates/library/common/browse_library.mako +++ b/templates/library/common/browse_library.mako @@ -226,6 +226,9 @@ Delete template %endif %if not branch_deleted( folder ) and not ldda.library_dataset.deleted and can_manage: + %if not trans.app.security_agent.dataset_is_public( ldda.dataset ): + Make public + %endif Edit permissions %endif %if not branch_deleted( folder ) and not ldda.library_dataset.deleted and can_modify: @@ -314,7 +317,7 @@ %if folder.deleted: %endif - %if not branch_deleted( folder ) and ( can_add or can_modify or can_manage ): + %if not branch_deleted( folder ): %if not library.deleted:
%s' % field[ 'widget' ].value elif isinstance( field[ 'widget' ], TextField ) and field[ 'widget' ].value: has_contents = True label = field[ 'label' ] - widget = field[ 'widget' ] + value = field[ 'widget' ].value elif isinstance( field[ 'widget' ], SelectField ) and field[ 'widget' ].options: for option_label, option_value, selected in field['widget'].options: if selected: has_contents = True label = field[ 'label' ] - widget = field[ 'widget' ] + value = option_value elif isinstance( field[ 'widget' ], CheckboxField ) and field[ 'widget' ].checked: has_contents = True label = field[ 'label' ] - widget = field[ 'widget' ] + value = 'checked' elif isinstance( field[ 'widget' ], WorkflowField ) and str( field[ 'widget' ].value ).lower() not in [ 'none' ]: has_contents = True label = field[ 'label' ] @@ -40,11 +40,12 @@ widget = field[ 'widget' ] address = trans.sa_session.query( trans.model.UserAddress ).get( int( widget.value ) ) label = address.desc + value = address.get_html() %> %if has_contents: