Skip to content

Commit

Permalink
Fix open redirect
Browse files Browse the repository at this point in the history
Make sure the "next" URL is in the same origin as Horizon before
redirecting to it.

Conflicts:
	horizon/test/unit/workflows/test_workflows.py

Change-Id: I06b2bfc8e3638591615547780c3fa34b0abe19f6
Closes-bug: #1865026
(cherry picked from commit 2524671)
(cherry picked from commit baa370f)
  • Loading branch information
deshipu authored and amotoki committed Oct 19, 2020
1 parent dd8943b commit 6c208ed
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 3 deletions.
26 changes: 25 additions & 1 deletion horizon/test/unit/workflows/test_workflows.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@

from django import forms
from django import http
from django.test.utils import override_settings
import mock

import six

from horizon import base
Expand Down Expand Up @@ -401,3 +401,27 @@ def test_entry_point(self):

flow = TestWorkflow(req, entry_point="test_action_two")
self.assertEqual("test_action_two", flow.get_entry_point())

@override_settings(ALLOWED_HOSTS=['localhost'])
def test_redirect_url_safe(self):
url = 'http://localhost/test'
view = TestWorkflowView()
request = self.factory.get("/", data={
'next': url,
})
request.META['SERVER_NAME'] = "localhost"
view.request = request
context = view.get_context_data()
self.assertEqual(url, context['REDIRECT_URL'])

@override_settings(ALLOWED_HOSTS=['localhost'])
def test_redirect_url_unsafe(self):
url = 'http://evilcorp/test'
view = TestWorkflowView()
request = self.factory.get("/", data={
'next': url,
})
request.META['SERVER_NAME'] = "localhost"
view.request = request
context = view.get_context_data()
self.assertIsNone(context['REDIRECT_URL'])
12 changes: 10 additions & 2 deletions horizon/workflows/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from django import forms
from django import http
from django import shortcuts
from django.utils import http as utils_http
from django.views import generic

import six
Expand Down Expand Up @@ -92,8 +93,15 @@ def get_context_data(self, **kwargs):
workflow = self.get_workflow()
workflow.verify_integrity()
context[self.context_object_name] = workflow
next = self.request.GET.get(workflow.redirect_param_name)
context['REDIRECT_URL'] = next

redirect_to = self.request.GET.get(workflow.redirect_param_name)
# Make sure the requested redirect is safe
if redirect_to and not utils_http.is_safe_url(
url=redirect_to,
allowed_hosts=[self.request.get_host()]):
redirect_to = None
context['REDIRECT_URL'] = redirect_to

context['layout'] = self.get_layout()
# For consistency with Workflow class
context['modal'] = 'modal' in context['layout']
Expand Down
7 changes: 7 additions & 0 deletions releasenotes/notes/bug-cd9099c1ba78d637.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
security:
- |
An open redirect has been fixed, that could redirect users to arbitrary
addresses from certain views by specifying a "next" parameter in the URL.
Now the redirect will only work if the target URL is in the same domain,
and uses the same protocol.

0 comments on commit 6c208ed

Please sign in to comment.