-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Possibility of Open Redirect #13
Conversation
@@ -72,7 +73,7 @@ def logout(request, next_page=None, template_name='registration/logged_out.html' | |||
redirect_to = request.POST.get(redirect_field_name, getattr(settings, 'LOGOUT_REDIRECT_URL', '')) | |||
else: | |||
redirect_to = request.GET.get(redirect_field_name, getattr(settings, 'LOGOUT_REDIRECT_URL', '')) | |||
if redirect_to: | |||
if redirect_to and is_safe_url(redirect_to): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- ログアウト時のリダイレクト先が安全かを確認します。(ログアウト時のリダイレクトは、URLクエリで受け取れるため信用できない)
@@ -28,7 +30,7 @@ def test_login(self): | |||
'password': 'password', | |||
}) | |||
self.assertEquals(response.status_code, 302) | |||
self.assert_(response['Location'].endswith(settings.LOGIN_REDIRECT_URL)) | |||
self.assertTrue(response['Location'].endswith(settings.LOGIN_REDIRECT_URL)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- 非推奨のメソッドを使っていたので推奨のメソッドに差し替え。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@@ -58,41 +60,122 @@ def test_fail_login_blank_fields(self): | |||
def test_bad_redirect_space(self): | |||
bad_next_url = 'test space url' | |||
self.assertContains(self.client.get('/account/login/'), '<form') | |||
response = self.client.post('/account/login/?%s=%s' % (REDIRECT_FIELD_NAME, quote(bad_next_url)), { | |||
response = self.client.post('/account/login/', { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- redirectは、HTTP POSTパラメータで渡さないと読まれず、ただしくテストできてなかったので、テスト修正
- https://github.com/beproud/django-newauth/blob/master/newauth/views.py#L53
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
tests/test_views.py
Outdated
self.assertTrue(response['Location'].endswith(ok_url)) | ||
|
||
@pytest.mark.django_db | ||
class LogoutViewsTest(DjangoTestCase): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- ログアウト時のOpenRedirect用ユニットテストを追加するついでに、通常のlogout viewのテストも追加
tests/test_views.py
Outdated
import pytest | ||
from django.utils.six.moves.urllib_parse import quote | ||
from django.test import TestCase as DjangoTestCase | ||
from django.contrib.auth import REDIRECT_FIELD_NAME | ||
from django.conf import settings | ||
from django.http import HttpResponse | ||
from django import shortcuts | ||
|
||
from testapp.models import TestBasicUser | ||
|
||
|
||
@pytest.mark.django_db |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DjangoTestCase使ってるならこのmarkはいらいないのでは
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
いらなかったので消しました。
どなたかレビューお願いします! |
tests/test_views.py
Outdated
self.assertEquals(response.status_code, 302) | ||
self.assertTrue(response['Location'].endswith('/some/url?param=http://example.com/')) | ||
|
||
def test_ok_redirect(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- 正常系がなかったため、FIXME:のテストの切り分けが難しくなったと思われた。
- 正常系のテストケースを追加した。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
軽く見れる範囲でレビューしました
tests/test_views.py
Outdated
fixtures = ['authutils_testdata.json'] | ||
|
||
def setUp(self): | ||
super(ViewsTest, self).setUp() | ||
super(LoginViewsTest, self).setUp() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[SHOULD]
- Django の TestCase の setUp で superは不要です。
Wrapper around default __call__ method to perform common Django test
set up. This means that user-defined Test Cases aren't required to
include a call to super().setUp().
refs https://github.com/django/django/blob/master/django/test/testcases.py#L192
@@ -28,7 +30,7 @@ def test_login(self): | |||
'password': 'password', | |||
}) | |||
self.assertEquals(response.status_code, 302) | |||
self.assert_(response['Location'].endswith(settings.LOGIN_REDIRECT_URL)) | |||
self.assertTrue(response['Location'].endswith(settings.LOGIN_REDIRECT_URL)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@@ -58,41 +60,122 @@ def test_fail_login_blank_fields(self): | |||
def test_bad_redirect_space(self): | |||
bad_next_url = 'test space url' | |||
self.assertContains(self.client.get('/account/login/'), '<form') | |||
response = self.client.post('/account/login/?%s=%s' % (REDIRECT_FIELD_NAME, quote(bad_next_url)), { | |||
response = self.client.post('/account/login/', { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
}) | ||
self.assertEquals(response.status_code, 302) | ||
self.assert_(response['Location'].endswith(settings.LOGIN_REDIRECT_URL)) | ||
self.assertTrue(response['Location'].endswith(settings.LOGIN_REDIRECT_URL)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[MAY] LOGIN_REDIRECT_URL を明示的に設定した方が良い?
-
settings.LOGIN_REDIRECT_URL が具体的にどんな値なのかよくわからない(多分Djangoのデフォルト値?)
-
よくわからないからテストケースが妥当なのか判別つかない
-
settings.py に定義 or override_settingsを利用して、LOGIN_REDIRECT_URLがなんなのか明示的にした方が良さそう。
-
例えば、
settings.LOGIN_REDIRECT_URL="/"
だとしたら、bad_next_url とendswith で一致してバグっててもテストが通ってしまいそう。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- settings.py に定義 & override_settingsを利用のテストケース追加
tests/test_views.py
Outdated
self.assertEquals(response.status_code, 302) | ||
self.assertTrue(response['Location'].endswith('/some/url?param=http://example.com/')) | ||
|
||
def test_ok_redirect(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
tests/test_views.py
Outdated
class LogoutViewsTest(DjangoTestCase): | ||
fixtures = ['authutils_testdata.json'] | ||
|
||
@mock.patch('newauth.views.render') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[SHOULD] mockは無くてもテストできる
- mockが必要な場面になったらmockを使う方が良いかと。
- 普通に response 受け取ってテストすれば良い。
def test_get_logout_default(self):
"""
logout with HTTP GET
default LOGOUT_render_URL settings
"""
res = self.client.get('/account/logout/')
self.assertEqual(res.status_code, 200)
tests/test_views.py
Outdated
redirect_url = 'http://example.com/path/to/resource/' | ||
self.client.get('/account/logout/?%s=%s' % (REDIRECT_FIELD_NAME, quote(redirect_url))) | ||
mock_render.assert_called() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[MAY] 可能なら next_page 引数がある場合もテストする。
- login, logout 両方の view で next_page引数が受け取れるようになってる。
- 可能であれば それらを受け取る場合の分岐もテストケースにあると良さそう。(現状そのままでは self.cleint ではテストできないから面倒だけど)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[MAY] ついでに logout_then_login のテストがあっても良い。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logout_then_login のテスト
- こちらのテストケースが該当すると思います。
- https://github.com/beproud/django-newauth/blob/master/tests/test_api.py#L114
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
next_page 引数がある場合もテスト
- こちらすぐにどうやるかわからなかったので、Issueたてて、ひとまず保留したいと思います。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
こちらのテストケースが該当すると思います。
https://github.com/beproud/django-newauth/blob/master/tests/test_api.py#L114
- 私が言ってるのは、views.pyの下の方にひっそりと存在してる
logout_then_login
というview関数の話です。
https://github.com/beproud/django-newauth/blob/master/newauth/views.py#L85-L87
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
こちらすぐにどうやるかわからなかったので、Issueたてて、ひとまず保留したいと思います。
- 良いと思います。テストを書くのであれば以下の方法が考えれます。
案A. overriede_settings で ROOT_URL_CONF を上書きする。
- https://stackoverflow.com/a/31838024/7724457
- ここの name を override_settings 突っ込むの微妙だから、別ファイルにした方が良さそう。
- テスト用のURLパターンに next_page をダイレクトに渡す。
- https://docs.djangoproject.com/en/1.11/topics/http/urls/#passing-extra-options-to-view-functions
案B. login, logout を 関数としてテストする。
- self.clientは使わずにnext_pageが渡された場合の分岐をテストする。
- request は RequestFactoryなどで作って パスする
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Issue #14
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
オープンリダイレクトの可能性があったので修正しました。取り込みをお願いします。
以下の修正が含まれています。