~brad-marshall/charms/trusty/apache2-wsgi/fix-haproxy-relations

« back to all changes in this revision

Viewing changes to hooks/lib/jinja2/testsuite/security.py

  • Committer: Robin Winslow
  • Date: 2014-05-27 14:00:44 UTC
  • Revision ID: robin.winslow@canonical.com-20140527140044-8rpmb3wx4djzwa83
Add all files

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
"""
 
3
    jinja2.testsuite.security
 
4
    ~~~~~~~~~~~~~~~~~~~~~~~~~
 
5
 
 
6
    Checks the sandbox and other security features.
 
7
 
 
8
    :copyright: (c) 2010 by the Jinja Team.
 
9
    :license: BSD, see LICENSE for more details.
 
10
"""
 
11
import unittest
 
12
 
 
13
from jinja2.testsuite import JinjaTestCase
 
14
 
 
15
from jinja2 import Environment
 
16
from jinja2.sandbox import SandboxedEnvironment, \
 
17
     ImmutableSandboxedEnvironment, unsafe
 
18
from jinja2 import Markup, escape
 
19
from jinja2.exceptions import SecurityError, TemplateSyntaxError, \
 
20
     TemplateRuntimeError
 
21
from jinja2._compat import text_type
 
22
 
 
23
 
 
24
class PrivateStuff(object):
 
25
 
 
26
    def bar(self):
 
27
        return 23
 
28
 
 
29
    @unsafe
 
30
    def foo(self):
 
31
        return 42
 
32
 
 
33
    def __repr__(self):
 
34
        return 'PrivateStuff'
 
35
 
 
36
 
 
37
class PublicStuff(object):
 
38
    bar = lambda self: 23
 
39
    _foo = lambda self: 42
 
40
 
 
41
    def __repr__(self):
 
42
        return 'PublicStuff'
 
43
 
 
44
 
 
45
class SandboxTestCase(JinjaTestCase):
 
46
 
 
47
    def test_unsafe(self):
 
48
        env = SandboxedEnvironment()
 
49
        self.assert_raises(SecurityError, env.from_string("{{ foo.foo() }}").render,
 
50
                           foo=PrivateStuff())
 
51
        self.assert_equal(env.from_string("{{ foo.bar() }}").render(foo=PrivateStuff()), '23')
 
52
 
 
53
        self.assert_raises(SecurityError, env.from_string("{{ foo._foo() }}").render,
 
54
                           foo=PublicStuff())
 
55
        self.assert_equal(env.from_string("{{ foo.bar() }}").render(foo=PublicStuff()), '23')
 
56
        self.assert_equal(env.from_string("{{ foo.__class__ }}").render(foo=42), '')
 
57
        self.assert_equal(env.from_string("{{ foo.func_code }}").render(foo=lambda:None), '')
 
58
        # security error comes from __class__ already.
 
59
        self.assert_raises(SecurityError, env.from_string(
 
60
            "{{ foo.__class__.__subclasses__() }}").render, foo=42)
 
61
 
 
62
    def test_immutable_environment(self):
 
63
        env = ImmutableSandboxedEnvironment()
 
64
        self.assert_raises(SecurityError, env.from_string(
 
65
            '{{ [].append(23) }}').render)
 
66
        self.assert_raises(SecurityError, env.from_string(
 
67
            '{{ {1:2}.clear() }}').render)
 
68
 
 
69
    def test_restricted(self):
 
70
        env = SandboxedEnvironment()
 
71
        self.assert_raises(TemplateSyntaxError, env.from_string,
 
72
                      "{% for item.attribute in seq %}...{% endfor %}")
 
73
        self.assert_raises(TemplateSyntaxError, env.from_string,
 
74
                      "{% for foo, bar.baz in seq %}...{% endfor %}")
 
75
 
 
76
    def test_markup_operations(self):
 
77
        # adding two strings should escape the unsafe one
 
78
        unsafe = '<script type="application/x-some-script">alert("foo");</script>'
 
79
        safe = Markup('<em>username</em>')
 
80
        assert unsafe + safe == text_type(escape(unsafe)) + text_type(safe)
 
81
 
 
82
        # string interpolations are safe to use too
 
83
        assert Markup('<em>%s</em>') % '<bad user>' == \
 
84
               '<em>&lt;bad user&gt;</em>'
 
85
        assert Markup('<em>%(username)s</em>') % {
 
86
            'username': '<bad user>'
 
87
        } == '<em>&lt;bad user&gt;</em>'
 
88
 
 
89
        # an escaped object is markup too
 
90
        assert type(Markup('foo') + 'bar') is Markup
 
91
 
 
92
        # and it implements __html__ by returning itself
 
93
        x = Markup("foo")
 
94
        assert x.__html__() is x
 
95
 
 
96
        # it also knows how to treat __html__ objects
 
97
        class Foo(object):
 
98
            def __html__(self):
 
99
                return '<em>awesome</em>'
 
100
            def __unicode__(self):
 
101
                return 'awesome'
 
102
        assert Markup(Foo()) == '<em>awesome</em>'
 
103
        assert Markup('<strong>%s</strong>') % Foo() == \
 
104
               '<strong><em>awesome</em></strong>'
 
105
 
 
106
        # escaping and unescaping
 
107
        assert escape('"<>&\'') == '&#34;&lt;&gt;&amp;&#39;'
 
108
        assert Markup("<em>Foo &amp; Bar</em>").striptags() == "Foo & Bar"
 
109
        assert Markup("&lt;test&gt;").unescape() == "<test>"
 
110
 
 
111
    def test_template_data(self):
 
112
        env = Environment(autoescape=True)
 
113
        t = env.from_string('{% macro say_hello(name) %}'
 
114
                            '<p>Hello {{ name }}!</p>{% endmacro %}'
 
115
                            '{{ say_hello("<blink>foo</blink>") }}')
 
116
        escaped_out = '<p>Hello &lt;blink&gt;foo&lt;/blink&gt;!</p>'
 
117
        assert t.render() == escaped_out
 
118
        assert text_type(t.module) == escaped_out
 
119
        assert escape(t.module) == escaped_out
 
120
        assert t.module.say_hello('<blink>foo</blink>') == escaped_out
 
121
        assert escape(t.module.say_hello('<blink>foo</blink>')) == escaped_out
 
122
 
 
123
    def test_attr_filter(self):
 
124
        env = SandboxedEnvironment()
 
125
        tmpl = env.from_string('{{ cls|attr("__subclasses__")() }}')
 
126
        self.assert_raises(SecurityError, tmpl.render, cls=int)
 
127
 
 
128
    def test_binary_operator_intercepting(self):
 
129
        def disable_op(left, right):
 
130
            raise TemplateRuntimeError('that operator so does not work')
 
131
        for expr, ctx, rv in ('1 + 2', {}, '3'), ('a + 2', {'a': 2}, '4'):
 
132
            env = SandboxedEnvironment()
 
133
            env.binop_table['+'] = disable_op
 
134
            t = env.from_string('{{ %s }}' % expr)
 
135
            assert t.render(ctx) == rv
 
136
            env.intercepted_binops = frozenset(['+'])
 
137
            t = env.from_string('{{ %s }}' % expr)
 
138
            try:
 
139
                t.render(ctx)
 
140
            except TemplateRuntimeError as e:
 
141
                pass
 
142
            else:
 
143
                self.fail('expected runtime error')
 
144
 
 
145
    def test_unary_operator_intercepting(self):
 
146
        def disable_op(arg):
 
147
            raise TemplateRuntimeError('that operator so does not work')
 
148
        for expr, ctx, rv in ('-1', {}, '-1'), ('-a', {'a': 2}, '-2'):
 
149
            env = SandboxedEnvironment()
 
150
            env.unop_table['-'] = disable_op
 
151
            t = env.from_string('{{ %s }}' % expr)
 
152
            assert t.render(ctx) == rv
 
153
            env.intercepted_unops = frozenset(['-'])
 
154
            t = env.from_string('{{ %s }}' % expr)
 
155
            try:
 
156
                t.render(ctx)
 
157
            except TemplateRuntimeError as e:
 
158
                pass
 
159
            else:
 
160
                self.fail('expected runtime error')
 
161
 
 
162
 
 
163
def suite():
 
164
    suite = unittest.TestSuite()
 
165
    suite.addTest(unittest.makeSuite(SandboxTestCase))
 
166
    return suite