diff --git a/CHANGELOG.md b/CHANGELOG.md index 688e6469..8f15e04b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -78,6 +78,7 @@ non-ascii paths while adding files from "Connected file share" (issue #4428) () - Fixed job exporting () - Visibility and ignored information fail to be loaded (MOT dataset format) () +- Missed token with using social account authentication () ### Security - TDB diff --git a/cvat-core/src/server-proxy.ts b/cvat-core/src/server-proxy.ts index 9eaf63df..44fd1e29 100644 --- a/cvat-core/src/server-proxy.ts +++ b/cvat-core/src/server-proxy.ts @@ -449,7 +449,11 @@ class ServerProxy { async function authorized() { try { - await getSelf(); + const response = await getSelf(); + if (!store.get('token')) { + store.set('token', response.key); + Axios.defaults.headers.common.Authorization = `Token ${response.key}`; + } } catch (serverError) { if (serverError.code === 401) { removeToken(); diff --git a/cvat/apps/engine/schema.py b/cvat/apps/engine/schema.py index 8ebd21de..f18749c2 100644 --- a/cvat/apps/engine/schema.py +++ b/cvat/apps/engine/schema.py @@ -178,6 +178,13 @@ class MetaUserSerializerExtension(AnyOfProxySerializerExtension): # field here, because these serializers don't have such. target_component = 'MetaUser' +class MetaSelfUserSerializerExtension(AnyOfProxySerializerExtension): + # Need to replace oneOf to anyOf for MetaUser variants + # Otherwise, clients cannot distinguish between classes + # using just input data. Also, we can't use discrimintator + # field here, because these serializers don't have such. + target_component = 'MetaSelfUser' + class PolymorphicProjectSerializerExtension(AnyOfProxySerializerExtension): # Need to replace oneOf to anyOf for PolymorphicProject variants # Otherwise, clients cannot distinguish between classes diff --git a/cvat/apps/engine/serializers.py b/cvat/apps/engine/serializers.py index fd2448b5..4b6c604a 100644 --- a/cvat/apps/engine/serializers.py +++ b/cvat/apps/engine/serializers.py @@ -53,6 +53,12 @@ class UserSerializer(serializers.ModelSerializer): 'last_login': { 'allow_null': True } } +class SelfUserSerializer(UserSerializer): + key = serializers.CharField(allow_blank=True, required=False) + + class Meta(UserSerializer.Meta): + fields = UserSerializer.Meta.fields + ('key',) + class AttributeSerializer(serializers.ModelSerializer): values = serializers.ListField(allow_empty=True, child=serializers.CharField(max_length=200), diff --git a/cvat/apps/engine/views.py b/cvat/apps/engine/views.py index ba3059c4..0a286746 100644 --- a/cvat/apps/engine/views.py +++ b/cvat/apps/engine/views.py @@ -25,6 +25,9 @@ from django.db import IntegrityError from django.http import HttpResponse, HttpResponseNotFound, HttpResponseBadRequest from django.utils import timezone +from dj_rest_auth.models import get_token_model +from dj_rest_auth.app_settings import create_token + from drf_spectacular.types import OpenApiTypes from drf_spectacular.utils import ( OpenApiParameter, OpenApiResponse, PolymorphicProxySerializer, @@ -60,7 +63,7 @@ from cvat.apps.engine.models import ( ) from cvat.apps.engine.models import CloudStorage as CloudStorageModel from cvat.apps.engine.serializers import ( - AboutSerializer, AnnotationFileSerializer, BasicUserSerializer, + AboutSerializer, AnnotationFileSerializer, BasicUserSerializer, SelfUserSerializer, DataMetaReadSerializer, DataMetaWriteSerializer, DataSerializer, ExceptionSerializer, FileInfoSerializer, JobReadSerializer, JobWriteSerializer, LabeledDataSerializer, LogEventSerializer, ProjectReadSerializer, ProjectWriteSerializer, ProjectSearchSerializer, @@ -1917,21 +1920,21 @@ class UserViewSet(viewsets.GenericViewSet, mixins.ListModelMixin, return UserSerializer user = self.request.user + is_self = int(self.kwargs.get("pk", 0)) == user.id or \ + self.action == "self" if user.is_staff: - return UserSerializer + return UserSerializer if not is_self else SelfUserSerializer else: - is_self = int(self.kwargs.get("pk", 0)) == user.id or \ - self.action == "self" if is_self and self.request.method in SAFE_METHODS: - return UserSerializer + return SelfUserSerializer else: return BasicUserSerializer @extend_schema(summary='Method returns an instance of a user who is currently authorized', responses={ - '200': PolymorphicProxySerializer(component_name='MetaUser', + '200': PolymorphicProxySerializer(component_name='MetaSelfUser', serializers=[ - UserSerializer, BasicUserSerializer, + SelfUserSerializer, BasicUserSerializer, ], resource_type_field_name=None), }) @action(detail=False, methods=['GET']) @@ -1939,6 +1942,9 @@ class UserViewSet(viewsets.GenericViewSet, mixins.ListModelMixin, """ Method returns an instance of a user who is currently authorized """ + token_model = get_token_model() + token = create_token(token_model, request.user, None) + request.user.key = token serializer_class = self.get_serializer_class() serializer = serializer_class(request.user, context={ "request": request }) return Response(serializer.data) diff --git a/tests/python/rest_api/test_users.py b/tests/python/rest_api/test_users.py index 8d2215d5..d62ffc06 100644 --- a/tests/python/rest_api/test_users.py +++ b/tests/python/rest_api/test_users.py @@ -67,7 +67,9 @@ class TestGetUsers: def test_everybody_can_see_self(self, users_by_name): for user, data in users_by_name.items(): - self._test_can_see(user, data, id_="self", exclude_paths="root['last_login']") + self._test_can_see( + user, data, id_="self", exclude_paths=["root['last_login']", "root['key']"] + ) def test_non_members_cannot_see_list_of_members(self): self._test_cannot_see("user2", org="org1")