From c82d8c520b99990246d62f498ea978742d0152ef Mon Sep 17 00:00:00 2001 From: Sayyid Hamid Mahdavi Date: Wed, 16 Dec 2020 13:20:10 +0330 Subject: [PATCH] get just one service clients for all introspection requests --- apps/gooyal_oauth2/models.py | 4 - apps/gooyal_oauth2/validators.py | 16 ++- apps/gooyal_oauth2/views/__init__.py | 0 apps/gooyal_oauth2/views/introspect.py | 162 ------------------------- 4 files changed, 12 insertions(+), 170 deletions(-) delete mode 100644 apps/gooyal_oauth2/views/__init__.py delete mode 100644 apps/gooyal_oauth2/views/introspect.py diff --git a/apps/gooyal_oauth2/models.py b/apps/gooyal_oauth2/models.py index f4bbf46..918da77 100644 --- a/apps/gooyal_oauth2/models.py +++ b/apps/gooyal_oauth2/models.py @@ -1,7 +1,3 @@ -""" -Django models for the gooyal-restrict-scopes package. -""" - import requests from django.conf import settings from django.db import models diff --git a/apps/gooyal_oauth2/validators.py b/apps/gooyal_oauth2/validators.py index 479045d..93fd423 100755 --- a/apps/gooyal_oauth2/validators.py +++ b/apps/gooyal_oauth2/validators.py @@ -17,6 +17,17 @@ UserModel = get_user_model() class OAuth2Validator(BaseOAuth2Validator): # pylint: disable=w0223 + introspection_client = None + + def get_introspection_client(self, introspection_client_id, introspection_client_secret): + if not OAuth2Validator.introspection_client: + OAuth2Validator.introspection_client = service_clients.Client(client_id=introspection_client_id, + client_secret=introspection_client_secret, + grant_type=service_clients.AccountsClient.GRANT_CLIENT_CREDENTIALS, + scopes=['introspection']) + + return OAuth2Validator.introspection_client + def validate_user(self, username, password, client, request, *args, **kwargs): auth_fields = getattr(request, 'auth_fields', 'username:password').split(':') @@ -96,11 +107,8 @@ class OAuth2Validator(BaseOAuth2Validator): # pylint: disable=w0223 return None elif introspection_client_id and introspection_client_secret: - introspection_client = service_clients.Client(client_id=introspection_client_id, - client_secret=introspection_client_secret, - grant_type=service_clients.AccountsClient.GRANT_CLIENT_CREDENTIALS, - scopes=['introspection']) data = {"token": token} + introspection_client = self.get_introspection_client(introspection_client_id, introspection_client_secret) response = introspection_client.request(url=introspection_url, method='post', data=data, required_scopes=['introspection'], login_required=True) diff --git a/apps/gooyal_oauth2/views/__init__.py b/apps/gooyal_oauth2/views/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/apps/gooyal_oauth2/views/introspect.py b/apps/gooyal_oauth2/views/introspect.py deleted file mode 100644 index dd60e4c..0000000 --- a/apps/gooyal_oauth2/views/introspect.py +++ /dev/null @@ -1,162 +0,0 @@ -import calendar -import functools -import json - -from django.core.exceptions import ObjectDoesNotExist -from django.http import HttpResponse, HttpResponseForbidden -from django.utils.decorators import method_decorator -from django.views.decorators.csrf import csrf_exempt -from django.views.decorators.http import require_http_methods -from oauth2_provider.models import get_access_token_model -from oauth2_provider.oauth2_backends import OAuthLibCore -from oauth2_provider.views import ClientProtectedScopedResourceView -from oauthlib.oauth2 import Server - -# from apps.gooyal_oauth2.validators import IntrospectOAuth2Validator - - -# @method_decorator(csrf_exempt, name="dispatch") -# class IntrospectTokenView(ClientProtectedScopedResourceView): -# """ -# Implements an endpoint for token introspection based -# on RFC 7662 https://tools.ietf.org/html/rfc7662 -# -# To access this view the request must pass a OAuth2 Bearer Token -# which is allowed to access the scope `introspection`. -# """ -# required_scopes = ["introspection"] -# -# @staticmethod -# def get_token_response(token_value=None): -# try: -# token = get_access_token_model().objects.get(token=token_value) -# except ObjectDoesNotExist: -# return HttpResponse( -# content=json.dumps({"active": False}), -# status=401, -# content_type="application/json" -# ) -# else: -# if token.is_valid(): -# data = { -# "active": True, -# "scope": token.scope, -# "exp": int(calendar.timegm(token.expires.timetuple())), -# } -# if token.application: -# data["client_id"] = token.application.client_id -# if token.user: -# data["username"] = token.user.get_username() -# return HttpResponse(content=json.dumps(data), status=200, content_type="application/json") -# else: -# return HttpResponse(content=json.dumps({ -# "active": False, -# }), status=200, content_type="application/json") -# -# def get(self, request, *args, **kwargs): -# """ -# Get the token from the URL parameters. -# URL: https://example.com/introspect?token=mF_9.B5f-4.1JqM -# -# :param request: -# :param args: -# :param kwargs: -# :return: -# """ -# return self.get_token_response(request.GET.get("token", None)) -# -# def post(self, request, *args, **kwargs): -# """ -# Get the token from the body form parameters. -# Body: token=mF_9.B5f-4.1JqM -# -# :param request: -# :param args: -# :param kwargs: -# :return: -# """ -# return self.get_token_response(request.POST.get("token", None)) - - -# def protected_resource(scopes=None): -# """ -# Implementation of protected_resource decorator that saves the client on the -# request for the view function to use. -# -# Cribbed from django-oauth-toolkit. -# """ -# _scopes = scopes or [] -# -# def decorator(view_func): -# @functools.wraps(view_func) -# def _validate(request, *args, **kwargs): -# validator = IntrospectOAuth2Validator() -# core = OAuthLibCore(Server(validator)) -# valid, oauthlib_req = core.verify_request(request, scopes=_scopes) -# if valid: -# request.client = oauthlib_req.client -# request.resource_owner = oauthlib_req.user -# return view_func(request, *args, **kwargs) -# return HttpResponseForbidden() -# -# return _validate -# -# return decorator -# -# -# @require_http_methods(['GET', 'POST']) -# @csrf_exempt -# @protected_resource(scopes=['introspection']) -# def introspect_token(request): -# """ -# Version of the introspection view protected by a regular scope instead of -# read-write scopes. -# -# Also allows for the required scope to be changed using a setting. -# """ -# if request.method == 'GET': -# token = request.GET.get("token", None) -# else: -# token = request.POST.get("token", None) -# return IntrospectTokenView.get_token_response(token) - - -# @require_POST -# @csrf_exempt -# @protected_resource(scopes=[settings.REGISTER_SCOPE_SCOPE]) -# def register_scope(request): -# """ -# Implements an endpoint for registering a scope. -# """ -# #  Get the scope data from the request body -# scope_data = json.loads(request.body) if request.body else {} -# try: -# try: -# #  If a scope with the given name already exists, find it -# scope = Scope.objects.get(name=scope_data['name']) -# except Scope.DoesNotExist: -# #  If no scope with the given name exists, create it -# _ = Scope.objects.create( -# application=request.client, -# name=scope_data['name'], -# description=scope_data['description'], -# is_default=scope_data.get('is_default', False) -# ) -# #  Respond with a 201 Created -# return HttpResponse(status=201) -# except KeyError as exc: -# #  A key missing in the data should be reported as a bad request -# return HttpResponse( -# status=400, -# content="'{}' must be given in request data".format(exc.args[0]), -# content_type='text/plain' -# ) -# #  If the scope does exist, check that the current application is the -# #  owner of the scope before updating it -# if scope.application and scope.application == request.client: -# scope.description = scope_data['description'] -# scope.is_default = scope_data.get('is_default', False) -# scope.save() -# return HttpResponse(status=200) -# else: -# return HttpResponse(status=403)