Skip to content

Commit

Permalink
Fix issues with uncommon Santa target IDs
Browse files Browse the repository at this point in the history
 - Relax Signing ID verification
 - Fix Signing ID search
 - Fix Team ID search
 - Fix rule creation form
  • Loading branch information
np5 committed Apr 24, 2024
1 parent f71e1c6 commit e7a9f88
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 6 deletions.
1 change: 1 addition & 0 deletions tests/santa/test_rule_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ def test_sining_id_identifier(self):
("EQHXZ8M8AV:com.google.Chrome", True),
("EQHXZ8M8AV:chrome_crashpad_handler", True),
("EQHXZ8M8AV:not-a-thing", True),
("94KV3E626L:Frameworks[]Electron Framework", True),
("EQHXZ8M8AV", False)):
self.assertEqual(test_signing_id_identifier(identifier), result)

Expand Down
51 changes: 51 additions & 0 deletions tests/santa/test_setup_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from functools import reduce
import operator
import plistlib
import urllib.parse
from accounts.models import User
from unittest.mock import patch
from django.contrib.auth.models import Group, Permission
Expand Down Expand Up @@ -611,6 +612,36 @@ def test_create_configuration_team_id_rule_error(self):
self.assertTemplateUsed(response, "santa/rule_form.html")
self.assertFormError(response.context["form"], "target_identifier", "Invalid Team ID")

def test_create_configuration_team_id_rule_preselected_ok(self):
configuration = self._force_configuration()
self._login("santa.add_rule", "santa.view_rule")
response = self.client.post(reverse("santa:create_configuration_rule", args=(configuration.pk,))
+ "?" + urllib.parse.urlencode({"tea": "JQ525L2MZD"}),
{"policy": Rule.ALLOWLIST},
follow=True)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "santa/configuration_rules.html")
self.assertContains(response, "JQ525L2MZD")
rule = response.context["object_list"][0]
self.assertEqual(rule.configuration, configuration)
self.assertEqual(rule.target.identifier, "JQ525L2MZD")
self.assertEqual(rule.target.type, Target.TEAM_ID)

def test_create_configuration_team_id_rule_preselected_error(self):
# This is a test for when a team ID is picked from the list of target
# to create a rule, but … this is not a valid team ID.
# This should never happen!
configuration = self._force_configuration()
self._login("santa.add_rule", "santa.view_rule")
response = self.client.post(reverse("santa:create_configuration_rule", args=(configuration.pk,))
+ "?" + urllib.parse.urlencode({"tea": "NOT_A_TEAM_ID"}),
{"policy": Rule.ALLOWLIST},
follow=True)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "santa/rule_form.html")
self.assertFormError(response.context["form"],
None, "Invalid Team ID")

def test_create_conflict_configuration_rule(self):
self._login("santa.add_configuration", "santa.view_configuration",
"santa.add_rule", "santa.view_rule")
Expand Down Expand Up @@ -841,6 +872,16 @@ def test_pick_rule_team_id(self):
self.assertEqual(len(team_ids), 1)
self.assertEqual(team_ids[0][0].organizational_unit, self.file_team_id)

def test_pick_rule_team_id_special_chars(self):
configuration = self._force_configuration()
self._login("santa.add_rule")
response = self.client.get(reverse("santa:pick_rule_team_id", args=(configuration.pk,)),
{"query": "[]"})
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "santa/pick_rule_team_id.html")
team_ids = response.context["team_ids"]
self.assertEqual(len(team_ids), 0)

def test_pick_rule_signing_id_access_denied(self):
configuration = self._force_configuration()
self._login("santa.add_configuration", "santa.view_configuration")
Expand All @@ -859,6 +900,16 @@ def test_pick_rule_signing_id(self):
self.assertEqual(len(signing_ids), 1)
self.assertEqual(signing_ids[0][0].signing_id, self.file_signing_id)

def test_pick_rule_signing_id_special_chars(self):
configuration = self._force_configuration()
self._login("santa.add_rule")
response = self.client.get(reverse("santa:pick_rule_signing_id", args=(configuration.pk,)),
{"query": "94KV3E626L:Frameworks[]Electron Framework"})
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "santa/pick_rule_signing_id.html")
signing_ids = response.context["signing_ids"]
self.assertEqual(len(signing_ids), 0)

# terraform export

def test_terraform_export_redirect(self):
Expand Down
12 changes: 8 additions & 4 deletions zentral/contrib/santa/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ def test_signing_id_identifier(identifier):
team_id, signing_id = identifier.split(":", 1)
if not test_team_id(team_id) and team_id != "platform":
return False
return re.match(r'^([0-9a-zA-Z_\-]+\.)*([0-9a-zA-Z_\-]+)\Z', signing_id) is not None
return True


def test_team_id(team_id):
Expand Down Expand Up @@ -279,17 +279,21 @@ def clean(self):

# identifier
if target_identifier:
if "target_identifier" in self.fields:
error_field = "target_identifier"
else:
error_field = None
if target_type == Target.SIGNING_ID:
if not test_signing_id_identifier(target_identifier):
self.add_error("target_identifier", "Invalid Signing ID target identifier")
self.add_error(error_field, "Invalid Signing ID target identifier")
elif target_type == Target.TEAM_ID:
target_identifier = target_identifier.upper()
if not test_team_id(target_identifier):
self.add_error("target_identifier", "Invalid Team ID")
self.add_error(error_field, "Invalid Team ID")
else:
target_identifier = target_identifier.lower()
if not test_sha256(target_identifier):
self.add_error("target_identifier", "Invalid sha256")
self.add_error(error_field, "Invalid sha256")

# policy
try:
Expand Down
9 changes: 7 additions & 2 deletions zentral/contrib/santa/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -531,13 +531,17 @@ def search_teamid_objects(self, **kwargs):
q = kwargs.get("query")
if not q:
return []
q = "%{}%".format(connection.ops.prep_for_like_query(q))
query = (
"select c.organizational_unit, c.organization "
"from inventory_certificate as c "
"join inventory_file as f on (f.signed_by_id = c.id) "
"join inventory_source as s on (s.id = f.source_id) "
"where s.module = 'zentral.contrib.santa' and s.name = 'Santa events' "
"and (c.organizational_unit ~* %s or c.organization ~* %s)"
"and ("
" upper(c.organizational_unit) like upper(%s)"
" or upper(c.organization) like upper(%s)"
") "
"group by c.organizational_unit, c.organization "
"order by c.organization, c.organizational_unit"
)
Expand Down Expand Up @@ -565,12 +569,13 @@ def search_signingid_objects(self, **kwargs):
q = kwargs.get("query")
if not q:
return []
q = "%{}%".format(connection.ops.prep_for_like_query(q))
query = (
"select f.signing_id "
"from inventory_file as f "
"join inventory_source as s on (s.id = f.source_id) "
"where s.module = 'zentral.contrib.santa' and s.name = 'Santa events' "
"and f.signing_id ~* %s "
"and upper(f.signing_id) like upper(%s) "
"group by f.signing_id "
"order by f.signing_id"
)
Expand Down

0 comments on commit e7a9f88

Please sign in to comment.