Skip to content

Commit 838bc2e

Browse files
committed
improve permission_classes checking to support rest_condition as well as DRF 3.9+ bitwise operands
1 parent a932753 commit 838bc2e

File tree

1 file changed

+35
-2
lines changed

1 file changed

+35
-2
lines changed

rest_framework_json_api/schemas/openapi.py

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from django.utils.module_loading import import_string as import_class_from_dotted_path
77
from rest_framework import exceptions
88
from rest_framework.authentication import BasicAuthentication, SessionAuthentication
9+
from rest_framework.permissions import OperandHolder, SingleOperandHolder
910
from rest_framework.relations import ManyRelatedField
1011
from rest_framework.schemas import openapi as drf_openapi
1112
from rest_framework.schemas.utils import is_list_view
@@ -14,6 +15,14 @@
1415
from rest_framework_json_api.optional import OAuth2Authentication, TokenMatchesOASRequirements
1516
from rest_framework_json_api.views import RelationshipView
1617

18+
# DRF 3.9+ has native boolean conditions now
19+
# But older code may use rest_condition or other packages.
20+
try:
21+
from rest_condition import Condition as rest_condition_Condition
22+
except ImportError:
23+
rest_condition_Condition = None
24+
25+
1726
#: static OAS 3.0 component definitions that are referenced by AutoSchema.
1827
JSONAPI_COMPONENTS = {
1928
'schemas': {
@@ -566,8 +575,32 @@ def _get_oauth_security(self, path, method):
566575
self.openapi_schema['components']['securitySchemes']['oauth']['flows'] = flows
567576
# TODO: add JWT and SAML2 bearer
568577
content = []
569-
for perm_class in self.view.permission_classes:
570-
if issubclass(perm_class, TokenMatchesOASRequirements):
578+
# permission_classes can be a direct list of classes, or instances of Operands, etc.
579+
# TODO: this is kind of ugly. modularize it.
580+
for perm_class_or_condition in self.view.permission_classes:
581+
# check if DRF conditional operands were specified
582+
if isinstance(perm_class_or_condition, OperandHolder):
583+
if issubclass(perm_class_or_condition.op1_class, TokenMatchesOASRequirements):
584+
perm_class_instance = perm_class_or_condition.op1_class()
585+
elif issubclass(perm_class_or_condition.op2_class, TokenMatchesOASRequirements):
586+
perm_class_instance = perm_class_or_condition.op2_class()
587+
else:
588+
perm_class_instance = None
589+
elif isinstance(perm_class_or_condition, SingleOperandHolder):
590+
if issubclass(perm_class_or_condition.op1_class, TokenMatchesOASRequirements):
591+
perm_class_instance = perm_class_or_condition.op1_class()
592+
else:
593+
perm_class_instance = None
594+
# check for rest_condition.Condition
595+
elif (rest_condition_Condition and
596+
isinstance(perm_class_or_condition, rest_condition_Condition)):
597+
for cond in perm_class_or_condition.perms_or_conds:
598+
if issubclass(cond, TokenMatchesOASRequirements):
599+
perm_class_instance = cond()
600+
break
601+
else:
602+
perm_class_instance = perm_class_or_condition()
603+
if isinstance(perm_class_instance, TokenMatchesOASRequirements):
571604
alt_scopes = self.view.required_alternate_scopes
572605
if method not in alt_scopes:
573606
continue

0 commit comments

Comments
 (0)