This commit is contained in:
mahdavi 2020-08-13 10:06:25 +04:30
parent 94a8e3f25f
commit 46230c3cfe
6 changed files with 106 additions and 20 deletions

View file

@ -25,12 +25,12 @@ class ApplicationAdmin(ApplicationAdmin):
@admin.register(Resource)
class ResourceAdmin(admin.ModelAdmin):
list_display = ("token", "user", "expires")
list_display = ("name", "token", "user", "expires")
@admin.register(Scope)
class ScopeAdmin(admin.ModelAdmin):
list_display = ('name', 'description', 'is_default')
list_display = ('name', "resource", 'description', 'is_default')
# admin.site.register(RestrictedApplication, RestrictedApplicationAdmin)

View file

@ -40,7 +40,7 @@ class Resource(AbstractAccessToken):
application = None
uuid = models.UUIDField(primary_key=True, editable=False, default=uuid.uuid4, unique=True, db_index=True)
name = models.CharField(max_length=255, blank=True)
name = models.CharField(max_length=255)
user = models.ForeignKey(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, blank=True, null=True,
@ -55,6 +55,9 @@ class Resource(AbstractAccessToken):
def allow_scopes(self, scopes):
return scopes == [self.scope]
def __str__(self):
return self.name
class Scope(models.Model):
"""
@ -74,6 +77,13 @@ class Scope(models.Model):
help_text='The application to which the scope belongs.',
related_name='scopes'
)
resource = models.ForeignKey(
Resource,
models.PROTECT,
blank=True, null=True,
help_text='The resource of scope.',
related_name='scopes'
)
#: The name of the scope
name = models.CharField(
max_length=255,
@ -91,6 +101,23 @@ class Scope(models.Model):
help_text='Indicates if this scope should be included in the default scopes.'
)
@property
def final_name(self):
args = []
if self.resource:
args.append(self.resource.name)
args.append(self.name)
return '.'.join(args)
@property
def final_description(self):
resource_name = self.resource and self.resource.name
if resource_name:
return f"{resource_name} -> {self.description}"
return self.description
@classmethod
def register(cls, name, description, is_default=False):
"""

View file

@ -18,16 +18,16 @@ class Scopes(BaseScopes):
def get_queryset(self, application=None):
queryset = Scope.objects.all()
if application:
queryset = queryset.filter(name__in=application.allowed_scopes)
queryset = queryset.filter(name__in=application.allowed_scopes).order_by('resource__uuid')
return queryset
def get_all_scopes(self):
return {scope.name: scope.description for scope in self.get_queryset().all()}
return {scope.final_name: scope.final_description for scope in self.get_queryset().all()}
def get_available_scopes(self, application=None, request=None, *args, **kwargs):
scopes = [scope.name for scope in self.get_queryset(application).all()]
scopes = [scope.final_name for scope in self.get_queryset(application).all()]
return scopes
def get_default_scopes(self, application=None, request=None, *args, **kwargs):
return [scope.name for scope in self.get_queryset(application).filter(is_default=True).all()]
return [scope.final_name for scope in self.get_queryset(application).filter(is_default=True).all()]

View file

View file

@ -1,22 +1,81 @@
"""
Django views for the gooyal-dynamic-scopes package.
"""
import json
import calendar
import functools
import json
from django.conf import settings
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, require_POST
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 oauth2_provider.oauth2_backends import OAuthLibCore
from oauth2_provider.views import IntrospectTokenView
from apps.gooyal_oauth2.validators import IntrospectOAuth2Validator
from .models import Scope
@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):

View file

@ -20,7 +20,7 @@ from django.contrib.auth.views import LogoutView
from django.urls import path, include
from django.contrib import admin
from apps.gooyal_oauth2.views import introspect_token
from apps.gooyal_oauth2.views.introspect import introspect_token
from apps.transactions.views import TransactionList, TransactionDetail, TransactionPay, TransactionReceipt, \
ServiceTransactionVerify, ServiceTransactionSubmit
from apps.users.views import UserListView, UserDetailView, AccountView, RequestOTPView, ChangePasswordView, \