1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-22 13:34:15 +03:00

samba-tool user: Tests for virtualWDigest attributes

Add tests for the new virtualWDigest attributes, these return the hashes
stored in supplementalCredentials Primary:WDigest in a form suitable for
use with htdigest authentication.

Signed-off-by: Gary Lockyer <gary@catalyst.net.nz>
Reviewed-by: Garming Sam <garming@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
This commit is contained in:
Gary Lockyer 2017-05-08 10:00:09 +12:00 committed by Andrew Bartlett
parent f47d331e67
commit 81312ba4e2
3 changed files with 471 additions and 0 deletions

View File

@ -0,0 +1,456 @@
# 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
import binascii
import md5
import re
USER_NAME = "WdigestTestUser"
USER_PASS = samba.generate_random_password(32, 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)
return "%s:%s:%s" % (user, realm, binascii.hexlify(md5.new(data).digest()))
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 = 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:
result = re.sub(r"\n\s*", '', out)
self.assertMatch(result, "%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)

View File

@ -330,3 +330,17 @@
# We currently don't send referrals for LDAP modify of non-replicated attrs
^samba4.ldap.rodc.python\(rodc\).__main__.RodcTests.test_modify_nonreplicated.*
^samba4.ldap.rodc_rwdc.python.*.__main__.RodcRwdcTests.test_change_password_reveal_on_demand_kerberos
#
# Tests for the retrieval of the virtualWDigest attributes
# by the samba-tool user sub command
^samba.tests.samba_tool.user_wdigest.samba.tests.samba_tool.user_wdigest.UserCmdWdigestTestCase.test_Wdigest01.*
^samba.tests.samba_tool.user_wdigest.samba.tests.samba_tool.user_wdigest.UserCmdWdigestTestCase.test_Wdigest02.*
^samba.tests.samba_tool.user_wdigest.samba.tests.samba_tool.user_wdigest.UserCmdWdigestTestCase.test_Wdigest03.*
^samba.tests.samba_tool.user_wdigest.samba.tests.samba_tool.user_wdigest.UserCmdWdigestTestCase.test_Wdigest04.*
^samba.tests.samba_tool.user_wdigest.samba.tests.samba_tool.user_wdigest.UserCmdWdigestTestCase.test_Wdigest05.*
^samba.tests.samba_tool.user_wdigest.samba.tests.samba_tool.user_wdigest.UserCmdWdigestTestCase.test_Wdigest06.*
^samba.tests.samba_tool.user_wdigest.samba.tests.samba_tool.user_wdigest.UserCmdWdigestTestCase.test_Wdigest07.*
^samba.tests.samba_tool.user_wdigest.samba.tests.samba_tool.user_wdigest.UserCmdWdigestTestCase.test_Wdigest08.*
^samba.tests.samba_tool.user_wdigest.samba.tests.samba_tool.user_wdigest.UserCmdWdigestTestCase.test_Wdigest09.*
^samba.tests.samba_tool.user_wdigest.samba.tests.samba_tool.user_wdigest.UserCmdWdigestTestCase.test_Wdigest1.*
^samba.tests.samba_tool.user_wdigest.samba.tests.samba_tool.user_wdigest.UserCmdWdigestTestCase.test_Wdigest2.*

View File

@ -592,6 +592,7 @@ planpythontestsuite("ad_dc:local", "samba.tests.samba_tool.gpo")
planpythontestsuite("ad_dc_ntvfs:local", "samba.tests.samba_tool.processes")
planpythontestsuite("ad_dc_ntvfs:local", "samba.tests.samba_tool.user")
planpythontestsuite("ad_dc_ntvfs:local", "samba.tests.samba_tool.user_wdigest")
planpythontestsuite("ad_dc:local", "samba.tests.samba_tool.user")
planpythontestsuite("chgdcpass:local", "samba.tests.samba_tool.user_check_password_script")
planpythontestsuite("ad_dc_ntvfs:local", "samba.tests.samba_tool.group")