mirror of
https://github.com/samba-team/samba.git
synced 2025-12-17 04:23:50 +03:00
In addition to the attributes that caused some issues specifically with the test some other ldb.bytes objects (those seen to be used as strings) have been adjusted (with str()) to ensure they should work correct in PY3. Signed-off-by: Noel Power <noel.power@suse.com> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
467 lines
16 KiB
Python
467 lines
16 KiB
Python
# Tests for the samba-tool user sub command reading Primary:WDigest
|
|
#
|
|
# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2017
|
|
#
|
|
#
|
|
# 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 os
|
|
import time
|
|
import base64
|
|
import ldb
|
|
import samba
|
|
from samba.tests.samba_tool.base import SambaToolCmdTest
|
|
from samba import (
|
|
credentials,
|
|
nttime2unix,
|
|
dsdb
|
|
)
|
|
from samba.ndr import ndr_unpack
|
|
from samba.dcerpc import drsblobs
|
|
from hashlib import md5
|
|
import random
|
|
import string
|
|
from samba.compat import text_type
|
|
|
|
USER_NAME = "WdigestTestUser"
|
|
# Create a random 32 character password, containing only letters and
|
|
# digits to avoid issues when used on the command line.
|
|
USER_PASS = ''.join(random.choice(string.ascii_uppercase +
|
|
string.ascii_lowercase +
|
|
string.digits) for _ in range(32))
|
|
|
|
# Calculate the MD5 password digest from the supplied user, realm and password
|
|
#
|
|
|
|
|
|
def calc_digest(user, realm, password):
|
|
data = "%s:%s:%s" % (user, realm, password)
|
|
if isinstance(data, text_type):
|
|
data = data.encode('utf8')
|
|
|
|
return "%s:%s:%s" % (user, realm, md5(data).hexdigest())
|
|
|
|
|
|
class UserCmdWdigestTestCase(SambaToolCmdTest):
|
|
"""Tests for samba-tool user subcommands extraction of the wdigest values
|
|
Test results validated against Windows Server 2012 R2.
|
|
NOTE: That as at 22-05-2017 the values Documented at
|
|
3.1.1.8.11.3.1 WDIGEST_CREDENTIALS Construction
|
|
are incorrect.
|
|
"""
|
|
users = []
|
|
samdb = None
|
|
|
|
def setUp(self):
|
|
super(UserCmdWdigestTestCase, self).setUp()
|
|
self.lp = samba.tests.env_loadparm()
|
|
self.samdb = self.getSamDB(
|
|
"-H", "ldap://%s" % os.environ["DC_SERVER"],
|
|
"-U%s%%%s" % (os.environ["DC_USERNAME"],
|
|
os.environ["DC_PASSWORD"]))
|
|
self.dns_domain = self.samdb.domain_dns_name()
|
|
res = self.samdb.search(
|
|
base=self.samdb.get_config_basedn(),
|
|
expression="ncName=%s" % self.samdb.get_default_basedn(),
|
|
attrs=["nETBIOSName"])
|
|
self.netbios_domain = str(res[0]["nETBIOSName"][0])
|
|
self.runsubcmd("user",
|
|
"create",
|
|
USER_NAME,
|
|
USER_PASS,
|
|
"-H",
|
|
"ldap://%s" % os.environ["DC_SERVER"],
|
|
"-U%s%%%s" % (
|
|
os.environ["DC_USERNAME"],
|
|
os.environ["DC_PASSWORD"]))
|
|
|
|
def tearDown(self):
|
|
super(UserCmdWdigestTestCase, self).tearDown()
|
|
self.runsubcmd("user", "delete", USER_NAME)
|
|
|
|
def _testWDigest(self, attribute, expected, missing=False):
|
|
|
|
(result, out, err) = self.runsubcmd("user",
|
|
"getpassword",
|
|
USER_NAME,
|
|
"--attributes",
|
|
attribute)
|
|
self.assertCmdSuccess(result,
|
|
out,
|
|
err,
|
|
"Ensure getpassword runs")
|
|
self.assertEqual(err, "", "getpassword")
|
|
self.assertMatch(out,
|
|
"Got password OK",
|
|
"getpassword out[%s]" % out)
|
|
|
|
if missing:
|
|
self.assertTrue(attribute not in out)
|
|
else:
|
|
self.assertMatch(out.replace('\n ', ''),
|
|
"%s: %s" % (attribute, expected))
|
|
|
|
def test_Wdigest_no_suffix(self):
|
|
attribute = "virtualWDigest"
|
|
self._testWDigest(attribute, None, True)
|
|
|
|
def test_Wdigest_non_numeric_suffix(self):
|
|
attribute = "virtualWDigestss"
|
|
self._testWDigest(attribute, None, True)
|
|
|
|
def test_Wdigest00(self):
|
|
attribute = "virtualWDigest00"
|
|
self._testWDigest(attribute, None, True)
|
|
|
|
# Hash01 MD5(sAMAccountName,
|
|
# NETBIOSDomainName,
|
|
# password)
|
|
#
|
|
def test_Wdigest01(self):
|
|
attribute = "virtualWDigest01"
|
|
expected = calc_digest(USER_NAME,
|
|
self.netbios_domain,
|
|
USER_PASS)
|
|
self._testWDigest(attribute, expected)
|
|
|
|
# Hash02 MD5(LOWER(sAMAccountName),
|
|
# LOWER(NETBIOSDomainName),
|
|
# password)
|
|
#
|
|
def test_Wdigest02(self):
|
|
attribute = "virtualWDigest02"
|
|
expected = calc_digest(USER_NAME.lower(),
|
|
self.netbios_domain.lower(),
|
|
USER_PASS)
|
|
self._testWDigest(attribute, expected)
|
|
|
|
# Hash03 MD5(UPPER(sAMAccountName),
|
|
# UPPER(NETBIOSDomainName),
|
|
# password)
|
|
#
|
|
def test_Wdigest03(self):
|
|
attribute = "virtualWDigest03"
|
|
expected = calc_digest(USER_NAME.upper(),
|
|
self.netbios_domain.upper(),
|
|
USER_PASS)
|
|
self._testWDigest(attribute, expected)
|
|
|
|
# Hash04 MD5(sAMAccountName,
|
|
# UPPER(NETBIOSDomainName),
|
|
# password)
|
|
#
|
|
def test_Wdigest04(self):
|
|
attribute = "virtualWDigest04"
|
|
expected = calc_digest(USER_NAME,
|
|
self.netbios_domain.upper(),
|
|
USER_PASS)
|
|
self._testWDigest(attribute, expected)
|
|
|
|
# Hash05 MD5(sAMAccountName,
|
|
# LOWER(NETBIOSDomainName),
|
|
# password)
|
|
#
|
|
def test_Wdigest05(self):
|
|
attribute = "virtualWDigest05"
|
|
expected = calc_digest(USER_NAME,
|
|
self.netbios_domain.lower(),
|
|
USER_PASS)
|
|
self._testWDigest(attribute, expected)
|
|
|
|
# Hash06 MD5(UPPER(sAMAccountName),
|
|
# LOWER(NETBIOSDomainName),
|
|
# password)
|
|
#
|
|
def test_Wdigest06(self):
|
|
attribute = "virtualWDigest06"
|
|
expected = calc_digest(USER_NAME.upper(),
|
|
self.netbios_domain.lower(),
|
|
USER_PASS)
|
|
self._testWDigest(attribute, expected)
|
|
|
|
# Hash07 MD5(LOWER(sAMAccountName),
|
|
# UPPER(NETBIOSDomainName),
|
|
# password)
|
|
#
|
|
def test_Wdigest07(self):
|
|
attribute = "virtualWDigest07"
|
|
expected = calc_digest(USER_NAME.lower(),
|
|
self.netbios_domain.upper(),
|
|
USER_PASS)
|
|
self._testWDigest(attribute, expected)
|
|
|
|
# Hash08 MD5(sAMAccountName,
|
|
# DNSDomainName,
|
|
# password)
|
|
#
|
|
# Note: Samba lowercases the DNSDomainName at provision time,
|
|
# Windows preserves the case. This means that the WDigest08 values
|
|
# calculated byt Samba and Windows differ.
|
|
#
|
|
def test_Wdigest08(self):
|
|
attribute = "virtualWDigest08"
|
|
expected = calc_digest(USER_NAME,
|
|
self.dns_domain,
|
|
USER_PASS)
|
|
self._testWDigest(attribute, expected)
|
|
|
|
# Hash09 MD5(LOWER(sAMAccountName),
|
|
# LOWER(DNSDomainName),
|
|
# password)
|
|
#
|
|
def test_Wdigest09(self):
|
|
attribute = "virtualWDigest09"
|
|
expected = calc_digest(USER_NAME.lower(),
|
|
self.dns_domain.lower(),
|
|
USER_PASS)
|
|
self._testWDigest(attribute, expected)
|
|
|
|
# Hash10 MD5(UPPER(sAMAccountName),
|
|
# UPPER(DNSDomainName),
|
|
# password)
|
|
#
|
|
def test_Wdigest10(self):
|
|
attribute = "virtualWDigest10"
|
|
expected = calc_digest(USER_NAME.upper(),
|
|
self.dns_domain.upper(),
|
|
USER_PASS)
|
|
self._testWDigest(attribute, expected)
|
|
|
|
# Hash11 MD5(sAMAccountName,
|
|
# UPPER(DNSDomainName),
|
|
# password)
|
|
#
|
|
def test_Wdigest11(self):
|
|
attribute = "virtualWDigest11"
|
|
expected = calc_digest(USER_NAME,
|
|
self.dns_domain.upper(),
|
|
USER_PASS)
|
|
self._testWDigest(attribute, expected)
|
|
|
|
# Hash12 MD5(sAMAccountName,
|
|
# LOWER(DNSDomainName),
|
|
# password)
|
|
#
|
|
def test_Wdigest12(self):
|
|
attribute = "virtualWDigest12"
|
|
expected = calc_digest(USER_NAME,
|
|
self.dns_domain.lower(),
|
|
USER_PASS)
|
|
self._testWDigest(attribute, expected)
|
|
|
|
# Hash13 MD5(UPPER(sAMAccountName),
|
|
# LOWER(DNSDomainName),
|
|
# password)
|
|
#
|
|
def test_Wdigest13(self):
|
|
attribute = "virtualWDigest13"
|
|
expected = calc_digest(USER_NAME.upper(),
|
|
self.dns_domain.lower(),
|
|
USER_PASS)
|
|
self._testWDigest(attribute, expected)
|
|
|
|
# Hash14 MD5(LOWER(sAMAccountName),
|
|
# UPPER(DNSDomainName),
|
|
# password)
|
|
#
|
|
|
|
def test_Wdigest14(self):
|
|
attribute = "virtualWDigest14"
|
|
expected = calc_digest(USER_NAME.lower(),
|
|
self.dns_domain.upper(),
|
|
USER_PASS)
|
|
self._testWDigest(attribute, expected)
|
|
|
|
# Hash15 MD5(userPrincipalName,
|
|
# password)
|
|
#
|
|
def test_Wdigest15(self):
|
|
attribute = "virtualWDigest15"
|
|
name = "%s@%s" % (USER_NAME, self.dns_domain)
|
|
expected = calc_digest(name,
|
|
"",
|
|
USER_PASS)
|
|
self._testWDigest(attribute, expected)
|
|
|
|
# Hash16 MD5(LOWER(userPrincipalName),
|
|
# password)
|
|
#
|
|
def test_Wdigest16(self):
|
|
attribute = "virtualWDigest16"
|
|
name = "%s@%s" % (USER_NAME.lower(), self.dns_domain.lower())
|
|
expected = calc_digest(name,
|
|
"",
|
|
USER_PASS)
|
|
self._testWDigest(attribute, expected)
|
|
|
|
# Hash17 MD5(UPPER(userPrincipalName),
|
|
# password)
|
|
#
|
|
def test_Wdigest17(self):
|
|
attribute = "virtualWDigest17"
|
|
name = "%s@%s" % (USER_NAME.upper(), self.dns_domain.upper())
|
|
expected = calc_digest(name,
|
|
"",
|
|
USER_PASS)
|
|
self._testWDigest(attribute, expected)
|
|
|
|
# Hash18 MD5(NETBIOSDomainName\sAMAccountName,
|
|
# password)
|
|
#
|
|
def test_Wdigest18(self):
|
|
attribute = "virtualWDigest18"
|
|
name = "%s\\%s" % (self.netbios_domain, USER_NAME)
|
|
expected = calc_digest(name,
|
|
"",
|
|
USER_PASS)
|
|
self._testWDigest(attribute, expected)
|
|
|
|
# Hash19 MD5(LOWER(NETBIOSDomainName\sAMAccountName),
|
|
# password)
|
|
#
|
|
def test_Wdigest19(self):
|
|
attribute = "virtualWDigest19"
|
|
name = "%s\\%s" % (self.netbios_domain, USER_NAME)
|
|
expected = calc_digest(name.lower(),
|
|
"",
|
|
USER_PASS)
|
|
self._testWDigest(attribute, expected)
|
|
|
|
# Hash20 MD5(UPPER(NETBIOSDomainName\sAMAccountName),
|
|
# password)
|
|
#
|
|
def test_Wdigest20(self):
|
|
attribute = "virtualWDigest20"
|
|
name = "%s\\%s" % (self.netbios_domain, USER_NAME)
|
|
expected = calc_digest(name.upper(),
|
|
"",
|
|
USER_PASS)
|
|
self._testWDigest(attribute, expected)
|
|
|
|
# Hash21 MD5(sAMAccountName,
|
|
# "Digest",
|
|
# password)
|
|
#
|
|
def test_Wdigest21(self):
|
|
attribute = "virtualWDigest21"
|
|
expected = calc_digest(USER_NAME,
|
|
"Digest",
|
|
USER_PASS)
|
|
self._testWDigest(attribute, expected)
|
|
|
|
# Hash22 MD5(LOWER(sAMAccountName),
|
|
# "Digest",
|
|
# password)
|
|
#
|
|
def test_Wdigest22(self):
|
|
attribute = "virtualWDigest22"
|
|
expected = calc_digest(USER_NAME.lower(),
|
|
"Digest",
|
|
USER_PASS)
|
|
self._testWDigest(attribute, expected)
|
|
|
|
# Hash23 MD5(UPPER(sAMAccountName),
|
|
# "Digest",
|
|
# password)
|
|
#
|
|
def test_Wdigest23(self):
|
|
attribute = "virtualWDigest23"
|
|
expected = calc_digest(USER_NAME.upper(),
|
|
"Digest",
|
|
USER_PASS)
|
|
self._testWDigest(attribute, expected)
|
|
|
|
# Hash24 MD5(userPrincipalName),
|
|
# "Digest",
|
|
# password)
|
|
#
|
|
def test_Wdigest24(self):
|
|
attribute = "virtualWDigest24"
|
|
name = "%s@%s" % (USER_NAME, self.dns_domain)
|
|
expected = calc_digest(name,
|
|
"Digest",
|
|
USER_PASS)
|
|
self._testWDigest(attribute, expected)
|
|
|
|
# Hash25 MD5(LOWER(userPrincipalName),
|
|
# "Digest",
|
|
# password)
|
|
#
|
|
def test_Wdigest25(self):
|
|
attribute = "virtualWDigest25"
|
|
name = "%s@%s" % (USER_NAME, self.dns_domain.lower())
|
|
expected = calc_digest(name.lower(),
|
|
"Digest",
|
|
USER_PASS)
|
|
self._testWDigest(attribute, expected)
|
|
|
|
# Hash26 MD5(UPPER(userPrincipalName),
|
|
# "Digest",
|
|
# password)
|
|
#
|
|
def test_Wdigest26(self):
|
|
attribute = "virtualWDigest26"
|
|
name = "%s@%s" % (USER_NAME, self.dns_domain.lower())
|
|
expected = calc_digest(name.upper(),
|
|
"Digest",
|
|
USER_PASS)
|
|
self._testWDigest(attribute, expected)
|
|
# Hash27 MD5(NETBIOSDomainName\sAMAccountName,
|
|
# "Digest",
|
|
# password)
|
|
#
|
|
|
|
def test_Wdigest27(self):
|
|
attribute = "virtualWDigest27"
|
|
name = "%s\\%s" % (self.netbios_domain, USER_NAME)
|
|
expected = calc_digest(name,
|
|
"Digest",
|
|
USER_PASS)
|
|
self._testWDigest(attribute, expected)
|
|
|
|
# Hash28 MD5(LOWER(NETBIOSDomainName\sAMAccountName),
|
|
# "Digest",
|
|
# password)
|
|
#
|
|
def test_Wdigest28(self):
|
|
attribute = "virtualWDigest28"
|
|
name = "%s\\%s" % (self.netbios_domain.lower(), USER_NAME.lower())
|
|
expected = calc_digest(name,
|
|
"Digest",
|
|
USER_PASS)
|
|
self._testWDigest(attribute, expected)
|
|
|
|
# Hash29 MD5(UPPER(NETBIOSDomainName\sAMAccountName),
|
|
# "Digest",
|
|
# password)
|
|
#
|
|
def test_Wdigest29(self):
|
|
attribute = "virtualWDigest29"
|
|
name = "%s\\%s" % (self.netbios_domain.upper(), USER_NAME.upper())
|
|
expected = calc_digest(name,
|
|
"Digest",
|
|
USER_PASS)
|
|
self._testWDigest(attribute, expected)
|
|
|
|
def test_Wdigest30(self):
|
|
attribute = "virtualWDigest30"
|
|
self._testWDigest(attribute, None, True)
|
|
|
|
# Check digest calculation against an known htdigest value
|
|
def test_calc_digest(self):
|
|
htdigest = "gary:fred:2204fcc247cb47ded249ef2fe0013255"
|
|
digest = calc_digest("gary", "fred", "password")
|
|
self.assertEqual(htdigest, digest)
|