1
0
mirror of https://github.com/samba-team/samba.git synced 2025-06-07 03:17:08 +03:00
samba-mirror/source4/dsdb/tests/python/ldap_modify_order.py
Douglas Bagnall e5a099482d pytests: try ldap.modify_order with normal user
We run the tests again, trying to modify as a normal user rather than
Administrator.

It turns out that we do not always return the same error code as
Windows, but in all these tests both Windows and Samba always return
some kind of error (as you might hope).

Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2019-05-01 05:32:25 +00:00

373 lines
13 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008-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 <http://www.gnu.org/licenses/>.
from __future__ import print_function
import optparse
import sys
import os
from itertools import permutations
import traceback
sys.path.insert(0, "bin/python")
import samba
from samba.tests.subunitrun import SubunitOptions, TestProgram
import samba.getopt as options
from samba.auth import system_session
from ldb import SCOPE_BASE, LdbError
from ldb import Message, MessageElement, Dn
from ldb import FLAG_MOD_ADD, FLAG_MOD_REPLACE, FLAG_MOD_DELETE
from samba.samdb import SamDB
from samba.tests import delete_force
TEST_DATA_DIR = os.path.join(
os.path.dirname(__file__),
'testdata')
LDB_STRERR = {}
def _build_ldb_strerr():
import ldb
for k, v in vars(ldb).items():
if k.startswith('ERR_') and isinstance(v, int):
LDB_STRERR[v] = k
_build_ldb_strerr()
class ModifyOrderTests(samba.tests.TestCase):
def setUp(self):
super().setUp()
self.admin_dsdb = get_dsdb(admin_creds)
self.base_dn = self.admin_dsdb.domain_dn()
def delete_object(self, dn):
delete_force(self.admin_dsdb, dn)
def get_user_dn(self, name):
return "CN=%s,CN=Users,%s" % (name, self.base_dn)
def _test_modify_order(self,
start_attrs,
mod_attrs,
extra_search_attrs=(),
name=None):
if name is None:
name = traceback.extract_stack()[-2][2][5:]
if opts.normal_user:
name += '-non-admin'
username = "user123"
password = "pass123@#$@#"
self.admin_dsdb.newuser(username, password)
self.addCleanup(self.delete_object, self.get_user_dn(username))
mod_creds = self.insta_creds(template=admin_creds,
username=username,
userpass=password)
else:
mod_creds = admin_creds
mod_dsdb = get_dsdb(mod_creds)
sig = []
op_lut = ['', 'add', 'replace', 'delete']
search_attrs = set(extra_search_attrs)
lines = [name, "initial attrs:"]
for k, v in start_attrs:
lines.append("%20s: %r" % (k, v))
search_attrs.add(k)
for k, v, op in mod_attrs:
search_attrs.add(k)
search_attrs = sorted(search_attrs)
header = "\n".join(lines)
sig.append(header)
clusters = {}
for i, attrs in enumerate(permutations(mod_attrs)):
# for each permuation we construct a string describing the
# requested operations, and a string describing the result
# (which may be an exception). The we cluster the
# attribute strings by their results.
dn = "cn=ldaptest_%s_%d,cn=users,%s" % (name, i, self.base_dn)
m = Message()
m.dn = Dn(self.admin_dsdb, dn)
# We are using Message objects here for add (rather than the
# more convenient dict) because we maybe care about the order
# in which attributes are added.
for k, v in start_attrs:
m[k] = MessageElement(v, 0, k)
self.admin_dsdb.add(m)
self.addCleanup(self.delete_object, dn)
m = Message()
m.dn = Dn(mod_dsdb, dn)
attr_lines = []
for k, v, op in attrs:
if v is None:
v = dn
m[k] = MessageElement(v, op, k)
attr_lines.append("%16s %-8s %s" % (k, op_lut[op], v))
attr_str = '\n'.join(attr_lines)
try:
mod_dsdb.modify(m)
except LdbError as e:
err, _ = e.args
s = LDB_STRERR.get(err, "unknown error")
result_str = "%s (%d)" % (s, err)
else:
res = self.admin_dsdb.search(base=dn, scope=SCOPE_BASE,
attrs=search_attrs)
lines = []
for k, v in sorted(dict(res[0]).items()):
if k != "dn" or k in extra_search_attrs:
lines.append("%20s: %r" % (k, sorted(v)))
result_str = '\n'.join(lines)
clusters.setdefault(result_str, []).append(attr_str)
for s, attrs in sorted(clusters.items()):
sig.extend([
"== result ===[%3d]=======================" % len(attrs),
s,
"-- operations ---------------------------"])
for a in attrs:
sig.append(a)
sig.append("-" * 34)
sig = '\n'.join(sig).replace(self.base_dn, "{base dn}")
if opts.verbose:
print(sig)
if opts.rewrite_ground_truth:
f = open(os.path.join(TEST_DATA_DIR, name + '.expected'), 'w')
f.write(sig)
f.close()
f = open(os.path.join(TEST_DATA_DIR, name + '.expected'))
expected = f.read()
f.close()
self.assertStringsEqual(sig, expected)
def test_modify_order_mixed(self):
start_attrs = [("objectclass", "user"),
("carLicense", ["1", "2", "3"]),
("otherTelephone", "123")]
mod_attrs = [("carLicense", "3", FLAG_MOD_DELETE),
("carLicense", "4", FLAG_MOD_ADD),
("otherTelephone", "4", FLAG_MOD_REPLACE),
("otherTelephone", "123", FLAG_MOD_DELETE)]
self._test_modify_order(start_attrs, mod_attrs)
def test_modify_order_mixed2(self):
start_attrs = [("objectclass", "user"),
("carLicense", ["1", "2", "3"]),
("ipPhone", "123")]
mod_attrs = [("carLicense", "3", FLAG_MOD_DELETE),
("carLicense", "4", FLAG_MOD_ADD),
("ipPhone", "4", FLAG_MOD_REPLACE),
("ipPhone", "123", FLAG_MOD_DELETE)]
self._test_modify_order(start_attrs, mod_attrs)
def test_modify_order_telephone(self):
start_attrs = [("objectclass", "user"),
("otherTelephone", "123")]
mod_attrs = [("carLicense", "3", FLAG_MOD_REPLACE),
("carLicense", "4", FLAG_MOD_ADD),
("otherTelephone", "4", FLAG_MOD_REPLACE),
("otherTelephone", "4", FLAG_MOD_ADD),
("otherTelephone", "123", FLAG_MOD_DELETE)]
self._test_modify_order(start_attrs, mod_attrs)
def test_modify_order_telephone_delete_delete(self):
start_attrs = [("objectclass", "user"),
("otherTelephone", "123")]
mod_attrs = [("carLicense", "3", FLAG_MOD_REPLACE),
("carLicense", "4", FLAG_MOD_DELETE),
("otherTelephone", "4", FLAG_MOD_REPLACE),
("otherTelephone", "4", FLAG_MOD_DELETE),
("otherTelephone", "123", FLAG_MOD_DELETE)]
self._test_modify_order(start_attrs, mod_attrs)
def test_modify_order_objectclass(self):
start_attrs = [("objectclass", "user"),
("otherTelephone", "123")]
mod_attrs = [("objectclass", "computer", FLAG_MOD_REPLACE),
("objectclass", "user", FLAG_MOD_DELETE),
("objectclass", "person", FLAG_MOD_DELETE)]
self._test_modify_order(start_attrs, mod_attrs)
def test_modify_order_objectclass2(self):
start_attrs = [("objectclass", "user")]
mod_attrs = [("objectclass", "computer", FLAG_MOD_REPLACE),
("objectclass", "user", FLAG_MOD_ADD),
("objectclass", "attributeSchema", FLAG_MOD_REPLACE),
("objectclass", "inetOrgPerson", FLAG_MOD_ADD),
("objectclass", "person", FLAG_MOD_DELETE)]
self._test_modify_order(start_attrs, mod_attrs)
def test_modify_order_singlevalue(self):
start_attrs = [("objectclass", "user"),
("givenName", "a")]
mod_attrs = [("givenName", "a", FLAG_MOD_REPLACE),
("givenName", ["b", "a"], FLAG_MOD_REPLACE),
("givenName", "b", FLAG_MOD_DELETE),
("givenName", "a", FLAG_MOD_DELETE),
("givenName", "c", FLAG_MOD_ADD)]
self._test_modify_order(start_attrs, mod_attrs)
def test_modify_order_inapplicable(self):
#attrbutes that don't go on a user
start_attrs = [("objectclass", "user"),
("givenName", "a")]
mod_attrs = [("dhcpSites", "b", FLAG_MOD_REPLACE),
("dhcpSites", "b", FLAG_MOD_DELETE),
("dhcpSites", "c", FLAG_MOD_ADD)]
self._test_modify_order(start_attrs, mod_attrs)
def test_modify_order_sometimes_inapplicable(self):
# attributes that don't go on a user, but do on a computer,
# which we sometimes change into.
start_attrs = [("objectclass", "user"),
("givenName", "a")]
mod_attrs = [("objectclass", "computer", FLAG_MOD_REPLACE),
("objectclass", "person", FLAG_MOD_DELETE),
("dnsHostName", "b", FLAG_MOD_ADD),
("dnsHostName", "c", FLAG_MOD_REPLACE)]
self._test_modify_order(start_attrs, mod_attrs)
def test_modify_order_account_locality_device(self):
# account, locality, and device all take l (locality name) but
# only device takes owner. We shouldn't be able to change
# objectclass at all.
start_attrs = [("objectclass", "account"),
("l", "a")]
mod_attrs = [("objectclass", ["device", "top"], FLAG_MOD_REPLACE),
("l", "a", FLAG_MOD_DELETE),
("owner", "c", FLAG_MOD_ADD)
]
self._test_modify_order(start_attrs, mod_attrs)
def test_modify_order_container_flags_multivalue(self):
# account, locality, and device all take l (locality name)
# but only device takes owner
start_attrs = [("objectclass", "container"),
("wWWHomePage", "a")]
mod_attrs = [("flags", ["0", "1"], FLAG_MOD_ADD),
("flags", "65355", FLAG_MOD_ADD),
("flags", "65355", FLAG_MOD_DELETE),
("flags", ["2", "101"], FLAG_MOD_REPLACE),
]
self._test_modify_order(start_attrs, mod_attrs)
def test_modify_order_container_flags(self):
#flags should be an integer
start_attrs = [("objectclass", "container")]
mod_attrs = [("flags", "0x6", FLAG_MOD_ADD),
("flags", "5", FLAG_MOD_ADD),
("flags", "101", FLAG_MOD_REPLACE),
("flags", "c", FLAG_MOD_DELETE),
]
self._test_modify_order(start_attrs, mod_attrs)
def test_modify_order_member(self):
name = "modify_order_member_other_group"
dn2 = "cn=%s,%s" % (name, self.base_dn)
m = Message()
m.dn = Dn(self.admin_dsdb, dn2)
self.admin_dsdb.add({"dn": dn2, "objectclass": "group"})
self.addCleanup(self.delete_object, dn2)
start_attrs = [("objectclass", "group"),
("member", dn2)]
mod_attrs = [("member", None, FLAG_MOD_DELETE),
("member", None, FLAG_MOD_REPLACE),
("member", dn2, FLAG_MOD_DELETE),
("member", None, FLAG_MOD_ADD),
]
self._test_modify_order(start_attrs, mod_attrs, ["memberOf"])
def get_dsdb(creds=None):
if creds is None:
creds = admin_creds
dsdb = SamDB(host,
credentials=creds,
session_info=system_session(lp),
lp=lp)
return dsdb
parser = optparse.OptionParser("ldap_modify_order.py [options] <host>")
sambaopts = options.SambaOptions(parser)
parser.add_option_group(sambaopts)
parser.add_option_group(options.VersionOptions(parser))
credopts = options.CredentialsOptions(parser)
parser.add_option_group(credopts)
subunitopts = SubunitOptions(parser)
parser.add_option_group(subunitopts)
parser.add_option("--rewrite-ground-truth", action="store_true",
help="write expected values")
parser.add_option("-v", "--verbose", action="store_true")
parser.add_option("--normal-user", action="store_true")
opts, args = parser.parse_args()
if len(args) < 1:
parser.print_usage()
sys.exit(1)
host = args[0]
lp = sambaopts.get_loadparm()
admin_creds = credopts.get_credentials(lp)
if "://" not in host:
if os.path.isfile(host):
host = "tdb://%s" % host
else:
host = "ldap://%s" % host
TestProgram(module=__name__, opts=subunitopts)