[hg] galaxy 2609: Fix security problem with grids. Template shou...
details: http://www.bx.psu.edu/hg/galaxy/rev/36c479b93d7e changeset: 2609:36c479b93d7e user: James Taylor <james@jamestaylor.org> date: Sun Aug 23 12:28:36 2009 -0400 description: Fix security problem with grids. Template should not be passed at call time, it must be passed at configure time. 6 file(s) affected in this change: lib/galaxy/web/controllers/history.py lib/galaxy/web/controllers/requests.py lib/galaxy/web/controllers/requests_admin.py lib/galaxy/web/framework/helpers/grids.py manage_db.sh templates/grid.mako diffs (325 lines): diff -r 19b86ccccf6f -r 36c479b93d7e lib/galaxy/web/controllers/history.py --- a/lib/galaxy/web/controllers/history.py Sun Aug 23 12:26:46 2009 -0400 +++ b/lib/galaxy/web/controllers/history.py Sun Aug 23 12:28:36 2009 -0400 @@ -39,6 +39,7 @@ # Grid definition title = "Stored histories" model_class = model.History + template='/history/grid.mako' default_sort_key = "-create_time" columns = [ grids.GridColumn( "Name", key="name", @@ -86,6 +87,7 @@ return history.user.email # Grid definition title = "Histories shared with you by others" + template='/history/grid.mako' model_class = model.History default_sort_key = "-update_time" columns = [ @@ -161,7 +163,7 @@ status, message = self._list_undelete( trans, histories ) trans.sa_session.flush() # Render the list view - return self.stored_list_grid( trans, status=status, message=message, template='/history/grid.mako', **kwargs ) + return self.stored_list_grid( trans, status=status, message=message, **kwargs ) def _list_delete( self, trans, histories ): """Delete histories""" n_deleted = 0 @@ -240,14 +242,14 @@ if operation == "clone": if not id: message = "Select a history to clone" - return self.shared_list_grid( trans, status='error', message=message, template='/history/grid.mako', **kwargs ) + return self.shared_list_grid( trans, status='error', message=message, **kwargs ) # When cloning shared histories, only copy active datasets new_kwargs = { 'clone_choice' : 'active' } return self.clone( trans, id, **new_kwargs ) elif operation == 'unshare': if not id: message = "Select a history to unshare" - return self.shared_list_grid( trans, status='error', message=message, template='/history/grid.mako', **kwargs ) + return self.shared_list_grid( trans, status='error', message=message, **kwargs ) ids = util.listify( id ) histories = [] for history_id in ids: @@ -261,7 +263,7 @@ message = "Unshared %d shared histories" % len( ids ) status = 'done' # Render the list view - return self.shared_list_grid( trans, status=status, message=message, template='/history/grid.mako', **kwargs ) + return self.shared_list_grid( trans, status=status, message=message, **kwargs ) @web.expose def delete_current( self, trans ): """Delete just the active history -- this does not require a logged in user.""" diff -r 19b86ccccf6f -r 36c479b93d7e lib/galaxy/web/controllers/requests.py --- a/lib/galaxy/web/controllers/requests.py Sun Aug 23 12:26:46 2009 -0400 +++ b/lib/galaxy/web/controllers/requests.py Sun Aug 23 12:28:36 2009 -0400 @@ -16,6 +16,7 @@ class RequestsListGrid( grids.Grid ): title = "Sequencing Requests" + template = '/requests/grid.mako' model_class = model.Request default_sort_key = "-create_time" show_filter = model.Request.states.UNSUBMITTED @@ -103,7 +104,7 @@ self.request_grid.default_filter = dict(state=kwargs['show_filter'], deleted=False) self.request_grid.show_filter = kwargs.get('show_filter', trans.app.model.Request.states.UNSUBMITTED) # Render the list view - return self.request_grid( trans, template='/requests/grid.mako', **kwargs ) + return self.request_grid( trans, **kwargs ) def __show_request(self, trans, id, add_sample=False): try: diff -r 19b86ccccf6f -r 36c479b93d7e lib/galaxy/web/controllers/requests_admin.py --- a/lib/galaxy/web/controllers/requests_admin.py Sun Aug 23 12:26:46 2009 -0400 +++ b/lib/galaxy/web/controllers/requests_admin.py Sun Aug 23 12:28:36 2009 -0400 @@ -14,6 +14,7 @@ class RequestsListGrid( grids.Grid ): title = "Sequencing Requests" + template = "admin/requests/grid.mako" model_class = model.Request default_sort_key = "-create_time" show_filter = model.Request.states.SUBMITTED @@ -101,7 +102,7 @@ self.request_grid.default_filter = dict(state=kwargs['show_filter'], deleted=False) self.request_grid.show_filter = kwargs.get('show_filter', trans.app.model.Request.states.SUBMITTED) # Render the list view - return self.request_grid( trans, template='/admin/requests/grid.mako', **kwargs ) + return self.request_grid( trans, **kwargs ) @web.expose @web.require_admin def edit(self, trans, **kwd): diff -r 19b86ccccf6f -r 36c479b93d7e lib/galaxy/web/framework/helpers/grids.py --- a/lib/galaxy/web/framework/helpers/grids.py Sun Aug 23 12:26:46 2009 -0400 +++ b/lib/galaxy/web/framework/helpers/grids.py Sun Aug 23 12:28:36 2009 -0400 @@ -14,8 +14,9 @@ title = "" exposed = True model_class = None - template = None + template = "grid.mako" columns = [] + operations = [] standard_filters = [] default_filter = None default_sort_key = None @@ -25,7 +26,6 @@ def __call__( self, trans, **kwargs ): status = kwargs.get( 'status', None ) message = kwargs.get( 'message', None ) - template = kwargs.get( 'template', None ) session = trans.sa_session # Build initial query query = self.build_initial_query( session ) @@ -77,7 +77,7 @@ else: new_kwargs[ 'id' ] = trans.security.encode_id( id ) return url_for( **new_kwargs ) - return trans.fill_template( template, + return trans.fill_template( self.template, grid=self, query=query, sort_key=sort_key, diff -r 19b86ccccf6f -r 36c479b93d7e templates/grid.mako --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/templates/grid.mako Sun Aug 23 12:28:36 2009 -0400 @@ -0,0 +1,196 @@ +<%inherit file="/base.mako"/> +<%def name="title()">${grid.title}</%def> + +%if message: + <p> + <div class="${message_type}message transient-message">${message}</div> + <div style="clear: both"></div> + </p> +%endif + +<%def name="javascripts()"> + ${parent.javascripts()} + <script type="text/javascript"> + ## TODO: generalize and move into galaxy.base.js + $(document).ready(function() { + $(".grid").each( function() { + var grid = this; + var checkboxes = $(this).find("input.grid-row-select-checkbox"); + var update = $(this).find( "span.grid-selected-count" ); + $(checkboxes).each( function() { + $(this).change( function() { + var n = $(checkboxes).filter("[checked]").size(); + update.text( n ); + }); + }) + }); + }); + ## Can this be moved into base.mako? + %if refresh_frames: + %if 'masthead' in refresh_frames: + ## Refresh masthead == user changes (backward compatibility) + if ( parent.user_changed ) { + %if trans.user: + parent.user_changed( "${trans.user.email}", ${int( app.config.is_admin_user( trans.user ) )} ); + %else: + parent.user_changed( null, false ); + %endif + } + %endif + %if 'history' in refresh_frames: + if ( parent.frames && parent.frames.galaxy_history ) { + parent.frames.galaxy_history.location.href="${h.url_for( controller='root', action='history')}"; + if ( parent.force_right_panel ) { + parent.force_right_panel( 'show' ); + } + } + %endif + %if 'tools' in refresh_frames: + if ( parent.frames && parent.frames.galaxy_tools ) { + parent.frames.galaxy_tools.location.href="${h.url_for( controller='root', action='tool_menu')}"; + if ( parent.force_left_panel ) { + parent.force_left_panel( 'show' ); + } + } + %endif + %endif + </script> +</%def> + +<%def name="stylesheets()"> + <link href="${h.url_for('/static/style/base.css')}" rel="stylesheet" type="text/css" /> + <style> + ## Not generic to all grids -- move to base? + .count-box { + min-width: 1.1em; + padding: 5px; + border-width: 1px; + border-style: solid; + text-align: center; + display: inline-block; + } + </style> +</%def> + +<div class="grid-header"> + <h2>${grid.title}</h2> + %if grid.standard_filters: + <span class="title">Filter:</span> + %for i, filter in enumerate( grid.standard_filters ): + %if i > 0: + <span>|</span> + %endif + <span class="filter"><a href="${url( filter.get_url_args() )}">${filter.label}</a></span> + %endfor + %endif +</div> + + +<form action="${url()}" method="post" > + <table class="grid"> + <thead> + <tr> + <th></th> + %for column in grid.columns: + %if column.visible: + <% + href = "" + extra = "" + if column.sortable: + if sort_key == column.key: + if sort_order == "asc": + href = url( sort=( "-" + column.key ) ) + extra = "↓" + else: + href = url( sort=( column.key ) ) + extra = "↑" + else: + href = url( sort=column.key ) + %> + <th\ + %if column.ncells > 1: + colspan="${column.ncells}" + %endif + > + %if href: + <a href="${href}">${column.label}</a> + %else: + ${column.label} + %endif + <span>${extra}</span> + </th> + %endif + %endfor + <th></th> + </tr> + </thead> + <tbody> + %for i, item in enumerate( query ): + <tr \ + %if current_item == item: + class="current" \ + %endif + > + ## Item selection column + <td style="width: 1.5em;"> + <input type="checkbox" name="id" value=${trans.security.encode_id( item.id )} class="grid-row-select-checkbox" /> + </td> + ## Data columns + %for column in grid.columns: + %if column.visible: + <% + # Link + link = column.get_link( trans, grid, item ) + if link: + href = url( **link ) + else: + href = None + # Value (coerced to list so we can loop) + value = column.get_value( trans, grid, item ) + if column.ncells == 1: + value = [ value ] + %> + %for cellnum, v in enumerate( value ): + <% + # Attach popup menu? + if column.attach_popup and cellnum == 0: + extra = '<a id="grid-%d-popup" class="arrow" style="display: none;"><span>▼</span></a>' % i + else: + extra = "" + %> + %if href: + <td><div class="menubutton split"><a class="label" href="${href}">${v}${extra}</a></td> + %else: + <td >${v}${extra}</td> + %endif + %endfor + %endif + %endfor + ## Actions column + <td> + <div popupmenu="grid-${i}-popup"> + %for operation in grid.operations: + %if operation.allowed( item ): + <a class="action-button" href="${url( operation=operation.label, id=item.id )}">${operation.label}</a> + %endif + %endfor + </div> + </td> + </tr> + %endfor + </tbody> + <tfoot> + <tr> + <td></td> + <td colspan="100"> + For <span class="grid-selected-count"></span> selected items: + %for operation in grid.operations: + %if operation.allow_multiple: + <input type="submit" name="operation" value="${operation.label}" class="action-button"> + %endif + %endfor + </td> + </tr> + </tfoot> + </table> +</form>
participants (1)
-
Greg Von Kuster