authentik.enterprise.endpoints.connectors.agent.views.apple_register

  1from django.urls import reverse
  2from drf_spectacular.utils import extend_schema
  3from rest_framework.exceptions import ValidationError
  4from rest_framework.fields import CharField
  5from rest_framework.permissions import IsAuthenticated
  6from rest_framework.request import Request
  7from rest_framework.response import Response
  8from rest_framework.views import APIView
  9
 10from authentik.api.validation import validate
 11from authentik.core.api.users import UserSelfSerializer
 12from authentik.core.api.utils import PassiveSerializer
 13from authentik.endpoints.connectors.agent.auth import AgentAuth
 14from authentik.endpoints.connectors.agent.models import (
 15    AgentDeviceConnection,
 16    AgentDeviceUserBinding,
 17    DeviceAuthenticationToken,
 18    DeviceToken,
 19)
 20from authentik.enterprise.api import EnterpriseRequiredMixin
 21from authentik.lib.generators import generate_key
 22
 23
 24class RegisterDeviceView(APIView):
 25
 26    class AgentPSSODeviceRegistration(EnterpriseRequiredMixin, PassiveSerializer):
 27        """Register Apple device via Platform SSO"""
 28
 29        device_signing_key = CharField()
 30        device_encryption_key = CharField()
 31        sign_key_id = CharField()
 32        enc_key_id = CharField()
 33
 34    class AgentPSSODeviceRegistrationResponse(PassiveSerializer):
 35        """authentik settings for Platform SSO tokens"""
 36
 37        client_id = CharField()
 38        issuer = CharField()
 39        token_endpoint = CharField()
 40        jwks_endpoint = CharField()
 41        audience = CharField()
 42        nonce_endpoint = CharField()
 43
 44    permission_classes = [IsAuthenticated]
 45    pagination_class = None
 46    filter_backends = []
 47    serializer_class = AgentPSSODeviceRegistration
 48    authentication_classes = [AgentAuth]
 49
 50    @extend_schema(
 51        responses={
 52            200: AgentPSSODeviceRegistrationResponse(),
 53        }
 54    )
 55    @validate(AgentPSSODeviceRegistration)
 56    def post(self, request: Request, body: AgentPSSODeviceRegistration) -> Response:
 57        device_token: DeviceToken = request.auth
 58        conn: AgentDeviceConnection = device_token.device
 59        conn.apple_signing_key = body.validated_data["device_signing_key"]
 60        conn.apple_encryption_key = body.validated_data["device_encryption_key"]
 61        conn.apple_sign_key_id = body.validated_data["sign_key_id"]
 62        conn.apple_enc_key_id = body.validated_data["enc_key_id"]
 63        conn.apple_key_exchange_key = generate_key()
 64        conn.save()
 65        return Response(
 66            data={
 67                "client_id": str(conn.connector.pk),
 68                "issuer": self.request.build_absolute_uri(
 69                    reverse("authentik_enterprise_endpoints_connectors_agent:psso-token")
 70                ),
 71                "audience": str(conn.device.pk),
 72                "token_endpoint": request.build_absolute_uri(
 73                    reverse("authentik_enterprise_endpoints_connectors_agent:psso-token")
 74                ),
 75                "jwks_endpoint": request.build_absolute_uri(
 76                    reverse("authentik_enterprise_endpoints_connectors_agent:psso-jwks")
 77                ),
 78                "nonce_endpoint": request.build_absolute_uri(
 79                    reverse("authentik_enterprise_endpoints_connectors_agent:psso-nonce")
 80                ),
 81            }
 82        )
 83
 84
 85class RegisterUserView(APIView):
 86
 87    class AgentPSSOUserRegistration(EnterpriseRequiredMixin, PassiveSerializer):
 88        """Register Apple device user via Platform SSO"""
 89
 90        user_auth = CharField()
 91        user_secure_enclave_key = CharField()
 92        enclave_key_id = CharField()
 93
 94    permission_classes = [IsAuthenticated]
 95    pagination_class = None
 96    filter_backends = []
 97    serializer_class = AgentPSSOUserRegistration
 98    authentication_classes = [AgentAuth]
 99
100    @extend_schema(
101        responses={
102            200: UserSelfSerializer(),
103        }
104    )
105    @validate(AgentPSSOUserRegistration)
106    def post(self, request: Request, body: AgentPSSOUserRegistration) -> Response:
107        device_token: DeviceToken = request.auth
108        conn: AgentDeviceConnection = device_token.device
109        user_token = DeviceAuthenticationToken.objects.filter(
110            device=conn.device,
111            token=body.validated_data["user_auth"],
112            device_token=device_token,
113        ).first()
114        if not user_token:
115            raise ValidationError("Invalid user authentication")
116        AgentDeviceUserBinding.objects.update_or_create(
117            target=conn.device,
118            user=user_token.user,
119            connector=conn.connector,
120            create_defaults={
121                "is_primary": True,
122                "order": 0,
123            },
124            defaults={
125                "apple_secure_enclave_key": body.validated_data["user_secure_enclave_key"],
126                "apple_enclave_key_id": body.validated_data["enclave_key_id"],
127            },
128        )
129        return Response(
130            UserSelfSerializer(instance=user_token.user, context={"request": request}).data
131        )
class RegisterDeviceView(rest_framework.views.APIView):
25class RegisterDeviceView(APIView):
26
27    class AgentPSSODeviceRegistration(EnterpriseRequiredMixin, PassiveSerializer):
28        """Register Apple device via Platform SSO"""
29
30        device_signing_key = CharField()
31        device_encryption_key = CharField()
32        sign_key_id = CharField()
33        enc_key_id = CharField()
34
35    class AgentPSSODeviceRegistrationResponse(PassiveSerializer):
36        """authentik settings for Platform SSO tokens"""
37
38        client_id = CharField()
39        issuer = CharField()
40        token_endpoint = CharField()
41        jwks_endpoint = CharField()
42        audience = CharField()
43        nonce_endpoint = CharField()
44
45    permission_classes = [IsAuthenticated]
46    pagination_class = None
47    filter_backends = []
48    serializer_class = AgentPSSODeviceRegistration
49    authentication_classes = [AgentAuth]
50
51    @extend_schema(
52        responses={
53            200: AgentPSSODeviceRegistrationResponse(),
54        }
55    )
56    @validate(AgentPSSODeviceRegistration)
57    def post(self, request: Request, body: AgentPSSODeviceRegistration) -> Response:
58        device_token: DeviceToken = request.auth
59        conn: AgentDeviceConnection = device_token.device
60        conn.apple_signing_key = body.validated_data["device_signing_key"]
61        conn.apple_encryption_key = body.validated_data["device_encryption_key"]
62        conn.apple_sign_key_id = body.validated_data["sign_key_id"]
63        conn.apple_enc_key_id = body.validated_data["enc_key_id"]
64        conn.apple_key_exchange_key = generate_key()
65        conn.save()
66        return Response(
67            data={
68                "client_id": str(conn.connector.pk),
69                "issuer": self.request.build_absolute_uri(
70                    reverse("authentik_enterprise_endpoints_connectors_agent:psso-token")
71                ),
72                "audience": str(conn.device.pk),
73                "token_endpoint": request.build_absolute_uri(
74                    reverse("authentik_enterprise_endpoints_connectors_agent:psso-token")
75                ),
76                "jwks_endpoint": request.build_absolute_uri(
77                    reverse("authentik_enterprise_endpoints_connectors_agent:psso-jwks")
78                ),
79                "nonce_endpoint": request.build_absolute_uri(
80                    reverse("authentik_enterprise_endpoints_connectors_agent:psso-nonce")
81                ),
82            }
83        )

Intentionally simple parent class for all views. Only implements dispatch-by-method and simple sanity checking.

permission_classes = [<class 'rest_framework.permissions.IsAuthenticated'>]
pagination_class = None
filter_backends = []
serializer_class = <class 'RegisterDeviceView.AgentPSSODeviceRegistration'>
authentication_classes = [<class 'authentik.endpoints.connectors.agent.auth.AgentAuth'>]
@extend_schema(responses={200: AgentPSSODeviceRegistrationResponse()})
@validate(AgentPSSODeviceRegistration)
def post( self, request: rest_framework.request.Request, body: RegisterDeviceView.AgentPSSODeviceRegistration) -> rest_framework.response.Response:
51    @extend_schema(
52        responses={
53            200: AgentPSSODeviceRegistrationResponse(),
54        }
55    )
56    @validate(AgentPSSODeviceRegistration)
57    def post(self, request: Request, body: AgentPSSODeviceRegistration) -> Response:
58        device_token: DeviceToken = request.auth
59        conn: AgentDeviceConnection = device_token.device
60        conn.apple_signing_key = body.validated_data["device_signing_key"]
61        conn.apple_encryption_key = body.validated_data["device_encryption_key"]
62        conn.apple_sign_key_id = body.validated_data["sign_key_id"]
63        conn.apple_enc_key_id = body.validated_data["enc_key_id"]
64        conn.apple_key_exchange_key = generate_key()
65        conn.save()
66        return Response(
67            data={
68                "client_id": str(conn.connector.pk),
69                "issuer": self.request.build_absolute_uri(
70                    reverse("authentik_enterprise_endpoints_connectors_agent:psso-token")
71                ),
72                "audience": str(conn.device.pk),
73                "token_endpoint": request.build_absolute_uri(
74                    reverse("authentik_enterprise_endpoints_connectors_agent:psso-token")
75                ),
76                "jwks_endpoint": request.build_absolute_uri(
77                    reverse("authentik_enterprise_endpoints_connectors_agent:psso-jwks")
78                ),
79                "nonce_endpoint": request.build_absolute_uri(
80                    reverse("authentik_enterprise_endpoints_connectors_agent:psso-nonce")
81                ),
82            }
83        )
class RegisterDeviceView.AgentPSSODeviceRegistration(authentik.enterprise.api.EnterpriseRequiredMixin, authentik.core.api.utils.PassiveSerializer):
27    class AgentPSSODeviceRegistration(EnterpriseRequiredMixin, PassiveSerializer):
28        """Register Apple device via Platform SSO"""
29
30        device_signing_key = CharField()
31        device_encryption_key = CharField()
32        sign_key_id = CharField()
33        enc_key_id = CharField()

Register Apple device via Platform SSO

device_signing_key
device_encryption_key
sign_key_id
enc_key_id
class RegisterDeviceView.AgentPSSODeviceRegistrationResponse(authentik.core.api.utils.PassiveSerializer):
35    class AgentPSSODeviceRegistrationResponse(PassiveSerializer):
36        """authentik settings for Platform SSO tokens"""
37
38        client_id = CharField()
39        issuer = CharField()
40        token_endpoint = CharField()
41        jwks_endpoint = CharField()
42        audience = CharField()
43        nonce_endpoint = CharField()

authentik settings for Platform SSO tokens

client_id
issuer
token_endpoint
jwks_endpoint
audience
nonce_endpoint
class RegisterUserView(rest_framework.views.APIView):
 86class RegisterUserView(APIView):
 87
 88    class AgentPSSOUserRegistration(EnterpriseRequiredMixin, PassiveSerializer):
 89        """Register Apple device user via Platform SSO"""
 90
 91        user_auth = CharField()
 92        user_secure_enclave_key = CharField()
 93        enclave_key_id = CharField()
 94
 95    permission_classes = [IsAuthenticated]
 96    pagination_class = None
 97    filter_backends = []
 98    serializer_class = AgentPSSOUserRegistration
 99    authentication_classes = [AgentAuth]
100
101    @extend_schema(
102        responses={
103            200: UserSelfSerializer(),
104        }
105    )
106    @validate(AgentPSSOUserRegistration)
107    def post(self, request: Request, body: AgentPSSOUserRegistration) -> Response:
108        device_token: DeviceToken = request.auth
109        conn: AgentDeviceConnection = device_token.device
110        user_token = DeviceAuthenticationToken.objects.filter(
111            device=conn.device,
112            token=body.validated_data["user_auth"],
113            device_token=device_token,
114        ).first()
115        if not user_token:
116            raise ValidationError("Invalid user authentication")
117        AgentDeviceUserBinding.objects.update_or_create(
118            target=conn.device,
119            user=user_token.user,
120            connector=conn.connector,
121            create_defaults={
122                "is_primary": True,
123                "order": 0,
124            },
125            defaults={
126                "apple_secure_enclave_key": body.validated_data["user_secure_enclave_key"],
127                "apple_enclave_key_id": body.validated_data["enclave_key_id"],
128            },
129        )
130        return Response(
131            UserSelfSerializer(instance=user_token.user, context={"request": request}).data
132        )

Intentionally simple parent class for all views. Only implements dispatch-by-method and simple sanity checking.

permission_classes = [<class 'rest_framework.permissions.IsAuthenticated'>]
pagination_class = None
filter_backends = []
serializer_class = <class 'RegisterUserView.AgentPSSOUserRegistration'>
authentication_classes = [<class 'authentik.endpoints.connectors.agent.auth.AgentAuth'>]
@extend_schema(responses={200: UserSelfSerializer()})
@validate(AgentPSSOUserRegistration)
def post( self, request: rest_framework.request.Request, body: RegisterUserView.AgentPSSOUserRegistration) -> rest_framework.response.Response:
101    @extend_schema(
102        responses={
103            200: UserSelfSerializer(),
104        }
105    )
106    @validate(AgentPSSOUserRegistration)
107    def post(self, request: Request, body: AgentPSSOUserRegistration) -> Response:
108        device_token: DeviceToken = request.auth
109        conn: AgentDeviceConnection = device_token.device
110        user_token = DeviceAuthenticationToken.objects.filter(
111            device=conn.device,
112            token=body.validated_data["user_auth"],
113            device_token=device_token,
114        ).first()
115        if not user_token:
116            raise ValidationError("Invalid user authentication")
117        AgentDeviceUserBinding.objects.update_or_create(
118            target=conn.device,
119            user=user_token.user,
120            connector=conn.connector,
121            create_defaults={
122                "is_primary": True,
123                "order": 0,
124            },
125            defaults={
126                "apple_secure_enclave_key": body.validated_data["user_secure_enclave_key"],
127                "apple_enclave_key_id": body.validated_data["enclave_key_id"],
128            },
129        )
130        return Response(
131            UserSelfSerializer(instance=user_token.user, context={"request": request}).data
132        )
class RegisterUserView.AgentPSSOUserRegistration(authentik.enterprise.api.EnterpriseRequiredMixin, authentik.core.api.utils.PassiveSerializer):
88    class AgentPSSOUserRegistration(EnterpriseRequiredMixin, PassiveSerializer):
89        """Register Apple device user via Platform SSO"""
90
91        user_auth = CharField()
92        user_secure_enclave_key = CharField()
93        enclave_key_id = CharField()

Register Apple device user via Platform SSO

user_auth
user_secure_enclave_key
enclave_key_id