~ubuntu-branches/ubuntu/raring/horizon/raring

« back to all changes in this revision

Viewing changes to debian/patches/CVE-2012-2144.patch

  • Committer: Package Import Robot
  • Author(s): Chuck Short
  • Date: 2012-05-24 14:33:20 UTC
  • mfrom: (1.1.14)
  • Revision ID: package-import@ubuntu.com-20120524143320-i7eswfq6ecxlvh5a
Tags: 2012.2~f1-0ubuntu1
* New usptream release. 
* Prepare for quantal:
  - debian/patches/fix-coverage-binary-name.patch: Refreshed.
* Temporarily pass the testsuite.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
Origin: upstream, abc532fa90eac1cc970423339347e318aa8d1b1a
2
 
Description: Horizon session fixation and reuse
3
 
 https://lists.launchpad.net/openstack/msg11263.html
4
 
Bug: https://bugs.launchpad.net/horizon/+bug/978896
5
 
 
6
 
Index: horizon-2012.1/horizon/exceptions.py
7
 
===================================================================
8
 
--- horizon-2012.1.orig/horizon/exceptions.py   2012-05-05 07:19:50.000000000 -0500
9
 
+++ horizon-2012.1/horizon/exceptions.py        2012-05-05 07:20:36.000000000 -0500
10
 
@@ -203,7 +203,7 @@
11
 
     if issubclass(exc_type, UNAUTHORIZED):
12
 
         if ignore:
13
 
             return NotAuthorized
14
 
-        request.session.clear()
15
 
+        request.user_logout()
16
 
         if not handled:
17
 
             LOG.debug("Unauthorized: %s" % exc_value)
18
 
             # We get some pretty useless error messages back from
19
 
Index: horizon-2012.1/horizon/middleware.py
20
 
===================================================================
21
 
--- horizon-2012.1.orig/horizon/middleware.py   2012-05-05 07:19:50.000000000 -0500
22
 
+++ horizon-2012.1/horizon/middleware.py        2012-05-05 07:20:36.000000000 -0500
23
 
@@ -49,6 +49,15 @@
24
 
 
25
 
         Adds a :class:`~horizon.users.User` object to ``request.user``.
26
 
         """
27
 
+        # A quick and dirty way to log users out
28
 
+        def user_logout(request):
29
 
+            if hasattr(request, '_cached_user'):
30
 
+                del request._cached_user
31
 
+            # Use flush instead of clear, so we rotate session keys in
32
 
+            # addition to clearing all the session data
33
 
+            request.session.flush()
34
 
+        request.__class__.user_logout = user_logout
35
 
+
36
 
         request.__class__.user = users.LazyUser()
37
 
         request.horizon = {'dashboard': None, 'panel': None}
38
 
 
39
 
Index: horizon-2012.1/horizon/tests/auth_tests.py
40
 
===================================================================
41
 
--- horizon-2012.1.orig/horizon/tests/auth_tests.py     2012-05-05 07:19:50.000000000 -0500
42
 
+++ horizon-2012.1/horizon/tests/auth_tests.py  2012-05-05 07:20:36.000000000 -0500
43
 
@@ -18,6 +18,8 @@
44
 
 #    License for the specific language governing permissions and limitations
45
 
 #    under the License.
46
 
 
47
 
+import time
48
 
+
49
 
 from django import http
50
 
 from django.core.urlresolvers import reverse
51
 
 from keystoneclient import exceptions as keystone_exceptions
52
 
@@ -220,3 +222,53 @@
53
 
 
54
 
         self.assertRedirectsNoFollow(res, reverse('splash'))
55
 
         self.assertNotIn(KEY, self.client.session)
56
 
+
57
 
+    def test_session_fixation(self):
58
 
+        session_ids = []
59
 
+        form_data = {'method': 'Login',
60
 
+                     'region': 'http://localhost:5000/v2.0',
61
 
+                     'password': self.user.password,
62
 
+                     'username': self.user.name}
63
 
+
64
 
+        self.mox.StubOutWithMock(api, 'token_create')
65
 
+        self.mox.StubOutWithMock(api, 'tenant_list_for_token')
66
 
+        self.mox.StubOutWithMock(api, 'token_create_scoped')
67
 
+
68
 
+        aToken = self.tokens.unscoped_token
69
 
+        bToken = self.tokens.scoped_token
70
 
+
71
 
+        api.token_create(IsA(http.HttpRequest), "", self.user.name,
72
 
+                         self.user.password).AndReturn(aToken)
73
 
+        api.tenant_list_for_token(IsA(http.HttpRequest),
74
 
+                                  aToken.id).AndReturn([self.tenants.first()])
75
 
+        api.token_create_scoped(IsA(http.HttpRequest),
76
 
+                                self.tenant.id,
77
 
+                                aToken.id).AndReturn(bToken)
78
 
+
79
 
+        api.token_create(IsA(http.HttpRequest), "", self.user.name,
80
 
+                         self.user.password).AndReturn(aToken)
81
 
+        api.tenant_list_for_token(IsA(http.HttpRequest),
82
 
+                                  aToken.id).AndReturn([self.tenants.first()])
83
 
+        api.token_create_scoped(IsA(http.HttpRequest),
84
 
+                                self.tenant.id,
85
 
+                                aToken.id).AndReturn(bToken)
86
 
+        self.mox.ReplayAll()
87
 
+
88
 
+        res = self.client.get(reverse('horizon:auth_login'))
89
 
+        self.assertEqual(res.cookies.get('sessionid'), None)
90
 
+        res = self.client.post(reverse('horizon:auth_login'), form_data)
91
 
+        session_ids.append(res.cookies['sessionid'].value)
92
 
+
93
 
+        self.assertEquals(self.client.session['user_name'],
94
 
+                          self.user.name)
95
 
+        self.client.session['foobar'] = 'MY TEST VALUE'
96
 
+        res = self.client.get(reverse('horizon:auth_logout'))
97
 
+        session_ids.append(res.cookies['sessionid'].value)
98
 
+        self.assertEqual(len(self.client.session.items()), 0)
99
 
+        # Sleep for 1 second so the session values are different if
100
 
+        # using the signed_cookies backend.
101
 
+        time.sleep(1)
102
 
+        res = self.client.post(reverse('horizon:auth_login'), form_data)
103
 
+        session_ids.append(res.cookies['sessionid'].value)
104
 
+        # Make sure all 3 session id values are different
105
 
+        self.assertEqual(len(session_ids), len(set(session_ids)))
106
 
Index: horizon-2012.1/horizon/users.py
107
 
===================================================================
108
 
--- horizon-2012.1.orig/horizon/users.py        2012-05-05 07:19:50.000000000 -0500
109
 
+++ horizon-2012.1/horizon/users.py     2012-05-05 07:20:36.000000000 -0500
110
 
@@ -59,7 +59,7 @@
111
 
         # If any of those keys are missing from the session it is
112
 
         # overwhelmingly likely that we're dealing with an outdated session.
113
 
         LOG.exception("Error while creating User from session.")
114
 
-        request.session.clear()
115
 
+        request.user_logout()
116
 
         raise exceptions.NotAuthorized(_("Your session has expired. "
117
 
                                          "Please log in again."))
118
 
 
119
 
Index: horizon-2012.1/horizon/views/auth.py
120
 
===================================================================
121
 
--- horizon-2012.1.orig/horizon/views/auth.py   2012-05-05 07:19:50.000000000 -0500
122
 
+++ horizon-2012.1/horizon/views/auth.py        2012-05-05 07:20:36.000000000 -0500
123
 
@@ -96,6 +96,6 @@
124
 
 
125
 
 def logout(request):
126
 
     """ Clears the session and logs the current user out. """
127
 
-    request.session.clear()
128
 
+    request.user_logout()
129
 
     # FIXME(gabriel): we don't ship a view named splash
130
 
     return shortcuts.redirect('splash')
131
 
Index: horizon-2012.1/horizon/views/auth_forms.py
132
 
===================================================================
133
 
--- horizon-2012.1.orig/horizon/views/auth_forms.py     2012-05-05 07:19:50.000000000 -0500
134
 
+++ horizon-2012.1/horizon/views/auth_forms.py  2012-05-05 07:20:36.000000000 -0500
135
 
@@ -77,6 +77,16 @@
136
 
             self.fields['region'].widget = forms.widgets.HiddenInput()
137
 
 
138
 
     def handle(self, request, data):
139
 
+        if 'user_name' in request.session:
140
 
+            if request.session['user_name'] != data['username']:
141
 
+                # To avoid reusing another user's session, create a
142
 
+                # new, empty session if the existing session
143
 
+                # corresponds to a different authenticated user.
144
 
+                request.session.flush()
145
 
+        # Always cycle the session key when viewing the login form to
146
 
+        # prevent session fixation
147
 
+        request.session.cycle_key()
148
 
+
149
 
         # For now we'll allow fallback to OPENSTACK_KEYSTONE_URL if the
150
 
         # form post doesn't include a region.
151
 
         endpoint = data.get('region', None) or settings.OPENSTACK_KEYSTONE_URL
152
 
@@ -116,7 +126,7 @@
153
 
                 # If we get here we don't want to show a stack trace to the
154
 
                 # user. However, if we fail here, there may be bad session
155
 
                 # data that's been cached already.
156
 
-                request.session.clear()
157
 
+                request.user_logout()
158
 
                 exceptions.handle(request,
159
 
                                   message=_("An error occurred authenticating."
160
 
                                             " Please try again later."),