1
0
mirror of https://github.com/samba-team/samba.git synced 2025-03-27 22:50:26 +03:00

python: tests: blackbox test for GMSA

Signed-off-by: Rob van der Linde <rob@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
This commit is contained in:
Rob van der Linde 2023-12-07 15:53:01 +13:00 committed by Douglas Bagnall
parent 339e7ae186
commit 128710c2f3
3 changed files with 175 additions and 0 deletions

View File

@ -0,0 +1,171 @@
# Unix SMB/CIFS implementation.
#
# Blackbox tests for reading Group Managed Service Account passwords
#
# Copyright (C) Catalyst.Net Ltd. 2023
#
# Written by Rob van der Linde <rob@catalyst.net.nz>
#
# 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 <http://www.gnu.org/licenses/>.
#
import sys
import os
sys.path.insert(0, "bin/python")
os.environ["PYTHONUNBUFFERED"] = "1"
from ldb import SCOPE_BASE
from samba.credentials import Credentials, MUST_USE_KERBEROS
from samba.dcerpc import security, samr
from samba.dsdb import UF_WORKSTATION_TRUST_ACCOUNT
from samba.netcmd.domain.models import User
from samba.ndr import ndr_pack, ndr_unpack
from samba.tests import connect_samdb, connect_samdb_env, delete_force
from samba.tests import BlackboxTestCase
DC_SERVER = os.environ["SERVER"]
SERVER = os.environ["SERVER"]
SERVER_USERNAME = os.environ["USERNAME"]
SERVER_PASSWORD = os.environ["PASSWORD"]
HOST = f"ldap://{SERVER}"
CREDS = f"-U{SERVER_USERNAME}%{SERVER_PASSWORD}"
class GMSAPasswordTest(BlackboxTestCase):
"""Blackbox tests for GMSA getpassword and connecting as that user."""
@classmethod
def setUpClass(cls):
cls.lp = cls.get_loadparm()
cls.env_creds = cls.get_env_credentials(lp=cls.lp,
env_username="USERNAME",
env_password="PASSWORD",
env_domain="DOMAIN",
env_realm="REALM")
cls.samdb = connect_samdb(HOST, lp=cls.lp, credentials=cls.env_creds)
super().setUpClass()
@classmethod
def setUpTestData(cls):
cls.username = "GMSA_Test_User$"
cls.base_dn = f"CN=Managed Service Accounts,{cls.samdb.domain_dn()}"
cls.user_dn = f"CN={cls.username},{cls.base_dn}"
msg = cls.samdb.search(base="", scope=SCOPE_BASE, attrs=["tokenGroups"])[0]
connecting_user_sid = str(ndr_unpack(security.dom_sid, msg["tokenGroups"][0]))
domain_sid = security.dom_sid(cls.samdb.get_domain_sid())
allow_sddl = f"O:SYD:(A;;RP;;;{connecting_user_sid})"
allow_sd = ndr_pack(security.descriptor.from_sddl(allow_sddl, domain_sid))
details = {
"dn": str(cls.user_dn),
"objectClass": "msDS-GroupManagedServiceAccount",
"msDS-ManagedPasswordInterval": "1",
"msDS-GroupMSAMembership": allow_sd,
"sAMAccountName": cls.username,
"userAccountControl": str(UF_WORKSTATION_TRUST_ACCOUNT),
}
cls.samdb.add(details)
cls.addClassCleanup(delete_force, cls.samdb, cls.user_dn)
cls.user = User.get(cls.samdb, username=cls.username)
def getpassword(self, attrs):
cmd = f"user getpassword --attributes={attrs} {self.username}"
ldif = self.check_output(cmd).decode()
res = self.samdb.parse_ldif(ldif)
_, user_message = next(res)
# check each attr is returned
for attr in attrs.split(","):
self.assertIn(attr, user_message)
return user_message
def test_getpassword(self):
self.getpassword("virtualClearTextUTF16,unicodePwd")
self.getpassword("virtualClearTextUTF16")
self.getpassword("unicodePwd")
def test_utf16_password(self):
user_msg = self.getpassword("virtualClearTextUTF16")
password = user_msg["virtualClearTextUTF16"][0]
creds = self.insta_creds(template=self.env_creds)
creds.set_username(self.username)
creds.set_utf16_password(password)
db = connect_samdb(HOST, credentials=creds, lp=self.lp)
msg = db.search(base="", scope=SCOPE_BASE, attrs=["tokenGroups"])[0]
connecting_user_sid = str(ndr_unpack(security.dom_sid, msg["tokenGroups"][0]))
self.assertEqual(self.user.object_sid, connecting_user_sid)
def test_utf8_password(self):
user_msg = self.getpassword("virtualClearTextUTF8")
password = str(user_msg["virtualClearTextUTF8"][0])
creds = self.insta_creds(template=self.env_creds)
# Because the password has been converted to utf-8 via UTF16_MUNGED
# the nthash is no longer valid. We need to use AES kerberos ciphers
# for this to work.
creds.set_kerberos_state(MUST_USE_KERBEROS)
creds.set_username(self.username)
creds.set_password(password)
db = connect_samdb(HOST, credentials=creds, lp=self.lp)
msg = db.search(base="", scope=SCOPE_BASE, attrs=["tokenGroups"])[0]
connecting_user_sid = str(ndr_unpack(security.dom_sid, msg["tokenGroups"][0]))
self.assertEqual(self.user.object_sid, connecting_user_sid)
def test_unicode_pwd(self):
user_msg = self.getpassword("unicodePwd")
creds = self.insta_creds(template=self.env_creds)
creds.set_username(self.username)
nt_pass = samr.Password()
nt_pass.hash = list(user_msg["unicodePwd"][0])
creds.set_nt_hash(nt_pass)
db = connect_samdb(HOST, credentials=creds, lp=self.lp)
msg = db.search(base="", scope=SCOPE_BASE, attrs=["tokenGroups"])[0]
connecting_user_sid = str(ndr_unpack(security.dom_sid, msg["tokenGroups"][0]))
self.assertEqual(self.user.object_sid, connecting_user_sid)
@classmethod
def _make_cmdline(cls, line):
"""Override to pass line as samba-tool subcommand instead.
Automatically fills in HOST and CREDS as well.
"""
if isinstance(line, list):
cmd = ["samba-tool"] + line + ["-H", SERVER, CREDS]
else:
cmd = f"samba-tool {line} -H {HOST} {CREDS}"
return super()._make_cmdline(cmd)
if __name__ == "__main__":
import unittest
unittest.main()

View File

@ -0,0 +1 @@
^samba.tests.samba_tool.user_getpassword_gmsa.samba.tests.samba_tool.user_getpassword_gmsa.GMSAPasswordTest

View File

@ -1124,6 +1124,9 @@ planpythontestsuite("none", "samba.tests.samba_tool.visualize")
for env in all_fl_envs:
planpythontestsuite(env + ":local", "samba.tests.samba_tool.fsmo")
# test getpassword for group managed service accounts
planpythontestsuite("ad_dc_default", "samba.tests.samba_tool.user_getpassword_gmsa")
# test samba-tool user, group, contact and computer edit command
for env in all_fl_envs:
env += ":local"