Files
salmannawaz 57b480b04f Update all edx-platform REST endpoints to support JWT Auth (#34152)
* chore: update API endpoints to support default JWT auth

The default DRF Auth classes were recently updated to allow for both JWT and Session auth by default. Any endpoint that overrides the AUTHENTICATION_CLASSES but has just session, just JWT or just both of those should be updated to remove the override.

Details in https://github.com/openedx/edx-platform/issues/33662
2024-02-13 10:46:58 -05:00

162 lines
5.4 KiB
Python

"""
Views served by the Agreements app
"""
from django.conf import settings
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from opaque_keys.edx.keys import CourseKey
from common.djangoapps.student import auth
from common.djangoapps.student.roles import CourseStaffRole
from openedx.core.djangoapps.agreements.api import (
create_integrity_signature,
create_lti_pii_signature,
get_integrity_signature,
)
from openedx.core.djangoapps.agreements.serializers import IntegritySignatureSerializer, LTIPIISignatureSerializer
def is_user_course_or_global_staff(user, course_id):
"""
Return whether a user is course staff for a given course, described by the course_id,
or is global staff.
"""
return user.is_staff or auth.user_has_role(user, CourseStaffRole(CourseKey.from_string(course_id)))
class AuthenticatedAPIView(APIView):
"""
Authenticated API View.
"""
permission_classes = (IsAuthenticated,)
class IntegritySignatureView(AuthenticatedAPIView):
"""
Endpoint for an Integrity Signature
/integrity_signature/{course_id}
Supports:
HTTP GET: Returns an existing signed integrity agreement (by course id and user)
HTTP GET
** Scenarios **
?username=xyz
returns an existing signed integrity agreement for the given user and course
HTTP POST
* If an integrity signature does not exist for the user + course, creates one and
returns it. If one does exist, returns the existing signature.
"""
def get(self, request, course_id):
"""
In order to check whether the user has signed the integrity agreement for a given course.
Should return the following:
username (str)
course_id (str)
created_at (str)
If a username is not given, it should default to the requesting user (or masqueraded user).
Only staff should be able to access this endpoint for other users.
"""
if not settings.FEATURES.get('ENABLE_INTEGRITY_SIGNATURE'):
return Response(
status=status.HTTP_404_NOT_FOUND,
)
# check that user can make request
user = request.user.username
requested_user = request.GET.get('username')
is_staff = is_user_course_or_global_staff(request.user, course_id)
if not is_staff and requested_user and (user != requested_user):
return Response(
status=status.HTTP_403_FORBIDDEN,
data={
"message": "User does not have permission to view integrity agreement."
}
)
username = requested_user if requested_user else user
signature = get_integrity_signature(username, course_id)
if signature is None:
return Response(
status=status.HTTP_404_NOT_FOUND,
)
serializer = IntegritySignatureSerializer(signature)
return Response(serializer.data)
def post(self, request, course_id):
"""
Create an integrity signature for the requesting user and course. If a signature
already exists, returns the existing signature instead of creating a new one.
/api/agreements/v1/integrity_signature/{course_id}
Example response:
{
username: "janedoe",
course_id: "org.2/course_2/Run_2",
created_at: "2021-04-23T18:25:43.511Z"
}
"""
if not settings.FEATURES.get('ENABLE_INTEGRITY_SIGNATURE'):
return Response(
status=status.HTTP_404_NOT_FOUND,
)
username = request.user.username
signature = create_integrity_signature(username, course_id)
serializer = IntegritySignatureSerializer(signature)
return Response(serializer.data)
class LTIPIISignatureView(AuthenticatedAPIView):
"""
Endpoint for a LTI PII Signature
/lti_pii_signature/{course_id}
HTTP POST
* If an LTI PII signature does not exist for the user + course, creates one and
returns it. If one does exist, returns the existing signature.
"""
def post(self, request, course_id):
"""
Create an LTI PII signature for the requesting user and course. If a signature
already exists, returns the existing signature instead of creating a new one.
/api/agreements/v1/lti_pii_signature/{course_id}
Example response:
{
username: "janedoe",
course_id: "org.2/course_2/Run_2",
created_at: "2021-04-23T18:25:43.511Z"
}
"""
if not settings.FEATURES.get('ENABLE_LTI_PII_ACKNOWLEDGEMENT'):
return Response(
status=status.HTTP_404_NOT_FOUND,
)
serializer = LTIPIISignatureSerializer(data=request.data)
statusStr = ""
if serializer.is_valid():
username = request.user.username
lti_tools = request.data.get("lti_tools")
signature = create_lti_pii_signature(username, course_id, lti_tools)
serializer = LTIPIISignatureSerializer(signature)
statusStr = status.HTTP_200_OK
else:
statusStr = status.HTTP_500_INTERNAL_SERVER_ERROR
return Response(data=serializer.data, status=statusStr)