Skip to content

Commit

Permalink
Add firmware password MDM management
Browse files Browse the repository at this point in the history
  • Loading branch information
np5 committed Aug 11, 2023
1 parent b72b9dd commit bb4358a
Show file tree
Hide file tree
Showing 10 changed files with 676 additions and 6 deletions.
179 changes: 178 additions & 1 deletion tests/mdm/test_management_enrolled_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -837,7 +837,7 @@ def test_enrolled_device_no_perms_no_set_recovery_lock_command_link(self):
def test_enrolled_device_not_apple_silicon_no_set_recovery_lock_command_link(self):
session, _, _ = force_dep_enrollment_session(self.mbu, completed=True)
self.assertFalse(session.enrolled_device.apple_silicon)
self._login("mdm.view_enrolleddevice")
self._login("mdm.view_enrolleddevice", "mdm.add_devicecommand")
response = self.client.get(reverse("mdm:enrolled_device", args=(session.enrolled_device.pk,)))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "mdm/enrolleddevice_detail.html")
Expand Down Expand Up @@ -1014,6 +1014,183 @@ def test_create_enrolled_device_set_recovery_lock_command_clear_ok(self):
"NewPassword": ""},
)

# create set firmware password command

def test_enrolled_device_no_perms_no_set_firmware_password_command_link(self):
session, _, _ = force_dep_enrollment_session(self.mbu, completed=True)
self.assertFalse(session.enrolled_device.apple_silicon)
self._login("mdm.view_enrolleddevice")
response = self.client.get(reverse("mdm:enrolled_device", args=(session.enrolled_device.pk,)))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "mdm/enrolleddevice_detail.html")
self.assertNotContains(
response,
reverse("mdm:create_enrolled_device_command", args=(session.enrolled_device.pk, "SetFirmwarePassword"))
)

def test_enrolled_device_apple_silicon_no_set_firmware_password_command_link(self):
session, _, _ = force_dep_enrollment_session(self.mbu, completed=True)
session.enrolled_device.apple_silicon = True
session.enrolled_device.save()
self._login("mdm.view_enrolleddevice", "mdm.add_devicecommand")
response = self.client.get(reverse("mdm:enrolled_device", args=(session.enrolled_device.pk,)))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "mdm/enrolleddevice_detail.html")
self.assertNotContains(
response,
reverse("mdm:create_enrolled_device_command", args=(session.enrolled_device.pk, "SetFirmwarePassword"))
)

def test_enrolled_device_set_firmware_password_command_link(self):
session, _, _ = force_dep_enrollment_session(self.mbu, completed=True)
self._login("mdm.view_enrolleddevice", "mdm.add_devicecommand")
response = self.client.get(reverse("mdm:enrolled_device", args=(session.enrolled_device.pk,)))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "mdm/enrolleddevice_detail.html")
self.assertContains(
response,
reverse("mdm:create_enrolled_device_command", args=(session.enrolled_device.pk, "SetFirmwarePassword"))
)

def test_create_enrolled_device_set_firmware_password_command_redirect(self):
session, _, _ = force_dep_enrollment_session(self.mbu, completed=True)
self._login_redirect(reverse("mdm:create_enrolled_device_command",
args=(session.enrolled_device.pk, "SetFirmwarePassword")))

def test_create_enrolled_device_set_firmware_password_command_permission_denied(self):
session, _, _ = force_dep_enrollment_session(self.mbu, completed=True)
self._login("mdm.view_enrolleddevice")
response = self.client.get(
reverse("mdm:create_enrolled_device_command",
args=(session.enrolled_device.pk, "SetFirmwarePassword"))
)
self.assertEqual(response.status_code, 403)

def test_create_enrolled_device_set_firmware_password_command_get(self):
session, _, _ = force_dep_enrollment_session(self.mbu, completed=True)
self._login("mdm.add_devicecommand")
response = self.client.get(
reverse("mdm:create_enrolled_device_command",
args=(session.enrolled_device.pk, "SetFirmwarePassword"))
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "mdm/enrolleddevice_create_command.html")

def test_create_enrolled_device_set_firmware_password_command_pwd_too_short(self):
session, _, _ = force_dep_enrollment_session(self.mbu, completed=True)
self._login("mdm.view_enrolleddevice", "mdm.add_devicecommand")
response = self.client.post(
reverse("mdm:create_enrolled_device_command",
args=(session.enrolled_device.pk, "SetFirmwarePassword")),
{"new_password": "1234567"},
follow=True
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "mdm/enrolleddevice_create_command.html")
self.assertFormError(
response.context["form"],
"new_password",
"The password must be at least 8 characters long."
)

def test_create_enrolled_device_set_firmware_password_command_pwd_too_long(self):
session, _, _ = force_dep_enrollment_session(self.mbu, completed=True)
self._login("mdm.view_enrolleddevice", "mdm.add_devicecommand")
response = self.client.post(
reverse("mdm:create_enrolled_device_command",
args=(session.enrolled_device.pk, "SetFirmwarePassword")),
{"new_password": 33 * "1"},
follow=True
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "mdm/enrolleddevice_create_command.html")
self.assertFormError(
response.context["form"],
"new_password",
"The password must be at most 32 characters long."
)

def test_create_enrolled_device_set_firmware_password_command_pwd_non_ascii(self):
session, _, _ = force_dep_enrollment_session(self.mbu, completed=True)
self._login("mdm.view_enrolleddevice", "mdm.add_devicecommand")
response = self.client.post(
reverse("mdm:create_enrolled_device_command",
args=(session.enrolled_device.pk, "SetFirmwarePassword")),
{"new_password": 8 * "é"},
follow=True
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "mdm/enrolleddevice_create_command.html")
self.assertFormError(
response.context["form"],
"new_password",
"The characters in this value must consist of low-ASCII, printable characters (0x20 through 0x7E) "
"to ensure that all characters are enterable on the EFI login screen."
)

def test_create_enrolled_device_set_firmware_password_command_pwd_clear_non_existing(self):
session, _, _ = force_dep_enrollment_session(self.mbu, completed=True)
self._login("mdm.view_enrolleddevice", "mdm.add_devicecommand")
response = self.client.post(
reverse("mdm:create_enrolled_device_command",
args=(session.enrolled_device.pk, "SetFirmwarePassword")),
{"new_password": ""},
follow=True
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "mdm/enrolleddevice_create_command.html")
self.assertFormError(
response.context["form"],
"new_password",
"No current firmware password set: this field is required."
)

def test_create_enrolled_device_set_firmware_password_command_ok(self):
session, _, _ = force_dep_enrollment_session(self.mbu, completed=True)
session.enrolled_device.set_recovery_password("87654321")
session.enrolled_device.save()
self._login("mdm.view_enrolleddevice", "mdm.add_devicecommand")
response = self.client.post(
reverse("mdm:create_enrolled_device_command",
args=(session.enrolled_device.pk, "SetFirmwarePassword")),
{"new_password": "12345678"},
follow=True
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "mdm/enrolleddevice_detail.html")
self.assertContains(response, "Set firmware password command successfully created")
db_cmd = session.enrolled_device.commands.first()
self.assertEqual(db_cmd.name, "SetFirmwarePassword")
cmd = load_command(db_cmd)
self.assertEqual(
cmd.build_command(),
{"CurrentPassword": "87654321",
"NewPassword": "12345678"},
)

def test_create_enrolled_device_set_firmware_password_command_clear_ok(self):
session, _, _ = force_dep_enrollment_session(self.mbu, completed=True)
session.enrolled_device.set_recovery_password("87654321")
session.enrolled_device.save()
self._login("mdm.view_enrolleddevice", "mdm.add_devicecommand")
response = self.client.post(
reverse("mdm:create_enrolled_device_command",
args=(session.enrolled_device.pk, "SetFirmwarePassword")),
{"new_password": ""},
follow=True
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "mdm/enrolleddevice_detail.html")
self.assertContains(response, "Set firmware password command successfully created")
db_cmd = session.enrolled_device.commands.first()
self.assertEqual(db_cmd.name, "SetFirmwarePassword")
cmd = load_command(db_cmd)
self.assertEqual(
cmd.build_command(),
{"CurrentPassword": "87654321",
"NewPassword": ""},
)

# create rotate filevault key command

def test_enrolled_device_no_rotate_filevault_key_command_link(self):
Expand Down
161 changes: 160 additions & 1 deletion tests/mdm/test_security_info_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@
from zentral.contrib.mdm.commands.scheduling import _update_base_inventory
from zentral.contrib.mdm.commands.setup_filevault import get_escrow_key_certificate_der_bytes
from zentral.contrib.mdm.crypto import encrypt_cms_payload
from zentral.contrib.mdm.events import FileVaultPRKUpdatedEvent
from zentral.contrib.mdm.events import (FileVaultPRKUpdatedEvent,
RecoveryPasswordClearedEvent,
RecoveryPasswordSetEvent,
RecoveryPasswordUpdatedEvent)
from zentral.contrib.mdm.models import Blueprint, Channel, Platform, RequestStatus
from .utils import force_dep_enrollment_session

Expand Down Expand Up @@ -203,6 +206,162 @@ def test_process_acknowledged_response_same_filevault_prk(self, post_event):
events = list(call_args.args[0] for call_args in post_event.call_args_list)
self.assertEqual(len(events), 0)

@patch("zentral.core.queues.backends.kombu.EventQueues.post_event")
def test_process_acknowledged_response_pending_firmware_password_pending(self, post_event):
self.assertIsNone(self.enrolled_device.recovery_password)
self.enrolled_device.set_pending_firmware_password("12345678")
self.enrolled_device.save()
new_db_cmd_qs = self.enrolled_device.commands.filter(name="RestartDevice")
self.assertEqual(new_db_cmd_qs.count(), 0)
cmd = SecurityInfo.create_for_device(self.enrolled_device)
security_info = copy.deepcopy(self.security_info)
security_info["SecurityInfo"]["FirmwarePasswordStatus"] = {
"PasswordExists": False,
"AllowOroms": True,
"ChangePending": True
}
with self.captureOnCommitCallbacks(execute=True):
cmd.process_response(security_info, self.dep_enrollment_session, self.mbu)
self.enrolled_device.refresh_from_db()
self.assertEqual(self.enrolled_device.get_pending_firmware_password(), "12345678")
self.assertIsNone(self.enrolled_device.recovery_password)
events = list(call_args.args[0] for call_args in post_event.call_args_list)
self.assertEqual(len(events), 0)
self.assertEqual(new_db_cmd_qs.count(), 1)
new_db_cmd = new_db_cmd_qs.first()
self.assertEqual(new_db_cmd.kwargs, {"NotifyUser": True})

@patch("zentral.core.queues.backends.kombu.EventQueues.post_event")
def test_process_acknowledged_response_pending_firmware_password_set(self, post_event):
self.assertIsNone(self.enrolled_device.recovery_password)
self.enrolled_device.set_pending_firmware_password("12345678")
self.enrolled_device.save()
cmd = SecurityInfo.create_for_device(self.enrolled_device)
security_info = copy.deepcopy(self.security_info)
security_info["SecurityInfo"]["FirmwarePasswordStatus"] = {
"PasswordExists": True,
"AllowOroms": True,
"Mode": "command",
"ChangePending": False,
}
with self.captureOnCommitCallbacks(execute=True):
cmd.process_response(security_info, self.dep_enrollment_session, self.mbu)
self.enrolled_device.refresh_from_db()
self.assertIsNone(self.enrolled_device.get_pending_firmware_password())
self.assertIsNone(self.enrolled_device.pending_firmware_password_created_at)
self.assertEqual(self.enrolled_device.get_recovery_password(), "12345678")
self.assertEqual(self.enrolled_device.commands.filter(name="RestartDevice").count(), 0)
events = list(call_args.args[0] for call_args in post_event.call_args_list)
self.assertEqual(len(events), 1)
event = events[0]
self.assertIsInstance(event, RecoveryPasswordSetEvent)
self.assertEqual(
event.payload,
{'command': {'request_type': 'SecurityInfo',
'uuid': str(cmd.uuid)},
'password_type': 'firmware_password'}
)
metadata = event.metadata.serialize()
self.assertEqual(metadata["machine_serial_number"], self.enrolled_device.serial_number)
self.assertEqual(metadata["objects"], {"mdm_command": [str(cmd.uuid)]})
self.assertEqual(set(metadata["tags"]), {"mdm", "recovery_password"})

@patch("zentral.core.queues.backends.kombu.EventQueues.post_event")
def test_process_acknowledged_response_pending_firmware_password_update(self, post_event):
self.assertIsNone(self.enrolled_device.recovery_password)
self.enrolled_device.set_recovery_password("87654321")
self.enrolled_device.set_pending_firmware_password("12345678")
self.enrolled_device.save()
cmd = SecurityInfo.create_for_device(self.enrolled_device)
security_info = copy.deepcopy(self.security_info)
security_info["SecurityInfo"]["FirmwarePasswordStatus"] = {
"PasswordExists": True,
"AllowOroms": True,
"Mode": "command",
"ChangePending": False,
}
with self.captureOnCommitCallbacks(execute=True):
cmd.process_response(security_info, self.dep_enrollment_session, self.mbu)
self.enrolled_device.refresh_from_db()
self.assertIsNone(self.enrolled_device.get_pending_firmware_password())
self.assertIsNone(self.enrolled_device.pending_firmware_password_created_at)
self.assertEqual(self.enrolled_device.get_recovery_password(), "12345678")
self.assertEqual(self.enrolled_device.commands.filter(name="RestartDevice").count(), 0)
events = list(call_args.args[0] for call_args in post_event.call_args_list)
self.assertEqual(len(events), 1)
event = events[0]
self.assertIsInstance(event, RecoveryPasswordUpdatedEvent)
self.assertEqual(
event.payload,
{'command': {'request_type': 'SecurityInfo',
'uuid': str(cmd.uuid)},
'password_type': 'firmware_password'}
)
metadata = event.metadata.serialize()
self.assertEqual(metadata["machine_serial_number"], self.enrolled_device.serial_number)
self.assertEqual(metadata["objects"], {"mdm_command": [str(cmd.uuid)]})
self.assertEqual(set(metadata["tags"]), {"mdm", "recovery_password"})

@patch("zentral.core.queues.backends.kombu.EventQueues.post_event")
def test_process_acknowledged_response_pending_firmware_password_clear(self, post_event):
self.assertIsNone(self.enrolled_device.recovery_password)
self.enrolled_device.set_recovery_password("87654321")
self.enrolled_device.set_pending_firmware_password("")
self.enrolled_device.save()
cmd = SecurityInfo.create_for_device(self.enrolled_device)
security_info = copy.deepcopy(self.security_info)
security_info["SecurityInfo"]["FirmwarePasswordStatus"] = {
"PasswordExists": False,
"AllowOroms": True,
"Mode": "command",
"ChangePending": False,
}
with self.captureOnCommitCallbacks(execute=True):
cmd.process_response(security_info, self.dep_enrollment_session, self.mbu)
self.enrolled_device.refresh_from_db()
self.assertIsNone(self.enrolled_device.get_pending_firmware_password())
self.assertIsNone(self.enrolled_device.pending_firmware_password_created_at)
self.assertIsNone(self.enrolled_device.get_recovery_password())
self.assertEqual(self.enrolled_device.commands.filter(name="RestartDevice").count(), 0)
events = list(call_args.args[0] for call_args in post_event.call_args_list)
self.assertEqual(len(events), 1)
event = events[0]
self.assertIsInstance(event, RecoveryPasswordClearedEvent)
self.assertEqual(
event.payload,
{'command': {'request_type': 'SecurityInfo',
'uuid': str(cmd.uuid)},
'password_type': 'firmware_password'}
)
metadata = event.metadata.serialize()
self.assertEqual(metadata["machine_serial_number"], self.enrolled_device.serial_number)
self.assertEqual(metadata["objects"], {"mdm_command": [str(cmd.uuid)]})
self.assertEqual(set(metadata["tags"]), {"mdm", "recovery_password"})

@patch("zentral.core.queues.backends.kombu.EventQueues.post_event")
def test_process_acknowledged_response_pending_firmware_password_clear_error(self, post_event):
self.assertIsNone(self.enrolled_device.recovery_password)
self.enrolled_device.set_recovery_password("87654321")
self.enrolled_device.set_pending_firmware_password("")
self.enrolled_device.save()
cmd = SecurityInfo.create_for_device(self.enrolled_device)
security_info = copy.deepcopy(self.security_info)
security_info["SecurityInfo"]["FirmwarePasswordStatus"] = {
"PasswordExists": True, # the problem
"AllowOroms": True,
"Mode": "command",
"ChangePending": False,
}
with self.captureOnCommitCallbacks(execute=True):
cmd.process_response(security_info, self.dep_enrollment_session, self.mbu)
self.enrolled_device.refresh_from_db()
self.assertEqual(self.enrolled_device.get_recovery_password(), "87654321")
self.assertIsNone(self.enrolled_device.pending_firmware_password)
self.assertIsNone(self.enrolled_device.pending_firmware_password_created_at)
# no events
events = list(call_args.args[0] for call_args in post_event.call_args_list)
self.assertEqual(len(events), 0)

def test_process_acknowledged_ios_response(self):
start = datetime.utcnow()
self.assertIsNone(self.enrolled_device.security_info)
Expand Down
Loading

0 comments on commit bb4358a

Please sign in to comment.