diff --git a/authentik/core/api/tokens.py b/authentik/core/api/tokens.py index a2066dae9..0133506f9 100644 --- a/authentik/core/api/tokens.py +++ b/authentik/core/api/tokens.py @@ -1,9 +1,12 @@ """Tokens API Viewset""" +from django.db.models.base import Model from django.http.response import Http404 +from drf_yasg2.utils import swagger_auto_schema from rest_framework.decorators import action +from rest_framework.fields import CharField from rest_framework.request import Request from rest_framework.response import Response -from rest_framework.serializers import ModelSerializer +from rest_framework.serializers import ModelSerializer, Serializer from rest_framework.viewsets import ModelViewSet from authentik.core.models import Token @@ -19,6 +22,18 @@ class TokenSerializer(ModelSerializer): fields = ["pk", "identifier", "intent", "user", "description"] +class TokenViewSerializer(Serializer): + """Show token's current key""" + + key = CharField(read_only=True) + + def create(self, validated_data: dict) -> Model: + raise NotImplementedError + + def update(self, instance: Model, validated_data: dict) -> Model: + raise NotImplementedError + + class TokenViewSet(ModelViewSet): """Token Viewset""" @@ -26,6 +41,7 @@ class TokenViewSet(ModelViewSet): queryset = Token.filter_not_expired() serializer_class = TokenSerializer + @swagger_auto_schema(responses={200: TokenViewSerializer(many=False)}) @action(detail=True) def view_key(self, request: Request, identifier: str) -> Response: """Return token key and log access""" @@ -33,5 +49,5 @@ class TokenViewSet(ModelViewSet): if not tokens.exists(): raise Http404 token = tokens.first() - Event.new(EventAction.TOKEN_VIEW, token=token).from_http(request) - return Response({"key": token.key}) + Event.new(EventAction.SECRET_VIEW, token=token).from_http(request) + return Response(TokenViewSerializer({"key": token.key}).data) diff --git a/authentik/events/migrations/0013_auto_20210209_1657.py b/authentik/events/migrations/0013_auto_20210209_1657.py new file mode 100644 index 000000000..abd909a44 --- /dev/null +++ b/authentik/events/migrations/0013_auto_20210209_1657.py @@ -0,0 +1,57 @@ +# Generated by Django 3.1.6 on 2021-02-09 16:57 +from django.apps.registry import Apps +from django.db import migrations, models +from django.db.backends.base.schema import BaseDatabaseSchemaEditor + + +def token_view_to_secret_view(apps: Apps, schema_editor: BaseDatabaseSchemaEditor): + from authentik.events.models import EventAction + + db_alias = schema_editor.connection.alias + Event = apps.get_model("authentik_events", "Event") + + Event.objects.using(db_alias).filter(action="token_view").update( + action=EventAction.SECRET_VIEW + ) + + +class Migration(migrations.Migration): + + dependencies = [ + ("authentik_events", "0012_auto_20210202_1821"), + ] + + operations = [ + migrations.AlterField( + model_name="event", + name="action", + field=models.TextField( + choices=[ + ("login", "Login"), + ("login_failed", "Login Failed"), + ("logout", "Logout"), + ("user_write", "User Write"), + ("suspicious_request", "Suspicious Request"), + ("password_set", "Password Set"), + ("secret_view", "Secret View"), + ("invitation_used", "Invite Used"), + ("authorize_application", "Authorize Application"), + ("source_linked", "Source Linked"), + ("impersonation_started", "Impersonation Started"), + ("impersonation_ended", "Impersonation Ended"), + ("policy_execution", "Policy Execution"), + ("policy_exception", "Policy Exception"), + ("property_mapping_exception", "Property Mapping Exception"), + ("system_task_execution", "System Task Execution"), + ("system_task_exception", "System Task Exception"), + ("configuration_error", "Configuration Error"), + ("model_created", "Model Created"), + ("model_updated", "Model Updated"), + ("model_deleted", "Model Deleted"), + ("update_available", "Update Available"), + ("custom_", "Custom Prefix"), + ] + ), + ), + migrations.RunPython(token_view_to_secret_view), + ] diff --git a/authentik/events/models.py b/authentik/events/models.py index 3ab92c2de..d77f69cad 100644 --- a/authentik/events/models.py +++ b/authentik/events/models.py @@ -42,7 +42,7 @@ class EventAction(models.TextChoices): SUSPICIOUS_REQUEST = "suspicious_request" PASSWORD_SET = "password_set" # noqa # nosec - TOKEN_VIEW = "token_view" # nosec + SECRET_VIEW = "secret_view" # noqa # nosec INVITE_USED = "invitation_used" diff --git a/authentik/policies/event_matcher/migrations/0007_auto_20210209_1657.py b/authentik/policies/event_matcher/migrations/0007_auto_20210209_1657.py new file mode 100644 index 000000000..906e89fa9 --- /dev/null +++ b/authentik/policies/event_matcher/migrations/0007_auto_20210209_1657.py @@ -0,0 +1,46 @@ +# Generated by Django 3.1.6 on 2021-02-09 16:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("authentik_policies_event_matcher", "0006_auto_20210203_1134"), + ] + + operations = [ + migrations.AlterField( + model_name="eventmatcherpolicy", + name="action", + field=models.TextField( + blank=True, + choices=[ + ("login", "Login"), + ("login_failed", "Login Failed"), + ("logout", "Logout"), + ("user_write", "User Write"), + ("suspicious_request", "Suspicious Request"), + ("password_set", "Password Set"), + ("secret_view", "Secret View"), + ("invitation_used", "Invite Used"), + ("authorize_application", "Authorize Application"), + ("source_linked", "Source Linked"), + ("impersonation_started", "Impersonation Started"), + ("impersonation_ended", "Impersonation Ended"), + ("policy_execution", "Policy Execution"), + ("policy_exception", "Policy Exception"), + ("property_mapping_exception", "Property Mapping Exception"), + ("system_task_execution", "System Task Execution"), + ("system_task_exception", "System Task Exception"), + ("configuration_error", "Configuration Error"), + ("model_created", "Model Created"), + ("model_updated", "Model Updated"), + ("model_deleted", "Model Deleted"), + ("update_available", "Update Available"), + ("custom_", "Custom Prefix"), + ], + help_text="Match created events with this action type. When left empty, all action types will be matched.", + ), + ), + ] diff --git a/swagger.yaml b/swagger.yaml index d2438d795..ad126e7a7 100755 --- a/swagger.yaml +++ b/swagger.yaml @@ -565,9 +565,9 @@ paths: parameters: [] responses: '200': - description: '' + description: Show token's current key schema: - $ref: '#/definitions/Token' + $ref: '#/definitions/TokenView' tags: - core parameters: @@ -7713,6 +7713,15 @@ definitions: description: title: Description type: string + TokenView: + description: Show token's current key + type: object + properties: + key: + title: Key + type: string + readOnly: true + minLength: 1 User: description: User Serializer required: @@ -7801,7 +7810,7 @@ definitions: - user_write - suspicious_request - password_set - - token_view + - secret_view - invitation_used - authorize_application - source_linked @@ -8572,7 +8581,7 @@ definitions: - user_write - suspicious_request - password_set - - token_view + - secret_view - invitation_used - authorize_application - source_linked diff --git a/web/src/pages/events/EventInfo.ts b/web/src/pages/events/EventInfo.ts index a92c97efe..bd5632ad5 100644 --- a/web/src/pages/events/EventInfo.ts +++ b/web/src/pages/events/EventInfo.ts @@ -89,7 +89,7 @@ export class EventInfo extends LitElement { return html`

${gettext(`Attempted to log in as ${this.event.context.username}`)}

${this.defaultResponse()}`; - case "token_view": + case "secret_view": return html`

${gettext("Token:")}

${this.getModelInfo(this.event.context.token as EventContext)}`;