import synta
import synta.krb5 as krb5
import synta.oids as oids
def section(title):
print(f"\n{'─' * 60}\n{title}\n{'─' * 60}")
def demo_nt_constants():
section("NT_* name-type constants (RFC 4120 §6.2)")
nt_constants = [
("NT_UNKNOWN", krb5.NT_UNKNOWN, 0),
("NT_PRINCIPAL", krb5.NT_PRINCIPAL, 1),
("NT_SRV_INST", krb5.NT_SRV_INST, 2),
("NT_SRV_HST", krb5.NT_SRV_HST, 3),
("NT_SRV_XHST", krb5.NT_SRV_XHST, 4),
("NT_UID", krb5.NT_UID, 5),
("NT_X500_PRINCIPAL", krb5.NT_X500_PRINCIPAL, 6),
("NT_SMTP_NAME", krb5.NT_SMTP_NAME, 7),
("NT_ENTERPRISE", krb5.NT_ENTERPRISE, 10),
("NT_WELLKNOWN", krb5.NT_WELLKNOWN, 11),
("NT_SRV_HST_DOMAIN", krb5.NT_SRV_HST_DOMAIN, 12),
]
for name, val, expected in nt_constants:
assert val == expected, f"{name}: expected {expected}, got {val}"
print(f" {name:20} = {val}")
def demo_krb5_principal_name_oid():
section("KRB5_PRINCIPAL_NAME_OID — id-pkinit-san (1.3.6.1.5.2.2)")
oid = krb5.KRB5_PRINCIPAL_NAME_OID
print(f" KRB5_PRINCIPAL_NAME_OID = {oid}")
assert str(oid) == "1.3.6.1.5.2.2"
assert list(oid.components()) == [1, 3, 6, 1, 5, 2, 2]
assert oid == oids.PKINIT_SAN
print(f" == synta.oids.PKINIT_SAN: OK")
def demo_construct_all_name_types():
section("Construct Krb5PrincipalName for each NT_* type")
principals = [
("NT_PRINCIPAL", krb5.NT_PRINCIPAL, "EXAMPLE.COM", ["alice"]),
("NT_SRV_INST", krb5.NT_SRV_INST, "EXAMPLE.COM", ["krbtgt", "EXAMPLE.COM"]),
("NT_SRV_HST", krb5.NT_SRV_HST, "EXAMPLE.COM", ["host", "server.example.com"]),
("NT_ENTERPRISE", krb5.NT_ENTERPRISE, "EXAMPLE.COM", ["user@sub.example.com"]),
("NT_WELLKNOWN", krb5.NT_WELLKNOWN, "WELLKNOWN:ANONYMOUS", ["ANONYMOUS"]),
]
for label, name_type, realm, components in principals:
p = krb5.Krb5PrincipalName(realm, name_type, components)
assert p.realm == realm
assert p.name_type == name_type
assert list(p.components) == components
print(f" {label:16} → {repr(p)}")
def demo_roundtrip():
section("Encode to DER and decode back — all properties preserved")
p = krb5.Krb5PrincipalName("EXAMPLE.COM", krb5.NT_SRV_INST, ["krbtgt", "EXAMPLE.COM"])
der = p.to_der()
assert isinstance(der, bytes)
print(f" DER: {der.hex()}")
q = krb5.Krb5PrincipalName.from_der(der)
assert q.realm == p.realm
assert q.name_type == p.name_type
assert list(q.components) == list(p.components)
print(f" realm: {q.realm!r}")
print(f" name_type: {q.name_type} (NT_SRV_INST)")
print(f" components: {list(q.components)}")
print(" Round-trip: OK")
def demo_eq_and_repr():
section("__eq__ and __repr__")
a = krb5.Krb5PrincipalName("REALM", krb5.NT_PRINCIPAL, ["bob"])
b = krb5.Krb5PrincipalName("REALM", krb5.NT_PRINCIPAL, ["bob"])
c = krb5.Krb5PrincipalName("REALM", krb5.NT_PRINCIPAL, ["carol"])
assert a == b
assert not (a == c)
print(f" a == b: True (same principal)")
print(f" a == c: False (different components)")
r = repr(a)
assert "Krb5PrincipalName" in r
assert "REALM" in r
assert "bob" in r
print(f" repr: {r}")
def demo_validation_errors():
section("ValueError for non-ASCII realm or component")
try:
krb5.Krb5PrincipalName("RÉALM", krb5.NT_PRINCIPAL, ["alice"])
print(" No error (unexpected)")
except ValueError as e:
print(f" ValueError (non-ASCII realm): {e}")
try:
krb5.Krb5PrincipalName("REALM", krb5.NT_PRINCIPAL, ["alïce"])
print(" No error (unexpected)")
except ValueError as e:
print(f" ValueError (non-ASCII component): {e}")
def main():
print("=" * 60)
print("Example 18: Kerberos principal names")
print("=" * 60)
demo_nt_constants()
demo_krb5_principal_name_oid()
demo_construct_all_name_types()
demo_roundtrip()
demo_eq_and_repr()
demo_validation_errors()
print("\nAll Krb5PrincipalName examples completed.")
if __name__ == "__main__":
main()