diff --git a/omniport/core/open_auth/http_urls.py b/omniport/core/open_auth/http_urls.py index 101f6454..095658d3 100644 --- a/omniport/core/open_auth/http_urls.py +++ b/omniport/core/open_auth/http_urls.py @@ -1,13 +1,12 @@ from django.urls import path, include from django.views.decorators.http import require_POST from oauth2_provider.views import ( - AuthorizationView, TokenView, RevokeTokenView, ) from rest_framework import routers -from open_auth.views.application import ApplicationViewSet +from open_auth.views.application import ApplicationViewSet, OmniportAuthorizationView from open_auth.views.retrieve_data import GetUserData router = routers.SimpleRouter() @@ -18,7 +17,7 @@ urlpatterns = [ path( 'authorise/', - require_POST(AuthorizationView.as_view()), + require_POST(OmniportAuthorizationView.as_view()), name='authorise' ), path( diff --git a/omniport/core/open_auth/serializers/application.py b/omniport/core/open_auth/serializers/application.py index 749cf5bc..105aac0a 100644 --- a/omniport/core/open_auth/serializers/application.py +++ b/omniport/core/open_auth/serializers/application.py @@ -46,6 +46,7 @@ class Meta: model = Application fields = [ + 'id', 'client_id', 'redirect_uris', 'name', diff --git a/omniport/core/open_auth/views/application.py b/omniport/core/open_auth/views/application.py index 4389fef2..dbae2d53 100644 --- a/omniport/core/open_auth/views/application.py +++ b/omniport/core/open_auth/views/application.py @@ -1,4 +1,11 @@ from rest_framework import viewsets, mixins, permissions +from rest_framework.decorators import action +from django.http import HttpResponse +from oauth2_provider.exceptions import OAuthToolkitError +from oauth2_provider.models import get_application_model,get_access_token_model +from oauth2_provider.scopes import get_scopes_backend +from oauth2_provider.settings import oauth2_settings +from oauth2_provider.views import AuthorizationView from open_auth.models import Application from open_auth.serializers.application import ApplicationAuthoriseSerializer @@ -17,3 +24,100 @@ class ApplicationViewSet( queryset = Application.objects.filter(is_approved=True) lookup_field = 'client_id' pagination_class = None + + @action(methods=['get'], detail=False, url_name="get_token", url_path="get_token") + def get_token(self, request): + """ + Action view for getting the availabilty of token + for a particular view in order to skip authorization + after first consent + """ + + token=get_access_token_model().objects.filter( + user=request.user, + application=request.GET.get('id') + ).exists() + + return HttpResponse(token) + + +class OmniportAuthorizationView(AuthorizationView): + """ + Overrided the default implementation + of get method of AuthorizationView in order + to skip authorization even after the access + token has expired. + """ + + def get(self, request, *args, **kwargs): + """ + The code is similar to https://github.com/jazzband/django-oauth-toolkit/blob/master/oauth2_provider/views/base.py + Significant Changes marked with *** in the code + """ + + try: + require_approval = request.GET.get( + "approval_prompt", + oauth2_settings.REQUEST_APPROVAL_PROMPT, + ) + + if require_approval != 'auto_even_if_expired': + return super(OmniportAuthorizationView, self).get(request, *args, **kwargs) + + scopes, credentials = self.validate_authorization_request(request) + all_scopes = get_scopes_backend().get_all_scopes() + kwargs["scopes_descriptions"] = [all_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 = get_application_model().objects.get(client_id=credentials['client_id']) + + kwargs['application'] = application + kwargs['client_id'] = credentials['client_id'] + kwargs['redirect_uri'] = credentials['redirect_uri'] + kwargs['response_type'] = credentials['response_type'] + kwargs['state'] = credentials['state'] + + self.oauth2_data = kwargs + # following two loc are here only because of https://code.djangoproject.com/ticket/17795 + form = self.get_form(self.get_form_class()) + kwargs['form'] = form + + + #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 + #re 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 self.redirect(uri, application) + + #check for require_approval + assert require_approval == 'auto_even_if_expired' + + tokens = ( + get_access_token_model() + .objects.filter( + user=request.user, + application=kwargs["application"], + #expires__gt=timezone.now(), *** + ) + .all() + ) + + # 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 self.redirect(uri, application) + + # render an authorization prompt so the user can approve + # the application's requested scopes + return self.render_to_response(self.get_context_data(**kwargs)) + + except OAuthToolkitError as error: + return self.error_response(error) diff --git a/omniport/omniport/settings/base/authentication.py b/omniport/omniport/settings/base/authentication.py index d2516b3f..4f6468b5 100644 --- a/omniport/omniport/settings/base/authentication.py +++ b/omniport/omniport/settings/base/authentication.py @@ -49,3 +49,6 @@ SESSION_COOKIE_NAME = 'omniport_session' OAUTH2_PROVIDER_APPLICATION_MODEL = 'open_auth.Application' +OAUTH2_PROVIDER={ + 'REQUEST_APPROVAL_PROMPT':'auto_even_if_expired', + }