Files
edx-platform/common/djangoapps/third_party_auth/api/permissions.py
Robert Raposa 372d2e927c BOM-1264: add third-party-auth scope and usage (#23135)
* WIP: add third-party-auth scope and usage

BOM-1264


* Fix tests now that we do permissions in a more standard way.

Rather than manually setting the permission class we previously
explicitly raised a PermissionDenied exception.  The way DRF
permissoning logic works, if we use the WWW-Authenticate header in the
highest priority auth class, it will return a 401 instead of a 403.


* Added test to make sure having permissions gives access to user mapping api

* Test new filters logic.

Ensure that the filters we add to the application access model make it
into the JWT correctly.

* quality fix

* quality fix

* disable pylint warning

* quality fix

* fix indent prob

Co-authored-by: Feanil Patel <feanil@edx.org>
Co-authored-by: Manjinder Singh <49171515+jinder1s@users.noreply.github.com>
2020-02-21 11:25:28 -05:00

92 lines
3.1 KiB
Python

"""
Third party auth API related permissions
"""
import logging
from edx_django_utils.monitoring import set_custom_metric
from edx_rest_framework_extensions.auth.jwt.decoder import decode_jwt_filters
from edx_rest_framework_extensions.permissions import (
IsSuperuser,
JwtHasScope,
JwtRestrictedApplication,
NotJwtRestrictedApplication
)
from rest_condition import C
from rest_framework.permissions import BasePermission
from third_party_auth.models import ProviderApiPermissions
from openedx.core.lib.api.permissions import ApiKeyHeaderPermission
log = logging.getLogger(__name__)
class ThirdPartyAuthProviderApiPermission(BasePermission):
"""
Allow someone to access the view if they have valid OAuth client credential.
Deprecated: Only works for DOP oauth applications. To be removed as part of DOPrecation.
"""
def has_permission(self, request, view):
"""
Check if the OAuth client associated with auth token in current request has permission to access
the information for provider
"""
provider_id = view.kwargs.get('provider_id')
if not request.auth or not provider_id:
# doesn't have access token or no provider_id specified
return False
try:
ProviderApiPermissions.objects.get(client__pk=request.auth.client_id, provider_id=provider_id)
except ProviderApiPermissions.DoesNotExist:
return False
set_custom_metric('deprecated_ThirdPartyAuthProviderApiPermission', True)
return True
class JwtHasTpaProviderFilterForRequestedProvider(BasePermission):
"""
Ensures the JWT used to authenticate contains the appropriate tpa_provider
filter for the provider_id requested in the view.
"""
message = 'JWT missing required tpa_provider filter.'
def has_permission(self, request, view):
"""
Ensure that the provider_id kwarg provided to the view exists exists
in the tpa_provider filters in the JWT used to authenticate.
"""
provider_id = view.kwargs.get('provider_id')
if not provider_id:
log.warning("Permission JwtHasTpaProviderFilterForRequestedProvider requires a view with provider_id.")
return False
jwt_filters = decode_jwt_filters(request.auth)
for filter_type, filter_value in jwt_filters:
if filter_type == 'tpa_provider' and filter_value == provider_id:
return True
log.warning(
"Permission JwtHasTpaProviderFilterForRequestedProvider: required filter tpa_provider:%s was not found.",
provider_id,
)
return False
# TODO: Remove ApiKeyHeaderPermission. Check deprecated_api_key_header custom metric for active usage.
_NOT_JWT_RESTRICTED_TPA_PERMISSIONS = (
C(NotJwtRestrictedApplication) &
(C(IsSuperuser) | ApiKeyHeaderPermission | ThirdPartyAuthProviderApiPermission)
)
_JWT_RESTRICTED_TPA_PERMISSIONS = (
C(JwtRestrictedApplication) &
JwtHasScope &
JwtHasTpaProviderFilterForRequestedProvider
)
TPA_PERMISSIONS = (
(_NOT_JWT_RESTRICTED_TPA_PERMISSIONS | _JWT_RESTRICTED_TPA_PERMISSIONS)
)