def test_api_document_initiate_upload_student(self): """Student should not be able to initiate an upload.""" document = DocumentFactory() jwt_token = AccessToken() jwt_token.payload["resource_id"] = str(document.id) jwt_token.payload["roles"] = ["student"] jwt_token.payload["permissions"] = {"can_update": True} response = self.client.post( f"/api/documents/{document.id}/initiate-upload/", HTTP_AUTHORIZATION=f"Bearer {jwt_token}", ) self.assertEqual(response.status_code, 403)
def test_views_lti_development_post_bypass_lti_student(self): """In development, passport creation and LTI verification can be bypassed for a student.""" video = VideoFactory( playlist__consumer_site__domain="example.com", upload_state=random.choice([s[0] for s in STATE_CHOICES]), uploaded_on="2019-09-24 07:24:40+00", resolutions=[144, 240], ) # There is no need to provide an "oauth_consumer_key" data = { "resource_link_id": video.lti_id, "context_id": video.playlist.lti_id, "roles": "student", "context_title": "mathematics", "tool_consumer_instance_name": "ufr", "tool_consumer_instance_guid": "example.com", "user_id": "56255f3807599c377bf0e5bf072359fd", "launch_presentation_locale": "fr", } response = self.client.post( "/lti/videos/{!s}".format(video.pk), data, HTTP_REFERER="https://example.com", ) self.assertEqual(response.status_code, 200) self.assertContains(response, "<html>") content = response.content.decode("utf-8") match = re.search( '<div id="marsha-frontend-data" data-context="(.*)">', content ) context = json.loads(unescape(match.group(1))) jwt_token = AccessToken(context.get("jwt")) self.assertEqual(jwt_token.payload["resource_id"], str(video.id)) self.assertEqual(jwt_token.payload["user_id"], data["user_id"]) self.assertEqual(jwt_token.payload["context_id"], data["context_id"]) self.assertEqual(jwt_token.payload["roles"], [data["roles"]]) self.assertEqual(jwt_token.payload["locale"], "fr_FR") self.assertEqual( jwt_token.payload["permissions"], {"can_access_dashboard": False, "can_update": False}, ) self.assertDictEqual( jwt_token.payload["course"], {"school_name": "ufr", "course_name": "mathematics", "course_run": None}, ) self.assertEqual(context.get("state"), "success") self.assertIsNotNone(context.get("resource")) self.assertEqual(context.get("modelName"), "videos")
def test_api_document_create_instructor_with_playlist_token(self): """ Create document with playlist token. Used in the context of a lti select request (deep linking). """ playlist = PlaylistFactory(title="Playlist") jwt_token = AccessToken() jwt_token.payload["resource_id"] = "None" jwt_token.payload["roles"] = [ random.choice(["instructor", "administrator"]) ] jwt_token.payload["permissions"] = {"can_update": True} jwt_token.payload["playlist_id"] = str(playlist.id) self.assertEqual(Document.objects.count(), 0) response = self.client.post( "/api/documents/", { "lti_id": "document_one", "playlist": str(playlist.id), "title": "Some document", }, HTTP_AUTHORIZATION=f"Bearer {jwt_token}", ) self.assertEqual(Document.objects.count(), 1) self.assertEqual(response.status_code, 201) document = Document.objects.first() self.assertEqual( response.json(), { "active_stamp": None, "extension": None, "filename": "playlist_some-document", "id": str(document.id), "is_ready_to_show": False, "playlist": { "id": str(playlist.id), "lti_id": playlist.lti_id, "title": playlist.title, }, "show_download": True, "title": "Some document", "upload_state": "pending", "url": None, }, )
def put(self, request): auth = request.META.get('HTTP_AUTHORIZATION', b'') access_str = auth[7:] try: access = AccessToken(access_str) except: return Response({'code': 401, 'msg': 'token错误'}, status=401) artical = Artical.objects.get(pk=request.data['artical_id']) request.data['user_id'] = access['user_id'] serializer = ArticalSerializer(artical, data=request.data) if serializer.is_valid(): serializer.save() return Response({}, status=200) return Response(serializer.errors, status=500)
def test_views_lti_video_without_user_id_parameter(self, mock_get_consumer_site, mock_verify): """Ensure JWT is created if user_id is missing in the LTI request.""" passport = ConsumerSiteLTIPassportFactory() video = VideoFactory(playlist__consumer_site=passport.consumer_site, upload_state="ready") data = { "resource_link_id": video.lti_id, "context_id": video.playlist.lti_id, "context_title": "mathematics", "tool_consumer_instance_name": "ufr", "roles": "student", "oauth_consumer_key": passport.oauth_consumer_key, } mock_get_consumer_site.return_value = passport.consumer_site response = self.client.post("/lti/videos/{!s}".format(video.pk), data) self.assertEqual(response.status_code, 200) self.assertContains(response, "<html>") content = response.content.decode("utf-8") match = re.search( '<div id="marsha-frontend-data" data-context="(.*)">', content) context = json.loads(unescape(match.group(1))) jwt_token = AccessToken(context.get("jwt")) self.assertEqual(jwt_token.payload["resource_id"], str(video.id)) self.assertEqual(jwt_token.payload["context_id"], data["context_id"]) self.assertEqual(jwt_token.payload["roles"], [data["roles"]]) self.assertEqual(jwt_token.payload["locale"], "en_US") self.assertEqual( jwt_token.payload["permissions"], { "can_access_dashboard": False, "can_update": False }, ) self.assertDictEqual( jwt_token.payload["course"], { "school_name": "ufr", "course_name": "mathematics", "course_run": None }, ) self.assertEqual(context.get("modelName"), "videos") # Make sure we only go through LTI verification once as it is costly (getting passport + # signature) self.assertEqual(mock_verify.call_count, 1)
def test_api_video_participants_delete_asking_to_join_extra_data(self): """Extra data is ignored.""" video = VideoFactory( participants_asking_to_join=[ { "id": "1", "name": "Instructor", }, ] ) jwt_token = AccessToken() jwt_token.payload["resource_id"] = str(video.id) jwt_token.payload["roles"] = [random.choice(["instructor", "administrator"])] jwt_token.payload["permissions"] = {"can_update": True} jwt_token.payload["user"] = {"id": "56255f3807599c377bf0e5bf072359fd"} data = { "id": "1", "name": "Instructor", "extra_data": {"foo": "bar"}, } with mock.patch.object( channel_layers_utils, "dispatch_video_to_groups" ) as mock_dispatch_video_to_groups, mock.patch( "marsha.core.serializers.xmpp_utils.generate_jwt" ) as mock_jwt_encode: mock_jwt_encode.return_value = "xmpp_jwt" response = self.client.delete( f"/api/videos/{video.id}/participants-asking-to-join/", HTTP_AUTHORIZATION=f"Bearer {jwt_token}", data=data, content_type="application/json", ) video.refresh_from_db() mock_dispatch_video_to_groups.assert_called_once_with(video) self.assertEqual(response.status_code, 200) content = response.json() self.assertEqual( content, content | { "participants_asking_to_join": [], "participants_in_discussion": [], }, )
def test_views_lti_markdown_document_student(self, mock_get_consumer_site, mock_verify): """Validate the response returned for a student request.""" passport = ConsumerSiteLTIPassportFactory() markdown_document = MarkdownDocumentFactory( playlist__lti_id="course-v1:ufr+mathematics+00001", playlist__consumer_site=passport.consumer_site, is_draft=False, ) data = { "resource_link_id": markdown_document.lti_id, "context_id": markdown_document.playlist.lti_id, "roles": ["student"], "oauth_consumer_key": passport.oauth_consumer_key, "user_id": "56255f3807599c377bf0e5bf072359fd", "lis_person_sourcedid": "jane_doe", "launch_presentation_locale": "fr", } mock_get_consumer_site.return_value = passport.consumer_site response = self.client.post( f"/lti/markdown-documents/{markdown_document.id}", data) self.assertEqual(response.status_code, 200) self.assertContains(response, "<html>") content = response.content.decode("utf-8") match = re.search( '<div id="marsha-frontend-data" data-context="(.*)">', content) context = json.loads(html.unescape(match.group(1))) jwt_token = AccessToken(context.get("jwt")) self.assertEqual(context.get("state"), "success") self.assertIsNotNone(context.get("resource")) self.assertEqual(context.get("modelName"), "markdown-documents") self.assertEqual( jwt_token.payload["user"], { "email": None, "username": "******", "user_fullname": None, "id": "56255f3807599c377bf0e5bf072359fd", }, ) self.assertTrue(context.get("flags").get("markdown")) # Make sure we only go through LTI verification once as it is costly (getting passport + # signature) self.assertEqual(mock_verify.call_count, 1)
def test_api_document_create_instructor(self): """An instrustor should not be able to create a Markdown document.""" markdown_document = MarkdownDocumentFactory() jwt_token = AccessToken() jwt_token.payload["resource_id"] = str(markdown_document.pk) jwt_token.payload["roles"] = [ random.choice(["instructor", "administrator"]) ] jwt_token.payload["permissions"] = {"can_update": True} response = self.client.get("/api/markdown-documents/", HTTP_AUTHORIZATION=f"Bearer {jwt_token}") self.assertEqual(response.status_code, 403)
def get_user(scope): close_old_connections() query_string = parse_qs(scope['query_string'].decode()) token = query_string.get('token') if not token: return AnonymousUser() try: access_token = AccessToken(token[0]) user = User.objects.get(id=access_token['id']) except Exception as exception: return AnonymousUser() if not user.is_active: return AnonymousUser() return user
def test_views_lti_document_instructor_same_playlist( self, mock_get_consumer_site, mock_verify ): """Validate the format of the response returned by the view for an instructor request.""" passport = ConsumerSiteLTIPassportFactory() document = DocumentFactory( playlist__lti_id="course-v1:ufr+mathematics+00001", playlist__consumer_site=passport.consumer_site, ) data = { "resource_link_id": document.lti_id, "context_id": document.playlist.lti_id, "roles": random.choice(["instructor", "administrator"]), "oauth_consumer_key": passport.oauth_consumer_key, "user_id": "56255f3807599c377bf0e5bf072359fd", "launch_presentation_locale": "fr", } mock_get_consumer_site.return_value = passport.consumer_site response = self.client.post("/lti/documents/{!s}".format(document.pk), data) self.assertEqual(response.status_code, 200) self.assertContains(response, "<html>") content = response.content.decode("utf-8") match = re.search( '<div id="marsha-frontend-data" data-context="(.*)">', content ) context = json.loads(html.unescape(match.group(1))) jwt_token = AccessToken(context.get("jwt")) self.assertEqual(jwt_token.payload["resource_id"], str(document.id)) self.assertEqual(jwt_token.payload["user_id"], data["user_id"]) self.assertEqual(jwt_token.payload["context_id"], data["context_id"]) self.assertEqual(jwt_token.payload["roles"], [data["roles"]]) self.assertEqual(jwt_token.payload["locale"], "fr_FR") self.assertEqual( jwt_token.payload["permissions"], {"can_access_dashboard": True, "can_update": True}, ) self.assertDictEqual( jwt_token.payload["course"], {"school_name": "ufr", "course_name": "mathematics", "course_run": "00001"}, ) self.assertEqual(context.get("state"), "success") self.assertIsNotNone(context.get("resource")) self.assertEqual(context.get("modelName"), "documents") # Make sure we only go through LTI verification once as it is costly (getting passport + # signature) self.assertEqual(mock_verify.call_count, 1)
def test_api_video_participants_delete_asking_to_join_no_change(self): """No websocket update made if delete contains no change.""" video = VideoFactory( participants_asking_to_join=[ { "id": "1", "name": "Instructor", }, { "id": "2", "name": "Student 1", }, ] ) jwt_token = AccessToken() jwt_token.payload["resource_id"] = str(video.id) jwt_token.payload["roles"] = [random.choice(["instructor", "administrator"])] jwt_token.payload["permissions"] = {"can_update": True} jwt_token.payload["user"] = {"id": "56255f3807599c377bf0e5bf072359fd"} data = { "id": "3", "name": "Student 3", } with mock.patch.object( channel_layers_utils, "dispatch_video_to_groups" ) as mock_dispatch_video_to_groups, mock.patch( "marsha.core.serializers.xmpp_utils.generate_jwt" ) as mock_jwt_encode: mock_jwt_encode.return_value = "xmpp_jwt" response = self.client.delete( f"/api/videos/{video.id}/participants-asking-to-join/", HTTP_AUTHORIZATION=f"Bearer {jwt_token}", data=data, content_type="application/json", ) video.refresh_from_db() mock_dispatch_video_to_groups.assert_not_called() self.assertEqual(response.status_code, 400) content = response.json() self.assertEqual( content, {"detail": "Participant did not asked to join."}, )
def test_create_playlist_by_organization_administrator(self): """Organization administrators can create playlists.""" user = factories.UserFactory() org = factories.OrganizationFactory() factories.OrganizationAccessFactory( role=models.ADMINISTRATOR, organization=org, user=user ) consumer_site = factories.ConsumerSiteFactory() jwt_token = AccessToken() jwt_token.payload["resource_id"] = str(user.id) jwt_token.payload["user"] = { "id": str(user.id), "username": user.username, } self.assertEqual(models.Playlist.objects.count(), 0) response = self.client.post( "/api/playlists/", { "consumer_site": str(consumer_site.id), "lti_id": "playlist_twenty", "organization": str(org.id), "title": "Some playlist", }, HTTP_AUTHORIZATION=f"Bearer {jwt_token}", ) self.assertEqual(models.Playlist.objects.count(), 1) self.assertEqual(response.status_code, 201) self.assertEqual( response.json(), { "consumer_site": str(consumer_site.id), "created_by": None, "duplicated_from": None, "id": str(models.Playlist.objects.first().id), "is_portable_to_playlist": False, "is_portable_to_consumer_site": False, "is_public": False, "lti_id": "playlist_twenty", "organization": str(org.id), "portable_to": [], "title": "Some playlist", "users": [], }, )
def test_views_video_lti_post_bypass_lti_instructor_no_video(self): """When bypassing LTI, the "example.com" consumer site is automatically created.""" data = { "resource_link_id": "123", "roles": "instructor", "context_id": "abc", "tool_consumer_instance_guid": "example.com", "user_id": "56255f3807599c377bf0e5bf072359fd", } response = self.client.post("/lti-video/", data) self.assertEqual(response.status_code, 200) self.assertContains(response, "<html>") content = response.content.decode("utf-8") # Extract the JWT Token and state match = re.search( '<div class="marsha-frontend-data" data-jwt="(.*)" data-state="(.*)">', content, ) data_jwt = match.group(1) jwt_token = AccessToken(data_jwt) video = Video.objects.get() self.assertEqual(jwt_token.payload["video_id"], str(video.id)) self.assertEqual(jwt_token.payload["user_id"], data["user_id"]) self.assertEqual(jwt_token.payload["context_id"], data["context_id"]) self.assertEqual(jwt_token.payload["roles"], [data["roles"]]) data_state = match.group(2) self.assertEqual(data_state, "instructor") # Extract the video data data_video = re.search( '<div class="marsha-frontend-data" id="video" data-video="(.*)">', content ).group(1) self.assertEqual( json.loads(unescape(data_video)), { "active_stamp": None, "is_ready_to_play": False, "description": video.description, "id": str(video.id), "upload_state": "pending", "timed_text_tracks": [], "title": video.title, "urls": None, }, ) # The consumer site was created with a name and a domain name ConsumerSite.objects.get(name="example.com", domain="example.com")
def test_site_publicly_accessible(self): """Test site view publicly accessible with a connected user.""" user = factories.UserFactory(first_name="Jane", last_name="Doe", email="*****@*****.**") client = Client() client.force_login(user) response = client.get("/") self.assertEqual(response.status_code, 200) content = response.content.decode("utf-8") match = re.search( '<div id="marsha-frontend-data" data-context="(.*)">', content) context = json.loads(unescape(match.group(1))) jwt_token = AccessToken(context.get("jwt")) self.assertEqual(jwt_token.payload["resource_id"], str(user.id)) jwt_token.payload["user"] = { "id": str(user.id), } self.assertEqual(context.get("sentry_dsn"), "https://sentry.dsn") self.assertEqual(context.get("environment"), "test") self.assertEqual(context.get("frontend"), "Site") self.assertEqual(context.get("release"), "1.2.3") self.assertEqual( context.get("flags"), { "BBB": False, "live_raw": False, "markdown": True, "sentry": True }, ) self.assertEqual( context.get("static"), { "img": { "liveBackground": "/static/img/liveBackground.jpg", "liveErrorBackground": "/static/img/liveErrorBackground.jpg", }, "svg": { "icons": "/static/svg/icons.svg" }, }, ) self.assertIsNone(context.get("context_id")) self.assertIsNone(context.get("consumer_site"))
def test_api_thumbnail_administrator_read_detail_in_read_only(self): """Admin should not be able to read thumbnails in a read_only mode.""" thumbnail = ThumbnailFactory() jwt_token = AccessToken() jwt_token.payload["resource_id"] = str(thumbnail.video.id) jwt_token.payload["roles"] = ["administrator"] jwt_token.payload["permissions"] = {"can_update": False} response = self.client.get( "/api/thumbnails/{!s}/".format(thumbnail.id), HTTP_AUTHORIZATION="Bearer {!s}".format(jwt_token), ) self.assertEqual(response.status_code, 403)
def test_it_should_produce_a_json_web_token_when_valid(self): s = TokenObtainPairSerializer(context=MagicMock(), data={ TokenObtainPairSerializer.username_field: self.username, 'password': self.password, }) self.assertTrue(s.is_valid()) self.assertIn('access', s.validated_data) self.assertIn('refresh', s.validated_data) # Expecting token type claim to be correct for both tokens. If this is # the case, instantiating appropriate token subclass instances with # encoded tokens should not raise an exception. AccessToken(s.validated_data['access']) RefreshToken(s.validated_data['refresh'])
def test_api_timed_text_track_create_instructor_in_read_only(self): """Instructor should not be able to create a timed text track in read_only mode.""" timed_text_track = TimedTextTrackFactory() jwt_token = AccessToken() jwt_token.payload["resource_id"] = str(timed_text_track.video.id) jwt_token.payload["roles"] = [ random.choice(["instructor", "administrator"]) ] jwt_token.payload["permissions"] = {"can_update": False} response = self.client.post( "/api/timedtexttracks/", HTTP_AUTHORIZATION="Bearer {!s}".format(jwt_token)) self.assertEqual(response.status_code, 403)
def test_api_video_update_detail_token_user_title(self): """Token users should be able to update the title of their video through the API.""" video = VideoFactory(title="my title") jwt_token = AccessToken() jwt_token.payload["video_id"] = str(video.id) data = json.dumps({"title": "my new title"}) response = self.client.put( "/api/videos/{!s}/".format(video.id), data, HTTP_AUTHORIZATION="Bearer {!s}".format(jwt_token), content_type="application/json", ) self.assertEqual(response.status_code, 200) video.refresh_from_db() self.assertEqual(video.title, "my new title")
def test_api_thumbnail_instructor_read_detail_in_read_only(self): """Instructor should not be able to read thumbnails in a read_only mode.""" thumbnail = ThumbnailFactory() jwt_token = AccessToken() jwt_token.payload["resource_id"] = str(thumbnail.video.id) jwt_token.payload["roles"] = [random.choice(["instructor", "administrator"])] jwt_token.payload["permissions"] = {"can_update": False} response = self.client.get( f"/api/thumbnails/{thumbnail.id}/", HTTP_AUTHORIZATION=f"Bearer {jwt_token}", ) self.assertEqual(response.status_code, 403)
def test_api_video_read_detail_as_instructor_in_read_only(self): """An instructor with read_only set to True should not be able to read the video.""" video = VideoFactory(upload_state="ready") jwt_token = AccessToken() jwt_token.payload["resource_id"] = str(video.id) jwt_token.payload["roles"] = [random.choice(["instructor", "administrator"])] jwt_token.payload["permissions"] = {"can_update": False} # Get the video linked to the JWT token response = self.client.get( "/api/videos/{!s}/".format(video.id), HTTP_AUTHORIZATION="Bearer {!s}".format(jwt_token), ) self.assertEqual(response.status_code, 403)
def test_api_document_create_instructor(self): """An instrustor should not be able to create a document.""" document = DocumentFactory() jwt_token = AccessToken() jwt_token.payload["resource_id"] = str(document.id) jwt_token.payload["roles"] = [ random.choice(["instructor", "administrator"]) ] jwt_token.payload["permissions"] = {"can_update": True} response = self.client.get( "/api/documents/", HTTP_AUTHORIZATION="Bearer {!s}".format(jwt_token)) self.assertEqual(response.status_code, 404)
async def __call__(self, scope, receive, send): # Look up user from query string (you should also do things like # checking if it is a valid user ID, or if scope["user"] is already # populated). if scope.get("user"): return await self.inner(scope, receive, send) token = parse_qs(scope["query_string"].decode())["token"][0] try: AccessToken(token).verify() except TokenError: scope["user"] = AnonymousUser() return await self.inner(scope, receive, send) payload = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"]) scope["user"] = await get_user(int(payload["user_id"])) return await self.inner(scope, receive, send)
def setUp(self): factory = RequestFactory(enforce_csrf_checks=True) self.request = factory.post( reverse("donationpage-detail", kwargs={"pk": 1})) self.user = user_model.objects.create_user(email="*****@*****.**", password="******") self.request.user = self.user self.request._dont_enforce_csrf_checks = False valid_token_obj = AccessToken().for_user(self.user) self.valid_jwt = jwt.encode(valid_token_obj.payload, settings.SECRET_KEY, algorithm="HS256") self.invalid_jwt = "notavalidhmac" self.csrf_token = csrf._get_new_csrf_token()
def test_api_thumbnail_initiate_upload_instructor_read_only(self): """Instructor should not be able to initiate thumbnails upload in a read_only mode.""" thumbnail = ThumbnailFactory() jwt_token = AccessToken() jwt_token.payload["resource_id"] = str(thumbnail.video.id) jwt_token.payload["roles"] = [random.choice(["instructor", "administrator"])] jwt_token.payload["permissions"] = {"can_update": False} response = self.client.post( "/api/thumbnails/{!s}/initiate-upload/".format(thumbnail.id), HTTP_AUTHORIZATION="Bearer {!s}".format(jwt_token), ) self.assertEqual(response.status_code, 403)
def test_retrieve_playlist_through_document_token_instructor(self): """Playlist instructors can retrieve playlists through document token.""" document = factories.DocumentFactory() jwt_token = AccessToken() jwt_token.payload["resource_id"] = str(document.id) jwt_token.payload["roles"] = [random.choice(["instructor", "administrator"])] jwt_token.payload["permissions"] = {"can_update": True} response = self.client.get( f"/api/playlists/{document.playlist.id}/", HTTP_AUTHORIZATION=f"Bearer {jwt_token}", ) self.assertEqual(response.status_code, 200)
def test_jwt_user_login(client, sample_data): """ Should be able to login using username and password e get a token """ admin = sample_data['defaultUser'] data = {'username': admin['username'], 'password': admin['password']} resp = client.post('/api/auth/login', data, format='json') assert resp.status_code == status.HTTP_200_OK assert 'access' in resp.data assert 'refresh' in resp.data payload = AccessToken(resp.data.get('access')) for key, value in admin.items(): if key == 'password': continue assert key in payload and payload[key] == value
def test_api_thumbnail_read_detail_student(self): """Students users should not be allowed to read a thumbnail detail.""" video = VideoFactory() thumbnail = ThumbnailFactory(video=video) jwt_token = AccessToken() jwt_token.payload["resource_id"] = str(video.id) jwt_token.payload["roles"] = ["student"] response = self.client.get( "/api/thumbnails/{!s}/".format(thumbnail.id), HTTP_AUTHORIZATION="Bearer {!s}".format(jwt_token), ) self.assertEqual(response.status_code, 403)
def test_retrieve_playlist_by_random_logged_in_user(self): """Random logged-in users cannot retrieve playlists unrelated to them.""" user = factories.UserFactory() playlist = factories.PlaylistFactory() jwt_token = AccessToken() jwt_token.payload["resource_id"] = str(user.id) jwt_token.payload["user_id"] = str(user.id) response = self.client.get( f"/api/playlists/{playlist.id}/", HTTP_AUTHORIZATION=f"Bearer {jwt_token}", ) self.assertEqual(response.status_code, 403)
def get_user(scope): close_old_connections() query_string = parse_qs(scope['query_string'].decode()) token = query_string.get('token') if not token: return AnonymousUser() try: jwt_obj = JWTAuthentication() access_token = AccessToken(token[0]) user = jwt_obj.get_user(access_token) except ObjectDoesNotExist as e: return AnonymousUser() if not user.is_active: return AnonymousUser() return user
def test_api_video_read_detail_admin_token_user(self): """Administrator should be able to read detail of a video.""" video = VideoFactory(upload_state="pending") jwt_token = AccessToken() jwt_token.payload["resource_id"] = str(video.id) jwt_token.payload["roles"] = ["administrator"] jwt_token.payload["permissions"] = {"can_update": True} # Get the video linked to the JWT token response = self.client.get( "/api/videos/{!s}/".format(video.id), HTTP_AUTHORIZATION="Bearer {!s}".format(jwt_token), ) self.assertEqual(response.status_code, 200)