components/openstack/horizon/patches/11-CVE-2014-3473-3474-3475.patch
branchs11-update
changeset 4072 db0cec748ec0
parent 4067 4be1f488dda8
child 4094 78203277f011
equal deleted inserted replaced
4067:4be1f488dda8 4072:db0cec748ec0
     1 Upstream patch fixed in Havana 2013.2.4 and Icehouse 2014.1.2
       
     2 
       
     3 From c844bd692894353c60b320005b804970605e910f Mon Sep 17 00:00:00 2001
       
     4 From: Julie Pichon <[email protected]>
       
     5 Date: Thu, 22 May 2014 16:45:03 +0100
       
     6 Subject: [PATCH] Fix multiple Cross-Site Scripting (XSS) vulnerabilities
       
     7 
       
     8  * Ensure user emails are properly escaped
       
     9 
       
    10 User emails in the Users and Groups panel are being passed through the
       
    11 urlize filter to transform them into clickable links. However, urlize
       
    12 expects input to be already escaped and safe. We should make sure to
       
    13 escape the strings first as email addresses are not validated and can
       
    14 contain any type of string.
       
    15 
       
    16 Closes-Bug: #1320235
       
    17 
       
    18  * Ensure network names are properly escaped in the Launch Instance menu
       
    19 
       
    20 Closes-Bug: #1322197
       
    21 
       
    22  * Escape the URLs generated for the Horizon tables
       
    23 
       
    24 When generating the Horizon tables, there was an assumption that only
       
    25 the anchor text needed to be escaped. However some URLs are generated
       
    26 based on user-provided data and should be escaped as well. Also escape
       
    27 the link attributes for good measure.
       
    28 
       
    29  * Use 'reverse' to generate the Resource URLs in the stacks tables
       
    30 
       
    31 Closes-Bug: #1308727
       
    32 
       
    33 Conflicts:
       
    34 	horizon/tables/base.py
       
    35 	openstack_dashboard/dashboards/admin/users/tables.py
       
    36 
       
    37 Change-Id: Ic8a92e69f66c2d265a802f350e30f091181aa42e
       
    38 ---
       
    39  horizon/static/horizon/js/horizon.instances.js     |    9 ++++++++-
       
    40  horizon/tables/base.py                             |    4 +++-
       
    41  .../dashboards/admin/groups/tables.py              |    3 ++-
       
    42  .../dashboards/admin/users/tables.py               |    3 ++-
       
    43  .../dashboards/project/stacks/tables.py            |   10 ++++++++--
       
    44  .../dashboards/project/stacks/tabs.py              |    6 ++++++
       
    45  6 files changed, 29 insertions(+), 6 deletions(-)
       
    46 
       
    47 diff --git a/horizon/static/horizon/js/horizon.instances.js b/horizon/static/horizon/js/horizon.instances.js
       
    48 index c901180..c6ff323 100644
       
    49 --- a/horizon/static/horizon/js/horizon.instances.js
       
    50 +++ b/horizon/static/horizon/js/horizon.instances.js
       
    51 @@ -51,8 +51,15 @@ horizon.instances = {
       
    52      $(this.get_network_element("")).each(function(){
       
    53        var $this = $(this);
       
    54        var $input = $this.children("input");
       
    55 +      var name = $this.text().replace(/^\s+/,"")
       
    56 +                             .replace(/&/g, '&amp;')
       
    57 +                             .replace(/</g, '&lt;')
       
    58 +                             .replace(/>/g, '&gt;')
       
    59 +                             .replace(/"/g, '&quot;')
       
    60 +                             .replace(/'/g, '&#x27;')
       
    61 +                             .replace(/\//g, '&#x2F;');
       
    62        var network_property = {
       
    63 -        name:$this.text().replace(/^\s+/,""),
       
    64 +        name:name,
       
    65          id:$input.attr("id"),
       
    66          value:$input.attr("value")
       
    67        };
       
    68 diff --git a/horizon/tables/base.py b/horizon/tables/base.py
       
    69 index adc284c..9011b77 100644
       
    70 --- a/horizon/tables/base.py
       
    71 +++ b/horizon/tables/base.py
       
    72 @@ -585,7 +585,9 @@ class Cell(html.HTMLElement):
       
    73              link_classes = ' '.join(self.column.link_classes)
       
    74              # Escape the data inside while allowing our HTML to render
       
    75              data = mark_safe('<a href="%s" class="%s">%s</a>' %
       
    76 -                             (self.url, link_classes, escape(data)))
       
    77 +                             (escape(self.url),
       
    78 +                              escape(link_classes),
       
    79 +                              escape(data)))
       
    80          return data
       
    81  
       
    82      @property
       
    83 diff --git a/openstack_dashboard/dashboards/admin/groups/tables.py b/openstack_dashboard/dashboards/admin/groups/tables.py
       
    84 index bce8f50..ff8103b 100644
       
    85 --- a/openstack_dashboard/dashboards/admin/groups/tables.py
       
    86 +++ b/openstack_dashboard/dashboards/admin/groups/tables.py
       
    87 @@ -161,7 +161,8 @@ class AddMembersLink(tables.LinkAction):
       
    88  class UsersTable(tables.DataTable):
       
    89      name = tables.Column('name', verbose_name=_('User Name'))
       
    90      email = tables.Column('email', verbose_name=_('Email'),
       
    91 -                          filters=[defaultfilters.urlize])
       
    92 +                          filters=[defaultfilters.escape,
       
    93 +                                   defaultfilters.urlize])
       
    94      id = tables.Column('id', verbose_name=_('User ID'))
       
    95      enabled = tables.Column('enabled', verbose_name=_('Enabled'),
       
    96                              status=True,
       
    97 diff --git a/openstack_dashboard/dashboards/admin/users/tables.py b/openstack_dashboard/dashboards/admin/users/tables.py
       
    98 index d47d68d..c0b0ea5 100644
       
    99 --- a/openstack_dashboard/dashboards/admin/users/tables.py
       
   100 +++ b/openstack_dashboard/dashboards/admin/users/tables.py
       
   101 @@ -117,7 +117,8 @@ class UsersTable(tables.DataTable):
       
   102      )
       
   103      name = tables.Column('name', verbose_name=_('User Name'))
       
   104      email = tables.Column('email', verbose_name=_('Email'),
       
   105 -                          filters=[defaultfilters.urlize])
       
   106 +                          filters=[defaultfilters.escape,
       
   107 +                                   defaultfilters.urlize])
       
   108      # Default tenant is not returned from Keystone currently.
       
   109      #default_tenant = tables.Column('default_tenant',
       
   110      #                               verbose_name=_('Default Project'))
       
   111 diff --git a/openstack_dashboard/dashboards/project/stacks/tables.py b/openstack_dashboard/dashboards/project/stacks/tables.py
       
   112 index f0bc731..822726b 100644
       
   113 --- a/openstack_dashboard/dashboards/project/stacks/tables.py
       
   114 +++ b/openstack_dashboard/dashboards/project/stacks/tables.py
       
   115 @@ -12,6 +12,7 @@
       
   116  # License for the specific language governing permissions and limitations
       
   117  # under the License.
       
   118  
       
   119 +from django.core import urlresolvers
       
   120  from django.http import Http404  # noqa
       
   121  from django.template.defaultfilters import timesince  # noqa
       
   122  from django.template.defaultfilters import title  # noqa
       
   123 @@ -94,11 +95,16 @@ class StacksTable(tables.DataTable):
       
   124          row_actions = (DeleteStack, )
       
   125  
       
   126  
       
   127 +def get_resource_url(obj):
       
   128 +    return urlresolvers.reverse('horizon:project:stacks:resource',
       
   129 +                                args=(obj.stack_id, obj.resource_name))
       
   130 +
       
   131 +
       
   132  class EventsTable(tables.DataTable):
       
   133  
       
   134      logical_resource = tables.Column('resource_name',
       
   135                                       verbose_name=_("Stack Resource"),
       
   136 -                                     link=lambda d: d.resource_name,)
       
   137 +                                     link=get_resource_url)
       
   138      physical_resource = tables.Column('physical_resource_id',
       
   139                                        verbose_name=_("Resource"),
       
   140                                        link=mappings.resource_to_url)
       
   141 @@ -142,7 +148,7 @@ class ResourcesTable(tables.DataTable):
       
   142  
       
   143      logical_resource = tables.Column('resource_name',
       
   144                                       verbose_name=_("Stack Resource"),
       
   145 -                                     link=lambda d: d.resource_name)
       
   146 +                                     link=get_resource_url)
       
   147      physical_resource = tables.Column('physical_resource_id',
       
   148                                       verbose_name=_("Resource"),
       
   149                                       link=mappings.resource_to_url)
       
   150 diff --git a/openstack_dashboard/dashboards/project/stacks/tabs.py b/openstack_dashboard/dashboards/project/stacks/tabs.py
       
   151 index 15ef833..b5886f3 100644
       
   152 --- a/openstack_dashboard/dashboards/project/stacks/tabs.py
       
   153 +++ b/openstack_dashboard/dashboards/project/stacks/tabs.py
       
   154 @@ -75,6 +75,9 @@ class StackEventsTab(tabs.Tab):
       
   155              stack_identifier = '%s/%s' % (stack.stack_name, stack.id)
       
   156              events = api.heat.events_list(self.request, stack_identifier)
       
   157              LOG.debug('got events %s' % events)
       
   158 +            # The stack id is needed to generate the resource URL.
       
   159 +            for event in events:
       
   160 +                event.stack_id = stack.id
       
   161          except Exception:
       
   162              events = []
       
   163              messages.error(request, _(
       
   164 @@ -95,6 +98,9 @@ class StackResourcesTab(tabs.Tab):
       
   165              stack_identifier = '%s/%s' % (stack.stack_name, stack.id)
       
   166              resources = api.heat.resources_list(self.request, stack_identifier)
       
   167              LOG.debug('got resources %s' % resources)
       
   168 +            # The stack id is needed to generate the resource URL.
       
   169 +            for r in resources:
       
   170 +                r.stack_id = stack.id
       
   171          except Exception:
       
   172              resources = []
       
   173              messages.error(request, _(
       
   174 -- 
       
   175 1.7.9.5