diff --git a/tests/mdm/test_dep_enrollment.py b/tests/mdm/test_dep_enrollment.py index 480638f14f..ce3a0c057c 100644 --- a/tests/mdm/test_dep_enrollment.py +++ b/tests/mdm/test_dep_enrollment.py @@ -72,6 +72,8 @@ def test_dep_enrollment_reenrollment_session(self): self.assertIsNone(reenrollment_session.user_enrollment) self.assertEqual(reenrollment_session.status, ReEnrollmentSession.STARTED) self.assertEqual(reenrollment_session.realm_user, realm_user) + self.assertEqual(reenrollment_session.first_enrolled_at, session.created_at) + self.assertEqual(reenrollment_session.device_enrolled_at, session.device_enrolled_at) re_s, dep_s = list(session.enrolled_device.iter_enrollment_session_info()) self.assertEqual(re_s["session_type"], "RE") self.assertEqual(re_s["id"], reenrollment_session.pk) diff --git a/tests/mdm/test_ota_enrollment.py b/tests/mdm/test_ota_enrollment.py index 3178b8750d..abafa242ae 100644 --- a/tests/mdm/test_ota_enrollment.py +++ b/tests/mdm/test_ota_enrollment.py @@ -56,6 +56,8 @@ def test_ota_enrollment_reenrollment_session(self): self.assertEqual(reenrollment_session.ota_enrollment, enrollment) self.assertIsNone(reenrollment_session.user_enrollment) self.assertEqual(reenrollment_session.status, ReEnrollmentSession.STARTED) + self.assertEqual(reenrollment_session.first_enrolled_at, session.created_at) + self.assertEqual(reenrollment_session.device_enrolled_at, session.device_enrolled_at) re_s, ota_s = list(session.enrolled_device.iter_enrollment_session_info()) self.assertEqual(re_s["session_type"], "RE") self.assertEqual(re_s["id"], reenrollment_session.pk) diff --git a/tests/mdm/test_user_enrollment.py b/tests/mdm/test_user_enrollment.py index 31ad660232..06788b4e02 100644 --- a/tests/mdm/test_user_enrollment.py +++ b/tests/mdm/test_user_enrollment.py @@ -47,6 +47,8 @@ def test_user_enrollment_reenrollment_session(self): self.assertIsNone(reenrollment_session.ota_enrollment) self.assertEqual(reenrollment_session.user_enrollment, enrollment) self.assertEqual(reenrollment_session.status, ReEnrollmentSession.STARTED) + self.assertEqual(reenrollment_session.first_enrolled_at, session.created_at) + self.assertEqual(reenrollment_session.device_enrolled_at, session.device_enrolled_at) re_s, user_s = list(session.enrolled_device.iter_enrollment_session_info()) self.assertEqual(re_s["session_type"], "RE") self.assertEqual(re_s["id"], reenrollment_session.pk) diff --git a/zentral/contrib/mdm/migrations/0068_reenrollmentsession_first_enrolled_at.py b/zentral/contrib/mdm/migrations/0068_reenrollmentsession_first_enrolled_at.py new file mode 100644 index 0000000000..7a399960e8 --- /dev/null +++ b/zentral/contrib/mdm/migrations/0068_reenrollmentsession_first_enrolled_at.py @@ -0,0 +1,49 @@ +# Generated by Django 4.1.9 on 2023-08-07 15:48 + +from django.db import migrations, models + + +def update_first_enrolled_at(apps, schema_editor): + ReEnrollmentSession = apps.get_model("mdm", "ReEnrollmentSession") + for res in ReEnrollmentSession.objects.all(): + enrollment = None + for attr, s_attr in (("dep_enrollment", "depenrollmentsession_set"), + ("ota_enrollment", "otaenrollmentsession_set"), + ("user_enrollment", "userenrollmentsession_set")): + enrollment = getattr(res, attr, None) + if enrollment: + break + es = None + if enrollment: + es = ( + getattr(enrollment, s_attr) + .filter(enrolled_device__serial_number=res.enrolled_device.serial_number) + .order_by("-created_at") + .first() + ) + if es: + res.first_enrolled_at = es.created_at + else: + res.first_enrolled_at = res.created_at + res.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('mdm', '0067_recoverypasswordconfig_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='reenrollmentsession', + name='first_enrolled_at', + field=models.DateTimeField(null=True), + ), + migrations.RunPython(update_first_enrolled_at), + migrations.AlterField( + model_name='reenrollmentsession', + name='first_enrolled_at', + field=models.DateTimeField(), + ), + ] diff --git a/zentral/contrib/mdm/models.py b/zentral/contrib/mdm/models.py index 20d6d69cac..81a3c9b724 100644 --- a/zentral/contrib/mdm/models.py +++ b/zentral/contrib/mdm/models.py @@ -1084,6 +1084,10 @@ def _set_next_status(self, next_status, test, **update_dict): else: raise EnrollmentSessionStatusError(self, next_status) + @property + def device_enrolled_at(self): + return self.created_at + # Abstract MDM enrollment model @@ -1871,10 +1875,13 @@ def create_from_enrollment_session(self, enrollment_session): ) new_es.save(secret_length=57) # CN max 64 - $ separator - prefix MDM$RE new_es.tags.set(tags) - enrollment_session = self.model(status=self.model.STARTED, - enrollment_secret=new_es, - enrolled_device=enrolled_device, # important, see _reenroll !! - realm_user=enrollment_session.realm_user) + enrollment_session = self.model( + status=self.model.STARTED, + enrollment_secret=new_es, + enrolled_device=enrolled_device, # important, see _reenroll !! + realm_user=enrollment_session.realm_user, + first_enrolled_at=enrollment_session.device_enrolled_at, + ) if isinstance(enrollment, DEPEnrollment): enrollment_session.dep_enrollment = enrollment elif isinstance(enrollment, OTAEnrollment): @@ -1905,6 +1912,7 @@ class ReEnrollmentSession(EnrollmentSession): enrollment_secret = models.OneToOneField(EnrollmentSecret, on_delete=models.PROTECT, related_name="reenrollment_session") scep_request = models.ForeignKey(EnrollmentSecretRequest, on_delete=models.PROTECT, null=True, related_name="+") + first_enrolled_at = models.DateTimeField() objects = ReEnrollmentSessionManager() @@ -1922,6 +1930,10 @@ def get_prefix(self): else: raise ValueError("Wrong enrollment sessions status") + @property + def device_enrolled_at(self): + return self.first_enrolled_at + def serialize_for_event(self): return super().serialize_for_event("re", self.get_enrollment().serialize_for_event())