diff --git a/AUTHORS b/AUTHORS index fa3820f64..0c46746e7 100644 --- a/AUTHORS +++ b/AUTHORS @@ -45,6 +45,7 @@ Jesse Gibbs Jim Graham Jonas Nygaard Pedersen Jonathan Steffan +Joseph Abrahams Jozef Knaperek Julien Palard Jun Zhou diff --git a/oauth2_provider/migrations/0006_alter_application_client_secret.py b/oauth2_provider/migrations/0006_alter_application_client_secret.py index 88e148274..c63c08bb2 100644 --- a/oauth2_provider/migrations/0006_alter_application_client_secret.py +++ b/oauth2_provider/migrations/0006_alter_application_client_secret.py @@ -1,6 +1,5 @@ from django.db import migrations -from django.contrib.auth.hashers import identify_hasher, make_password -import logging +from oauth2_provider import settings import oauth2_provider.generators import oauth2_provider.models @@ -9,8 +8,8 @@ def forwards_func(apps, schema_editor): """ Forward migration touches every application.client_secret which will cause it to be hashed if not already the case. """ - Application = apps.get_model('oauth2_provider', 'application') - applications = Application.objects.all() + Application = apps.get_model(settings.APPLICATION_MODEL) + applications = Application._default_manager.all() for application in applications: application.save(update_fields=['client_secret']) diff --git a/tests/migrations/0001_initial.py b/tests/migrations/0001_initial.py index 8903a5a96..4baa18a57 100644 --- a/tests/migrations/0001_initial.py +++ b/tests/migrations/0001_initial.py @@ -1,9 +1,6 @@ -# Generated by Django 2.2.6 on 2019-10-24 20:21 +# Generated by Django 4.0.4 on 2022-05-27 21:07 -from django.conf import settings from django.db import migrations, models -import django.db.models.deletion -import oauth2_provider.generators class Migration(migrations.Migration): @@ -11,112 +8,41 @@ class Migration(migrations.Migration): initial = True dependencies = [ - migrations.swappable_dependency(settings.OAUTH2_PROVIDER_APPLICATION_MODEL), - migrations.swappable_dependency(settings.OAUTH2_PROVIDER_ACCESS_TOKEN_MODEL), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - migrations.swappable_dependency(settings.OAUTH2_PROVIDER_REFRESH_TOKEN_MODEL), + ] + + run_before = [ + ('oauth2_provider', '0001_initial'), ] operations = [ migrations.CreateModel( - name='SampleGrant', + name='BaseTestApplication', fields=[ - ('id', models.BigAutoField(primary_key=True, serialize=False)), - ('code', models.CharField(max_length=255, unique=True)), - ('expires', models.DateTimeField()), - ('redirect_uri', models.CharField(max_length=255)), - ('scope', models.TextField(blank=True)), - ('created', models.DateTimeField(auto_now_add=True)), - ('updated', models.DateTimeField(auto_now=True)), - ('code_challenge', models.CharField(blank=True, default='', max_length=128)), - ('code_challenge_method', models.CharField(blank=True, choices=[('plain', 'plain'), ('S256', 'S256')], default='', max_length=10)), - ('custom_field', models.CharField(max_length=255)), - ('application', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.OAUTH2_PROVIDER_APPLICATION_MODEL)), - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tests_samplegrant', to=settings.AUTH_USER_MODEL)), - ("nonce", models.CharField(blank=True, max_length=255, default="")), - ("claims", models.TextField(blank=True)), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ], - options={ - 'abstract': False, - }, ), migrations.CreateModel( - name='SampleApplication', + name='SampleAccessToken', fields=[ - ('id', models.BigAutoField(primary_key=True, serialize=False)), - ('client_id', models.CharField(db_index=True, default=oauth2_provider.generators.generate_client_id, max_length=100, unique=True)), - ('redirect_uris', models.TextField(blank=True, help_text='Allowed URIs list, space separated')), - ('client_type', models.CharField(choices=[('confidential', 'Confidential'), ('public', 'Public')], max_length=32)), - ('authorization_grant_type', models.CharField(choices=[('authorization-code', 'Authorization code'), ('implicit', 'Implicit'), ('password', 'Resource owner password-based'), ('client-credentials', 'Client credentials'), ('openid-hybrid', 'OpenID connect hybrid')], max_length=32)), - ('client_secret', models.CharField(blank=True, db_index=True, default=oauth2_provider.generators.generate_client_secret, max_length=255)), - ('name', models.CharField(blank=True, max_length=255)), - ('skip_authorization', models.BooleanField(default=False)), - ('created', models.DateTimeField(auto_now_add=True)), - ('updated', models.DateTimeField(auto_now=True)), - ('custom_field', models.CharField(max_length=255)), - ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='tests_sampleapplication', to=settings.AUTH_USER_MODEL)), - ('algorithm', models.CharField(max_length=5, choices=[('RS256', 'RSA with SHA-2 256'), ('HS256', 'HMAC with SHA-2 256')], default='RS256')), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ], - options={ - 'abstract': False, - }, ), migrations.CreateModel( - name='SampleAccessToken', + name='SampleApplication', fields=[ - ('id', models.BigAutoField(primary_key=True, serialize=False)), - ('token', models.CharField(max_length=255, unique=True)), - ('expires', models.DateTimeField()), - ('scope', models.TextField(blank=True)), - ('created', models.DateTimeField(auto_now_add=True)), - ('updated', models.DateTimeField(auto_now=True)), - ('custom_field', models.CharField(max_length=255)), - ('application', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.OAUTH2_PROVIDER_APPLICATION_MODEL)), - ('source_refresh_token', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='s_refreshed_access_token', to=settings.OAUTH2_PROVIDER_REFRESH_TOKEN_MODEL)), - ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='tests_sampleaccesstoken', to=settings.AUTH_USER_MODEL)), - ('id_token', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='access_token', to=settings.OAUTH2_PROVIDER_ID_TOKEN_MODEL)), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ], - options={ - 'abstract': False, - }, ), migrations.CreateModel( - name='BaseTestApplication', + name='SampleGrant', fields=[ - ('id', models.BigAutoField(primary_key=True, serialize=False)), - ('client_id', models.CharField(db_index=True, default=oauth2_provider.generators.generate_client_id, max_length=100, unique=True)), - ('redirect_uris', models.TextField(blank=True, help_text='Allowed URIs list, space separated')), - ('client_type', models.CharField(choices=[('confidential', 'Confidential'), ('public', 'Public')], max_length=32)), - ('authorization_grant_type', models.CharField(choices=[('authorization-code', 'Authorization code'), ('implicit', 'Implicit'), ('password', 'Resource owner password-based'), ('client-credentials', 'Client credentials'), ('openid-hybrid', 'OpenID connect hybrid')], max_length=32)), - ('client_secret', models.CharField(blank=True, db_index=True, default=oauth2_provider.generators.generate_client_secret, max_length=255)), - ('name', models.CharField(blank=True, max_length=255)), - ('skip_authorization', models.BooleanField(default=False)), - ('created', models.DateTimeField(auto_now_add=True)), - ('updated', models.DateTimeField(auto_now=True)), - ('allowed_schemes', models.TextField(blank=True)), - ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='tests_basetestapplication', to=settings.AUTH_USER_MODEL)), - ('algorithm', models.CharField(max_length=5, choices=[('RS256', 'RSA with SHA-2 256'), ('HS256', 'HMAC with SHA-2 256')], default='RS256')), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ], - options={ - 'abstract': False, - }, ), migrations.CreateModel( name='SampleRefreshToken', fields=[ - ('id', models.BigAutoField(primary_key=True, serialize=False)), - ('token', models.CharField(max_length=255)), - ('created', models.DateTimeField(auto_now_add=True)), - ('updated', models.DateTimeField(auto_now=True)), - ('revoked', models.DateTimeField(null=True)), - ('custom_field', models.CharField(max_length=255)), - ('access_token', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='s_refresh_token', to=settings.OAUTH2_PROVIDER_ACCESS_TOKEN_MODEL)), - ('application', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.OAUTH2_PROVIDER_APPLICATION_MODEL)), - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tests_samplerefreshtoken', to=settings.AUTH_USER_MODEL)), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ], - options={ - 'abstract': False, - 'unique_together': {('token', 'revoked')}, - }, ), ] diff --git a/tests/migrations/0002_swapped_models.py b/tests/migrations/0002_swapped_models.py new file mode 100644 index 000000000..412f19927 --- /dev/null +++ b/tests/migrations/0002_swapped_models.py @@ -0,0 +1,346 @@ +# Generated by Django 4.0.4 on 2022-05-27 21:12 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import oauth2_provider.generators +import oauth2_provider.models + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + migrations.swappable_dependency(settings.OAUTH2_PROVIDER_ID_TOKEN_MODEL), + ('tests', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='basetestapplication', + name='algorithm', + field=models.CharField(blank=True, choices=[('', 'No OIDC support'), ('RS256', 'RSA with SHA-2 256'), ('HS256', 'HMAC with SHA-2 256')], default='', max_length=5), + ), + migrations.AddField( + model_name='basetestapplication', + name='allowed_schemes', + field=models.TextField(blank=True), + ), + migrations.AddField( + model_name='basetestapplication', + name='authorization_grant_type', + field=models.CharField(choices=[('authorization-code', 'Authorization code'), ('implicit', 'Implicit'), ('password', 'Resource owner password-based'), ('client-credentials', 'Client credentials'), ('openid-hybrid', 'OpenID connect hybrid')], max_length=32), + preserve_default=False, + ), + migrations.AddField( + model_name='basetestapplication', + name='client_id', + field=models.CharField(db_index=True, default=oauth2_provider.generators.generate_client_id, max_length=100, unique=True), + ), + migrations.AddField( + model_name='basetestapplication', + name='client_secret', + field=oauth2_provider.models.ClientSecretField(blank=True, db_index=True, default=oauth2_provider.generators.generate_client_secret, help_text='Hashed on Save. Copy it now if this is a new secret.', max_length=255), + ), + migrations.AddField( + model_name='basetestapplication', + name='client_type', + field=models.CharField(choices=[('confidential', 'Confidential'), ('public', 'Public')], max_length=32), + preserve_default=False, + ), + migrations.AddField( + model_name='basetestapplication', + name='created', + field=models.DateTimeField(auto_now_add=True), + preserve_default=False, + ), + migrations.AddField( + model_name='basetestapplication', + name='name', + field=models.CharField(blank=True, max_length=255), + ), + migrations.AddField( + model_name='basetestapplication', + name='redirect_uris', + field=models.TextField(blank=True, help_text='Allowed URIs list, space separated'), + ), + migrations.AddField( + model_name='basetestapplication', + name='skip_authorization', + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name='basetestapplication', + name='updated', + field=models.DateTimeField(auto_now=True), + ), + migrations.AddField( + model_name='basetestapplication', + name='user', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='sampleaccesstoken', + name='application', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.OAUTH2_PROVIDER_APPLICATION_MODEL), + ), + migrations.AddField( + model_name='sampleaccesstoken', + name='created', + field=models.DateTimeField(auto_now_add=True), + preserve_default=False, + ), + migrations.AddField( + model_name='sampleaccesstoken', + name='custom_field', + field=models.CharField(max_length=255), + preserve_default=False, + ), + migrations.AddField( + model_name='sampleaccesstoken', + name='expires', + field=models.DateTimeField(), + preserve_default=False, + ), + migrations.AddField( + model_name='sampleaccesstoken', + name='id_token', + field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='access_token', to=settings.OAUTH2_PROVIDER_ID_TOKEN_MODEL), + ), + migrations.AddField( + model_name='sampleaccesstoken', + name='scope', + field=models.TextField(blank=True), + ), + migrations.AddField( + model_name='sampleaccesstoken', + name='source_refresh_token', + field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='s_refreshed_access_token', to=settings.OAUTH2_PROVIDER_REFRESH_TOKEN_MODEL), + ), + migrations.AddField( + model_name='sampleaccesstoken', + name='token', + field=models.CharField(max_length=255, unique=True), + preserve_default=False, + ), + migrations.AddField( + model_name='sampleaccesstoken', + name='updated', + field=models.DateTimeField(auto_now=True), + ), + migrations.AddField( + model_name='sampleaccesstoken', + name='user', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='sampleapplication', + name='algorithm', + field=models.CharField(blank=True, choices=[('', 'No OIDC support'), ('RS256', 'RSA with SHA-2 256'), ('HS256', 'HMAC with SHA-2 256')], default='', max_length=5), + ), + migrations.AddField( + model_name='sampleapplication', + name='authorization_grant_type', + field=models.CharField(choices=[('authorization-code', 'Authorization code'), ('implicit', 'Implicit'), ('password', 'Resource owner password-based'), ('client-credentials', 'Client credentials'), ('openid-hybrid', 'OpenID connect hybrid')], max_length=32), + preserve_default=False, + ), + migrations.AddField( + model_name='sampleapplication', + name='client_id', + field=models.CharField(db_index=True, default=oauth2_provider.generators.generate_client_id, max_length=100, unique=True), + ), + migrations.AddField( + model_name='sampleapplication', + name='client_secret', + field=oauth2_provider.models.ClientSecretField(blank=True, db_index=True, default=oauth2_provider.generators.generate_client_secret, help_text='Hashed on Save. Copy it now if this is a new secret.', max_length=255), + ), + migrations.AddField( + model_name='sampleapplication', + name='client_type', + field=models.CharField(choices=[('confidential', 'Confidential'), ('public', 'Public')], max_length=32), + preserve_default=False, + ), + migrations.AddField( + model_name='sampleapplication', + name='created', + field=models.DateTimeField(auto_now_add=True), + preserve_default=False, + ), + migrations.AddField( + model_name='sampleapplication', + name='custom_field', + field=models.CharField(max_length=255), + preserve_default=False, + ), + migrations.AddField( + model_name='sampleapplication', + name='name', + field=models.CharField(blank=True, max_length=255), + ), + migrations.AddField( + model_name='sampleapplication', + name='redirect_uris', + field=models.TextField(blank=True, help_text='Allowed URIs list, space separated'), + ), + migrations.AddField( + model_name='sampleapplication', + name='skip_authorization', + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name='sampleapplication', + name='updated', + field=models.DateTimeField(auto_now=True), + ), + migrations.AddField( + model_name='sampleapplication', + name='user', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='samplegrant', + name='application', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.OAUTH2_PROVIDER_APPLICATION_MODEL), + preserve_default=False, + ), + migrations.AddField( + model_name='samplegrant', + name='claims', + field=models.TextField(blank=True), + ), + migrations.AddField( + model_name='samplegrant', + name='code', + field=models.CharField(max_length=255, unique=True), + preserve_default=False, + ), + migrations.AddField( + model_name='samplegrant', + name='code_challenge', + field=models.CharField(blank=True, default='', max_length=128), + ), + migrations.AddField( + model_name='samplegrant', + name='code_challenge_method', + field=models.CharField(blank=True, choices=[('plain', 'plain'), ('S256', 'S256')], default='', max_length=10), + ), + migrations.AddField( + model_name='samplegrant', + name='created', + field=models.DateTimeField(auto_now_add=True), + preserve_default=False, + ), + migrations.AddField( + model_name='samplegrant', + name='custom_field', + field=models.CharField(max_length=255), + preserve_default=False, + ), + migrations.AddField( + model_name='samplegrant', + name='expires', + field=models.DateTimeField(), + preserve_default=False, + ), + migrations.AddField( + model_name='samplegrant', + name='nonce', + field=models.CharField(blank=True, default='', max_length=255), + ), + migrations.AddField( + model_name='samplegrant', + name='redirect_uri', + field=models.TextField(), + preserve_default=False, + ), + migrations.AddField( + model_name='samplegrant', + name='scope', + field=models.TextField(blank=True), + ), + migrations.AddField( + model_name='samplegrant', + name='updated', + field=models.DateTimeField(auto_now=True), + ), + migrations.AddField( + model_name='samplegrant', + name='user', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s', to=settings.AUTH_USER_MODEL), + preserve_default=False, + ), + migrations.AddField( + model_name='samplerefreshtoken', + name='access_token', + field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='s_refresh_token', to=settings.OAUTH2_PROVIDER_ACCESS_TOKEN_MODEL), + ), + migrations.AddField( + model_name='samplerefreshtoken', + name='application', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.OAUTH2_PROVIDER_APPLICATION_MODEL), + preserve_default=False, + ), + migrations.AddField( + model_name='samplerefreshtoken', + name='created', + field=models.DateTimeField(auto_now_add=True), + preserve_default=False, + ), + migrations.AddField( + model_name='samplerefreshtoken', + name='custom_field', + field=models.CharField(max_length=255), + preserve_default=False, + ), + migrations.AddField( + model_name='samplerefreshtoken', + name='revoked', + field=models.DateTimeField(null=True), + ), + migrations.AddField( + model_name='samplerefreshtoken', + name='token', + field=models.CharField(default=1, max_length=255), + preserve_default=False, + ), + migrations.AddField( + model_name='samplerefreshtoken', + name='updated', + field=models.DateTimeField(auto_now=True), + ), + migrations.AddField( + model_name='samplerefreshtoken', + name='user', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s', to=settings.AUTH_USER_MODEL), + preserve_default=False, + ), + migrations.AlterField( + model_name='basetestapplication', + name='id', + field=models.BigAutoField(primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='sampleaccesstoken', + name='id', + field=models.BigAutoField(primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='sampleapplication', + name='id', + field=models.BigAutoField(primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='samplegrant', + name='id', + field=models.BigAutoField(primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='samplerefreshtoken', + name='id', + field=models.BigAutoField(primary_key=True, serialize=False), + ), + migrations.AlterUniqueTogether( + name='samplerefreshtoken', + unique_together={('token', 'revoked')}, + ), + ] diff --git a/tests/settings.py b/tests/settings.py index 27dcfe9a3..9315a6e39 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -54,6 +54,7 @@ "django.template.context_processors.debug", "django.template.context_processors.i18n", "django.template.context_processors.media", + "django.template.context_processors.request", "django.template.context_processors.static", "django.template.context_processors.tz", "django.contrib.messages.context_processors.messages", diff --git a/tests/settings_swapped.py b/tests/settings_swapped.py new file mode 100644 index 000000000..cb3a37571 --- /dev/null +++ b/tests/settings_swapped.py @@ -0,0 +1,6 @@ +from .settings import * # noqa + + +OAUTH2_PROVIDER_ACCESS_TOKEN_MODEL = "tests.SampleAccessToken" +OAUTH2_PROVIDER_APPLICATION_MODEL = "tests.SampleApplication" +OAUTH2_PROVIDER_REFRESH_TOKEN_MODEL = "tests.SampleRefreshToken" diff --git a/tox.ini b/tox.ini index 117a5e901..63a78e773 100644 --- a/tox.ini +++ b/tox.ini @@ -2,6 +2,7 @@ envlist = flake8, migrations, + migrate_swapped, docs, sphinxlint, py{37,38,39}-dj22, @@ -12,7 +13,7 @@ envlist = [gh-actions] python = 3.7: py37 - 3.8: py38, docs, flake8, migrations, sphinxlint + 3.8: py38, docs, flake8, migrations, migrate_swapped, sphinxlint 3.9: py39 3.10: py310 @@ -98,6 +99,14 @@ setenv = PYTHONWARNINGS = all commands = django-admin makemigrations --dry-run --check +[testenv:migrate_swapped] +setenv = + DJANGO_SETTINGS_MODULE = tests.settings_swapped + PYTHONPATH = {toxinidir} + PYTHONWARNINGS = all +commands = + django-admin migrate + [testenv:build] deps = setuptools>=39.0