From 205d3becd49b4d067e72ef8b5ec4d69769c7c5dd Mon Sep 17 00:00:00 2001 From: Alexandre `Zopieux` Macabies Date: Tue, 13 Jan 2015 17:03:01 +0000 Subject: [PATCH 01/12] Added Django >=1.7 AppConfig and updated get_application_model() accordingly --- oauth2_provider/__init__.py | 2 ++ oauth2_provider/apps.py | 6 ++++++ oauth2_provider/models.py | 12 +++++++++++- 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 oauth2_provider/apps.py diff --git a/oauth2_provider/__init__.py b/oauth2_provider/__init__.py index f6c203077..42c87e16c 100644 --- a/oauth2_provider/__init__.py +++ b/oauth2_provider/__init__.py @@ -3,3 +3,5 @@ __author__ = "Massimiliano Pippi & Federico Frenguelli" VERSION = __version__ # synonym + +default_app_config = 'oauth2_provider.apps.OAuth2ProviderConfig' diff --git a/oauth2_provider/apps.py b/oauth2_provider/apps.py new file mode 100644 index 000000000..c27bceefe --- /dev/null +++ b/oauth2_provider/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class OAuth2ProviderConfig(AppConfig): + name = 'oauth2_provider' + verbose_name = "OAuth2 provider" diff --git a/oauth2_provider/models.py b/oauth2_provider/models.py index 688d64834..a334e467d 100644 --- a/oauth2_provider/models.py +++ b/oauth2_provider/models.py @@ -239,7 +239,17 @@ def get_application_model(): except ValueError: e = "APPLICATION_MODEL must be of the form 'app_label.model_name'" raise ImproperlyConfigured(e) - app_model = get_model(app_label, model_name) + + try: + # Django >=1.7 + from django.apps import apps + try: + app_model = apps.get_model(app_label, model_name) + except LookupError: + app_model = None + except ImportError: + app_model = get_model(app_label, model_name) + if app_model is None: e = "APPLICATION_MODEL refers to model {0} that has not been installed" raise ImproperlyConfigured(e.format(oauth2_settings.APPLICATION_MODEL)) From 7640255e6206a496e23388ca717e36467196c543 Mon Sep 17 00:00:00 2001 From: Alexandre `Zopieux` Macabies Date: Tue, 13 Jan 2015 17:18:42 +0000 Subject: [PATCH 02/12] Trying to use monkey-patching for get_application_model() --- oauth2_provider/apps.py | 22 ++++++++++++++++++++++ oauth2_provider/forms.py | 4 ++-- oauth2_provider/oauth2_validators.py | 16 ++++++++-------- oauth2_provider/views/application.py | 2 +- oauth2_provider/views/base.py | 4 +--- 5 files changed, 34 insertions(+), 14 deletions(-) diff --git a/oauth2_provider/apps.py b/oauth2_provider/apps.py index c27bceefe..eca559276 100644 --- a/oauth2_provider/apps.py +++ b/oauth2_provider/apps.py @@ -4,3 +4,25 @@ class OAuth2ProviderConfig(AppConfig): name = 'oauth2_provider' verbose_name = "OAuth2 provider" + + def ready(self): + from .models import get_application_model + Application = get_application_model() + + # monkey-patch ApplicationOwnerIsUserMixin model + from .views.application import ApplicationOwnerIsUserMixin + ApplicationOwnerIsUserMixin.model = Application + + # monkey-patch RegistrationForm model + from .forms import RegistrationForm + RegistrationForm.Meta.model = Application + + # monkey-patch GRANT_TYPE_MAPPING + from . import oauth2_validators + oauth2_validators.GRANT_TYPE_MAPPING = { + 'authorization_code': (Application.GRANT_AUTHORIZATION_CODE,), + 'password': (Application.GRANT_PASSWORD,), + 'client_credentials': (Application.GRANT_CLIENT_CREDENTIALS,), + 'refresh_token': (Application.GRANT_AUTHORIZATION_CODE, Application.GRANT_PASSWORD, + Application.GRANT_CLIENT_CREDENTIALS) + } diff --git a/oauth2_provider/forms.py b/oauth2_provider/forms.py index 8f7b3ab34..16d5a683d 100644 --- a/oauth2_provider/forms.py +++ b/oauth2_provider/forms.py @@ -1,6 +1,6 @@ from django import forms -from .models import get_application_model +# from .models import get_application_model class AllowForm(forms.Form): @@ -24,5 +24,5 @@ class RegistrationForm(forms.ModelForm): TODO: add docstring """ class Meta: - model = get_application_model() + # model = get_application_model() fields = ('name', 'client_id', 'client_secret', 'client_type', 'authorization_grant_type', 'redirect_uris') diff --git a/oauth2_provider/oauth2_validators.py b/oauth2_provider/oauth2_validators.py index 6a79f3f7d..8961eeca0 100644 --- a/oauth2_provider/oauth2_validators.py +++ b/oauth2_provider/oauth2_validators.py @@ -13,17 +13,17 @@ from .models import Grant, AccessToken, RefreshToken, get_application_model from .settings import oauth2_settings -Application = get_application_model() +# Application = get_application_model() log = logging.getLogger('oauth2_provider') -GRANT_TYPE_MAPPING = { - 'authorization_code': (Application.GRANT_AUTHORIZATION_CODE,), - 'password': (Application.GRANT_PASSWORD,), - 'client_credentials': (Application.GRANT_CLIENT_CREDENTIALS,), - 'refresh_token': (Application.GRANT_AUTHORIZATION_CODE, Application.GRANT_PASSWORD, - Application.GRANT_CLIENT_CREDENTIALS) -} +# GRANT_TYPE_MAPPING = { +# 'authorization_code': (Application.GRANT_AUTHORIZATION_CODE,), +# 'password': (Application.GRANT_PASSWORD,), +# 'client_credentials': (Application.GRANT_CLIENT_CREDENTIALS,), +# 'refresh_token': (Application.GRANT_AUTHORIZATION_CODE, Application.GRANT_PASSWORD, +# Application.GRANT_CLIENT_CREDENTIALS) +# } class OAuth2Validator(RequestValidator): diff --git a/oauth2_provider/views/application.py b/oauth2_provider/views/application.py index 2d6ef617f..55d0133d3 100644 --- a/oauth2_provider/views/application.py +++ b/oauth2_provider/views/application.py @@ -11,7 +11,7 @@ class ApplicationOwnerIsUserMixin(LoginRequiredMixin): """ This mixin is used to provide an Application queryset filtered by the current request.user. """ - model = get_application_model() + # model = get_application_model() fields = '__all__' def get_queryset(self): diff --git a/oauth2_provider/views/base.py b/oauth2_provider/views/base.py index b7a5309af..1237a48c9 100644 --- a/oauth2_provider/views/base.py +++ b/oauth2_provider/views/base.py @@ -16,8 +16,6 @@ from ..models import get_application_model from .mixins import OAuthLibMixin -Application = get_application_model() - log = logging.getLogger('oauth2_provider') @@ -115,7 +113,7 @@ def get(self, request, *args, **kwargs): kwargs['scopes_descriptions'] = [oauth2_settings.SCOPES[scope] for scope in scopes] kwargs['scopes'] = scopes # at this point we know an Application instance with such client_id exists in the database - application = Application.objects.get(client_id=credentials['client_id']) # TODO: cache it! + application = get_application_model().objects.get(client_id=credentials['client_id']) # TODO: cache it! kwargs['application'] = application kwargs.update(credentials) self.oauth2_data = kwargs From 7f8c59975c8624eb471051e79f0d4e769a2e1e7d Mon Sep 17 00:00:00 2001 From: Alexandre `Zopieux` Macabies Date: Tue, 13 Jan 2015 19:56:30 +0000 Subject: [PATCH 03/12] Fixed Application monkey-patching in oauth2_validators --- oauth2_provider/apps.py | 1 + oauth2_provider/oauth2_validators.py | 12 +++--------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/oauth2_provider/apps.py b/oauth2_provider/apps.py index eca559276..3a6d3ba33 100644 --- a/oauth2_provider/apps.py +++ b/oauth2_provider/apps.py @@ -19,6 +19,7 @@ def ready(self): # monkey-patch GRANT_TYPE_MAPPING from . import oauth2_validators + oauth2_validators.Application = Application oauth2_validators.GRANT_TYPE_MAPPING = { 'authorization_code': (Application.GRANT_AUTHORIZATION_CODE,), 'password': (Application.GRANT_PASSWORD,), diff --git a/oauth2_provider/oauth2_validators.py b/oauth2_provider/oauth2_validators.py index 8961eeca0..f4ecd8bc6 100644 --- a/oauth2_provider/oauth2_validators.py +++ b/oauth2_provider/oauth2_validators.py @@ -10,20 +10,14 @@ from oauthlib.oauth2 import RequestValidator from .compat import unquote_plus -from .models import Grant, AccessToken, RefreshToken, get_application_model +from .models import Grant, AccessToken, RefreshToken from .settings import oauth2_settings -# Application = get_application_model() +Application = None log = logging.getLogger('oauth2_provider') -# GRANT_TYPE_MAPPING = { -# 'authorization_code': (Application.GRANT_AUTHORIZATION_CODE,), -# 'password': (Application.GRANT_PASSWORD,), -# 'client_credentials': (Application.GRANT_CLIENT_CREDENTIALS,), -# 'refresh_token': (Application.GRANT_AUTHORIZATION_CODE, Application.GRANT_PASSWORD, -# Application.GRANT_CLIENT_CREDENTIALS) -# } +GRANT_TYPE_MAPPING = {} class OAuth2Validator(RequestValidator): From ae5591cf1212929ec3d2e19a8ed6ca0d22530640 Mon Sep 17 00:00:00 2001 From: Zopieux Date: Tue, 13 Jan 2015 20:32:03 +0000 Subject: [PATCH 04/12] Added `Application.redirect_uri_schemes` List of the schemes used by the Application `redirect_uris` --- oauth2_provider/models.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/oauth2_provider/models.py b/oauth2_provider/models.py index a334e467d..1be7a85d9 100644 --- a/oauth2_provider/models.py +++ b/oauth2_provider/models.py @@ -12,6 +12,7 @@ from django.utils.translation import ugettext_lazy as _ from django.utils.encoding import python_2_unicode_compatible from django.core.exceptions import ImproperlyConfigured +from django.utils.six.moves.urllib.parse import urlparse from .settings import oauth2_settings from .compat import AUTH_USER_MODEL @@ -96,6 +97,18 @@ def redirect_uri_allowed(self, uri): """ return uri in self.redirect_uris.split() + @property + def redirect_uri_schemes(self): + """ + Returns the set of schemes used by the :attr:`redirect_uris`. + """ + schemes = set() + for uri in self.redirect_uris.split(): + parsed = urlparse(uri) + if parsed.scheme: + schemes.add(parsed.scheme) + return schemes + def clean(self): from django.core.exceptions import ValidationError if not self.redirect_uris \ From ce2d282405135660ebc874a231be606d5612d604 Mon Sep 17 00:00:00 2001 From: Zopieux Date: Tue, 13 Jan 2015 20:38:33 +0000 Subject: [PATCH 05/12] Using CustomSchemesHttpResponseRedirect HttpResponseRedirect is very restrictive on the "safe" schemes: HTTP, HTTPS, FTP. As such, it does not allow redirections to custom schemes such as mobile callback handlers eg. `my-app://oauth/callback/` It was replaced with CustomSchemesHttpResponseRedirect that takes a list of allowed schemes. --- oauth2_provider/views/base.py | 37 +++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/oauth2_provider/views/base.py b/oauth2_provider/views/base.py index 1237a48c9..372478575 100644 --- a/oauth2_provider/views/base.py +++ b/oauth2_provider/views/base.py @@ -5,6 +5,8 @@ from django.views.generic import View, FormView from django.utils import timezone from django.utils.decorators import method_decorator +from django.utils.encoding import force_text +from django.utils.six.moves.urllib.parse import urlparse from oauthlib.oauth2 import Server @@ -19,6 +21,24 @@ log = logging.getLogger('oauth2_provider') +class CustomSchemesHttpResponseRedirect(HttpResponseRedirect): + """ + HttpResponseRedirect subclass that accepts an `allowed_schemes` + positional argument to overwrite the default set of schemes. + Warning: if `allowed_schemes` is empty, all schemes are allowed. + """ + def __init__(self, redirect_to, *args, **kwargs): + parsed = urlparse(force_text(redirect_to)) + try: + self.allowed_schemes = kwargs.pop('allowed_schemes') + except KeyError: + pass + if self.allowed_schemes and parsed.scheme and parsed.scheme not in self.allowed_schemes: + raise DisallowedRedirect("Unsafe redirect to URL with protocol '%s'" % parsed.scheme) + super(HttpResponseRedirectBase, self).__init__(*args, **kwargs) + self['Location'] = iri_to_uri(redirect_to) + + class BaseAuthorizationView(LoginRequiredMixin, OAuthLibMixin, View): """ Implements a generic endpoint to handle *Authorization Requests* as in :rfc:`4.1.1`. The view @@ -124,16 +144,20 @@ def get(self, request, *args, **kwargs): # Check to see if the user has already granted access and return # a successful response depending on 'approval_prompt' url parameter require_approval = request.GET.get('approval_prompt', oauth2_settings.REQUEST_APPROVAL_PROMPT) + + def build_authorization_response(): + uri, headers, body, status = self.create_authorization_response( + request=self.request, scopes=" ".join(scopes), + credentials=credentials, allow=True) + redirect_schemes = application.redirect_uri_schemes + return CustomSchemesHttpResponseRedirect(uri, allowed_schemes=redirect_schemes) # If skip_authorization field is True, skip the authorization screen even # if this is the first use of the application and there was no previous authorization. # This is useful for in-house applications-> assume an in-house applications # are already approved. if application.skip_authorization: - uri, headers, body, status = self.create_authorization_response( - request=self.request, scopes=" ".join(scopes), - credentials=credentials, allow=True) - return HttpResponseRedirect(uri) + return build_authorization_response() elif require_approval == 'auto': tokens = request.user.accesstoken_set.filter(application=kwargs['application'], @@ -141,10 +165,7 @@ def get(self, request, *args, **kwargs): # check past authorizations regarded the same scopes as the current one for token in tokens: if token.allow_scopes(scopes): - uri, headers, body, status = self.create_authorization_response( - request=self.request, scopes=" ".join(scopes), - credentials=credentials, allow=True) - return HttpResponseRedirect(uri) + return build_authorization_response() return self.render_to_response(self.get_context_data(**kwargs)) From 8e220ba9805e6525853f8318a1faddb2fb6d9ac4 Mon Sep 17 00:00:00 2001 From: Alexandre `Zopieux` Macabies Date: Tue, 13 Jan 2015 20:42:37 +0000 Subject: [PATCH 06/12] Moved CustomSchemesHttpResponseRedirect in views/util.py --- oauth2_provider/views/base.py | 23 ++--------------------- oauth2_provider/views/util.py | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 21 deletions(-) create mode 100644 oauth2_provider/views/util.py diff --git a/oauth2_provider/views/base.py b/oauth2_provider/views/base.py index 372478575..73ed3a326 100644 --- a/oauth2_provider/views/base.py +++ b/oauth2_provider/views/base.py @@ -5,8 +5,6 @@ from django.views.generic import View, FormView from django.utils import timezone from django.utils.decorators import method_decorator -from django.utils.encoding import force_text -from django.utils.six.moves.urllib.parse import urlparse from oauthlib.oauth2 import Server @@ -17,28 +15,11 @@ from ..forms import AllowForm from ..models import get_application_model from .mixins import OAuthLibMixin +from .util import CustomSchemesHttpResponseRedirect log = logging.getLogger('oauth2_provider') -class CustomSchemesHttpResponseRedirect(HttpResponseRedirect): - """ - HttpResponseRedirect subclass that accepts an `allowed_schemes` - positional argument to overwrite the default set of schemes. - Warning: if `allowed_schemes` is empty, all schemes are allowed. - """ - def __init__(self, redirect_to, *args, **kwargs): - parsed = urlparse(force_text(redirect_to)) - try: - self.allowed_schemes = kwargs.pop('allowed_schemes') - except KeyError: - pass - if self.allowed_schemes and parsed.scheme and parsed.scheme not in self.allowed_schemes: - raise DisallowedRedirect("Unsafe redirect to URL with protocol '%s'" % parsed.scheme) - super(HttpResponseRedirectBase, self).__init__(*args, **kwargs) - self['Location'] = iri_to_uri(redirect_to) - - class BaseAuthorizationView(LoginRequiredMixin, OAuthLibMixin, View): """ Implements a generic endpoint to handle *Authorization Requests* as in :rfc:`4.1.1`. The view @@ -144,7 +125,7 @@ def get(self, request, *args, **kwargs): # Check to see if the user has already granted access and return # a successful response depending on 'approval_prompt' url parameter require_approval = request.GET.get('approval_prompt', oauth2_settings.REQUEST_APPROVAL_PROMPT) - + def build_authorization_response(): uri, headers, body, status = self.create_authorization_response( request=self.request, scopes=" ".join(scopes), diff --git a/oauth2_provider/views/util.py b/oauth2_provider/views/util.py new file mode 100644 index 000000000..9368979f3 --- /dev/null +++ b/oauth2_provider/views/util.py @@ -0,0 +1,22 @@ +from django.http import HttpResponseRedirect +from django.core.exceptions import DisallowedRedirect +from django.utils.encoding import force_text +from django.utils.six.moves.urllib.parse import urlparse + + +class CustomSchemesHttpResponseRedirect(HttpResponseRedirect): + """ + HttpResponseRedirect subclass that accepts an `allowed_schemes` + positional argument to overwrite the default set of schemes. + Warning: if `allowed_schemes` is empty, all schemes are allowed. + """ + def __init__(self, redirect_to, *args, **kwargs): + parsed = urlparse(force_text(redirect_to)) + try: + self.allowed_schemes = kwargs.pop('allowed_schemes') + except KeyError: + pass + if self.allowed_schemes and parsed.scheme and parsed.scheme not in self.allowed_schemes: + raise DisallowedRedirect("Unsafe redirect to URL with protocol '%s'" % parsed.scheme) + super(HttpResponseRedirect, self).__init__(*args, **kwargs) + self['Location'] = iri_to_uri(redirect_to) From 6832ba01b950b79ea27319f2e385bd42d335deac Mon Sep 17 00:00:00 2001 From: Alexandre `Zopieux` Macabies Date: Tue, 13 Jan 2015 20:52:25 +0000 Subject: [PATCH 07/12] Refactored SchemedHttpResponseRedirect --- oauth2_provider/views/base.py | 4 ++-- oauth2_provider/views/util.py | 26 ++++++++++++++------------ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/oauth2_provider/views/base.py b/oauth2_provider/views/base.py index 73ed3a326..ad482d905 100644 --- a/oauth2_provider/views/base.py +++ b/oauth2_provider/views/base.py @@ -15,7 +15,7 @@ from ..forms import AllowForm from ..models import get_application_model from .mixins import OAuthLibMixin -from .util import CustomSchemesHttpResponseRedirect +from .util import SchemedHttpResponseRedirect log = logging.getLogger('oauth2_provider') @@ -131,7 +131,7 @@ def build_authorization_response(): request=self.request, scopes=" ".join(scopes), credentials=credentials, allow=True) redirect_schemes = application.redirect_uri_schemes - return CustomSchemesHttpResponseRedirect(uri, allowed_schemes=redirect_schemes) + return SchemedHttpResponseRedirect(uri, allowed_schemes=redirect_schemes) # If skip_authorization field is True, skip the authorization screen even # if this is the first use of the application and there was no previous authorization. diff --git a/oauth2_provider/views/util.py b/oauth2_provider/views/util.py index 9368979f3..95ad722c5 100644 --- a/oauth2_provider/views/util.py +++ b/oauth2_provider/views/util.py @@ -1,22 +1,24 @@ -from django.http import HttpResponseRedirect -from django.core.exceptions import DisallowedRedirect -from django.utils.encoding import force_text -from django.utils.six.moves.urllib.parse import urlparse +from django.http import HttpResponseRedirectBase -class CustomSchemesHttpResponseRedirect(HttpResponseRedirect): +class SchemedHttpResponseRedirectBase(HttpResponseRedirectBase): """ - HttpResponseRedirect subclass that accepts an `allowed_schemes` + HttpResponseRedirectBase-like class that accepts an `allowed_schemes` positional argument to overwrite the default set of schemes. - Warning: if `allowed_schemes` is empty, all schemes are allowed. + Warning: if `allowed_schemes` is empty, no scheme is allowed. """ + def __init__(self, redirect_to, *args, **kwargs): - parsed = urlparse(force_text(redirect_to)) try: self.allowed_schemes = kwargs.pop('allowed_schemes') except KeyError: pass - if self.allowed_schemes and parsed.scheme and parsed.scheme not in self.allowed_schemes: - raise DisallowedRedirect("Unsafe redirect to URL with protocol '%s'" % parsed.scheme) - super(HttpResponseRedirect, self).__init__(*args, **kwargs) - self['Location'] = iri_to_uri(redirect_to) + super(HttpResponseRedirectBase, self).__init__(*args, **kwargs) + + +class SchemedHttpResponseRedirect(SchemedHttpResponseRedirectBase): + status_code = 302 + + +class SchemedHttpResponsePermanentRedirect(SchemedHttpResponseRedirectBase): + status_code = 301 From e15926390da31e6beea1f683366090d44b9c12b3 Mon Sep 17 00:00:00 2001 From: Alexandre `Zopieux` Macabies Date: Tue, 13 Jan 2015 20:54:15 +0000 Subject: [PATCH 08/12] Fixed http.response import --- oauth2_provider/views/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oauth2_provider/views/util.py b/oauth2_provider/views/util.py index 95ad722c5..f9f479f8a 100644 --- a/oauth2_provider/views/util.py +++ b/oauth2_provider/views/util.py @@ -1,4 +1,4 @@ -from django.http import HttpResponseRedirectBase +from django.http.response import HttpResponseRedirectBase class SchemedHttpResponseRedirectBase(HttpResponseRedirectBase): From 9f61225640676266870cce9eb677ac4abd16d393 Mon Sep 17 00:00:00 2001 From: Alexandre `Zopieux` Macabies Date: Tue, 13 Jan 2015 20:55:30 +0000 Subject: [PATCH 09/12] Forgot redirect_to argument --- oauth2_provider/views/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oauth2_provider/views/util.py b/oauth2_provider/views/util.py index f9f479f8a..df1763b2b 100644 --- a/oauth2_provider/views/util.py +++ b/oauth2_provider/views/util.py @@ -13,7 +13,7 @@ def __init__(self, redirect_to, *args, **kwargs): self.allowed_schemes = kwargs.pop('allowed_schemes') except KeyError: pass - super(HttpResponseRedirectBase, self).__init__(*args, **kwargs) + super(HttpResponseRedirectBase, self).__init__(redirect_to, *args, **kwargs) class SchemedHttpResponseRedirect(SchemedHttpResponseRedirectBase): From ba296444f922c6a25776b2246cae13216a9d14a7 Mon Sep 17 00:00:00 2001 From: Alexandre `Zopieux` Macabies Date: Tue, 13 Jan 2015 20:57:59 +0000 Subject: [PATCH 10/12] Fixed wrong super() class --- oauth2_provider/views/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oauth2_provider/views/util.py b/oauth2_provider/views/util.py index df1763b2b..10fe5cc21 100644 --- a/oauth2_provider/views/util.py +++ b/oauth2_provider/views/util.py @@ -13,7 +13,7 @@ def __init__(self, redirect_to, *args, **kwargs): self.allowed_schemes = kwargs.pop('allowed_schemes') except KeyError: pass - super(HttpResponseRedirectBase, self).__init__(redirect_to, *args, **kwargs) + super(SchemedHttpResponseRedirectBase, self).__init__(redirect_to, *args, **kwargs) class SchemedHttpResponseRedirect(SchemedHttpResponseRedirectBase): From df5e1473fba323a322f502f110f4d2f8fa6afdeb Mon Sep 17 00:00:00 2001 From: Alexandre `Zopieux` Macabies Date: Tue, 13 Jan 2015 21:06:18 +0000 Subject: [PATCH 11/12] Added the SchemedHttpResponseRedirect trick to form_valid() --- oauth2_provider/views/base.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/oauth2_provider/views/base.py b/oauth2_provider/views/base.py index ad482d905..57b9e05fe 100644 --- a/oauth2_provider/views/base.py +++ b/oauth2_provider/views/base.py @@ -101,9 +101,9 @@ def form_valid(self, form): allow = form.cleaned_data.get('allow') uri, headers, body, status = self.create_authorization_response( request=self.request, scopes=scopes, credentials=credentials, allow=allow) - self.success_url = uri - log.debug("Success url for the request: {0}".format(self.success_url)) - return super(AuthorizationView, self).form_valid(form) + log.debug("Redirect uri for the request: {0}".format(uri)) + application = get_application_model().objects.get(client_id=credentials['client_id']) # TODO: cache it! + return SchemedHttpResponseRedirect(uri, allowed_schemes=application.redirect_uri_schemes) except OAuthToolkitError as error: return self.error_response(error) From bec4875d868216a76f62729d055cad9a0fcd0984 Mon Sep 17 00:00:00 2001 From: Alexandre `Zopieux` Macabies Date: Tue, 13 Jan 2015 21:40:18 +0000 Subject: [PATCH 12/12] Sanitazied the monkey-patching with FIXMEs and moved get_model to compat --- oauth2_provider/apps.py | 7 ++++--- oauth2_provider/compat.py | 7 +++++++ oauth2_provider/forms.py | 5 ++--- oauth2_provider/models.py | 8 +------- oauth2_provider/oauth2_validators.py | 5 +++-- oauth2_provider/views/application.py | 4 ++-- 6 files changed, 19 insertions(+), 17 deletions(-) diff --git a/oauth2_provider/apps.py b/oauth2_provider/apps.py index 3a6d3ba33..58b00ed4f 100644 --- a/oauth2_provider/apps.py +++ b/oauth2_provider/apps.py @@ -6,18 +6,19 @@ class OAuth2ProviderConfig(AppConfig): verbose_name = "OAuth2 provider" def ready(self): + # Monkey-patch Meta.model and other root objects from .models import get_application_model Application = get_application_model() - # monkey-patch ApplicationOwnerIsUserMixin model + # monkey-patch views/application.ApplicationOwnerIsUserMixin model from .views.application import ApplicationOwnerIsUserMixin ApplicationOwnerIsUserMixin.model = Application - # monkey-patch RegistrationForm model + # monkey-patch forms.RegistrationForm model from .forms import RegistrationForm RegistrationForm.Meta.model = Application - # monkey-patch GRANT_TYPE_MAPPING + # monkey-patch oauth2_validators.Appliacation and GRANT_TYPE_MAPPING from . import oauth2_validators oauth2_validators.Application = Application oauth2_validators.GRANT_TYPE_MAPPING = { diff --git a/oauth2_provider/compat.py b/oauth2_provider/compat.py index e82e4ef97..658a53112 100644 --- a/oauth2_provider/compat.py +++ b/oauth2_provider/compat.py @@ -25,6 +25,13 @@ else: AUTH_USER_MODEL = 'auth.User' +try: + # Django's new application loading system + from django.apps import apps + get_model = apps.get_model +except ImportError: + from django.db.models import get_model + try: from django.contrib.auth import get_user_model except ImportError: diff --git a/oauth2_provider/forms.py b/oauth2_provider/forms.py index 16d5a683d..cd5e64239 100644 --- a/oauth2_provider/forms.py +++ b/oauth2_provider/forms.py @@ -1,7 +1,5 @@ from django import forms -# from .models import get_application_model - class AllowForm(forms.Form): allow = forms.BooleanField(required=False) @@ -24,5 +22,6 @@ class RegistrationForm(forms.ModelForm): TODO: add docstring """ class Meta: - # model = get_application_model() + # FIXME: monkey-patched in apps.py + model = None fields = ('name', 'client_id', 'client_secret', 'client_type', 'authorization_grant_type', 'redirect_uris') diff --git a/oauth2_provider/models.py b/oauth2_provider/models.py index 1be7a85d9..5eadfa15b 100644 --- a/oauth2_provider/models.py +++ b/oauth2_provider/models.py @@ -3,19 +3,13 @@ from django.core.urlresolvers import reverse from django.db import models from django.utils import timezone -try: - # Django's new application loading system - from django.apps import apps - get_model = apps.get_model -except ImportError: - from django.db.models import get_model from django.utils.translation import ugettext_lazy as _ from django.utils.encoding import python_2_unicode_compatible from django.core.exceptions import ImproperlyConfigured from django.utils.six.moves.urllib.parse import urlparse from .settings import oauth2_settings -from .compat import AUTH_USER_MODEL +from .compat import AUTH_USER_MODEL, get_model from .generators import generate_client_secret, generate_client_id from .validators import validate_uris diff --git a/oauth2_provider/oauth2_validators.py b/oauth2_provider/oauth2_validators.py index f4ecd8bc6..ebf450531 100644 --- a/oauth2_provider/oauth2_validators.py +++ b/oauth2_provider/oauth2_validators.py @@ -13,12 +13,13 @@ from .models import Grant, AccessToken, RefreshToken from .settings import oauth2_settings +# FIXME: monkey-patched in apps.py Application = None +# FIXME: monkey-patched in apps.py +GRANT_TYPE_MAPPING = {} log = logging.getLogger('oauth2_provider') -GRANT_TYPE_MAPPING = {} - class OAuth2Validator(RequestValidator): def _extract_basic_auth(self, request): diff --git a/oauth2_provider/views/application.py b/oauth2_provider/views/application.py index 55d0133d3..2cf039aa5 100644 --- a/oauth2_provider/views/application.py +++ b/oauth2_provider/views/application.py @@ -4,14 +4,14 @@ from braces.views import LoginRequiredMixin from ..forms import RegistrationForm -from ..models import get_application_model class ApplicationOwnerIsUserMixin(LoginRequiredMixin): """ This mixin is used to provide an Application queryset filtered by the current request.user. """ - # model = get_application_model() + # FIXME: monkey-patched in apps.py + model = None fields = '__all__' def get_queryset(self):