# Unix SMB/CIFS implementation. Tests for dsdb_dn objects
# Copyright (C) Andrew Tridgell 2011
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
"""Tests for dsdb_dn objects"""
import os
import samba
from samba.samdb import BinaryDn, PlainDn, StringDn
from samba.key_credential_link import KeyCredentialLinkDn
from samba.tests import TestCaseInTempDir
class DsdbDnTests(TestCaseInTempDir):
def _temp_ldb(self, name=None):
if name is None:
name = f"{self.unique_name()}.ldb"
url = os.path.join(self.tempdir, name)
sam = samba.Ldb(url=url)
def _cleanup():
sam.disconnect()
os.unlink(url)
self.addCleanup(_cleanup)
return sam
def test_BinaryDn(self):
sam = self._temp_ldb()
dn1 = BinaryDn(sam, "B:8:0000000d:;DC=samba,DC=example,DC=com")
dn2 = BinaryDn(sam, "B:8:0000000D:;DC=samba,DC=example,DC=com")
self.assertEqual(dn2.binary, b"\0\0\0\x0d")
self.assertEqual(dn1.binary, dn2.binary)
self.assertEqual(dn1.prefix, "B:8:0000000D:")
self.assertEqual(13, dn2.get_binary_integer())
self.assertEqual(list(dn1.binary), [0, 0, 0, 13])
dn2.binary = b'123'
self.assertEqual(dn2.prefix, "B:6:313233:")
dn2.prefix = 'B:10:1234abcdef:'
self.assertEqual(dn2.prefix, "B:10:1234ABCDEF:")
self.assertEqual(dn2.get_binary_integer(), 0x1234ABCDEF)
self.assertEqual(list(dn2.binary), [0x12, 0x34, 0xAB, 0xCD, 0xEF])
for badstring, errmsg in (('B:11:1234abcdef0:', "Invalid hex string"),
('B:6:1234:', "Invalid length"),
('B:2:1234:', "Invalid length"),
('B:0:1234:', "Invalid length"),
('B:4:123g:', "Invalid prefix"),
('B:4:1234 :', "Invalid prefix"),
('b:4:1234:', "Invalid prefix"),
('S:4:1234:', "Invalid prefix"),
('S:4:123¼:', "Invalid prefix"),
('S:4:1234', "Invalid prefix"),
('B:4:1234', "Invalid prefix"),
):
with self.assertRaises(ValueError) as cm:
dn2.prefix = badstring
self.assertIn(errmsg, str(cm.exception))
def test_KeyCredentialLinkDn_valid(self):
"""Simple KeyCredentialLinkDn objects."""
sam = self._temp_ldb()
for name, dnstring, count in [
('empty', "B:8:00020000:DC=example,DC=com", 0),
('key id',
"B:78:00020000"
"2000" "01" # length, key id
"000102030405060708090A0B0C0D0E0F"
"101112131415161718191A1B1C1D1E1F"
":DC=example,DC=com", 1),
('key hash',
"B:78:00020000"
"2000" "02" # length, key hash
"000102030405060708090A0B0C0D0E0F"
"101112131415161718191A1B1C1D1E1F"
":DC=example,DC=com", 1),
('key usage',
"B:16:00020000"
"0100" "04" # length, key_usage
"01"
":DC=example,DC=com", 1),
]:
print(f"{name}: {dnstring}")
k = KeyCredentialLinkDn(sam, dnstring)
self.assertEqual(k.blob.count, count)
b = BinaryDn(sam, dnstring)
self.assertEqual(k, b)
self.assertEqual(str(k), str(b))
self.assertEqual(str(k).upper(), dnstring.upper())
def test_KeyCredentialLinkDn_invalid(self):
"""KeyCredentialLinkDn objects that should fail."""
sam = self._temp_ldb()
for name, dnstring, valid_binary in [
('bad version', "B:8:00030000:DC=example,DC=com", True),
('length mismatch 1',
"B:78:00020000"
"2200" "01" # length, key_id
"000102030405060708090A0B0C0D0E0F"
"101112131415161718191A1B1C1D1E1F"
":DC=example,DC=com", True),
('length mismatch 2',
"B:80:00020000"
"2000" "01" # length, key_id
"000102030405060708090A0B0C0D0E0F"
"101112131415161718191A1B1C1D1E1F00"
":DC=example,DC=com", True),
('binary length mismatch',
"B:10:00020000"
":DC=example,DC=com", False),
#('bad key usage',
# "B:16:00020000"
# "0100" "04" # length, key_usage
# "FF"
# ":DC=example,DC=com", True),
('bad entry id 00',
"B:16:00020000"
"0100" "00" # length, invalid
"FF"
":DC=example,DC=com", True),
('bad entry id ff',
"B:16:00020000"
"0100" "FF" # length, invalid
"FF"
":DC=example,DC=com", True),
]:
print(name)
with self.assertRaises(ValueError) as cm:
k = KeyCredentialLinkDn(sam, dnstring)
print(cm.exception)
try:
b = BinaryDn(sam, dnstring)
except ValueError:
if valid_binary:
self.fail(f"{name}: expected {dnstring} to be valid binary dn")
else:
if not valid_binary:
self.fail(f"{name}: expected {dnstring} to be invalid binary dn, "
f"got {b}")
def test_PlainDn(self):
sam = self._temp_ldb("test_PlainDn.ldb")
url = self.tempdir + "/test_PlainDn.ldb"
sam = samba.Ldb(url=url)
dn1 = PlainDn(sam, "DC=foo,DC=bar")
self.assertEqual(dn1.prefix, '')
self.assertIsNone(dn1.binary)
def test_StringDn(self):
sam = self._temp_ldb("test_StringDn.ldb")
dn1 = StringDn(sam, "S:8:0000000d:;DC=samba,DC=example,DC=com")
dn2 = StringDn(sam, "S:8:0000000D:;DC=samba,DC=example,DC=com")
self.assertEqual(dn1.binary, b"0000000d")
self.assertEqual(dn2.binary, b"0000000D")
# TODO: determine whether string DNs should have case-insensitive comparisons
self.assertNotEqual(dn1.binary, dn2.binary)
dn1.prefix = 'S:5:ā”:'
self.assertEqual(dn1.binary, b'\xc4\x81\xe2\x80\x9d')
self.assertEqual(dn1.prefix, 'S:5:ā”:')
def test_dsdb_Dn_sorted(self):
sam = self._temp_ldb("test_dsdb_Dn_sorted.ldb")
dn1 = BinaryDn(sam, "B:8:0000000D:;OU=dn1,DC=samba,DC=example,DC=com")
dn2 = BinaryDn(sam, "B:8:0000000C:;OU=dn1,DC=samba,DC=example,DC=com")
dn3 = BinaryDn(sam, "B:8:0000000F:;OU=dn3,DC=samba,DC=example,DC=com")
dn4 = BinaryDn(sam, "B:8:00000000:;OU=dn4,DC=samba,DC=example,DC=com")
dn5 = PlainDn(sam, ";OU=dn5,DC=samba,DC=example,DC=com")
dn6 = PlainDn(sam, ";OU=dn6,DC=samba,DC=example,DC=com")
unsorted_links14 = [dn1, dn2, dn3, dn4]
sorted_vals14 = [str(dn) for dn in sorted(unsorted_links14)]
self.assertEqual(sorted_vals14[0], str(dn3))
self.assertEqual(sorted_vals14[1], str(dn2))
self.assertEqual(sorted_vals14[2], str(dn1))
self.assertEqual(sorted_vals14[3], str(dn4))
unsorted_links56 = [dn5, dn6]
sorted_vals56 = [str(dn) for dn in sorted(unsorted_links56)]
self.assertEqual(sorted_vals56[0], str(dn6))
self.assertEqual(sorted_vals56[1], str(dn5))