User interface to permissions, and a bunch of changes to ensure that

both permitted_actions and groups are set appropriately on datasets.
Somewhat tested and mostly working, but needs more testing.

Greg: If a userless session has a history, if that user logs in,
the DefaultHistoryGroupAssociation for the current history as well
as the datasets in that history are supposed to be updated with the
permissions in DefaultUserGroupAssociation, but this isn't happening.
Possibly because the default permissions on userless histories create
datasets in the public group with only the DATASET_ACCESS permission
(or possibly for another reason).  What are the implications of giving
public users DATASET_MANAGE_PERMISSIONS?
This commit is contained in:
Nate Coraor
2008-08-20 18:11:04 -04:00
parent f7e517388b
commit 3802816b69
18 changed files with 299 additions and 221 deletions
+1 -1
View File
@@ -619,7 +619,7 @@ def init( file_path, url, engine_options={}, create_tables=False ):
orphans = result.Dataset.get_by( history_id = None )
if orphans:
for dataset in orphans:
result.security_agent.set_dataset_groups( dataset, [ public_group ] )
result.security_agent.set_dataset_permissions( dataset, [ ( public_group, result.security_agent.permitted_actions.DATASET_ACCESS ) ] )
else:
result.security_agent.guess_public_group()
log.debug( "Public Group identified as id = %s." % ( Group.public_id ) )
+91 -74
View File
@@ -7,10 +7,6 @@ from galaxy.util.bunch import Bunch
log = logging.getLogger(__name__)
# TODO, Nate: Think about whether the following permitted actions are appropriate for the dataset and
# group objects. What should be the default "public" permitted actions? Make sure that the public group
# and public datasets are set with the correct permitted actions. Also make sure that "private" settings
# are correct when an authenticated user creates things inside their "private" environment.
class RBACAgent:
"""Class that handles galaxy security"""
permitted_actions = Bunch(
@@ -23,9 +19,14 @@ class RBACAgent:
# use in a job, etc).
DATASET_ACCESS = 'dataset_access'
)
permitted_action_descriptions = Bunch(
DATASET_EDIT_METADATA = "Edit this dataset's metadata in the library",
DATASET_MANAGE_PERMISSIONS = "Manage the groups associated with this dataset (and those groups' permissions on the dataset)",
DATASET_ACCESS = "View, import, and perform analyses on this dataset"
)
def allow_action( self, user, action, **kwd ):
raise 'No valid method of checking action (%s) on %s for user %s.' % ( action, kwd, user )
def guess_derived_groups_permitted_actions_for_datasets( self, datasets = [] ):
def guess_derived_permissions_for_datasets( self, datasets = [] ):
raise "Unimplemented Method"
def associate_components( self, **kwd ):
raise 'No valid method of associating provided components: %s' % kwd
@@ -35,12 +36,12 @@ class RBACAgent:
raise 'No valid method of creating group with %s' % ( kwd )
def create_private_user_group( self, user ):
raise "Unimplemented Method"
def user_set_default_access( self, user, groups = None, history = False, dataset = False ):
def user_set_default_access( self, user, permissions = None, history = False, dataset = False ):
raise "Unimplemented Method"
def setup_new_user( self, user ):
self.user_set_default_access( user, history = True, dataset = True )
self.associate_components( user=user, group=self.get_public_group() )
def history_set_default_access( self, history, groups=None, dataset=False ):
def history_set_default_access( self, history, permissions=None, dataset=False ):
raise "Unimplemented Method"
def set_public_group( self, group ):
raise "Unimplemented Method"
@@ -48,7 +49,7 @@ class RBACAgent:
raise "Unimplemented Method"
def guess_public_group( self ):
raise "Unimplemented Method"
def set_dataset_groups( self, dataset, groups ):
def set_dataset_permissions( self, dataset, permissions ):
raise "Unimplemented Method"
def set_dataset_permitted_actions( self, dataset ):
raise "Unimplemented Method"
@@ -56,6 +57,24 @@ class RBACAgent:
raise "Unimplemented Method"
def components_are_associated( self, **kwd ):
return bool( self.get_component_associations( **kwd ) )
def convert_permitted_action_strings( self, permitted_action_strings ):
"""
When getting permitted actions from an untrusted source like a
form, ensure that they match our actual permitted actions.
"""
return filter( lambda x: x is not None, [ self.permitted_actions.get( action_string ) for action_string in permitted_action_strings ] )
def get_permitted_action_description( self, permitted_action ):
"""
Return the description of a permitted_action, regardless of
whether permitted_action is a key or value.
"""
if self.permitted_action_descriptions.get( permitted_action ) is not None:
return self.permitted_action_descriptions.get( permitted_action )
else:
for k, v in self.permitted_actions.items():
if v == permitted_action:
return self.permitted_action_descriptions.get( k )
return permitted_action # so at least something useful is printable
class GalaxyRBACAgent( RBACAgent ):
def __init__( self, model, permitted_actions=None ):
@@ -83,35 +102,41 @@ class GalaxyRBACAgent( RBACAgent ):
if action in group_dataset_assoc.permitted_actions:
return True
return False # No user and dataset not in public group, or user lacks permission
def guess_derived_groups_for_datasets( self, datasets=[] ):
# TODO, Nate: Make sure this method is functionally correct.
"""Returns a list of groups for the output dataset based upon itself and provided datasets"""
access_groups = None
priority_access_group = None
def guess_derived_permissions_for_datasets( self, datasets=[] ):
"""Returns a list of group/action tuples for the output dataset based upon provided datasets"""
intersect = None
priority_access_perms = None
for dataset in datasets:
# Determine access groups for output datasets - these groups are the
# intersection across all inputs. If we end up with no intersection
# between inputs, then we rely on priorities
if isinstance( dataset, self.model.HistoryDatasetAssociation ):
dataset = dataset.dataset
groups = [ data_group_assoc.group for data_group_assoc in dataset.groups ]
for group in groups:
if priority_access_group is None or priority_access_group.priority < group.priority:
priority_access_group = group
if access_groups is None:
access_groups = set( groups )
assocs = [ assoc for assoc in dataset.groups ]
for assoc in assocs:
if priority_access_perms is None or priority_access_perms[0].priority < assoc.group.priority:
priority_access_perms = ( assoc.group, assoc.permitted_actions )
if intersect is None:
intersect = [ (a.group, a.permitted_actions) for a in assocs ]
else:
access_groups.intersection_update( set( groups ) )
# Complete lists for output dataset access
if access_groups:
access_groups = list( access_groups)
else:
access_groups = []
# Intersect existing perms with new perms
#access_assocs = filter( lambda x: x.group in [ a.group for a in access_assocs ], assocs )
new_intersect = []
for group, actions in intersect:
matches = filter( lambda x: x.group == group, assocs )
# Could a dataset ever have more than one GDA with the same group id?
if len( matches ) > 1:
log.error( "Unable to derive permissions, duplicate group_dataset_association rows exist for group %d, dataset %d" % (group.id, dataset.id) )
elif len( matches ) == 1:
# compare permitted_actions
pa_intersect = filter( lambda x: x in actions, matches[0].permitted_actions )
new_intersect.append( ( group, pa_intersect ) )
intersect = new_intersect
# If we have no groups left after intersection, take the highest priority group
if not access_groups:
if priority_access_group:
access_groups = [ priority_access_group ]
return access_groups
if not intersect:
if priority_access_perms:
intersect = [ priority_access_perms ]
return intersect
def get_group( self, id ):
return self.model.Group.get( id )
raise 'No valid method of retrieving requested group %s' % ( id )
@@ -125,29 +150,18 @@ class GalaxyRBACAgent( RBACAgent ):
if 'dataset' in kwd:
if 'group' in kwd:
return self.associate_group_dataset( kwd['group'], kwd['dataset'] )
elif 'permissions' in kwd:
return self.associate_group_dataset( kwd['permissions'][0], kwd['dataset'], kwd['permissions'][1] )
elif 'user' in kwd:
if 'group' in kwd:
return self.associate_user_group( kwd['user'], kwd['group'] )
raise 'No valid method of associating provided components: %s' % kwd
def disassociate_components( self, **kwd ):
assert len( kwd ) == 2, 'You must specify exactly 2 Galaxy security components to disassociate.'
if 'dataset' in kwd:
if 'group' in kwd:
return self.disassociate_group_dataset( kwd['group'], kwd['dataset'] )
raise 'No valid method of associating provided components: %s' % kwd
def associate_group_dataset( self, group, dataset, permitted_actions=[] ):
if not permitted_actions:
if isinstance( dataset.permitted_actions, Bunch ):
permitted_actions = dataset.permitted_actions.__dict__.values()
else:
permitted_actions = dataset.permitted_actions
def associate_group_dataset( self, group, dataset, permitted_actions=[ RBACAgent.permitted_actions.DATASET_ACCESS ] ):
# HACK: The default permitted_actions should really not be used... need to find cases where this is done and correct it
log.debug("In associate_permissions_dataset, dataset: %d, group: %d, permitted_actions: %s" % ( dataset.id, group.id, permitted_actions ) )
assoc = self.model.GroupDatasetAssociation( group, dataset, permitted_actions )
assoc.flush()
return assoc
def disassociate_group_dataset( self, group, dataset ):
assoc = self.model.GroupDatasetAssociation.selectone_by( group_id = group.id, dataset_id = dataset.id )
assoc.delete()
assoc.flush()
def associate_user_group( self, user, group ):
assoc = self.model.UserGroupAssociation( user, group )
assoc.flush()
@@ -161,66 +175,69 @@ class GalaxyRBACAgent( RBACAgent ):
self.associate_components( group=group, user=user )
group.flush()
return group
def user_set_default_access( self, user, groups = None, history = False, dataset = False ):
# TODO, Nate: Make sure this method is functionally correct with permitted actions set appropriately.
if groups is None:
groups = [ self.create_private_user_group( user ) ]
if groups is not None:
def user_set_default_access( self, user, permissions = None, history = False, dataset = False ):
if permissions is None:
permissions = [ ( self.create_private_user_group( user ), self.permitted_actions.__dict__.values() ) ]
if permissions is not None:
for assoc in user.default_groups: #this is the association not the actual group
assoc.delete()
assoc.flush()
for group in groups:
if isinstance( group, self.model.Group ):
permitted_actions = group.permitted_actions.__dict__.values()
else:
permitted_actions = group.permitted_actions
for group, permitted_actions in permissions:
log.debug("In user_set_default_access, user: %s, group: %s, permitted_actions: %s" % (user.email, group.name, str( permitted_actions)))
assoc = self.model.DefaultUserGroupAssociation( user, group, permitted_actions )
assoc.flush()
if history:
for history in user.histories:
self.history_set_default_access( history, groups=groups, dataset=dataset )
def history_set_default_access( self, history, groups=None, dataset=False ):
# TODO, Nate: Make sure this method is functionally correct with permitted actions set appropriately.
if groups is None:
self.history_set_default_access( history, permissions=permissions, dataset=dataset )
def user_get_default_access( self, user ):
return [ ( duga.group, duga.permitted_actions ) for duga in user.default_groups ]
def history_set_default_access( self, history, permissions=None, dataset=False ):
if permissions is None:
if history.user:
groups = [ assoc.group for assoc in history.user.default_groups ]
permissions = self.user_get_default_access( history.user )
else:
groups = [ self.get_public_group() ]
if groups is not None:
# FIXME: should this be all permissions?
permissions = [ ( self.get_public_group(), [ self.permitted_actions.DATASET_ACCESS ] ) ]
if permissions is not None:
for assoc in history.default_groups: #this is the association not the actual group
assoc.delete()
assoc.flush()
for group in groups:
if isinstance( group, self.model.Group ):
permitted_actions = group.permitted_actions.__dict__.values()
else:
permitted_actions = group.permitted_actions
for group, permitted_actions in permissions:
log.debug("In history_set_default_access, history: %s, group: %s, permitted_actions: %s" % (history.id, group.name, str( permitted_actions)))
assoc = self.model.DefaultHistoryGroupAssociation( history, group, permitted_actions )
assoc.flush()
if dataset:
for data in history.datasets:
for hda in data.dataset.history_associations:
if history.user and hda.history not in history.user.histories:
self.set_dataset_groups( data.dataset, [ self.get_public_group() ] )
self.set_dataset_permissions( data.dataset, [ ( self.get_public_group(), [ self.permitted_actions.DATASET_ACCESS ] ) ] )
break
else:
self.set_dataset_groups( data.dataset, groups )
self.set_dataset_permissions( data.dataset, permissions )
def history_get_default_access( self, history ):
return [ ( dhga.group, dhga.permitted_actions ) for dhga in history.default_groups ]
def get_public_group( self ):
return self.model.Group.get_public_group()
def set_public_group( self, group ):
return self.model.Group.set_public_group( group )
def guess_public_group( self ):
return self.model.Group.guess_public_group()
def set_dataset_groups( self, dataset, groups ):
def set_dataset_permissions( self, dataset, permissions ):
"""
Apply permissions (a list of (group, permitted_action) tuples)
to a dataset, removing any existing permissions. permissions can
also be a list of GroupDatasetAssociations (for simplicity).
"""
if isinstance( dataset, self.model.HistoryDatasetAssociation ):
dataset = dataset.dataset
for group_dataset_assoc in dataset.groups:
group_dataset_assoc.delete()
group_dataset_assoc.flush()
for group in groups:
if not isinstance( group, self.model.Group ):
group = group.group
self.associate_components( dataset=dataset, group=group )
if isinstance( permissions[0], self.model.GroupDatasetAssociation ):
permissions = [ ( gda.group, gda.permitted_actions ) for gda in permissions ]
for ptuple in permissions:
log.debug("In set_dataset_permissions, before elf.associate_components, dataset: %s, group: %s, permitted_actions: %s" % ( str(dataset.id), str(ptuple[0].id), str(ptuple[1])))
self.associate_components( dataset=dataset, permissions=ptuple )
def get_component_associations( self, **kwd ):
# TODO, Nate: Make sure this method is functionally correct.
assert len( kwd ) == 2, 'You must specify exactly 2 Galaxy security components to check for associations.'
+2 -4
View File
@@ -1085,8 +1085,7 @@ class Tool:
else: visible = False
ext = fields.pop(0).lower()
child_dataset = self.app.model.HistoryDatasetAssociation( extension=ext, parent_id=outdata.id, designation=designation, visible=visible, dbkey=outdata.dbkey, create_dataset=True )
# TODO, Nate: Make sure the following is functionally correct.
self.app.security_agent.set_dataset_groups( child_dataset.dataset, outdata.dataset.groups )
self.app.security_agent.set_dataset_permissions( child_dataset.dataset, outdata.dataset.groups )
# Move data from temp location to dataset location
shutil.move( filename, child_dataset.file_name )
child_dataset.flush()
@@ -1123,8 +1122,7 @@ class Tool:
ext = fields.pop(0).lower()
# Create new primary dataset
primary_data = self.app.model.HistoryDatasetAssociation( extension=ext, designation=designation, visible=visible, dbkey=outdata.dbkey, create_dataset=True )
# TODO, Nate: Make sure the following is functionally correct.
self.app.security_agent.set_dataset_groups( primary_data.dataset, outdata.dataset.groups )
self.app.security_agent.set_dataset_permissions( primary_data.dataset, outdata.dataset.groups )
primary_data.flush()
# Move data from temp location to dataset location
shutil.move( filename, primary_data.file_name )
+3 -4
View File
@@ -86,11 +86,10 @@ class DefaultToolAction( object ):
# Determine output dataset permitted_actions list
existing_datasets = [ inp for inp in inp_data.values() if inp ]
if existing_datasets:
output_access_groups = trans.app.security_agent.guess_derived_groups_for_datasets( existing_datasets )
output_permissions = trans.app.security_agent.guess_derived_permissions_for_datasets( existing_datasets )
else:
# No valid inputs, we will use history defaults
output_access_groups = [ group.group for group in trans.history.default_groups ]
output_permissions = trans.app.security_agent.history_get_default_access( trans.history )
# Build name for output datasets based on tool name and input names
if len( input_names ) == 1:
on_text = input_names[0]
@@ -132,7 +131,7 @@ class DefaultToolAction( object ):
data = trans.app.model.HistoryDatasetAssociation( extension=ext, create_dataset=True )
# Commit the dataset immediately so it gets database assigned unique id
data.flush()
trans.app.security_agent.set_dataset_groups( data.dataset, output_access_groups )
trans.app.security_agent.set_dataset_permissions( data.dataset, output_permissions )
# Create an empty file immediately
open( data.file_name, "w" ).close()
# This may not be neccesary with the new parent/child associations
+2 -4
View File
@@ -66,8 +66,7 @@ class UploadToolAction( object ):
def upload_empty(self, trans, err_code, err_msg):
data = trans.app.model.HistoryDatasetAssociation( create_dataset=True )
# TODO, Nate: Make sure the following is appropriate.
trans.app.security_agent.set_dataset_groups( data.dataset, trans.history.default_groups )
trans.app.security_agent.set_dataset_permissions( data.dataset, trans.app.security_agent.history_get_default_access( trans.history ) )
data.name = err_code
data.extension = "txt"
data.dbkey = "?"
@@ -161,8 +160,7 @@ class UploadToolAction( object ):
info = 'uploaded %s file' %data_type
data = trans.app.model.HistoryDatasetAssociation( history = trans.history, extension = ext, create_dataset = True )
# TODO, Nate: Make sure the following is appropriate.
trans.app.security_agent.set_dataset_groups( data.dataset, trans.history.default_groups )
trans.app.security_agent.set_dataset_permissions( data.dataset, trans.app.security_agent.history_get_default_access( trans.history ) )
data.name = file_name
data.dbkey = dbkey
data.info = info
+5 -5
View File
@@ -992,15 +992,15 @@ class DataToolParameter( ToolParameter ):
>>> group.flush()
>>> Group.public_id = group.id
>>> dataset1 = HistoryDatasetAssociation( id=1, extension='txt', create_dataset=True )
>>> security_agent.set_dataset_groups( dataset1, [ group ] )
>>> security_agent.set_dataset_permissions( dataset1, [ ( group, security_agent.permitted_actions.__dict__.values() ) ] )
>>> dataset2 = HistoryDatasetAssociation( id=2, extension='bed', create_dataset=True )
>>> security_agent.set_dataset_groups( dataset2, [ group ] )
>>> security_agent.set_dataset_permissions( dataset2, [ ( group, security_agent.permitted_actions.__dict__.values() ) ] )
>>> dataset3 = HistoryDatasetAssociation( id=3, extension='fasta', create_dataset=True )
>>> security_agent.set_dataset_groups( dataset3, [ group ] )
>>> security_agent.set_dataset_permissions( dataset3, [ ( group, security_agent.permitted_actions.__dict__.values() ) ] )
>>> dataset4 = HistoryDatasetAssociation( id=4, extension='png', create_dataset=True )
>>> security_agent.set_dataset_groups( dataset4, [ group ] )
>>> security_agent.set_dataset_permissions( dataset4, [ ( group, security_agent.permitted_actions.__dict__.values() ) ] )
>>> dataset5 = HistoryDatasetAssociation( id=5, extension='interval', create_dataset=True )
>>> security_agent.set_dataset_groups( dataset5, [ group ] )
>>> security_agent.set_dataset_permissions( dataset5, [ ( group, security_agent.permitted_actions.__dict__.values() ) ] )
>>> hist.add_dataset( dataset1 )
>>> hist.add_dataset( dataset2 )
>>> hist.add_dataset( dataset3 )
+1 -2
View File
@@ -104,8 +104,7 @@ class ASync( BaseController ):
#history.datasets.add_dataset( data )
data = trans.app.model.HistoryDatasetAssociation( create_dataset = True, extension = GALAXY_TYPE )
# TODO, Nate: Make sure the following is functionally correct.
trans.app.security_agent.set_dataset_groups( data.dataset, trans.history.default_groups )
trans.app.security_agent.set_dataset_permissions( data.dataset, trans.app.security_agent.history_get_default_access( trans.history ) )
data.name = GALAXY_NAME
data.dbkey = GALAXY_BUILD
data.info = GALAXY_INFO
+1 -1
View File
@@ -126,4 +126,4 @@ class DatasetInterface( BaseController ):
except:
raise paste.httpexceptions.HTTPNotFound( "File Not Found (%s)." % ( filename ) )
else:
raise paste.httpexceptions.HTTPForbidden( "You are not permitted to access this dataset." )
return trans.show_error_message( "You are not privileged to access this dataset." )
+26 -43
View File
@@ -14,8 +14,6 @@ import urllib
log = logging.getLogger( __name__ )
class RootController( BaseController ):
# TODO, Nate: This is where a lot of the new dataset security stuff is managed.
# Make sure it is is functionally correct.
@web.expose
def default(self, trans, target1=None, target2=None, **kwd):
@@ -266,23 +264,18 @@ class RootController( BaseController ):
"""The user clicked the change_permission button on the 'Change permissions' form"""
if not trans.user:
return trans.show_error_message( "You must be logged in if you want to change dataset permitted actions." )
private_dataset = 'private_dataset'
public_group = trans.app.security_agent.get_public_group()
if private_dataset in kwd and trans.app.security_agent.dataset_has_group( data.dataset.id, public_group.id ):
#check user has permission and then remove public group
if trans.app.security_agent.allow_action( trans.user, data.dataset.permitted_actions.DATASET_MANAGE_PERMISSIONS, dataset = data.dataset ):
trans.app.security_agent.disassociate_components( dataset = data, group = public_group )
else:
return trans.show_error_message( "You are not authorized to change this dataset's permitted actions." )
elif private_dataset not in kwd and not trans.app.security_agent.dataset_has_group( data.dataset.id, public_group.id ):
#check user has permission and then add public group
if trans.app.security_agent.allow_action( trans.user, data.dataset.permitted_actions.DATASET_MANAGE_PERMISSIONS, dataset = data.dataset ):
trans.app.security_agent.associate_components( dataset = data, group = public_group)
else:
return trans.show_error_message( "You are not authorized to change this dataset's permitted actions." )
if trans.app.security_agent.allow_action( trans.user, data.dataset.permitted_actions.DATASET_MANAGE_PERMISSIONS, dataset = data.dataset ):
group_args = [ k.replace('group_', '', 1) for k in kwd if k.startswith('group_') ]
group_ids_checked = filter( lambda x: not x.count('_'), group_args )
permissions = []
for group_id in group_ids_checked:
action_strings = [ action.replace(group_id + '_', '', 1) for action in group_args if action.startswith(group_id + '_') ]
actions = trans.app.security_agent.convert_permitted_action_strings( action_strings )
permissions.append( ( trans.app.security_agent.get_group( group_id ), actions ) )
trans.app.security_agent.set_dataset_permissions( data.dataset, permissions )
return trans.show_ok_message( "Dataset permissions have been set.", refresh_frames=['history'] )
else:
return trans.show_error_message( "You have not specified a valid change of permitted actions." )
return trans.show_ok_message( 'Permitted actions have been changed.', refresh_frames=['history'] )
return trans.show_error_message( "You are not authorized to change this dataset's permitted actions." )
data.datatype.before_edit( data )
@@ -596,12 +589,12 @@ class RootController( BaseController ):
"""Adds a POSTed file to a History"""
try:
history = trans.app.model.History.get( history_id )
groups = history.default_groups
groups = trans.app.security_agent.history_get_default_access( history )
if copy_access_from:
copy_access_from = trans.app.model.HistoryDatasetAssociation.get( copy_access_from )
groups = copy_access_from.dataset.groups
group_dataset_associations = copy_access_from.dataset.groups
data = trans.app.model.HistoryDatasetAssociation( name = name, info = info, extension = ext, dbkey = dbkey, create_dataset = True )
trans.app.security_agent.set_dataset_groups( data.dataset, groups )
trans.app.security_agent.set_dataset_permissions( data.dataset, group_dataset_associations )
data.flush()
data_file = open( data.file_name, "wb" )
file_data.file.seek( 0 )
@@ -629,34 +622,24 @@ class RootController( BaseController ):
if 'set_permitted_actions' in kwd:
"""The user clicked the set_permitted_actions button on the set_permitted_actions form"""
history = trans.get_history()
group_in = []
group_out = []
# Collect groups as entered by user
for name, value in kwd.items():
if name.startswith( "group_" ):
group = trans.app.security_agent.get_group( name.replace( "group_", "", 1 ) )
if not group:
return trans.show_error_message( 'You have specified an invalid group.' )
if value == 'in':
group_in.append( group )
else:
group_out.append( group )
if not group_in:
group_args = [ k.replace('group_', '', 1) for k in kwd if k.startswith('group_') ]
group_ids_checked = filter( lambda x: not x.count('_'), group_args )
if not group_ids_checked:
return trans.show_error_message( "You must specify at least one default group." )
cur_groups = [ assoc.group for assoc in history.default_groups ]
group_in.sort()
cur_groups.sort()
if cur_groups != group_in:
trans.app.security_agent.history_set_default_access( history, groups=group_in )
return trans.show_ok_message( 'Default history permitted actions have been changed.' )
else:
return trans.show_error_message( "You did not specify any changes to this history's default permitted actions." )
permissions = []
for group_id in group_ids_checked:
group = trans.app.security_agent.get_group( group_id )
if not group:
return trans.show_error_message( 'You have specified an invalid group.' )
action_strings = [ action.replace(group_id + '_', '', 1) for action in group_args if action.startswith(group_id + '_') ]
permissions.append( ( group, trans.app.security_agent.convert_permitted_action_strings( action_strings ) ) )
trans.app.security_agent.history_set_default_access( history, permissions = permissions )
return trans.show_ok_message( 'Default history permitted actions have been changed.' )
return trans.fill_template( 'history/permissions.mako' )
else:
#user not logged in, history group must be only public
return trans.show_error_message( "You must be logged in to change a history's default permitted actions." )
@web.expose
def dataset_make_primary( self, trans, id=None):
"""Copies a dataset and makes primary"""
+13 -23
View File
@@ -170,33 +170,23 @@ class User( BaseController ):
@web.expose
def set_default_permitted_actions( self, trans, **kwd ):
# TODO, Nate: Make sure this method is functionally correct.
"""Sets the user's default permitted actions for the new histories"""
if trans.user:
if 'set_permitted_actions' in kwd:
"""The user clicked the set_permitted_actions button on the set_permitted_actions form"""
group_in = []
group_out = []
# Collect groups as entered by user
for name, value in kwd.items():
if name.startswith( "group_" ):
group = trans.app.security_agent.get_group( name.replace( "group_", "", 1 ) )
if not group:
return trans.show_error_message( 'You have specified an invalid group.' )
if value == 'in':
group_in.append( group )
else:
group_out.append( group )
if not group_in:
return trans.show_error_message( "You must specify at least one default group." )
cur_groups = [ assoc.group for assoc in trans.user.default_groups ]
group_in.sort()
cur_groups.sort()
if cur_groups != group_in:
trans.app.security_agent.user_set_default_access( trans.user, groups = group_in )
return trans.show_ok_message( 'Default new history permitted actions have been changed.' )
else:
return trans.show_error_message( "You did not specify any changes to new history's default permitted actions." )
group_args = [ k.replace('group_', '', 1) for k in kwd if k.startswith('group_') ]
group_ids_checked = filter( lambda x: not x.count('_'), group_args )
if not group_ids_checked:
return trans.show_error_message( "You must specify at least one default group." )
permissions = []
for group_id in group_ids_checked:
group = trans.app.security_agent.get_group( group_id )
if not group:
return trans.show_error_message( 'You have specified an invalid group.' )
action_strings = [ action.replace(group_id + '_', '', 1) for action in group_args if action.startswith(group_id + '_') ]
permissions.append( ( group, trans.app.security_agent.convert_permitted_action_strings( action_strings ) ) )
trans.app.security_agent.user_set_default_access( trans.user, permissions )
return trans.show_ok_message( 'Default new history permitted actions have been changed.' )
return trans.fill_template( 'user/permissions.mako' )
else:
# User not logged in, history group must be only public
+1 -2
View File
@@ -433,10 +433,9 @@ class UniverseWebTransaction( base.DefaultWebTransaction ):
galaxy_session.flush()
self.__galaxy_session = galaxy_session
if history is not None and user is not None:
# TODO, Nate: Make sure the following is functionally correct
if not history.user:
# This user will now acquire previously non-owned history, so set permitted actions to user's default
self.app.security_agent.history_set_default_access( history, groups=user.default_groups, dataset=True )
self.app.security_agent.history_set_default_access( history, dataset=True )
history.user_id = user.id
history.flush()
self.__history = history
+5 -1
View File
@@ -414,4 +414,8 @@ div.popupmenu-item:hover {
.popup-arrow:hover {
color: black;
}
}
div.permissionContainer {
padding-left: 20px;
}
+66 -19
View File
@@ -133,33 +133,80 @@
<p />
%if trans.app.config.enable_beta_features and trans.user and ( trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_MANAGE_PERMISSIONS, dataset = data ) ):
%if trans.user and ( trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_MANAGE_PERMISSIONS, dataset = data ) ):
<script type="text/javascript">
var q = jQuery.noConflict();
q( document ).ready( function () {
// initialize state
q("input.groupCheckbox").each( function() {
if ( ! q(this).is(":checked") ) q("div#" + this.name).hide();
});
// handle events
q("input.groupCheckbox").click( function() {
if ( q(this).is(":checked") ) {
q("div#" + this.name).slideDown("fast");
} else {
q("div#" + this.name).slideUp("fast");
}
});
});
</script>
<div class="toolForm">
<div class="toolFormTitle">Change Permitted Actions</div>
<div class="toolFormTitle">Change Dataset Access Permissions</div>
<div class="toolFormBody">
<form name="change_permission_form" action="${h.url_for( action='edit' )}" method="post">
<input type="hidden" name="id" value="${data.id}">
<div class="form-row">
<label>
Private Dataset:
</label>
<% checked = "" %>
%if not trans.app.security_agent.dataset_has_group( data.id, trans.app.model.Group.get_public_group().id ):
<% checked = " checked" %>
%endif
<div style="float: left; width: 250px; margin-right: 10px;">
<input type="checkbox" name="private_dataset"${checked}>
</div>
<div style="clear: both"></div>
<div class="toolParamHelp" style="clear: both;">
This will prevent other users from viewing or utilizing this dataset, even if you share your history with them.
</div>
<div style="clear: both"></div>
</div>
<div class="form-row">
<% user_groups = [ assoc.group for assoc in trans.user.groups ] %>
<% dataset_group_ids = [ assoc.group.id for assoc in data.dataset.groups ] %>
<div class="toolParamHelp" style="clear: both;">
Check each group which should have access to this dataset.
</div>
%for group in user_groups:
%if group.id in dataset_group_ids:
<% assoc = filter( lambda x: x.group_id == group.id, data.dataset.groups )[0] %>
%else:
<% assoc = None %>
%endif
<input type="checkbox" name="group_${group.id}" class="groupCheckbox"
%if assoc is not None:
checked
%endif
/> ${group.name} <br/>
<div class="permissionContainer" id="group_${group.id}">
%for k, v in trans.app.security_agent.permitted_actions.items():
<input type="checkbox" name="group_${group.id}_${k}"
%if assoc is not None and v in assoc.permitted_actions:
checked
%endif
/> ${trans.app.security_agent.get_permitted_action_description(k)} <br/>
%endfor
</div>
%endfor
<input type="submit" name="change_permission" value="Save">
</div>
</form>
</div>
</div>
%elif trans.user and ( trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_ACCESS, dataset = data ) ):
<div class="toolForm">
<div class="toolFormTitle">Dataset Access Permissions</div>
<div class="toolFormBody">
<div class="form-row">
<label>The following groups may perform the actions listed on this dataset:</label>
<br/>
%for assoc in data.dataset.groups:
${assoc.group.name}
<ul>
%for action in assoc.permitted_actions:
<li>${trans.app.security_agent.get_permitted_action_description(action)}</li>
%endfor
</ul>
%endfor
<div class="toolParamHelp" style="clear: both;">
You do not have permission to edit this dataset's permissions.
</div>
</div>
</div>
</div>
%endif
+40 -16
View File
@@ -2,6 +2,23 @@
<%def name="title()">Change Default History Permitted Actions</%def>
%if trans.user:
<script type="text/javascript">
var q = jQuery.noConflict();
q( document ).ready( function () {
// initialize state
q("input.groupCheckbox").each( function() {
if ( ! q(this).is(":checked") ) q("div#" + this.name).hide();
});
// handle events
q("input.groupCheckbox").click( function() {
if ( q(this).is(":checked") ) {
q("div#" + this.name).slideDown("fast");
} else {
q("div#" + this.name).slideUp("fast");
}
});
});
</script>
<div class="toolForm">
<div class="toolFormTitle">Change Default History Permitted Actions</div>
<div class="toolFormBody">
@@ -9,27 +26,34 @@
<div class="form-row">
<% user_groups = [ assoc.group for assoc in trans.user.groups ] %>
<% cur_groups = [ assoc.group for assoc in trans.get_history().default_groups ] %>
<div style="float: left; width: 250px; margin-right: 10px;">
<table>
<tr><th>Group</th><th>In</th><th>Out</th></tr>
%for group in user_groups:
<tr><td>${group.name}</td><td><input type="radio" name="group_${group.id}" value="in"
%if group in cur_groups:
checked
%endif
></td><td><input type="radio" name="group_${group.id}" value="out"
%if group not in cur_groups:
checked
%endif
></td></tr>
<input type="checkbox" name="group_${group.id}" class="groupCheckbox"
%if group in cur_groups:
<% assoc = filter( lambda x: x.group_id == group.id, trans.get_history().default_groups )[0] %>
checked
%else:
<% assoc = None %>
%endif
/> ${group.name} <br/>
<div class="permissionContainer" id="group_${group.id}">
%for k, v in trans.app.security_agent.permitted_actions.items():
<input type="checkbox" name="group_${group.id}_${k}"
%if assoc is not None and v in assoc.permitted_actions:
checked
%endif
/> ${trans.app.security_agent.get_permitted_action_description(k)} <br/>
%endfor
</div>
%endfor
</table>
</div>
<div style="clear: both"></div>
<div class="toolParamHelp" style="clear: both;">
This will change the default permitted actions assigned to new datasets for your current history.
This will change the default permitted actions assigned
to new datasets in your current history. You may also
specify the defaults for new histories via the
<a href="${h.url_for(controller='user')}">user options</a>.
</div>
<div style="clear: both"></div>
</div>
@@ -39,4 +63,4 @@
</form>
</div>
</div>
%endif
%endif
+39 -16
View File
@@ -2,6 +2,23 @@
<%def name="title()">Change Default History Permitted Actions</%def>
%if trans.user:
<script type="text/javascript">
var q = jQuery.noConflict();
q( document ).ready( function () {
// initialize state
q("input.groupCheckbox").each( function() {
if ( ! q(this).is(":checked") ) q("div#" + this.name).hide();
});
// handle events
q("input.groupCheckbox").click( function() {
if ( q(this).is(":checked") ) {
q("div#" + this.name).slideDown("fast");
} else {
q("div#" + this.name).slideUp("fast");
}
});
});
</script>
<div class="toolForm">
<div class="toolFormTitle">Change Default Permitted Actions for new Histories </div>
<div class="toolFormBody">
@@ -9,27 +26,33 @@
<div class="form-row">
<% user_groups = [ assoc.group for assoc in trans.user.groups ] %>
<% cur_groups = [ assoc.group for assoc in trans.user.default_groups ] %>
<div style="float: left; width: 250px; margin-right: 10px;">
<table>
<tr><th>Group</th><th>In</th><th>Out</th></tr>
%for group in user_groups:
<tr><td>${group.name}</td><td><input type="radio" name="group_${group.id}" value="in"
%if group in cur_groups:
checked
%endif
></td><td><input type="radio" name="group_${group.id}" value="out"
%if group not in cur_groups:
checked
%endif
></td></tr>
<input type="checkbox" name="group_${group.id}" class="groupCheckbox"
%if group in cur_groups:
<% assoc = filter( lambda x: x.group_id == group.id, trans.user.default_groups )[0] %>
checked
%else:
<% assoc = None %>
%endif
/> ${group.name} <br/>
<div class="permissionContainer" id="group_${group.id}">
%for k, v in trans.app.security_agent.permitted_actions.items():
<input type="checkbox" name="group_${group.id}_${k}"
%if assoc is not None and v in assoc.permitted_actions:
checked
%endif
/> ${trans.app.security_agent.get_permitted_action_description(k)} <br/>
%endfor
</div>
%endfor
</table>
</div>
<div style="clear: both"></div>
<div class="toolParamHelp" style="clear: both;">
This will change the default permitted actions assigned to new datasets for new histories.
This will change the default permitted actions assigned
to new datasets in new histories. You may also specify
per-history defaults via the
<a href="${h.url_for(controller='root', action='history_options')}">history options</a>.
</div>
<div style="clear: both"></div>
</div>
@@ -39,4 +62,4 @@
</form>
</div>
</div>
%endif
%endif
+1 -2
View File
@@ -38,8 +38,7 @@ def exec_after_process(app, inp_data, out_data, param_dict, tool, stdout, stderr
newdata.extension = file_type
newdata.name = basic_name + " (" + description + ")"
history.add_dataset( newdata )
#TODO, Nate: Make sure the following is functionally correct
app.security_agent.set_dataset_groups( newdata.dataset, base_dataset.dataset.groups )
app.security_agent.set_dataset_permissions( newdata.dataset, base_dataset.dataset.groups )
app.model.flush()
try:
copyfile(filepath,newdata.file_name)
+1 -2
View File
@@ -129,8 +129,7 @@ def exec_after_process(app, inp_data, out_data, param_dict, tool, stdout, stderr
newdata.extension = file_type
newdata.name = basic_name + " (" + microbe_info[kingdom][org]['chrs'][chr]['data'][description]['feature'] +" for "+microbe_info[kingdom][org]['name']+":"+chr + ")"
newdata.flush()
#TODO, Nate: Make sure the following is functionally correct
app.security_agent.set_dataset_groups( newdata.dataset, base_dataset.dataset.groups )
app.security_agent.set_dataset_permissions( newdata.dataset, base_dataset.dataset.groups )
history.add_dataset( newdata )
app.model.flush()
try:
+1 -2
View File
@@ -32,8 +32,7 @@ def exec_after_process(app, inp_data, out_data, param_dict, tool, stdout, stderr
newdata.name = basic_name + " (" + dbkey + ")"
newdata.flush()
history.add_dataset( newdata )
#TODO, Nate: Make sure the following is functionally correct
app.security_agent.set_dataset_groups( newdata.dataset, output_data.dataset.groups )
app.security_agent.set_dataset_permissions( newdata.dataset, output_data.dataset.groups )
newdata.flush()
history.flush()
app.model.flush()