diff --git a/authentik/admin/templates/generic/form_non_model.html b/authentik/admin/templates/generic/form_non_model.html deleted file mode 100644 index 6223e33c7..000000000 --- a/authentik/admin/templates/generic/form_non_model.html +++ /dev/null @@ -1,20 +0,0 @@ -{% extends base_template|default:"generic/form.html" %} - -{% load authentik_utils %} -{% load i18n %} - -{% block above_form %} -

- {% trans form.title %} -

-{% endblock %} - -{% block beneath_form %} -

- {% trans form.body %} -

-{% endblock %} - -{% block action %} -{% trans 'Confirm' %} -{% endblock %} diff --git a/authentik/admin/urls.py b/authentik/admin/urls.py index 732cf956e..33d2e0a58 100644 --- a/authentik/admin/urls.py +++ b/authentik/admin/urls.py @@ -10,7 +10,6 @@ from authentik.admin.views import ( groups, outposts, outposts_service_connections, - overview, policies, policies_bindings, property_mappings, @@ -25,16 +24,6 @@ from authentik.admin.views import ( from authentik.providers.saml.views.metadata import MetadataImportView urlpatterns = [ - path( - "overview/cache/flow/", - overview.FlowCacheClearView.as_view(), - name="overview-clear-flow-cache", - ), - path( - "overview/cache/policy/", - overview.PolicyCacheClearView.as_view(), - name="overview-clear-policy-cache", - ), # Applications path( "applications/create/", diff --git a/authentik/admin/views/overview.py b/authentik/admin/views/overview.py deleted file mode 100644 index 021154f9a..000000000 --- a/authentik/admin/views/overview.py +++ /dev/null @@ -1,47 +0,0 @@ -"""authentik administration overview""" -from django.contrib.messages.views import SuccessMessageMixin -from django.core.cache import cache -from django.http.request import HttpRequest -from django.http.response import HttpResponse -from django.utils.translation import gettext as _ -from django.views.generic import FormView -from structlog.stdlib import get_logger - -from authentik.admin.forms.overview import FlowCacheClearForm, PolicyCacheClearForm -from authentik.admin.mixins import AdminRequiredMixin -from authentik.core.api.applications import user_app_cache_key - -LOGGER = get_logger() - - -class PolicyCacheClearView(AdminRequiredMixin, SuccessMessageMixin, FormView): - """View to clear Policy cache""" - - form_class = PolicyCacheClearForm - success_url = "/" - template_name = "generic/form_non_model.html" - success_message = _("Successfully cleared Policy cache") - - def post(self, request: HttpRequest, *args, **kwargs) -> HttpResponse: - keys = cache.keys("policy_*") - cache.delete_many(keys) - LOGGER.debug("Cleared Policy cache", keys=len(keys)) - # Also delete user application cache - keys = cache.keys(user_app_cache_key("*")) - cache.delete_many(keys) - return super().post(request, *args, **kwargs) - - -class FlowCacheClearView(AdminRequiredMixin, SuccessMessageMixin, FormView): - """View to clear Flow cache""" - - form_class = FlowCacheClearForm - success_url = "/" - template_name = "generic/form_non_model.html" - success_message = _("Successfully cleared Flow cache") - - def post(self, request: HttpRequest, *args, **kwargs) -> HttpResponse: - keys = cache.keys("flow_*") - cache.delete_many(keys) - LOGGER.debug("Cleared flow cache", keys=len(keys)) - return super().post(request, *args, **kwargs) diff --git a/authentik/flows/api/flows.py b/authentik/flows/api/flows.py index 6cccbfd7f..850a80734 100644 --- a/authentik/flows/api/flows.py +++ b/authentik/flows/api/flows.py @@ -3,10 +3,10 @@ from dataclasses import dataclass from django.core.cache import cache from django.db.models import Model -from django.http.response import JsonResponse +from django.http.response import HttpResponseBadRequest, JsonResponse from django.shortcuts import get_object_or_404 from drf_yasg2 import openapi -from drf_yasg2.utils import swagger_auto_schema +from drf_yasg2.utils import no_body, swagger_auto_schema, unset from guardian.shortcuts import get_objects_for_user from rest_framework.decorators import action from rest_framework.exceptions import PermissionDenied @@ -19,6 +19,7 @@ from rest_framework.serializers import ( SerializerMethodField, ) from rest_framework.viewsets import ModelViewSet +from structlog.stdlib import get_logger from authentik.core.api.utils import CacheSerializer from authentik.flows.models import Flow @@ -26,6 +27,8 @@ from authentik.flows.planner import cache_key from authentik.flows.transfer.common import DataclassEncoder from authentik.flows.transfer.exporter import FlowExporter +LOGGER = get_logger() + class FlowSerializer(ModelSerializer): """Flow Serializer""" @@ -88,10 +91,24 @@ class FlowViewSet(ModelViewSet): @swagger_auto_schema(responses={200: CacheSerializer(many=False)}) @action(detail=False) - def cached(self, request: Request) -> Response: + def cache_info(self, request: Request) -> Response: """Info about cached flows""" return Response(data={"count": len(cache.keys("flow_*"))}) + @swagger_auto_schema( + request_body=no_body, + responses={204: "Successfully cleared cache", 400: "Bad request"}, + ) + @action(detail=False, methods=["POST"]) + def cache_clear(self, request: Request) -> Response: + """Clear flow cache""" + if not request.user.is_superuser: + return HttpResponseBadRequest() + keys = cache.keys("flow_*") + cache.delete_many(keys) + LOGGER.debug("Cleared flow cache", keys=len(keys)) + return Response(status=204) + @swagger_auto_schema( responses={ "200": openapi.Response( diff --git a/authentik/policies/api.py b/authentik/policies/api.py index e550cdb77..42ce8bc9f 100644 --- a/authentik/policies/api.py +++ b/authentik/policies/api.py @@ -1,8 +1,9 @@ """policy API Views""" from django.core.cache import cache from django.core.exceptions import ObjectDoesNotExist +from django.http.response import HttpResponseBadRequest from django.urls import reverse -from drf_yasg2.utils import swagger_auto_schema +from drf_yasg2.utils import no_body, swagger_auto_schema from rest_framework import mixins from rest_framework.decorators import action from rest_framework.request import Request @@ -13,7 +14,9 @@ from rest_framework.serializers import ( SerializerMethodField, ) from rest_framework.viewsets import GenericViewSet, ModelViewSet +from structlog.stdlib import get_logger +from authentik.core.api.applications import user_app_cache_key from authentik.core.api.utils import ( CacheSerializer, MetaNameSerializer, @@ -23,6 +26,8 @@ from authentik.lib.templatetags.authentik_utils import verbose_name from authentik.lib.utils.reflection import all_subclasses from authentik.policies.models import Policy, PolicyBinding, PolicyBindingModel +LOGGER = get_logger() + class PolicyBindingModelForeignKey(PrimaryKeyRelatedField): """rest_framework PrimaryKeyRelatedField which resolves @@ -139,10 +144,27 @@ class PolicyViewSet( @swagger_auto_schema(responses={200: CacheSerializer(many=False)}) @action(detail=False) - def cached(self, request: Request) -> Response: + def cache_info(self, request: Request) -> Response: """Info about cached policies""" return Response(data={"count": len(cache.keys("policy_*"))}) + @swagger_auto_schema( + request_body=no_body, + responses={204: "Successfully cleared cache", 400: "Bad request"}, + ) + @action(detail=False, methods=["POST"]) + def cache_clear(self, request: Request) -> Response: + """Clear policy cache""" + if not request.user.is_superuser: + return HttpResponseBadRequest() + keys = cache.keys("policy_*") + cache.delete_many(keys) + LOGGER.debug("Cleared Policy cache", keys=len(keys)) + # Also delete user application cache + keys = cache.keys(user_app_cache_key("*")) + cache.delete_many(keys) + return Response(status=204) + class PolicyBindingSerializer(ModelSerializer): """PolicyBinding Serializer""" diff --git a/swagger.yaml b/swagger.yaml index 89b19bd8f..7e2443740 100755 --- a/swagger.yaml +++ b/swagger.yaml @@ -2878,9 +2878,22 @@ paths: tags: - flows parameters: [] - /flows/instances/cached/: + /flows/instances/cache_clear/: + post: + operationId: flows_instances_cache_clear + description: Clear flow cache + parameters: [] + responses: + '204': + description: Successfully cleared cache + '400': + description: Bad request + tags: + - flows + parameters: [] + /flows/instances/cache_info/: get: - operationId: flows_instances_cached + operationId: flows_instances_cache_info description: Info about cached flows parameters: - name: flow_uuid @@ -4116,9 +4129,22 @@ paths: tags: - policies parameters: [] - /policies/all/cached/: + /policies/all/cache_clear/: + post: + operationId: policies_all_cache_clear + description: Clear policy cache + parameters: [] + responses: + '204': + description: Successfully cleared cache + '400': + description: Bad request + tags: + - policies + parameters: [] + /policies/all/cache_info/: get: - operationId: policies_all_cached + operationId: policies_all_cache_info description: Info about cached policies parameters: - name: bindings__isnull diff --git a/web/src/pages/admin-overview/cards/FlowCacheStatusCard.ts b/web/src/pages/admin-overview/cards/FlowCacheStatusCard.ts index d4fa394c5..fd338021a 100644 --- a/web/src/pages/admin-overview/cards/FlowCacheStatusCard.ts +++ b/web/src/pages/admin-overview/cards/FlowCacheStatusCard.ts @@ -9,7 +9,7 @@ import { DEFAULT_CONFIG } from "../../../api/Config"; export class FlowCacheStatusCard extends AdminStatusCard { getPrimaryValue(): Promise { - return new FlowsApi(DEFAULT_CONFIG).flowsInstancesCached({}).then((value) => { + return new FlowsApi(DEFAULT_CONFIG).flowsInstancesCacheInfo({}).then((value) => { return value.count || 0; }); } diff --git a/web/src/pages/admin-overview/cards/PolicyCacheStatusCard.ts b/web/src/pages/admin-overview/cards/PolicyCacheStatusCard.ts index 13fba5bd1..a98dff22b 100644 --- a/web/src/pages/admin-overview/cards/PolicyCacheStatusCard.ts +++ b/web/src/pages/admin-overview/cards/PolicyCacheStatusCard.ts @@ -10,7 +10,7 @@ import { DEFAULT_CONFIG } from "../../../api/Config"; export class PolicyCacheStatusCard extends AdminStatusCard { getPrimaryValue(): Promise { - return new PoliciesApi(DEFAULT_CONFIG).policiesAllCached({}).then((value) => { + return new PoliciesApi(DEFAULT_CONFIG).policiesAllCacheInfo({}).then((value) => { return value.count || 0; }); }