Skip to content

Commit f344b06

Browse files
authored
Disable 255 chars length limit for redirect uri (#902) (#903)
* Disable 255 chars length limit for redirect uri (#902) RFC 7230 recommends to design system to be capable to work with URI at least to 8000 chars long. This commit allows handle redirect_uri that is over 255 chars.
1 parent 86e78b9 commit f344b06

File tree

5 files changed

+64
-13
lines changed

5 files changed

+64
-13
lines changed

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Jens Timmerman
2626
Jerome Leclanche
2727
Jim Graham
2828
Paul Oswald
29+
Pavel Tvrdík
2930
pySilver
3031
Rodney Richardson
3132
Silvano Cerza

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1717
## [unreleased]
1818

1919
* #898 Added the ability to customize classes for django admin
20+
* #903 Disable `redirect_uri` field length limit for `AbstractGrant`
2021

2122
### Added
2223
* #884 Added support for Python 3.9
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 3.1.4 on 2020-12-11 13:14
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('oauth2_provider', '0002_auto_20190406_1805'),
10+
]
11+
12+
operations = [
13+
migrations.AlterField(
14+
model_name='grant',
15+
name='redirect_uri',
16+
field=models.TextField(),
17+
),
18+
]

oauth2_provider/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ class AbstractGrant(models.Model):
220220
code = models.CharField(max_length=255, unique=True) # code comes from oauthlib
221221
application = models.ForeignKey(oauth2_settings.APPLICATION_MODEL, on_delete=models.CASCADE)
222222
expires = models.DateTimeField()
223-
redirect_uri = models.CharField(max_length=255)
223+
redirect_uri = models.TextField()
224224
scope = models.TextField(blank=True)
225225

226226
created = models.DateTimeField(auto_now_add=True)

tests/test_models.py

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,15 @@
2222
UserModel = get_user_model()
2323

2424

25-
class TestModels(TestCase):
25+
class BaseTestModels(TestCase):
2626
def setUp(self):
2727
self.user = UserModel.objects.create_user("test_user", "[email protected]", "123456")
2828

29+
def tearDown(self):
30+
self.user.delete()
31+
32+
33+
class TestModels(BaseTestModels):
2934
def test_allow_scopes(self):
3035
self.client.login(username="test_user", password="123456")
3136
app = Application.objects.create(
@@ -103,10 +108,7 @@ def test_scopes_property(self):
103108
OAUTH2_PROVIDER_REFRESH_TOKEN_MODEL="tests.SampleRefreshToken",
104109
OAUTH2_PROVIDER_GRANT_MODEL="tests.SampleGrant",
105110
)
106-
class TestCustomModels(TestCase):
107-
def setUp(self):
108-
self.user = UserModel.objects.create_user("test_user", "[email protected]", "123456")
109-
111+
class TestCustomModels(BaseTestModels):
110112
def test_custom_application_model(self):
111113
"""
112114
If a custom application model is installed, it should be present in
@@ -237,7 +239,21 @@ def test_custom_grant_model_not_installed(self):
237239
oauth2_settings.GRANT_MODEL = "oauth2_provider.Grant"
238240

239241

240-
class TestGrantModel(TestCase):
242+
class TestGrantModel(BaseTestModels):
243+
def setUp(self):
244+
super().setUp()
245+
self.application = Application.objects.create(
246+
name="Test Application",
247+
redirect_uris="",
248+
user=self.user,
249+
client_type=Application.CLIENT_CONFIDENTIAL,
250+
authorization_grant_type=Application.GRANT_AUTHORIZATION_CODE,
251+
)
252+
253+
def tearDown(self):
254+
self.application.delete()
255+
super().tearDown()
256+
241257
def test_str(self):
242258
grant = Grant(code="test_code")
243259
self.assertEqual("%s" % grant, grant.code)
@@ -247,11 +263,26 @@ def test_expires_can_be_none(self):
247263
self.assertIsNone(grant.expires)
248264
self.assertTrue(grant.is_expired())
249265

266+
def test_redirect_uri_can_be_longer_than_255_chars(self):
267+
long_redirect_uri = "http://example.com/{}".format("authorized/" * 25)
268+
self.assertTrue(len(long_redirect_uri) > 255)
269+
grant = Grant.objects.create(
270+
user=self.user,
271+
code="test_code",
272+
application=self.application,
273+
expires=timezone.now(),
274+
redirect_uri=long_redirect_uri,
275+
scope="",
276+
)
277+
grant.refresh_from_db()
278+
279+
# It would be necessary to run test using another DB engine than sqlite
280+
# that transform varchar(255) into text data type.
281+
# https://sqlite.org/datatype3.html#affinity_name_examples
282+
self.assertEqual(grant.redirect_uri, long_redirect_uri)
250283

251-
class TestAccessTokenModel(TestCase):
252-
def setUp(self):
253-
self.user = UserModel.objects.create_user("test_user", "[email protected]", "123456")
254284

285+
class TestAccessTokenModel(BaseTestModels):
255286
def test_str(self):
256287
access_token = AccessToken(token="test_token")
257288
self.assertEqual("%s" % access_token, access_token.token)
@@ -273,15 +304,15 @@ def test_expires_can_be_none(self):
273304
self.assertTrue(access_token.is_expired())
274305

275306

276-
class TestRefreshTokenModel(TestCase):
307+
class TestRefreshTokenModel(BaseTestModels):
277308
def test_str(self):
278309
refresh_token = RefreshToken(token="test_token")
279310
self.assertEqual("%s" % refresh_token, refresh_token.token)
280311

281312

282-
class TestClearExpired(TestCase):
313+
class TestClearExpired(BaseTestModels):
283314
def setUp(self):
284-
self.user = UserModel.objects.create_user("test_user", "[email protected]", "123456")
315+
super().setUp()
285316
# Insert two tokens on database.
286317
app = Application.objects.create(
287318
name="test_app",

0 commit comments

Comments
 (0)