class APNSConfigSerializer(HyperlinkedMixin, ModelSerializer):
    APNS_VALIDATORS = [
        ContentTypeValidator(('application/x-pkcs12', )),
        FileSizeValidator(209712)  # 200kb
    ]
    PRODUCTION_VALIDATORS = APNS_VALIDATORS + [APNSCertificateValidator('Production')]
    DEVELOPMENT_VALIDATORS = APNS_VALIDATORS + [APNSCertificateValidator('Development')]

    hyperlinks = (
        ('self', 'apns-config', ('instance.name',)),
        ('remove_certificate', 'apns-remove-certificate', ('instance.name',)),
    )

    production_certificate = FileField(validators=PRODUCTION_VALIDATORS, required=False)
    development_certificate = FileField(validators=DEVELOPMENT_VALIDATORS, required=False)

    class Meta:
        model = APNSConfig
        fields = (
            'production_certificate_name',
            'production_certificate',
            'production_bundle_identifier',
            'production_expiration_date',
            'development_certificate_name',
            'development_certificate',
            'development_bundle_identifier',
            'development_expiration_date'
        )
        read_only_fields = (
            'production_expiration_date',
            'development_expiration_date'
        )

    def to_internal_value(self, data):
        ret = super().to_internal_value(data)
        production_certificate = ret.get('production_certificate')
        development_certificate = ret.get('development_certificate')

        if production_certificate:
            ret['production_certificate'] = production_certificate.read()

        if development_certificate:
            ret['development_certificate'] = development_certificate.read()

        return ret

    def to_representation(self, instance):
        ret = super().to_representation(instance)
        ret['production_certificate'] = bool(instance.production_certificate)
        ret['development_certificate'] = bool(instance.development_certificate)
        return ret
Beispiel #2
0
class FileSerializer(serializers.ModelSerializer):
    """
    This serializer allows uploading a file in the ai-django-fileupload pattern

    Use like this (example for a ModelViewSet:

    @detail_route(methods=['post'], parser_classes=(MultiPartParser,))
    def attach(self, request, pk=None):
        order = self.get_object()
        serializer = self.get_serializer(order, data=request.data)

        if serializer.is_valid():
            serializer.save()
            return Response({'status': _('Die Datei wurde erfolgreich hochgeladen.')})
        else:
            return Response(serializer.errors,
                            status=status.HTTP_400_BAD_REQUEST)
    """
    file = FileField(max_length=10 * 1024,
                     allow_empty_file=False,
                     help_text='The file with a size of up to 10 MB')

    class Meta:
        model = Attachment
        fields = ('file', )

    def validate(self, validated_data):
        validated_data['content_type'] = ContentType.objects.get_for_model(
            self.instance)
        validated_data['object_id'] = self.instance.pk
        return validated_data

    def update(self, instance, validated_data):
        return Attachment.objects.create(**validated_data)
Beispiel #3
0
class BlobSerializer(DocumentSerializer):
    """ Blob serializer
    """
    blob = FileField(write_only=True)
    handle = SerializerMethodField()
    upload_date = SerializerMethodField()

    class Meta:
        model = Blob
        fields = ['id',
                  'user_id',
                  'filename',
                  'handle',
                  'blob',
                  'upload_date']
        read_only_fields = ('id', 'user_id', 'handle', 'upload_date',)

    def get_handle(self, instance):
        """ Return handle

        Args:
            instance:

        Returns:

        """
        # get request from context
        request = self.context.get('request')
        # return download handle
        return get_blob_download_uri(instance, request)

    def get_upload_date(self, instance):
        """ Return upload date

        Args:
            instance:

        Returns:

        """
        # Return instance generation time
        return str(instance.id.generation_time)

    def create(self, validated_data):
        """ Create and return a new `Blob` instance, given the validated data.

        Args:
            validated_data:

        Returns:

        """
        # Create blob
        blob_object = Blob(filename=validated_data['blob'].name,
                           user_id=str(validated_data['user'].id))
        # Set file content
        blob_object.blob = validated_data['blob'].file

        # Save the blob
        return blob_api.insert(blob_object)
Beispiel #4
0
class UploadeBaseSerializer(serializers.Serializer):
    property_service = PropertyService()
    propertyId = IntegerField(min_value=1, required=True)
    modelName = CharField(min_length=2, required=True)
    image = ListField(child=FileField(), required=True)

    def create(self, validated_data):
        return self.property_service.upload_image(validated_data=validated_data)
Beispiel #5
0
class FileCreateSerializer(serializers.ModelSerializer):
    file = FileField(required=True)

    def create(self, validated_data):
        validated_data["name"] = validated_data.get("file")._name
        return super().create(validated_data)

    class Meta:
        model = Image
        fields = ("pk", "file")
Beispiel #6
0
class SAMLProviderImportSerializer(PassiveSerializer):
    """Import saml provider from XML Metadata"""

    name = CharField(required=True)
    # Using SlugField because https://github.com/OpenAPITools/openapi-generator/issues/3278
    authorization_flow = SlugRelatedField(
        queryset=Flow.objects.filter(designation=FlowDesignation.AUTHORIZATION),
        slug_field="slug",
    )
    file = FileField()
Beispiel #7
0
class SubmitResultCombinedSerializer(serializers.Serializer):
    # Result
    match = serializers.IntegerField()
    type = serializers.ChoiceField(choices=Result.TYPES)
    replay_file = serializers.FileField(required=False)
    game_steps = serializers.IntegerField()
    submitted_by = serializers.HiddenField(
        default=serializers.CurrentUserDefault())
    arenaclient_log = FileField(required=False)
    # Bot
    bot1_data = FileField(required=False)
    bot2_data = FileField(required=False)
    # Participant
    bot1_log = FileField(required=False)
    bot2_log = FileField(required=False)
    bot1_avg_step_time = FloatField(
        required=False, validators=[validate_not_nan, validate_not_inf])
    bot2_avg_step_time = FloatField(
        required=False, validators=[validate_not_nan, validate_not_inf])
Beispiel #8
0
class SocketSerializer(RevalidateMixin, MetadataMixin, DynamicFieldsMixin, HyperlinkedMixin, ModelSerializer):
    hyperlinks = (
        ('self', 'socket-detail', (
            'instance.name',
            'name',
        )),
        ('update', 'socket-update', (
            'instance.name',
            'name',
        )),
        ('endpoints', 'socket-endpoint-endpoint', (
            'instance.name',
            'name',
        )),
        ('handlers', 'socket-handler-list', (
            'instance.name',
            'name',
        )),
        ('zip_file', 'socket-zip-file', (
            'instance.name',
            'name',
        )),
    )

    name = LowercaseCharField(validators=[
        UniqueValidator(queryset=Socket.objects.all()),
        DjangoValidator()
    ])
    zip_file = FileField(write_only=True)
    zip_file_list = JSONField(validators=[FileListValidator()], default=None, write_only=True)
    config = JSONField(validators=[validate_config], default={})
    install_config = JSONField(write_only=True, default={})
    status = DisplayedChoiceField(Socket.STATUSES.as_choices(), read_only=True)
    status_info = JSONField(read_only=True)
    installed = JSONField(read_only=True)
    files = serializers.SerializerMethodField()
    environment = SlugRelatedField(slug_field='name',
                                   queryset=SocketEnvironment.objects.all(),
                                   default=None, allow_null=True)

    class Meta:
        model = Socket
        fields = ('name', 'description', 'created_at', 'updated_at', 'version',
                  'status', 'status_info', 'install_url', 'metadata', 'config',
                  'zip_file', 'zip_file_list', 'installed', 'files', 'environment',
                  'install_config', )
        read_only_fields = ('install_url', 'version')

    def get_files(self, obj):
        file_list = copy.deepcopy(obj.file_list)

        for val in file_list.values():
            if not val['file'].startswith('<'):
                val['file'] = default_storage.url(val['file'])
        return file_list
Beispiel #9
0
 def __init__(self, *args, **kwargs):
     super(CreateVerificationSerializer, self).__init__(*args, **kwargs)
     doc_types = DocumentType.objects.all()
     for doc_type in doc_types:
         self.fields[doc_type.api_key] = FileField(
             allow_null=True,
             max_length=100,
             required=False,
             validators=[validate_image_extension_api])
     self.documents_data = {
         doc_type.api_key: None
         for doc_type in doc_types
     }
Beispiel #10
0
class ProgramSerializer(serializers.HyperlinkedModelSerializer): 
    steps = ProgramStepSerializer(many=True, read_only=True)
    merchant = MerchantSerializer(read_only=True)
    program_logo = FileField(use_url=True)
    
    class Meta:
        model = Program
        fields = ('url', 'id', 'enroll_key', 'redeem_key', 'reward_key', 'publish_date', 
                  'expiry_date', 'content', 'program_logo', 'steps', 'merchant')
        read_only_fields = ('enroll_key', 'redeem_key', 'reward_key', 'id', )
        
    def to_representation(self, instance):
        ret = super().to_representation(instance)
        ret['content'] = html2text(ret['content'])[:-2]
        return ret      
Beispiel #11
0
class EventSerializer(serializers.ModelSerializer):
    teacher_user = serializers.PrimaryKeyRelatedField(
        queryset=MyUser.objects.all())
    student_user = serializers.PrimaryKeyRelatedField(
        many=True, queryset=MyUser.objects.all())
    recurrence = serializers.PrimaryKeyRelatedField(
        allow_null=True, queryset=Recurrence.objects.all())
    file = FileField(allow_null=True, required=False)

    class Meta:
        model = Event
        fields = [
            'id', 'title', 'start', 'end', 'teacher_user', 'student_user',
            'isRecurrence', 'recurrence', 'comment', 'file', 'color'
        ]
Beispiel #12
0
class ProductSerializer(ModelSerializer):
    is_on_sale = BooleanField(read_only=True)
    current_price = FloatField(read_only=True)
    description = CharField(min_length=2, max_length=200)
    cart_items = OrderSerializer(many=True, read_only=True)
    # price = FloatField(min_value=1.00, max_value=100000)
    price = DecimalField(
        min_value=1.00, max_value=100000,
        max_digits=None, decimal_places=2,
    )
    sale_start = DateTimeField(
        required=False,
        input_formats=['%I:%M %p %d %B %Y'], format=None, allow_null=True,
        help_text='Accepted format is "12:01 PM 16 April 2019"',
        style={'input_type': 'text', 'placeholder': '12:01 AM 28 July 2019'},
    )
    sale_end = DateTimeField(
        required=False,
        input_formats=['%I:%M %p %d %B %Y'], format=None, allow_null=True,
        help_text='Accepted format is "12:01 PM 16 April 2019"',
        style={'input_type': 'text', 'placeholder': '12:01 AM 28 July 2019'},
    )
    photo = ImageField(default=None)
    warranty = FileField(write_only=True, default=None)

    class Meta:
        model = Product
        fields = (
            'id', 'name', 'description', 'price', 'sale_start', 'sale_end',
            'is_on_sale', 'current_price', 'cart_items',
            'photo', 'warranty',
        )

    def update(self, instance, validated_data):
        if validated_data.get('warranty', None):
            instance.description += '\n\nWarranty Information:\n'
            instance.description += b'; '.join(
                validated_data['warranty'].readlines()
            ).decode('utf-8')
        return super().update(instance, validated_data)

    def create(self, validated_data):
        validated_data.pop('warranty')  # remove
        return Product.objects.create(**validated_data)
Beispiel #13
0
class RReadingCSVSerializer(ModelSerializer):
    file = FileField(label='Upload File')

    class Meta:
        model = RReading
        exclude = ['id', ]

    def create(self, validated_data):
        csv_input = validated_data.pop('file', None)
        id = validated_data.get("user")
        csv_file = csv_input
        if not csv_file.name.endswith('.csv'):
            messages.error(request, 'Please select a CSV file')
        data_set = csv_file.read().decode('UTF-8')
        io_string = io.StringIO(data_set)
        next(io_string)
        for column in csv.reader(io_string, delimiter=',', quotechar="|"):
            RReading.objects.create(user=id, intensity=column[0], level=column[1])

        return validated_data
Beispiel #14
0
class SocketEnvironmentSerializer(RevalidateMixin, MetadataMixin, DynamicFieldsMixin, HyperlinkedMixin,
                                  ModelSerializer):
    hyperlinks = (
        ('self', 'socket-environment-detail', (
            'instance.name',
            'name',
        )),
    )

    name = LowercaseCharField(validators=[
        UniqueValidator(queryset=SocketEnvironment.objects.all()),
        DjangoValidator()
    ])
    zip_file = FileField(write_only=True)
    status = DisplayedChoiceField(SocketEnvironment.STATUSES.as_choices(), read_only=True)
    status_info = JSONField(read_only=True)
    checksum = CharField(read_only=True)

    class Meta:
        model = SocketEnvironment
        fields = ('name', 'description', 'created_at', 'updated_at',
                  'status', 'status_info', 'metadata', 'zip_file', 'checksum')
Beispiel #15
0
class PictureUploadSerializer(serializers.HyperlinkedModelSerializer):
    file = FileField(allow_empty_file=False, required=True)

    class Meta:
        model = Picture
        fields = ("slug", "file", "name", "thumbnail", "id")
Beispiel #16
0
class FileUploadSerializer(PassiveSerializer):
    """Serializer to upload file"""

    file = FileField(required=False)
    clear = BooleanField(default=False)
Beispiel #17
0
     EmailField(),
     {
         'type': 'string',
         'format': 'email'
     },
 ),
 (
     # JSONField
     JSONField(),
     {
         'type': 'object'
     },
 ),
 (
     # FileField
     FileField(),
     {
         'type': 'string',
         'format': 'binary'
     },
 ),
 (
     # FloatField
     FloatField(),
     {
         'type': 'number'
     },
 ),
 (
     # ImageField
     ImageField(),
Beispiel #18
0
class MerchantSerializer(serializers.HyperlinkedModelSerializer):
    brand_logo = FileField(use_url=True)
    class Meta:
        model = Merchant
        fields = ('url', 'name', 'email', 'address', 'phone', 'content', 'brand_logo')   
Beispiel #19
0
class BlobSerializer(DocumentSerializer):
    """Blob serializer"""

    blob = FileField(write_only=True)
    handle = SerializerMethodField()
    upload_date = SerializerMethodField()
    if "core_linked_records_app" in settings.INSTALLED_APPS:
        pid = SerializerMethodField()

    class Meta(object):
        model = Blob
        fields = ["id", "user_id", "filename", "handle", "blob", "upload_date"]
        read_only_fields = ("id", "user_id", "filename", "handle",
                            "upload_date")
        if "core_linked_records_app" in settings.INSTALLED_APPS:
            fields.append("pid")
            read_only_fields = read_only_fields + ("pid", )

    def get_pid(self, instance):
        """Return pid

        Args:
            instance:

        Returns:

        """
        # return pid  if assigned
        if "core_linked_records_app" not in settings.INSTALLED_APPS:
            return None
        else:
            from core_linked_records_app.components.blob import (
                api as linked_blob_api, )
            from core_linked_records_app.settings import ID_PROVIDER_SYSTEM_NAME

            try:
                sub_url = reverse(
                    "core_linked_records_provider_record",
                    kwargs={
                        "provider": ID_PROVIDER_SYSTEM_NAME,
                        "record": ""
                    },
                )
                blob_pid = linked_blob_api.get_pid_for_blob(str(instance.id))

                return urljoin(settings.SERVER_URI,
                               join(sub_url, blob_pid.record_name))
            except:
                return None

    def get_handle(self, instance):
        """Return handle

        Args:
            instance:

        Returns:

        """
        # get request from context
        request = self.context.get("request")
        # return download handle
        return get_blob_download_uri(instance, request)

    def get_upload_date(self, instance):
        """Return upload date

        Args:
            instance:

        Returns:

        """
        # Return instance generation time
        return str(instance.id.generation_time)

    def create(self, validated_data):
        """Create and return a new `Blob` instance, given the validated data.

        Args:
            validated_data:

        Returns:

        """
        # Create blob
        blob_object = Blob(
            filename=validated_data["blob"].name,
            user_id=str(self.context["request"].user.id),
        )
        # Set file content
        blob_object.blob = validated_data["blob"].file

        # Save the blob
        return blob_api.insert(blob_object, self.context["request"].user)
Beispiel #20
0
class DeploymentUploadSerializer(Serializer):
    deployment_file = FileField()

    class Meta:
        fields = ['deployment_file']
Beispiel #21
0
class ProgramStepSerializer(serializers.HyperlinkedModelSerializer):
    reward_logo = FileField(use_url=True)
          
    class Meta:
        model = ProgramStep
        fields = ('url', 'id', 'redeem', 'reward', 'reward_logo')        
Beispiel #22
0
class FlowViewSet(ModelViewSet):
    """Flow Viewset"""

    queryset = Flow.objects.all()
    serializer_class = FlowSerializer
    lookup_field = "slug"
    search_fields = ["name", "slug", "designation", "title"]
    filterset_fields = ["flow_uuid", "name", "slug", "designation"]

    @permission_required(None, ["authentik_flows.view_flow_cache"])
    @extend_schema(responses={200: CacheSerializer(many=False)})
    @action(detail=False, pagination_class=None, filter_backends=[])
    def cache_info(self, request: Request) -> Response:
        """Info about cached flows"""
        return Response(data={"count": len(cache.keys("flow_*"))})

    @permission_required(None, ["authentik_flows.clear_flow_cache"])
    @extend_schema(
        request=OpenApiTypes.NONE,
        responses={
            204: OpenApiResponse(description="Successfully cleared cache"),
            400: OpenApiResponse(description="Bad request"),
        },
    )
    @action(detail=False, methods=["POST"])
    def cache_clear(self, request: Request) -> Response:
        """Clear flow cache"""
        keys = cache.keys("flow_*")
        cache.delete_many(keys)
        LOGGER.debug("Cleared flow cache", keys=len(keys))
        return Response(status=204)

    @permission_required(
        None,
        [
            "authentik_flows.add_flow",
            "authentik_flows.change_flow",
            "authentik_flows.add_flowstagebinding",
            "authentik_flows.change_flowstagebinding",
            "authentik_flows.add_stage",
            "authentik_flows.change_stage",
            "authentik_policies.add_policy",
            "authentik_policies.change_policy",
            "authentik_policies.add_policybinding",
            "authentik_policies.change_policybinding",
            "authentik_stages_prompt.add_prompt",
            "authentik_stages_prompt.change_prompt",
        ],
    )
    @extend_schema(
        request={
            "multipart/form-data":
            inline_serializer("SetIcon", fields={"file": FileField()})
        },
        responses={
            204: OpenApiResponse(description="Successfully imported flow"),
            400: OpenApiResponse(description="Bad request"),
        },
    )
    @action(detail=False, methods=["POST"], parser_classes=(MultiPartParser, ))
    def import_flow(self, request: Request) -> Response:
        """Import flow from .akflow file"""
        file = request.FILES.get("file", None)
        if not file:
            return HttpResponseBadRequest()
        importer = FlowImporter(file.read().decode())
        valid = importer.validate()
        if not valid:
            return HttpResponseBadRequest()
        successful = importer.apply()
        if not successful:
            return Response(status=204)
        return HttpResponseBadRequest()

    @permission_required(
        "authentik_flows.export_flow",
        [
            "authentik_flows.view_flow",
            "authentik_flows.view_flowstagebinding",
            "authentik_flows.view_stage",
            "authentik_policies.view_policy",
            "authentik_policies.view_policybinding",
            "authentik_stages_prompt.view_prompt",
        ],
    )
    @extend_schema(
        responses={
            "200": OpenApiResponse(response=OpenApiTypes.BINARY),
        }, )
    @action(detail=True, pagination_class=None, filter_backends=[])
    # pylint: disable=unused-argument
    def export(self, request: Request, slug: str) -> Response:
        """Export flow to .akflow file"""
        flow = self.get_object()
        exporter = FlowExporter(flow)
        response = JsonResponse(exporter.export(),
                                encoder=DataclassEncoder,
                                safe=False)
        response[
            "Content-Disposition"] = f'attachment; filename="{flow.slug}.akflow"'
        return response

    @extend_schema(responses={200: FlowDiagramSerializer()})
    @action(detail=True,
            pagination_class=None,
            filter_backends=[],
            methods=["get"])
    # pylint: disable=unused-argument
    def diagram(self, request: Request, slug: str) -> Response:
        """Return diagram for flow with slug `slug`, in the format used by flowchart.js"""
        flow = self.get_object()
        header = [
            DiagramElement("st", "start", "Start"),
        ]
        body: list[DiagramElement] = []
        footer = []
        # First, collect all elements we need
        for s_index, stage_binding in enumerate(
                get_objects_for_user(
                    request.user,
                    "authentik_flows.view_flowstagebinding").filter(
                        target=flow).order_by("order")):
            for p_index, policy_binding in enumerate(
                    get_objects_for_user(
                        request.user,
                        "authentik_policies.view_policybinding").filter(
                            target=stage_binding).exclude(
                                policy__isnull=True).order_by("order")):
                body.append(
                    DiagramElement(
                        f"stage_{s_index}_policy_{p_index}",
                        "condition",
                        f"Policy\n{policy_binding.policy.name}",
                    ))
            body.append(
                DiagramElement(
                    f"stage_{s_index}",
                    "operation",
                    f"Stage\n{stage_binding.stage.name}",
                ))
        # If the 2nd last element is a policy, we need to have an item to point to
        # for a negative case
        body.append(DiagramElement("e", "end", "End|future"), )
        if len(body) == 1:
            footer.append("st(right)->e")
        else:
            # Actual diagram flow
            footer.append(f"st(right)->{body[0].identifier}")
            for index in range(len(body) - 1):
                element: DiagramElement = body[index]
                if element.type == "condition":
                    # Policy passes, link policy yes to next stage
                    footer.append(
                        f"{element.identifier}(yes, right)->{body[index + 1].identifier}"
                    )
                    # Policy doesn't pass, go to stage after next stage
                    no_element = body[index + 1]
                    if no_element.type != "end":
                        no_element = body[index + 2]
                    footer.append(
                        f"{element.identifier}(no, bottom)->{no_element.identifier}"
                    )
                elif element.type == "operation":
                    footer.append(
                        f"{element.identifier}(bottom)->{body[index + 1].identifier}"
                    )
        diagram = "\n".join([str(x) for x in header + body + footer])
        return Response({"diagram": diagram})

    @permission_required("authentik_flows.change_flow")
    @extend_schema(
        request={
            "multipart/form-data":
            inline_serializer("SetIcon", fields={"file": FileField()})
        },
        responses={
            200: OpenApiResponse(description="Success"),
            400: OpenApiResponse(description="Bad request"),
        },
    )
    @action(
        detail=True,
        pagination_class=None,
        filter_backends=[],
        methods=["POST"],
        parser_classes=(MultiPartParser, ),
    )
    # pylint: disable=unused-argument
    def set_background(self, request: Request, slug: str):
        """Set Flow background"""
        flow: Flow = self.get_object()
        icon = request.FILES.get("file", None)
        if not icon:
            return HttpResponseBadRequest()
        flow.background = icon
        flow.save()
        return Response({})

    @permission_required("authentik_core.change_application")
    @extend_schema(
        request=inline_serializer("SetIconURL", fields={"url": CharField()}),
        responses={
            200: OpenApiResponse(description="Success"),
            400: OpenApiResponse(description="Bad request"),
        },
    )
    @action(
        detail=True,
        pagination_class=None,
        filter_backends=[],
        methods=["POST"],
    )
    # pylint: disable=unused-argument
    def set_background_url(self, request: Request, slug: str):
        """Set Flow background (as URL)"""
        flow: Flow = self.get_object()
        url = request.data.get("url", None)
        if not url:
            return HttpResponseBadRequest()
        flow.background = url
        flow.save()
        return Response({})

    @extend_schema(
        responses={
            200: LinkSerializer(many=False),
            400: OpenApiResponse(description="Flow not applicable"),
        }, )
    @action(detail=True, pagination_class=None, filter_backends=[])
    # pylint: disable=unused-argument
    def execute(self, request: Request, slug: str):
        """Execute flow for current user"""
        flow: Flow = self.get_object()
        planner = FlowPlanner(flow)
        planner.use_cache = False
        try:
            plan = planner.plan(self.request,
                                {PLAN_CONTEXT_PENDING_USER: request.user})
            self.request.session[SESSION_KEY_PLAN] = plan
        except FlowNonApplicableException as exc:
            return bad_request_message(
                request,
                _("Flow not applicable to current user/request: %(messages)s" %
                  {"messages": str(exc)}),
            )
        return Response({
            "link":
            request._request.build_absolute_uri(
                reverse("authentik_core:if-flow",
                        kwargs={"flow_slug": flow.slug}))
        })
Beispiel #23
0
class ApplicationViewSet(ModelViewSet):
    """Application Viewset"""

    queryset = Application.objects.all()
    serializer_class = ApplicationSerializer
    search_fields = [
        "name",
        "slug",
        "meta_launch_url",
        "meta_description",
        "meta_publisher",
    ]
    lookup_field = "slug"
    ordering = ["name"]

    def _filter_queryset_for_list(self, queryset: QuerySet) -> QuerySet:
        """Custom filter_queryset method which ignores guardian, but still supports sorting"""
        for backend in list(self.filter_backends):
            if backend == ObjectPermissionsFilter:
                continue
            queryset = backend().filter_queryset(self.request, queryset, self)
        return queryset

    def _get_allowed_applications(self,
                                  queryset: QuerySet) -> list[Application]:
        applications = []
        for application in queryset:
            engine = PolicyEngine(application, self.request.user, self.request)
            engine.build()
            if engine.passing:
                applications.append(application)
        return applications

    @extend_schema(
        request=inline_serializer(
            "CheckAccessRequest",
            fields={"for_user": IntegerField(required=False)}),
        responses={
            200: PolicyTestResultSerializer(),
            404: OpenApiResponse(description="for_user user not found"),
        },
    )
    @action(detail=True, methods=["POST"])
    # pylint: disable=unused-argument
    def check_access(self, request: Request, slug: str) -> Response:
        """Check access to a single application by slug"""
        # Don't use self.get_object as that checks for view_application permission
        # which the user might not have, even if they have access
        application = get_object_or_404(Application, slug=slug)
        # If the current user is superuser, they can set `for_user`
        for_user = self.request.user
        if self.request.user.is_superuser and "for_user" in request.data:
            for_user = get_object_or_404(User, pk=request.data.get("for_user"))
        engine = PolicyEngine(application, for_user, self.request)
        engine.build()
        result = engine.result
        response = PolicyTestResultSerializer(PolicyResult(False))
        if result.passing:
            response = PolicyTestResultSerializer(PolicyResult(True))
        if self.request.user.is_superuser:
            response = PolicyTestResultSerializer(result)
        return Response(response.data)

    @extend_schema(parameters=[
        OpenApiParameter(
            name="superuser_full_list",
            location=OpenApiParameter.QUERY,
            type=OpenApiTypes.BOOL,
        )
    ])
    def list(self, request: Request) -> Response:
        """Custom list method that checks Policy based access instead of guardian"""
        self.request.session.pop(USER_LOGIN_AUTHENTICATED, None)
        queryset = self._filter_queryset_for_list(self.get_queryset())
        self.paginate_queryset(queryset)

        should_cache = request.GET.get("search", "") == ""

        superuser_full_list = (str(
            request.GET.get("superuser_full_list", "false")).lower() == "true")
        if superuser_full_list and request.user.is_superuser:
            serializer = self.get_serializer(queryset, many=True)
            return self.get_paginated_response(serializer.data)

        allowed_applications = []
        if not should_cache:
            allowed_applications = self._get_allowed_applications(queryset)
        if should_cache:
            LOGGER.debug("Caching allowed application list")
            allowed_applications = cache.get(
                user_app_cache_key(self.request.user.pk))
            if not allowed_applications:
                allowed_applications = self._get_allowed_applications(queryset)
                cache.set(
                    user_app_cache_key(self.request.user.pk),
                    allowed_applications,
                    timeout=86400,
                )
        serializer = self.get_serializer(allowed_applications, many=True)
        return self.get_paginated_response(serializer.data)

    @permission_required("authentik_core.change_application")
    @extend_schema(
        request={
            "multipart/form-data":
            inline_serializer("SetIcon", fields={"file": FileField()})
        },
        responses={
            200: OpenApiResponse(description="Success"),
            400: OpenApiResponse(description="Bad request"),
        },
    )
    @action(
        detail=True,
        pagination_class=None,
        filter_backends=[],
        methods=["POST"],
        parser_classes=(MultiPartParser, ),
    )
    # pylint: disable=unused-argument
    def set_icon(self, request: Request, slug: str):
        """Set application icon"""
        app: Application = self.get_object()
        icon = request.FILES.get("file", None)
        if not icon:
            return HttpResponseBadRequest()
        app.meta_icon = icon
        app.save()
        return Response({})

    @permission_required("authentik_core.change_application")
    @extend_schema(
        request=inline_serializer("SetIconURL", fields={"url": CharField()}),
        responses={
            200: OpenApiResponse(description="Success"),
            400: OpenApiResponse(description="Bad request"),
        },
    )
    @action(
        detail=True,
        pagination_class=None,
        filter_backends=[],
        methods=["POST"],
    )
    # pylint: disable=unused-argument
    def set_icon_url(self, request: Request, slug: str):
        """Set application icon (as URL)"""
        app: Application = self.get_object()
        url = request.data.get("url", None)
        if not url:
            return HttpResponseBadRequest()
        app.meta_icon = url
        app.save()
        return Response({})

    @permission_required("authentik_core.view_application",
                         ["authentik_events.view_event"])
    @extend_schema(responses={200: CoordinateSerializer(many=True)})
    @action(detail=True, pagination_class=None, filter_backends=[])
    # pylint: disable=unused-argument
    def metrics(self, request: Request, slug: str):
        """Metrics for application logins"""
        app = self.get_object()
        return Response(
            get_events_per_1h(
                action=EventAction.AUTHORIZE_APPLICATION,
                context__authorized_application__pk=app.pk.hex,
            ))
Beispiel #24
0
class FileUploaderSerializer(UploadeBaseSerializer):
    image = ListField(child=FileField(), required=True)