From dd2225a47a5db33343ab2a62829447effe03d916 Mon Sep 17 00:00:00 2001 From: Shaun Kruger Date: Sat, 5 Jan 2019 01:53:01 -0700 Subject: [PATCH 1/9] Get unit tests running with django 1.11-2.1 --- Vagrantfile | 77 +++++++++ provider/compat/urls.py | 4 - provider/forms.py | 4 +- provider/oauth2/__init__.py | 6 - provider/oauth2/forms.py | 1 - provider/oauth2/migrations/0001_initial.py | 20 +-- provider/oauth2/models.py | 26 +-- .../oauth2/south_migrations/0001_initial.py | 153 ------------------ .../0002_auto__chg_field_client_user.py | 101 ------------ .../0003_auto__add_field_client_name.py | 102 ------------ .../0004_auto__add_index_accesstoken_token.py | 98 ----------- provider/oauth2/south_migrations/__init__.py | 0 provider/oauth2/tests.py | 12 +- provider/oauth2/urls.py | 8 +- provider/oauth2/views.py | 2 +- provider/utils.py | 8 +- provider/views.py | 14 +- test.sh | 17 +- tests/urls.py | 8 +- tox.ini | 44 ++--- 20 files changed, 149 insertions(+), 556 deletions(-) create mode 100644 Vagrantfile delete mode 100644 provider/compat/urls.py delete mode 100644 provider/oauth2/south_migrations/0001_initial.py delete mode 100644 provider/oauth2/south_migrations/0002_auto__chg_field_client_user.py delete mode 100644 provider/oauth2/south_migrations/0003_auto__add_field_client_name.py delete mode 100644 provider/oauth2/south_migrations/0004_auto__add_index_accesstoken_token.py delete mode 100644 provider/oauth2/south_migrations/__init__.py diff --git a/Vagrantfile b/Vagrantfile new file mode 100644 index 00000000..50036bc9 --- /dev/null +++ b/Vagrantfile @@ -0,0 +1,77 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +# All Vagrant configuration is done below. The "2" in Vagrant.configure +# configures the configuration version (we support older styles for +# backwards compatibility). Please don't change it unless you know what +# you're doing. +Vagrant.configure(2) do |config| + # The most common configuration options are documented and commented below. + # For a complete reference, please see the online documentation at + # https://docs.vagrantup.com. + + # Every Vagrant development environment requires a box. You can search for + # boxes at https://atlas.hashicorp.com/search. + config.vm.box = "ubuntu/bionic64" + + # Disable automatic box update checking. If you disable this, then + # boxes will only be checked for updates when the user runs + # `vagrant box outdated`. This is not recommended. + # config.vm.box_check_update = false + + # Create a forwarded port mapping which allows access to a specific port + # within the machine from a port on the host machine. In the example below, + # accessing "localhost:8080" will access port 80 on the guest machine. + # config.vm.network "forwarded_port", guest: 80, host: 8080 + # config.vm.network "forwarded_port", guest: 8000, host: 8000 + + # Create a private network, which allows host-only access to the machine + # using a specific IP. + # config.vm.network "private_network", ip: "192.168.33.10" + + # Create a public network, which generally matched to bridged network. + # Bridged networks make the machine appear as another physical device on + # your network. + # config.vm.network "public_network" + + # Share an additional folder to the guest VM. The first argument is + # the path on the host to the actual folder. The second argument is + # the path on the guest to mount the folder. And the optional third + # argument is a set of non-required options. + # config.vm.synced_folder "../data", "/vagrant_data" + + # Provider-specific configuration so you can fine-tune various + # backing providers for Vagrant. These expose provider-specific options. + # Example for VirtualBox: + # + config.vm.provider "virtualbox" do |vb| + # Display the VirtualBox GUI when booting the machine + # vb.gui = true + # Customize the amount of memory on the VM: + vb.memory = "1024" + end + # + # View the documentation for the provider you are using for more + # information on available options. + + # Define a Vagrant Push strategy for pushing to Atlas. Other push strategies + # such as FTP and Heroku are also available. See the documentation at + # https://docs.vagrantup.com/v2/push/atlas.html for more information. + # config.push.define "atlas" do |push| + # push.app = "YOUR_ATLAS_USERNAME/YOUR_APPLICATION_NAME" + # end + + # Enable provisioning with a shell script. Additional provisioners such as + # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the + # documentation for more information about their specific syntax and use. + config.vm.provision "shell", privileged: false, inline: <<-SHELL + sudo resize2fs /dev/sda1 + sudo apt-get update + sudo apt-get install -y build-essential python-dev python-pip python-virtualenv python3-dev python3 python3-virtualenv virtualenv virtualenvwrapper postgresql libpq-dev memcached redis-server redis-tools + + sudo -H pip install tox + + echo "export TOX_WORK_DIR=/tmp/" >> ~/.bash_aliases + + SHELL +end diff --git a/provider/compat/urls.py b/provider/compat/urls.py deleted file mode 100644 index d3026312..00000000 --- a/provider/compat/urls.py +++ /dev/null @@ -1,4 +0,0 @@ -try: - from django.conf.urls import patterns, url, include -except ImportError: # django 1.3 - from django.conf.urls.defaults import patterns, url, include diff --git a/provider/forms.py b/provider/forms.py index 9b7fd609..f7c68d8a 100644 --- a/provider/forms.py +++ b/provider/forms.py @@ -51,7 +51,7 @@ def _clean_fields(self): """ try: super(OAuthForm, self)._clean_fields() - except OAuthValidationError, e: + except OAuthValidationError as e: self._errors.update(e.args[0]) def _clean_form(self): @@ -60,5 +60,5 @@ def _clean_form(self): """ try: super(OAuthForm, self)._clean_form() - except OAuthValidationError, e: + except OAuthValidationError as e: self._errors.update(e.args[0]) diff --git a/provider/oauth2/__init__.py b/provider/oauth2/__init__.py index 1c67e6a4..8384f39e 100644 --- a/provider/oauth2/__init__.py +++ b/provider/oauth2/__init__.py @@ -1,7 +1 @@ -import backends -import forms -import models -import urls -import views - default_app_config = 'provider.oauth2.apps.Oauth2' diff --git a/provider/oauth2/forms.py b/provider/oauth2/forms.py index d8f92baa..8aff46b8 100644 --- a/provider/oauth2/forms.py +++ b/provider/oauth2/forms.py @@ -1,7 +1,6 @@ from django import forms from django.contrib.auth import authenticate from django.conf import settings -from django.utils.encoding import smart_unicode from django.utils.translation import ugettext as _ from provider.constants import RESPONSE_TYPE_CHOICES, SCOPES from provider.forms import OAuthForm, OAuthValidationError diff --git a/provider/oauth2/migrations/0001_initial.py b/provider/oauth2/migrations/0001_initial.py index a1d74d6b..7fece714 100644 --- a/provider/oauth2/migrations/0001_initial.py +++ b/provider/oauth2/migrations/0001_initial.py @@ -47,7 +47,7 @@ class Migration(migrations.Migration): ('client_secret', models.CharField(default=provider.utils.long_token, max_length=255)), ('client_type', models.IntegerField(choices=[(0, b'Confidential (Web applications)'), (1, b'Public (Native and JS applications)')])), ('auto_authorize', models.BooleanField(default=False)), - ('user', models.ForeignKey(related_name='oauth2_client', blank=True, to=settings.AUTH_USER_MODEL, null=True)), + ('user', models.ForeignKey(related_name='oauth2_client', blank=True, to=settings.AUTH_USER_MODEL, null=True, on_delete=models.DO_NOTHING)), ], options={ 'db_table': 'oauth2_client', @@ -61,7 +61,7 @@ class Migration(migrations.Migration): ('code', models.CharField(default=provider.utils.long_token, max_length=255)), ('expires', models.DateTimeField(default=provider.utils.get_code_expiry)), ('redirect_uri', models.CharField(max_length=255, blank=True)), - ('client', models.ForeignKey(to='oauth2.Client')), + ('client', models.ForeignKey(to='oauth2.Client', on_delete=models.DO_NOTHING)), ], options={ 'db_table': 'oauth2_grant', @@ -74,9 +74,9 @@ class Migration(migrations.Migration): ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('token', models.CharField(default=provider.utils.long_token, max_length=255)), ('expired', models.BooleanField(default=False)), - ('access_token', models.OneToOneField(related_name='refresh_token', to='oauth2.AccessToken')), - ('client', models.ForeignKey(to='oauth2.Client')), - ('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)), + ('access_token', models.OneToOneField(related_name='refresh_token', to='oauth2.AccessToken', on_delete=models.DO_NOTHING)), + ('client', models.ForeignKey(to='oauth2.Client', on_delete=models.DO_NOTHING)), + ('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING)), ], options={ 'db_table': 'oauth2_refreshtoken', @@ -103,13 +103,13 @@ class Migration(migrations.Migration): migrations.AddField( model_name='grant', name='user', - field=models.ForeignKey(to=settings.AUTH_USER_MODEL), + field=models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING), preserve_default=True, ), migrations.AddField( model_name='authorizedclient', name='client', - field=models.ForeignKey(to='oauth2.Client'), + field=models.ForeignKey(to='oauth2.Client', on_delete=models.DO_NOTHING), preserve_default=True, ), migrations.AddField( @@ -121,7 +121,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='authorizedclient', name='user', - field=models.ForeignKey(related_name='oauth2_authorized_client', to=settings.AUTH_USER_MODEL), + field=models.ForeignKey(related_name='oauth2_authorized_client', to=settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING), preserve_default=True, ), migrations.AlterUniqueTogether( @@ -131,7 +131,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='accesstoken', name='client', - field=models.ForeignKey(to='oauth2.Client'), + field=models.ForeignKey(to='oauth2.Client', on_delete=models.DO_NOTHING), preserve_default=True, ), migrations.AddField( @@ -143,7 +143,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='accesstoken', name='user', - field=models.ForeignKey(to=settings.AUTH_USER_MODEL), + field=models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING), preserve_default=True, ), migrations.RunSQL("INSERT INTO oauth2_scope (name, description) values ('read', 'Read-Only access') "), diff --git a/provider/oauth2/models.py b/provider/oauth2/models.py index 4b33f11a..c02f00e1 100644 --- a/provider/oauth2/models.py +++ b/provider/oauth2/models.py @@ -30,7 +30,7 @@ class Client(models.Model): Clients are outlined in the :rfc:`2` and its subsections. """ - user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='oauth2_client', + user = models.ForeignKey(settings.AUTH_USER_MODEL, models.DO_NOTHING, related_name='oauth2_client', blank=True, null=True) name = models.CharField(max_length=255, blank=True) url = models.URLField(help_text="Your application's URL.") @@ -90,10 +90,10 @@ def set_authorization_scope(self, user, client, scope_list): class AuthorizedClient(models.Model): - user = models.ForeignKey(settings.AUTH_USER_MODEL, + user = models.ForeignKey(settings.AUTH_USER_MODEL, models.DO_NOTHING, related_name='oauth2_authorized_client') - client = models.ForeignKey(Client) - scope = models.ManyToManyField(Scope) + client = models.ForeignKey('Client', models.DO_NOTHING) + scope = models.ManyToManyField('Scope') authorized_at = models.DateTimeField(auto_now_add=True, blank=True) objects = AuthorizedClientManager() @@ -120,12 +120,12 @@ class Grant(models.Model): * :attr:`redirect_uri` * :attr:`scope` """ - user = models.ForeignKey(settings.AUTH_USER_MODEL) - client = models.ForeignKey(Client) + user = models.ForeignKey(settings.AUTH_USER_MODEL, models.DO_NOTHING) + client = models.ForeignKey('Client', models.DO_NOTHING) code = models.CharField(max_length=255, default=long_token) expires = models.DateTimeField(default=get_code_expiry) redirect_uri = models.CharField(max_length=255, blank=True) - scope = models.ManyToManyField(Scope) + scope = models.ManyToManyField('Scope') def __unicode__(self): return self.code @@ -177,11 +177,11 @@ class AccessToken(models.Model): * :meth:`get_expire_delta` - returns an integer representing seconds to expiry """ - user = models.ForeignKey(settings.AUTH_USER_MODEL) + user = models.ForeignKey(settings.AUTH_USER_MODEL, models.DO_NOTHING) token = models.CharField(max_length=255, default=long_token, db_index=True) - client = models.ForeignKey(Client) + client = models.ForeignKey('Client', models.DO_NOTHING) expires = models.DateTimeField() - scope = models.ManyToManyField(Scope) + scope = models.ManyToManyField('Scope') objects = AccessTokenManager() @@ -246,11 +246,11 @@ class RefreshToken(models.Model): * :attr:`client` - :class:`Client` * :attr:`expired` - ``boolean`` """ - user = models.ForeignKey(settings.AUTH_USER_MODEL) + user = models.ForeignKey(settings.AUTH_USER_MODEL, models.DO_NOTHING) token = models.CharField(max_length=255, default=long_token) - access_token = models.OneToOneField(AccessToken, + access_token = models.OneToOneField('AccessToken', models.DO_NOTHING, related_name='refresh_token') - client = models.ForeignKey(Client) + client = models.ForeignKey('Client', models.DO_NOTHING) expired = models.BooleanField(default=False) objects = RefreshTokenManager() diff --git a/provider/oauth2/south_migrations/0001_initial.py b/provider/oauth2/south_migrations/0001_initial.py deleted file mode 100644 index 52797bf0..00000000 --- a/provider/oauth2/south_migrations/0001_initial.py +++ /dev/null @@ -1,153 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -from provider.compat import user_model_label - - -class Migration(SchemaMigration): - - def forwards(self, orm): - - # Adding model 'Client' - db.create_table('oauth2_client', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm[user_model_label])), - ('url', self.gf('django.db.models.fields.URLField')(max_length=200)), - ('redirect_uri', self.gf('django.db.models.fields.URLField')(max_length=200)), - ('client_id', self.gf('django.db.models.fields.CharField')(default='37b581bdc702c732aa65', max_length=255)), - ('client_secret', self.gf('django.db.models.fields.CharField')(default='5cf90561f7566aa81457f8a32187dcb8147c7b73', max_length=255)), - ('client_type', self.gf('django.db.models.fields.IntegerField')()), - )) - db.send_create_signal('oauth2', ['Client']) - - # Adding model 'Grant' - db.create_table('oauth2_grant', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm[user_model_label])), - ('client', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['oauth2.Client'])), - ('code', self.gf('django.db.models.fields.CharField')(default='f0cda1a5f4ae915431ff93f477c012b38e2429c4', max_length=255)), - ('expires', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime(2012, 2, 8, 10, 43, 45, 620301))), - ('redirect_uri', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)), - ('scope', self.gf('django.db.models.fields.IntegerField')(default=0)), - )) - db.send_create_signal('oauth2', ['Grant']) - - # Adding model 'AccessToken' - db.create_table('oauth2_accesstoken', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm[user_model_label])), - ('token', self.gf('django.db.models.fields.CharField')(default='b10b8f721e95117cb13c', max_length=255)), - ('client', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['oauth2.Client'])), - ('expires', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime(2013, 2, 7, 10, 33, 45, 618854))), - ('scope', self.gf('django.db.models.fields.IntegerField')(default=0)), - )) - db.send_create_signal('oauth2', ['AccessToken']) - - # Adding model 'RefreshToken' - db.create_table('oauth2_refreshtoken', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm[user_model_label])), - ('token', self.gf('django.db.models.fields.CharField')(default='84035a870dab7c820c2c501fb0b10f86fdf7a3fe', max_length=255)), - ('access_token', self.gf('django.db.models.fields.related.OneToOneField')(related_name='refresh_token', unique=True, to=orm['oauth2.AccessToken'])), - ('client', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['oauth2.Client'])), - ('expired', self.gf('django.db.models.fields.BooleanField')(default=False)), - )) - db.send_create_signal('oauth2', ['RefreshToken']) - - - def backwards(self, orm): - - # Deleting model 'Client' - db.delete_table('oauth2_client') - - # Deleting model 'Grant' - db.delete_table('oauth2_grant') - - # Deleting model 'AccessToken' - db.delete_table('oauth2_accesstoken') - - # Deleting model 'RefreshToken' - db.delete_table('oauth2_refreshtoken') - - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - user_model_label: { - 'Meta': {'object_name': user_model_label.split('.')[-1]}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'oauth2.accesstoken': { - 'Meta': {'object_name': 'AccessToken'}, - 'client': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['oauth2.Client']"}), - 'expires': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2013, 2, 7, 10, 33, 45, 624553)'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'scope': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'token': ('django.db.models.fields.CharField', [], {'default': "'d5c1f65020ebdc89f20c'", 'max_length': '255'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['%s']" % user_model_label}) - }, - 'oauth2.client': { - 'Meta': {'object_name': 'Client'}, - 'client_id': ('django.db.models.fields.CharField', [], {'default': "'306fb26cbcc87dd33cdb'", 'max_length': '255'}), - 'client_secret': ('django.db.models.fields.CharField', [], {'default': "'7e5785add4898448d53767f15373636b918cf0e3'", 'max_length': '255'}), - 'client_type': ('django.db.models.fields.IntegerField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'redirect_uri': ('django.db.models.fields.URLField', [], {'max_length': '200'}), - 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['%s']" % user_model_label}) - }, - 'oauth2.grant': { - 'Meta': {'object_name': 'Grant'}, - 'client': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['oauth2.Client']"}), - 'code': ('django.db.models.fields.CharField', [], {'default': "'310b2c63e27306ecf5307569dd62340cc4994b73'", 'max_length': '255'}), - 'expires': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 2, 8, 10, 43, 45, 625956)'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'redirect_uri': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), - 'scope': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['%s']" % user_model_label}) - }, - 'oauth2.refreshtoken': { - 'Meta': {'object_name': 'RefreshToken'}, - 'access_token': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'refresh_token'", 'unique': 'True', 'to': "orm['oauth2.AccessToken']"}), - 'client': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['oauth2.Client']"}), - 'expired': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'token': ('django.db.models.fields.CharField', [], {'default': "'ef0ab76037f17769ab2975a816e8f41a1c11d25e'", 'max_length': '255'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['%s']" % user_model_label}) - } - } - - complete_apps = ['oauth2'] diff --git a/provider/oauth2/south_migrations/0002_auto__chg_field_client_user.py b/provider/oauth2/south_migrations/0002_auto__chg_field_client_user.py deleted file mode 100644 index eab4fa54..00000000 --- a/provider/oauth2/south_migrations/0002_auto__chg_field_client_user.py +++ /dev/null @@ -1,101 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -from provider.compat import user_model_label - - -class Migration(SchemaMigration): - - def forwards(self, orm): - - # Changing field 'Client.user' - db.alter_column('oauth2_client', 'user_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm[user_model_label], null=True)) - - - def backwards(self, orm): - - # User chose to not deal with backwards NULL issues for 'Client.user' - raise RuntimeError("Cannot reverse this migration. 'Client.user' and its values cannot be restored.") - - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - user_model_label: { - 'Meta': {'object_name': user_model_label.split('.')[-1]}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'oauth2.accesstoken': { - 'Meta': {'object_name': 'AccessToken'}, - 'client': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['oauth2.Client']"}), - 'expires': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2013, 2, 7, 10, 34, 7, 491068)'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'scope': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'token': ('django.db.models.fields.CharField', [], {'default': "'ed2ee3f5209076916309'", 'max_length': '255'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['%s']" % user_model_label}) - }, - 'oauth2.client': { - 'Meta': {'object_name': 'Client'}, - 'client_id': ('django.db.models.fields.CharField', [], {'default': "'b1f489e6693d6ba20770'", 'max_length': '255'}), - 'client_secret': ('django.db.models.fields.CharField', [], {'default': "'ac43f96040354c910c8e57a4952d9a8e92f83555'", 'max_length': '255'}), - 'client_type': ('django.db.models.fields.IntegerField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'redirect_uri': ('django.db.models.fields.URLField', [], {'max_length': '200'}), - 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['%s']" % user_model_label, 'null': 'True', 'blank': 'True'}) - }, - 'oauth2.grant': { - 'Meta': {'object_name': 'Grant'}, - 'client': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['oauth2.Client']"}), - 'code': ('django.db.models.fields.CharField', [], {'default': "'d62c4606c1d7743b59480a85bf8a691aec67df0a'", 'max_length': '255'}), - 'expires': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 2, 8, 10, 44, 7, 492506)'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'redirect_uri': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), - 'scope': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['%s']" % user_model_label}) - }, - 'oauth2.refreshtoken': { - 'Meta': {'object_name': 'RefreshToken'}, - 'access_token': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'refresh_token'", 'unique': 'True', 'to': "orm['oauth2.AccessToken']"}), - 'client': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['oauth2.Client']"}), - 'expired': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'token': ('django.db.models.fields.CharField', [], {'default': "'9b79a016e6b5220883d0d576f34bcbee29ce36b1'", 'max_length': '255'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['%s']" % user_model_label}) - } - } - - complete_apps = ['oauth2'] diff --git a/provider/oauth2/south_migrations/0003_auto__add_field_client_name.py b/provider/oauth2/south_migrations/0003_auto__add_field_client_name.py deleted file mode 100644 index 3280407b..00000000 --- a/provider/oauth2/south_migrations/0003_auto__add_field_client_name.py +++ /dev/null @@ -1,102 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -from provider.compat import user_model_label - - -class Migration(SchemaMigration): - - def forwards(self, orm): - - # Adding field 'Client.name' - db.add_column('oauth2_client', 'name', self.gf('django.db.models.fields.CharField')(default='', max_length=255, blank=True), keep_default=False) - - - def backwards(self, orm): - - # Deleting field 'Client.name' - db.delete_column('oauth2_client', 'name') - - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - user_model_label: { - 'Meta': {'object_name': user_model_label.split('.')[-1]}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'oauth2.accesstoken': { - 'Meta': {'object_name': 'AccessToken'}, - 'client': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['oauth2.Client']"}), - 'expires': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2013, 2, 7, 10, 40, 0, 790902)'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'scope': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'token': ('django.db.models.fields.CharField', [], {'default': "'d9373f4d09149181e1c5'", 'max_length': '255'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['%s']" % user_model_label}) - }, - 'oauth2.client': { - 'Meta': {'object_name': 'Client'}, - 'client_id': ('django.db.models.fields.CharField', [], {'default': "'00385d74e0b239deac42'", 'max_length': '255'}), - 'client_secret': ('django.db.models.fields.CharField', [], {'default': "'460de077126ccc746473f8b2afab6a8aef9f542a'", 'max_length': '255'}), - 'client_type': ('django.db.models.fields.IntegerField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), - 'redirect_uri': ('django.db.models.fields.URLField', [], {'max_length': '200'}), - 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['%s']" % user_model_label, 'null': 'True', 'blank': 'True'}) - }, - 'oauth2.grant': { - 'Meta': {'object_name': 'Grant'}, - 'client': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['oauth2.Client']"}), - 'code': ('django.db.models.fields.CharField', [], {'default': "'ae889a1d0fc0c8569b47a7037c3d2da5cb7d0d43'", 'max_length': '255'}), - 'expires': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 2, 8, 10, 50, 0, 788579)'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'redirect_uri': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), - 'scope': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['%s']" % user_model_label}) - }, - 'oauth2.refreshtoken': { - 'Meta': {'object_name': 'RefreshToken'}, - 'access_token': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'refresh_token'", 'unique': 'True', 'to': "orm['oauth2.AccessToken']"}), - 'client': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['oauth2.Client']"}), - 'expired': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'token': ('django.db.models.fields.CharField', [], {'default': "'50d5f3e805e02073364c4ebfc55a94328afe25bd'", 'max_length': '255'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['%s']" % user_model_label}) - } - } - - complete_apps = ['oauth2'] diff --git a/provider/oauth2/south_migrations/0004_auto__add_index_accesstoken_token.py b/provider/oauth2/south_migrations/0004_auto__add_index_accesstoken_token.py deleted file mode 100644 index 9eb6ff64..00000000 --- a/provider/oauth2/south_migrations/0004_auto__add_index_accesstoken_token.py +++ /dev/null @@ -1,98 +0,0 @@ -# -*- coding: utf-8 -*- -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - - -class Migration(SchemaMigration): - - def forwards(self, orm): - # Adding index on 'AccessToken', fields ['token'] - db.create_index('oauth2_accesstoken', ['token']) - - - def backwards(self, orm): - # Removing index on 'AccessToken', fields ['token'] - db.delete_index('oauth2_accesstoken', ['token']) - - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'oauth2.accesstoken': { - 'Meta': {'object_name': 'AccessToken'}, - 'client': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['oauth2.Client']"}), - 'expires': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2014, 8, 8, 0, 0)'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'scope': ('django.db.models.fields.IntegerField', [], {'default': '2'}), - 'token': ('django.db.models.fields.CharField', [], {'default': "'ab8c8bcd91e8750462b631516b60b0b95dffe1f4'", 'max_length': '255', 'db_index': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) - }, - 'oauth2.client': { - 'Meta': {'object_name': 'Client'}, - 'client_id': ('django.db.models.fields.CharField', [], {'default': "'0a8e54e38c024606ba0a'", 'max_length': '255'}), - 'client_secret': ('django.db.models.fields.CharField', [], {'default': "'e53ddb9736f9eea65100885a1b20fb5f2bb0fb4d'", 'max_length': '255'}), - 'client_type': ('django.db.models.fields.IntegerField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), - 'redirect_uri': ('django.db.models.fields.URLField', [], {'max_length': '200'}), - 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'oauth2_client'", 'null': 'True', 'to': "orm['auth.User']"}) - }, - 'oauth2.grant': { - 'Meta': {'object_name': 'Grant'}, - 'client': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['oauth2.Client']"}), - 'code': ('django.db.models.fields.CharField', [], {'default': "'5e0ca84e98678a3b55b8901e85a20f995672aea2'", 'max_length': '255'}), - 'expires': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2013, 8, 8, 0, 0)'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'redirect_uri': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), - 'scope': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) - }, - 'oauth2.refreshtoken': { - 'Meta': {'object_name': 'RefreshToken'}, - 'access_token': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'refresh_token'", 'unique': 'True', 'to': "orm['oauth2.AccessToken']"}), - 'client': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['oauth2.Client']"}), - 'expired': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'token': ('django.db.models.fields.CharField', [], {'default': "'32e9eb7edda764ba8f752ae49223d42acea7cb88'", 'max_length': '255'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) - } - } - - complete_apps = ['oauth2'] \ No newline at end of file diff --git a/provider/oauth2/south_migrations/__init__.py b/provider/oauth2/south_migrations/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/provider/oauth2/tests.py b/provider/oauth2/tests.py index 1aef946a..d2860497 100644 --- a/provider/oauth2/tests.py +++ b/provider/oauth2/tests.py @@ -1,10 +1,10 @@ import json -import urlparse +from six.moves.urllib_parse import urlparse, parse_qs import datetime from unittest import SkipTest from django.http import QueryDict from django.conf import settings -from django.core.urlresolvers import reverse +from django.shortcuts import reverse from django.utils.html import escape from django.test import TestCase from django.contrib.auth.models import User @@ -74,7 +74,7 @@ def test_authorization_requires_login(self): # Login redirect self.assertEqual(302, response.status_code) - self.assertEqual('/login/', urlparse.urlparse(response['Location']).path) + self.assertEqual('/login/', urlparse(response['Location']).path) self.login() @@ -246,7 +246,7 @@ def _login_authorize_get_token(self): self._login_and_authorize() response = self.client.get(self.redirect_url()) - query = QueryDict(urlparse.urlparse(response['Location']).query) + query = QueryDict(urlparse(response['Location']).query) code = query['code'] response = self.client.post(self.access_token_url(), { @@ -273,7 +273,7 @@ def test_fetching_access_token_with_invalid_grant_type(self): self._login_and_authorize() response = self.client.get(self.redirect_url()) - query = QueryDict(urlparse.urlparse(response['Location']).query) + query = QueryDict(urlparse(response['Location']).query) code = query['code'] response = self.client.post(self.access_token_url(), { @@ -552,7 +552,7 @@ def test_clear_expired(self): self.assertTrue('code' in location) # verify that Grant with code exists - code = urlparse.parse_qs(location)['code'][0] + code = parse_qs(location)['code'][0] self.assertTrue(Grant.objects.filter(code=code).exists()) # use the code/grant diff --git a/provider/oauth2/urls.py b/provider/oauth2/urls.py index 872025a3..43abcc63 100644 --- a/provider/oauth2/urls.py +++ b/provider/oauth2/urls.py @@ -35,10 +35,12 @@ from django.contrib.auth.decorators import login_required from django.views.decorators.csrf import csrf_exempt -from django.conf.urls import patterns, url, include +from django.conf.urls import url, include from provider.oauth2 import views -urlpatterns = patterns('', +app_name = 'oauth2' + +urlpatterns = [ url('^authorize/?$', login_required(views.CaptureView.as_view()), name='capture'), @@ -51,4 +53,4 @@ url('^access_token/?$', csrf_exempt(views.AccessTokenView.as_view()), name='access_token'), -) +] diff --git a/provider/oauth2/views.py b/provider/oauth2/views.py index 0576833f..b17697e2 100644 --- a/provider/oauth2/views.py +++ b/provider/oauth2/views.py @@ -1,5 +1,5 @@ from datetime import timedelta -from django.core.urlresolvers import reverse +from django.shortcuts import reverse from provider import constants from provider.views import CaptureViewBase, AuthorizeViewBase, RedirectViewBase from provider.views import AccessTokenViewBase, OAuthError diff --git a/provider/utils.py b/provider/utils.py index 90644a51..25894901 100644 --- a/provider/utils.py +++ b/provider/utils.py @@ -14,8 +14,8 @@ def short_token(): """ Generate a hash that can be used as an application identifier """ - hash = hashlib.sha1(shortuuid.uuid()) - hash.update(settings.SECRET_KEY) + hash = hashlib.sha1(shortuuid.uuid().encode('utf8')) + hash.update(settings.SECRET_KEY.encode('utf8')) return hash.hexdigest()[::2] @@ -23,8 +23,8 @@ def long_token(): """ Generate a hash that can be used as an application secret """ - hash = hashlib.sha1(shortuuid.uuid()) - hash.update(settings.SECRET_KEY) + hash = hashlib.sha1(shortuuid.uuid().encode('utf8')) + hash.update(settings.SECRET_KEY.encode('utf8')) return hash.hexdigest() diff --git a/provider/views.py b/provider/views.py index 20a95f97..fae69faf 100644 --- a/provider/views.py +++ b/provider/views.py @@ -1,11 +1,15 @@ +from __future__ import absolute_import + import json -import urlparse + +from six.moves.urllib_parse import urlparse, ParseResult + from django.http import HttpResponse from django.http import HttpResponseRedirect, QueryDict from django.utils.translation import ugettext as _ from django.views.generic.base import TemplateView, View from django.core.exceptions import ObjectDoesNotExist -from oauth2.models import Client, Scope +from provider.oauth2.models import Client, Scope from provider import constants @@ -335,7 +339,7 @@ def get(self, request): redirect_uri = data.get('redirect_uri', None) or client.redirect_uri - parsed = urlparse.urlparse(redirect_uri) + parsed = urlparse(redirect_uri) query = QueryDict('', mutable=True) @@ -351,7 +355,7 @@ def get(self, request): parsed = parsed[:4] + (query.urlencode(), '') - redirect_uri = urlparse.ParseResult(*parsed).geturl() + redirect_uri = ParseResult(*parsed).geturl() self.clear_data(request) @@ -610,5 +614,5 @@ def post(self, request): try: return handler(request, request.POST, client) - except OAuthError, e: + except OAuthError as e: return self.error_response(e.args[0]) diff --git a/test.sh b/test.sh index 1bf50b06..986422a8 100755 --- a/test.sh +++ b/test.sh @@ -1,18 +1,5 @@ #!/bin/bash -DJ_VERSION=$(django-admin.py --version) +app_names=( provider provider.oauth2 ) -# exit if fail -[[ "$?" -ne "0" ]] && exit; - -IS_16=$(echo $DJ_VERSION | grep -E "1\.6|1\.7|1\.8|dev") - -# if django version is not 1.6 (non-0 exit) we have to pass different -# app names to test runner -if [ "$?" -ne "1" ]; then - app_names=( provider provider.oauth2 ) -else - app_names=( provider oauth2 ) -fi - -python manage.py test ${app_names[@]} --traceback --failfast +python manage.py test ${app_names[@]} --traceback diff --git a/tests/urls.py b/tests/urls.py index 23e4599f..5308d4fc 100644 --- a/tests/urls.py +++ b/tests/urls.py @@ -1,9 +1,9 @@ -from provider.compat.urls import patterns, include, url +from django.conf.urls import url, include from django.contrib import admin admin.autodiscover() -urlpatterns = patterns('', - url(r'^admin/', include(admin.site.urls)), +urlpatterns = [ + url(r'^admin/', admin.site.urls), url(r'^oauth2/', include('provider.oauth2.urls', namespace = 'oauth2')), -) +] diff --git a/tox.ini b/tox.ini index e200bc24..f38b8da0 100644 --- a/tox.ini +++ b/tox.ini @@ -1,45 +1,33 @@ [tox] +toxworkdir={env:TOX_WORK_DIR:.tox} downloadcache = {toxworkdir}/cache/ -envlist = py2.7-django.dev,py2.7-django1.6,py2.7-django1.5,py2.7-django1.4,py2.6-django1.6,py2.6-django1.5,py2.6-django1.4 +envlist = py{2.7,3.6}-django1.11,py3.6-django{2.0,2.1} [testenv] setenv = PYTHONPATH = {toxinidir} commands = {toxinidir}/test.sh -deps = +deps = shortuuid>=0.5.0 + sqlparse>=0.2.4 + six>=1.12.0 -[testenv:py2.7-django.dev] +[testenv:py2.7-django1.11] basepython = python2.7 -deps = https://github.com/django/django/zipball/master +deps = Django>=1.11,<2.0 {[testenv]deps} -[testenv:py2.7-django1.6] -basepython = python2.7 -deps = django>=1.6,<1.7 - {[testenv]deps} - -[testenv:py2.7-django1.5] -basepython = python2.7 -deps = django>=1.5,<1.6 - {[testenv]deps} - -[testenv:py2.7-django1.4] -basepython = python2.7 -deps = django>=1.4,<1.5 - {[testenv]deps} - -[testenv:py2.6-django1.6] -basepython = python2.6 -deps = django>=1.6,<1.7 +[testenv:py3.6-django1.11] +basepython = python3.6 +deps = Django>=1.11,<2.0 {[testenv]deps} -[testenv:py2.6-django1.5] -basepython = python2.6 -deps = django>=1.5,<1.6 +[testenv:py3.6-django2.0] +basepython = python3.6 +deps = Django>=2.0,<2.1 {[testenv]deps} -[testenv:py2.6-django1.4] -basepython = python2.6 -deps = django>=1.4,<1.5 +[testenv:py3.6-django2.1] +basepython = python3.6 +deps = Django>=2.1 {[testenv]deps} From e1ca1aac6e5c08ed83711d0653617f7d0296f844 Mon Sep 17 00:00:00 2001 From: Shaun Kruger Date: Sat, 5 Jan 2019 02:24:05 -0700 Subject: [PATCH 2/9] Update travis settings to test Django 2.1 on python 3.6 --- .travis.yml | 6 +++--- requirements.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7d69fa34..aaef9617 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,12 @@ language: python env: - - DJANGO="django>=1.7,<1.9" + - DJANGO="Django>=2.1" python: - - "2.7" + - "3.6" # command to install dependencies install: - pip install -q -r requirements.txt - - pip install sqlparse + - pip install sqlparse six - pip install -q $DJANGO --upgrade - python setup.py develop script: ./test.sh diff --git a/requirements.txt b/requirements.txt index 48327a0a..87992eab 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ -Django>=1.7 +Django>=2.1 shortuuid>=0.4 From 6ffe5ecb05b24611c1614f4f10ddf6442e6c5f45 Mon Sep 17 00:00:00 2001 From: Shaun Kruger Date: Sat, 5 Jan 2019 02:39:51 -0700 Subject: [PATCH 3/9] Update travis to use tox --- .travis.yml | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index aaef9617..8327ded9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,7 @@ +sudo: false language: python -env: - - DJANGO="Django>=2.1" python: + - "2.7" - "3.6" -# command to install dependencies -install: - - pip install -q -r requirements.txt - - pip install sqlparse six - - pip install -q $DJANGO --upgrade - - python setup.py develop -script: ./test.sh +install: pip install tox-travis +script: tox From a0dd730ca370a51e52fb5903e796e7e56bea7da5 Mon Sep 17 00:00:00 2001 From: Shaun Kruger Date: Sat, 5 Jan 2019 02:43:19 -0700 Subject: [PATCH 4/9] Set all environments for travis --- .travis.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8327ded9..e0c7d542 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,9 @@ sudo: false language: python python: - - "2.7" - - "3.6" + - "2.7-django1.11" + - "3.6-django1.11" + - "3.6-django2.0" + - "3.6-django2.1" install: pip install tox-travis script: tox From 965d9118b524e085767dbf966fa021502cc1e832 Mon Sep 17 00:00:00 2001 From: Shaun Kruger Date: Sat, 5 Jan 2019 02:47:42 -0700 Subject: [PATCH 5/9] Update tox and travis configs --- .travis.yml | 6 ++---- tox.ini | 5 +++++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index e0c7d542..8327ded9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,7 @@ sudo: false language: python python: - - "2.7-django1.11" - - "3.6-django1.11" - - "3.6-django2.0" - - "3.6-django2.1" + - "2.7" + - "3.6" install: pip install tox-travis script: tox diff --git a/tox.ini b/tox.ini index f38b8da0..b8a61861 100644 --- a/tox.ini +++ b/tox.ini @@ -12,6 +12,11 @@ deps = shortuuid>=0.5.0 sqlparse>=0.2.4 six>=1.12.0 +[travis] +python = + 2.7: py27 + 3.6: py36 + [testenv:py2.7-django1.11] basepython = python2.7 deps = Django>=1.11,<2.0 From 66a0f68544fb845b0cdb6a0b235f20aabd13df98 Mon Sep 17 00:00:00 2001 From: Shaun Kruger Date: Sat, 5 Jan 2019 02:49:38 -0700 Subject: [PATCH 6/9] Try different method of selecting testenvs from travis --- tox.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index b8a61861..10496130 100644 --- a/tox.ini +++ b/tox.ini @@ -14,8 +14,8 @@ deps = shortuuid>=0.5.0 [travis] python = - 2.7: py27 - 3.6: py36 + 2.7: py27-django1.11 + 3.6: py36-django{1.11,2.0,2.1} [testenv:py2.7-django1.11] basepython = python2.7 From 237efcab9fd7a44373d79e66baf20f73891816cb Mon Sep 17 00:00:00 2001 From: Shaun Kruger Date: Sat, 5 Jan 2019 02:51:36 -0700 Subject: [PATCH 7/9] Fix python version string --- tox.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index 10496130..d0c4758c 100644 --- a/tox.ini +++ b/tox.ini @@ -14,8 +14,8 @@ deps = shortuuid>=0.5.0 [travis] python = - 2.7: py27-django1.11 - 3.6: py36-django{1.11,2.0,2.1} + 2.7: py2.7-django1.11 + 3.6: py3.6-django{1.11,2.0,2.1} [testenv:py2.7-django1.11] basepython = python2.7 From 9d0b2339c279db95168d4065c29fd0d1f03a01cf Mon Sep 17 00:00:00 2001 From: Shaun Kruger Date: Sun, 6 Jan 2019 01:16:19 -0700 Subject: [PATCH 8/9] Finish updating code for Python3 and Django2 compatibility --- provider/oauth2/backends.py | 19 +++++++--- provider/oauth2/forms.py | 5 +-- provider/oauth2/tests.py | 42 +++++++++++++--------- provider/scope.py | 3 +- provider/templates/provider/authorize.html | 1 - provider/views.py | 2 +- requirements.txt | 2 ++ tests/settings.py | 26 ++++++++++++-- 8 files changed, 72 insertions(+), 28 deletions(-) diff --git a/provider/oauth2/backends.py b/provider/oauth2/backends.py index 2f5ad44a..f7d994a2 100644 --- a/provider/oauth2/backends.py +++ b/provider/oauth2/backends.py @@ -1,3 +1,5 @@ +import base64 + from provider.utils import now from provider.oauth2.forms import ClientAuthForm, PublicPasswordGrantForm from provider.oauth2.models import AccessToken @@ -28,8 +30,9 @@ def authenticate(self, request=None): return None try: - basic, base64 = auth.split(' ') - client_id, client_secret = base64.decode('base64').split(':') + basic, enc_user_passwd = auth.split(' ') + user_pass = base64.b64decode(enc_user_passwd).decode('utf8') + client_id, client_secret = user_pass.split(':') form = ClientAuthForm({ 'client_id': client_id, @@ -53,7 +56,11 @@ def authenticate(self, request=None): if request is None: return None - form = ClientAuthForm(request.REQUEST) + if hasattr(request, 'REQUEST'): + args = request.REQUEST + else: + args = request.POST or request.GET + form = ClientAuthForm(args) if form.is_valid(): return form.cleaned_data.get('client') @@ -74,7 +81,11 @@ def authenticate(self, request=None): if request is None: return None - form = PublicPasswordGrantForm(request.REQUEST) + if hasattr(request, 'REQUEST'): + args = request.REQUEST + else: + args = request.POST or request.GET + form = PublicPasswordGrantForm(args) if form.is_valid(): return form.cleaned_data.get('client') diff --git a/provider/oauth2/forms.py b/provider/oauth2/forms.py index 8aff46b8..548e813a 100644 --- a/provider/oauth2/forms.py +++ b/provider/oauth2/forms.py @@ -1,3 +1,4 @@ +from six import string_types from django import forms from django.contrib.auth import authenticate from django.conf import settings @@ -51,7 +52,7 @@ class ScopeModelChoiceField(forms.ModelMultipleChoiceField): # widget = forms.TextInput def to_python(self, value): - if isinstance(value, basestring): + if isinstance(value, string_types): return [s for s in value.split(' ') if s != ''] else: return value @@ -159,7 +160,7 @@ def save(self, **kwargs): grant = Grant(**kwargs) grant.save() - grant.scope = self.cleaned_data.get('scope') + grant.scope.set(self.cleaned_data.get('scope')) return grant diff --git a/provider/oauth2/tests.py b/provider/oauth2/tests.py index d2860497..94544277 100644 --- a/provider/oauth2/tests.py +++ b/provider/oauth2/tests.py @@ -1,6 +1,8 @@ +import base64 import json -from six.moves.urllib_parse import urlparse, parse_qs import datetime +from six.moves.urllib_parse import urlparse, parse_qs + from unittest import SkipTest from django.http import QueryDict from django.conf import settings @@ -49,14 +51,16 @@ def get_password(self): def _login_and_authorize(self, url_func=None): if url_func is None: - url_func = lambda: self.auth_url() + '?client_id=%s&response_type=code&state=abc' % self.get_client().client_id + url_func = lambda: self.auth_url() + '?client_id={}&response_type=code&state=abc'.format( + self.get_client().client_id + ) response = self.client.get(url_func()) response = self.client.get(self.auth_url2()) response = self.client.post(self.auth_url2(), {'authorize': True, 'scope': 'read'}) self.assertEqual(302, response.status_code, response.content) - self.assertTrue(self.redirect_url() in response['Location']) + self.assertIn(self.redirect_url(), response['Location']) class AuthorizationTest(BaseOAuth2TestCase): @@ -90,7 +94,7 @@ def test_authorization_requires_client_id(self): response = self.client.get(self.auth_url2()) self.assertEqual(400, response.status_code) - self.assertTrue("An unauthorized client tried to access your resources." in response.content) + self.assertIn("An unauthorized client tried to access your resources.", response.content.decode('utf8')) def test_authorization_rejects_invalid_client_id(self): self.login() @@ -98,7 +102,7 @@ def test_authorization_rejects_invalid_client_id(self): response = self.client.get(self.auth_url2()) self.assertEqual(400, response.status_code) - self.assertTrue("An unauthorized client tried to access your resources." in response.content) + self.assertIn(b"An unauthorized client tried to access your resources.", response.content) def test_authorization_requires_response_type(self): self.login() @@ -106,7 +110,7 @@ def test_authorization_requires_response_type(self): response = self.client.get(self.auth_url2()) self.assertEqual(400, response.status_code) - self.assertTrue(escape(u"No 'response_type' supplied.") in response.content) + self.assertIn(escape(u"No 'response_type' supplied."), response.content.decode('utf8')) def test_authorization_requires_supported_response_type(self): self.login() @@ -114,7 +118,7 @@ def test_authorization_requires_supported_response_type(self): response = self.client.get(self.auth_url2()) self.assertEqual(400, response.status_code) - self.assertTrue(escape(u"'unsupported' is not a supported response type.") in response.content) + self.assertIn(escape(u"'unsupported' is not a supported response type."), response.content.decode('utf8')) response = self.client.get(self.auth_url() + '?client_id=%s&response_type=code' % self.get_client().client_id) response = self.client.get(self.auth_url2()) @@ -133,7 +137,7 @@ def test_authorization_requires_a_valid_redirect_uri(self): response = self.client.get(self.auth_url2()) self.assertEqual(400, response.status_code) - self.assertTrue(escape(u"The requested redirect didn't match the client settings.") in response.content) + self.assertIn(escape("The requested redirect didn't match the client settings."), response.content.decode('utf8')) response = self.client.get(self.auth_url() + '?client_id=%s&response_type=code&redirect_uri=%s' % ( self.get_client().client_id, @@ -148,7 +152,7 @@ def test_authorization_requires_a_valid_scope(self): response = self.client.get(self.auth_url() + '?client_id=%s&response_type=code&scope=invalid+invalid2' % self.get_client().client_id) self.assertEqual(400, response.status_code) - self.assertTrue(escape(u"Invalid scope.") in response.content) + self.assertIn(escape(u"Invalid scope."), response.content.decode('utf8')) response = self.client.get(self.auth_url() + '?client_id=%s&response_type=code&scope=%s' % ( self.get_client().client_id, @@ -428,9 +432,12 @@ class AuthBackendTest(BaseOAuth2TestCase): def test_basic_client_backend(self): request = type('Request', (object,), {'META': {}})() - request.META['HTTP_AUTHORIZATION'] = "Basic " + "{0}:{1}".format( + user_pass = "{0}:{1}".format( self.get_client().client_id, - self.get_client().client_secret).encode('base64') + self.get_client().client_secret + ) + user_pass64 = base64.b64encode(user_pass.encode('utf8')).decode('utf8') + request.META['HTTP_AUTHORIZATION'] = "Basic {}".format(user_pass64) self.assertEqual(BasicClientBackend().authenticate(request).id, 2, "Didn't return the right client.") @@ -470,13 +477,13 @@ def test_authorization_enforces_SSL(self): response = self.client.get(self.auth_url()) self.assertEqual(400, response.status_code) - self.assertTrue("A secure connection is required." in response.content) + self.assertIn("A secure connection is required.", response.content.decode('utf8')) def test_access_token_enforces_SSL(self): response = self.client.post(self.access_token_url(), {}) self.assertEqual(400, response.status_code) - self.assertTrue("A secure connection is required." in response.content) + self.assertIn("A secure connection is required.", response.content.decode('utf8')) class ClientFormTest(TestCase): @@ -548,11 +555,12 @@ def test_clear_expired(self): self.assertEqual(302, response.status_code) location = response['Location'] - self.assertFalse('error' in location) - self.assertTrue('code' in location) - + self.assertNotIn('error', location) + self.assertIn('code', location) + print(location) # verify that Grant with code exists - code = parse_qs(location)['code'][0] + parsed_location = urlparse(location) + code = parse_qs(parsed_location.query)['code'][0] self.assertTrue(Grant.objects.filter(code=code).exists()) # use the code/grant diff --git a/provider/scope.py b/provider/scope.py index 46c9d4b7..da2f4d7d 100644 --- a/provider/scope.py +++ b/provider/scope.py @@ -7,6 +7,7 @@ See :class:`provider.scope.to_int` on how scopes are combined. """ +from functools import reduce from .constants import SCOPES @@ -73,7 +74,7 @@ def to_names(scope): """ return [ name - for (name, value) in SCOPE_NAME_DICT.iteritems() + for (name, value) in SCOPE_NAME_DICT.items() if check(value, scope) ] diff --git a/provider/templates/provider/authorize.html b/provider/templates/provider/authorize.html index 91286ec7..ec75ed2a 100644 --- a/provider/templates/provider/authorize.html +++ b/provider/templates/provider/authorize.html @@ -1,5 +1,4 @@ {% load scope %} -{% load url from future %} {% block content %} {% if not error %}

{{ client.name }} would like to access your data with the following permissions:

diff --git a/provider/views.py b/provider/views.py index fae69faf..6cd8a57f 100644 --- a/provider/views.py +++ b/provider/views.py @@ -61,7 +61,7 @@ def clear_data(self, request): """ Clear all OAuth related data from the session store. """ - for key in request.session.keys(): + for key in list(request.session.keys()): if key.startswith(constants.SESSION_KEY): del request.session[key] diff --git a/requirements.txt b/requirements.txt index 87992eab..78667f0b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,4 @@ Django>=2.1 shortuuid>=0.4 +six>=0.11.0 +sqlparse>=0.2.4 diff --git a/tests/settings.py b/tests/settings.py index b689fcc1..333f26bd 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -3,7 +3,6 @@ from django import VERSION as DJANGO_VERSION DEBUG = True -TEMPLATE_DEBUG = DEBUG ADMINS = ( ('Tester', 'test@example.com'), @@ -61,7 +60,23 @@ 'provider.oauth2', ) -MIDDLEWARE_CLASSES = ( +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + # 'django.template.context_processors.debug', + # 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + # 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +MIDDLEWARE = ( 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', @@ -70,6 +85,13 @@ 'django.middleware.clickjacking.XFrameOptionsMiddleware', ) +PASSWORD_HASHERS = [ + 'django.contrib.auth.hashers.PBKDF2PasswordHasher', + 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', + 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher', + 'django.contrib.auth.hashers.SHA1PasswordHasher', # Used by unit tests +] + # Use DiscoverRunner on Django 1.7 and above if DJANGO_VERSION[0] == 1 and DJANGO_VERSION[1] >= 7: TEST_RUNNER = 'django.test.runner.DiscoverRunner' From 2ca8e8d5f4e9e8c964419a9e66cf26427c02ab28 Mon Sep 17 00:00:00 2001 From: Shaun Kruger Date: Sun, 6 Jan 2019 23:18:28 -0700 Subject: [PATCH 9/9] Update version and release notes --- docs/changes.rst | 13 ++++++++++++- provider/__init__.py | 2 +- setup.py | 2 ++ tox.ini | 4 +--- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/docs/changes.rst b/docs/changes.rst index 7fe86d33..da4789a8 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -1,7 +1,18 @@ +v 2.0 +----- +* Update for current Django 1.11, 2.0, and 2.1. + +v 1.2 +----- +Updated to make skopes configurable in the database and update for Django 1.7 + +v 1.0 +----- +Forked from original project at caffeinehit/django-oauth2-provider v 0.2 ----- * *Breaking change* Moved ``provider.oauth2.scope`` to ``provider.scope`` * *Breaking change* Replaced the write scope with a new write scope that includes reading * Default scope for new ``provider.oauth2.models.AccessToken`` is now ``provider.constants.SCOPES[0][0]`` -* Access token response returns a space seperated list of scopes instead of an integer value \ No newline at end of file +* Access token response returns a space seperated list of scopes instead of an integer value diff --git a/provider/__init__.py b/provider/__init__.py index b2a95f90..f2dc0e40 100644 --- a/provider/__init__.py +++ b/provider/__init__.py @@ -1 +1 @@ -__version__ = "1.2" +__version__ = "2.0" diff --git a/setup.py b/setup.py index 16a4946e..a2b6faec 100644 --- a/setup.py +++ b/setup.py @@ -24,6 +24,8 @@ ], install_requires=[ "shortuuid>=0.4", + "six>=0.11.0", + "sqlparse>=0.2.4", ], include_package_data=True, zip_safe=False, diff --git a/tox.ini b/tox.ini index d0c4758c..94c8ab73 100644 --- a/tox.ini +++ b/tox.ini @@ -8,9 +8,7 @@ setenv = PYTHONPATH = {toxinidir} commands = {toxinidir}/test.sh -deps = shortuuid>=0.5.0 - sqlparse>=0.2.4 - six>=1.12.0 +deps = [travis] python =