114 lines
4.9 KiB
Python
114 lines
4.9 KiB
Python
"""
|
|
Viewset for auth/saml/v0/samlproviderconfig
|
|
"""
|
|
|
|
from django.shortcuts import get_object_or_404
|
|
from edx_rbac.mixins import PermissionRequiredMixin
|
|
from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication
|
|
from rest_framework import permissions, viewsets, status
|
|
from rest_framework.response import Response
|
|
from rest_framework.authentication import SessionAuthentication
|
|
from rest_framework.exceptions import ParseError, ValidationError
|
|
|
|
from enterprise.models import EnterpriseCustomerIdentityProvider, EnterpriseCustomer
|
|
from common.djangoapps.third_party_auth.utils import validate_uuid4_string
|
|
|
|
from ..models import SAMLProviderConfig
|
|
from .serializers import SAMLProviderConfigSerializer
|
|
from ..utils import convert_saml_slug_provider_id
|
|
|
|
|
|
class SAMLProviderMixin:
|
|
authentication_classes = [JwtAuthentication, SessionAuthentication]
|
|
permission_classes = [permissions.IsAuthenticated]
|
|
serializer_class = SAMLProviderConfigSerializer
|
|
|
|
|
|
class SAMLProviderConfigViewSet(PermissionRequiredMixin, SAMLProviderMixin, viewsets.ModelViewSet):
|
|
"""
|
|
A View to handle SAMLProviderConfig CRUD
|
|
|
|
Usage:
|
|
NOTE: Only the GET request requires a request parameter, otherwise pass the uuid as part
|
|
of the post body
|
|
|
|
GET /auth/saml/v0/provider_config/?enterprise-id=uuid
|
|
POST /auth/saml/v0/provider_config/ -d postData (must contain 'enterprise_customer_uuid')
|
|
DELETE /auth/saml/v0/provider_config/:pk -d postData (must contain 'enterprise_customer_uuid')
|
|
PATCH /auth/saml/v0/provider_config/:pk -d postData (must contain 'enterprise_customer_uuid')
|
|
|
|
permission_required refers to the Django permission name defined
|
|
in enterprise.rules.
|
|
The associated rule will allow edx-rbac to check if the EnterpriseCustomer
|
|
returned by the get_permission_object method here, can be
|
|
accessed by the user making this request (request.user)
|
|
Access is only allowed if the user has the system role
|
|
of 'ENTERPRISE_ADMIN' which is defined in enterprise.constants
|
|
"""
|
|
permission_required = 'enterprise.can_access_admin_dashboard'
|
|
|
|
def get_queryset(self):
|
|
"""
|
|
Find and return the matching providerconfig for the given enterprise uuid
|
|
if an association exists in EnterpriseCustomerIdentityProvider model
|
|
"""
|
|
if self.requested_enterprise_uuid is None:
|
|
raise ParseError('Required enterprise_customer_uuid is missing')
|
|
enterprise_customer_idp = get_object_or_404(
|
|
EnterpriseCustomerIdentityProvider,
|
|
enterprise_customer__uuid=self.requested_enterprise_uuid
|
|
)
|
|
return SAMLProviderConfig.objects.current_set().filter(
|
|
slug=convert_saml_slug_provider_id(enterprise_customer_idp.provider_id))
|
|
|
|
@property
|
|
def requested_enterprise_uuid(self):
|
|
"""
|
|
The enterprise customer uuid from request params or post body
|
|
"""
|
|
if self.request.method in ('POST', 'PUT'):
|
|
uuid_str = self.request.POST.get('enterprise_customer_uuid')
|
|
if uuid_str is None:
|
|
raise ParseError('Required enterprise_customer_uuid is missing')
|
|
return uuid_str
|
|
else:
|
|
uuid_str = self.request.query_params.get('enterprise_customer_uuid')
|
|
if validate_uuid4_string(uuid_str) is False:
|
|
raise ParseError('Invalid UUID enterprise_customer_id')
|
|
return uuid_str
|
|
|
|
def get_permission_object(self):
|
|
"""
|
|
Retrieve an EnterpriseCustomer uuid to do auth against
|
|
Right now this is the same as from the request object
|
|
meaning that only users belonging to the same enterprise
|
|
can access these endpoints, we have to sort out the operator role use case
|
|
"""
|
|
return self.requested_enterprise_uuid
|
|
|
|
def create(self, request, *args, **kwargs):
|
|
"""
|
|
Process POST /auth/saml/v0/provider_config/ {postData}
|
|
"""
|
|
|
|
customer_uuid = self.requested_enterprise_uuid
|
|
try:
|
|
enterprise_customer = EnterpriseCustomer.objects.get(pk=customer_uuid)
|
|
except EnterpriseCustomer.DoesNotExist:
|
|
raise ValidationError(f'Enterprise customer not found at uuid: {customer_uuid}') # lint-amnesty, pylint: disable=raise-missing-from
|
|
|
|
# Create the samlproviderconfig model first
|
|
serializer = self.get_serializer(data=request.data)
|
|
serializer.is_valid(raise_exception=True)
|
|
self.perform_create(serializer)
|
|
|
|
# Associate the enterprise customer with the provider
|
|
association_obj = EnterpriseCustomerIdentityProvider(
|
|
enterprise_customer=enterprise_customer,
|
|
provider_id=convert_saml_slug_provider_id(serializer.data['slug'])
|
|
)
|
|
association_obj.save()
|
|
|
|
headers = self.get_success_headers(serializer.data)
|
|
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
|