diff --git a/horizon/templatetags/shellfilter.py b/horizon/templatetags/shellfilter.py new file mode 100644 index 0000000000..e04592f5b3 --- /dev/null +++ b/horizon/templatetags/shellfilter.py @@ -0,0 +1,32 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from django.template import base +from django.template import defaultfilters +from django.utils import safestring + +register = base.Library() + + +@register.filter(is_safe=True) +@defaultfilters.stringfilter +def shellfilter(value): + """Replace HTML chars for shell usage.""" + replacements = {'\\': '\\\\', + '`': '\`', + "'": "\\'", + '"': '\\"'} + for search, repl in replacements.items(): + value = value.replace(search, repl) + return safestring.mark_safe(value) diff --git a/openstack_dashboard/dashboards/project/access_and_security/templates/access_and_security/api_access/openrc.sh.template b/openstack_dashboard/dashboards/project/access_and_security/templates/access_and_security/api_access/openrc.sh.template index d1733eb7fd..24bbeb7958 100644 --- a/openstack_dashboard/dashboards/project/access_and_security/templates/access_and_security/api_access/openrc.sh.template +++ b/openstack_dashboard/dashboards/project/access_and_security/templates/access_and_security/api_access/openrc.sh.template @@ -1,3 +1,4 @@ +{% load shellfilter %} #!/bin/bash # With the addition of Keystone, to use an openstack cloud you should @@ -12,11 +13,11 @@ export OS_AUTH_URL={{ auth_url }} # With the addition of Keystone we have standardized on the term **tenant** # as the entity that owns the resources. export OS_TENANT_ID={{ tenant_id }} -export OS_TENANT_NAME="{{ tenant_name }}" +export OS_TENANT_NAME="{{ tenant_name|shellfilter }}" # In addition to the owning entity (tenant), openstack stores the entity # performing the action as the **user**. -export OS_USERNAME={{ user.username }} +export OS_USERNAME="{{ user.username|shellfilter }}" # With Keystone you pass the keystone password. echo "Please enter your OpenStack Password: " diff --git a/openstack_dashboard/test/tests/templates.py b/openstack_dashboard/test/tests/templates.py new file mode 100644 index 0000000000..11942809e1 --- /dev/null +++ b/openstack_dashboard/test/tests/templates.py @@ -0,0 +1,71 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright (c) 2012 OpenStack, LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from django import template +from django.template import loader +from openstack_dashboard.test import helpers as test + + +class FakeUser(object): + username = "cool user" + + +class TemplateRenderTest(test.TestCase): + """ Tests for templates render """ + + def test_openrc_html_escape(self): + context = { + "user": FakeUser(), + "tenant_id": "some-cool-id", + "auth_url": "http://tests.com", + "tenant_name": "ENG Perf R&D"} + out = loader.render_to_string( + 'project/access_and_security/api_access/openrc.sh.template', + context, + template.Context(context)) + + self.assertFalse("&" in out) + self.assertTrue("ENG Perf R&D" in out) + + def test_openrc_html_evil_shell_escape(self): + context = { + "user": FakeUser(), + "tenant_id": "some-cool-id", + "auth_url": "http://tests.com", + "tenant_name": 'o"; sudo rm -rf /'} + out = loader.render_to_string( + 'project/access_and_security/api_access/openrc.sh.template', + context, + template.Context(context)) + + self.assertFalse('o"' in out) + self.assertTrue('\"' in out) + + def test_openrc_html_evil_shell_backslash_escape(self): + context = { + "user": FakeUser(), + "tenant_id": "some-cool-id", + "auth_url": "http://tests.com", + "tenant_name": 'o\"; sudo rm -rf /'} + out = loader.render_to_string( + 'project/access_and_security/api_access/openrc.sh.template', + context, + template.Context(context)) + + self.assertFalse('o\"' in out) + self.assertFalse('o"' in out) + self.assertTrue('\\"' in out)