diff --git a/provider/constants.py b/provider/constants.py index cf92ed42..0328cf66 100644 --- a/provider/constants.py +++ b/provider/constants.py @@ -30,6 +30,8 @@ ENFORCE_SECURE = getattr(settings, 'OAUTH_ENFORCE_SECURE', False) ENFORCE_CLIENT_SECURE = getattr(settings, 'OAUTH_ENFORCE_CLIENT_SECURE', True) +REDIRECT_URI_ENFORCE_PREFIX_ONLY = getattr(settings, 'OAUTH_REDIRECT_URI_ENFORCE_PREFIX_ONLY', False) + SESSION_KEY = getattr(settings, 'OAUTH_SESSION_KEY', 'oauth') SINGLE_ACCESS_TOKEN = getattr(settings, 'OAUTH_SINGLE_ACCESS_TOKEN', False) diff --git a/provider/oauth2/forms.py b/provider/oauth2/forms.py index 1e0485a7..33de5441 100644 --- a/provider/oauth2/forms.py +++ b/provider/oauth2/forms.py @@ -3,7 +3,10 @@ from django.utils.encoding import smart_unicode from django.utils.translation import ugettext as _ from .. import scope -from ..constants import RESPONSE_TYPE_CHOICES, SCOPES +from ..constants import (REDIRECT_URI_ENFORCE_PREFIX_ONLY, + RESPONSE_TYPE_CHOICES, + SCOPES, + ) from ..forms import OAuthForm, OAuthValidationError from ..scope import SCOPE_NAMES from ..utils import now @@ -159,7 +162,14 @@ def clean_redirect_uri(self): redirect_uri = self.cleaned_data.get('redirect_uri') if redirect_uri: - if not redirect_uri == self.client.redirect_uri: + valid = False + if REDIRECT_URI_ENFORCE_PREFIX_ONLY: + if redirect_uri.startswith(self.client.redirect_uri): + valid = True + else: + if redirect_uri == self.client.redirect_uri: + valid = True + if not valid: raise OAuthValidationError({ 'error': 'invalid_request', 'error_description': _("The requested redirect didn't " diff --git a/provider/oauth2/migrations/0004_auto__add_index_accesstoken_token__add_unique_accesstoken_token__chg_f.py b/provider/oauth2/migrations/0004_auto__add_index_accesstoken_token__add_unique_accesstoken_token__chg_f.py new file mode 100644 index 00000000..d0b8e16f --- /dev/null +++ b/provider/oauth2/migrations/0004_auto__add_index_accesstoken_token__add_unique_accesstoken_token__chg_f.py @@ -0,0 +1,110 @@ +# -*- 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(u'oauth2_accesstoken', ['token']) + + # Adding unique constraint on 'AccessToken', fields ['token'] + db.create_unique(u'oauth2_accesstoken', ['token']) + + + # Changing field 'Grant.redirect_uri' + db.alter_column(u'oauth2_grant', 'redirect_uri', self.gf('django.db.models.fields.CharField')(max_length=1000)) + + def backwards(self, orm): + # Removing unique constraint on 'AccessToken', fields ['token'] + db.delete_unique(u'oauth2_accesstoken', ['token']) + + # Removing index on 'AccessToken', fields ['token'] + db.delete_index(u'oauth2_accesstoken', ['token']) + + + # Changing field 'Grant.redirect_uri' + db.alter_column(u'oauth2_grant', 'redirect_uri', self.gf('django.db.models.fields.CharField')(max_length=255)) + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'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': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'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': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + u'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': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + u'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'}), + u'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'}) + }, + u'oauth2.accesstoken': { + 'Meta': {'object_name': 'AccessToken'}, + 'client': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['oauth2.Client']"}), + 'expires': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2014, 10, 29, 0, 0)'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'scope': ('django.db.models.fields.IntegerField', [], {'default': '2'}), + 'token': ('django.db.models.fields.CharField', [], {'default': "'1a958965c42a7317cea2da0f782e1b497c0377d0'", 'unique': 'True', 'max_length': '255', 'db_index': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}) + }, + u'oauth2.client': { + 'Meta': {'object_name': 'Client'}, + 'client_id': ('django.db.models.fields.CharField', [], {'default': "'7a7b2037eab276a6b868'", 'max_length': '255'}), + 'client_secret': ('django.db.models.fields.CharField', [], {'default': "'09c8b5b4b73356f5846b63cc1946cf766a6e75c9'", 'max_length': '255'}), + 'client_type': ('django.db.models.fields.IntegerField', [], {}), + u'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': u"orm['auth.User']"}) + }, + u'oauth2.grant': { + 'Meta': {'object_name': 'Grant'}, + 'client': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['oauth2.Client']"}), + 'code': ('django.db.models.fields.CharField', [], {'default': "'15fd7b8395106bfd36f897bda8a0a61c062457ee'", 'max_length': '255'}), + 'expires': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2013, 10, 29, 0, 0)'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'redirect_uri': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'blank': 'True'}), + 'scope': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}) + }, + u'oauth2.refreshtoken': { + 'Meta': {'object_name': 'RefreshToken'}, + 'access_token': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'refresh_token'", 'unique': 'True', 'to': u"orm['oauth2.AccessToken']"}), + 'client': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['oauth2.Client']"}), + 'expired': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'token': ('django.db.models.fields.CharField', [], {'default': "'8ad786156b50a1b6ed5c8313812d7c43129c462b'", 'max_length': '255'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}) + } + } + + complete_apps = ['oauth2'] \ No newline at end of file diff --git a/provider/oauth2/models.py b/provider/oauth2/models.py index 529a9cd4..a65e85b9 100644 --- a/provider/oauth2/models.py +++ b/provider/oauth2/models.py @@ -70,7 +70,7 @@ class Grant(models.Model): client = models.ForeignKey(Client) 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) + redirect_uri = models.CharField(max_length=1000, blank=True) scope = models.IntegerField(default=0) def __unicode__(self): @@ -98,7 +98,8 @@ class AccessToken(models.Model): expiry """ user = models.ForeignKey(AUTH_USER_MODEL) - token = models.CharField(max_length=255, default=long_token) + token = models.CharField(max_length=255, default=long_token, + unique=True, db_index=True) client = models.ForeignKey(Client) expires = models.DateTimeField(default=get_token_expiry) scope = models.IntegerField(default=constants.SCOPES[0][0],