>From e4028b9a81c498a20de5c12a1f0a788be7608463 Mon Sep 17 00:00:00 2001
From: Pavel Reichl <preichl@redhat.com>
Date: Mon, 5 Oct 2015 10:02:05 -0400
Subject: [PATCH 2/5] intg: new test for user local overrides

Introduce a new integration test for local view overrides.

Resolves:
https://fedorahosted.org/sssd/ticket/2732
---
 src/tests/intg/ldap_local_override_test.py | 376 +++++++++++++++++++++++++++++
 1 file changed, 376 insertions(+)
 create mode 100644 src/tests/intg/ldap_local_override_test.py

diff --git a/src/tests/intg/ldap_local_override_test.py b/src/tests/intg/ldap_local_override_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..35e47b012fdd271dd50b4c2ce3749d28a7a746d8
--- /dev/null
+++ b/src/tests/intg/ldap_local_override_test.py
@@ -0,0 +1,376 @@
+#
+# LDAP integration test
+#
+# Copyright (c) 2015 Red Hat, Inc.
+# Author: Pavel Reichl  <preichl@redhat.com>
+#
+# This 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; version 2 only
+#
+# 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 stat
+import ent
+import grp
+import pwd
+import config
+import signal
+import subprocess
+import time
+import pytest
+import ds_openldap
+import ldap_ent
+import sssd_id
+from util import unindent
+
+LDAP_BASE_DN = "dc=example,dc=com"
+
+
+@pytest.fixture(scope="module")
+def ds_inst(request):
+    """LDAP server instance fixture"""
+    ds_inst = ds_openldap.DSOpenLDAP(
+        config.PREFIX, 10389, LDAP_BASE_DN,
+        "cn=admin", "Secret123")
+    try:
+        ds_inst.setup()
+    except:
+        ds_inst.teardown()
+        raise
+    request.addfinalizer(lambda: ds_inst.teardown())
+    return ds_inst
+
+
+@pytest.fixture(scope="module")
+def ldap_conn(request, ds_inst):
+    """LDAP server connection fixture"""
+    ldap_conn = ds_inst.bind()
+    ldap_conn.ds_inst = ds_inst
+    request.addfinalizer(lambda: ldap_conn.unbind_s())
+    return ldap_conn
+
+
+def create_ldap_fixture(request, ldap_conn, ent_list):
+    """Add LDAP entries and add teardown for removing them"""
+    for entry in ent_list:
+        ldap_conn.add_s(entry[0], entry[1])
+
+    def teardown():
+        for entry in ent_list:
+            ldap_conn.delete_s(entry[0])
+    request.addfinalizer(teardown)
+
+
+def create_conf_fixture(request, contents):
+    """Generate sssd.conf and add teardown for removing it"""
+    conf = open(config.CONF_PATH, "w")
+    conf.write(contents)
+    conf.close()
+    os.chmod(config.CONF_PATH, stat.S_IRUSR | stat.S_IWUSR)
+    request.addfinalizer(lambda: os.unlink(config.CONF_PATH))
+
+
+def stop_sssd():
+    pid_file = open(config.PIDFILE_PATH, "r")
+    pid = int(pid_file.read())
+    os.kill(pid, signal.SIGTERM)
+    while True:
+        try:
+            os.kill(pid, signal.SIGCONT)
+        except:
+            break
+        time.sleep(1)
+
+
+def start_sssd():
+    """Start sssd"""
+    if subprocess.call(["sssd", "-D", "-f"]) != 0:
+        raise Exception("sssd start failed")
+
+
+def restart_sssd():
+    stop_sssd()
+    start_sssd()
+
+
+def create_sssd_fixture(request):
+    """Start sssd and add teardown for stopping it and removing state"""
+    if subprocess.call(["sssd", "-D", "-f"]) != 0:
+        raise Exception("sssd start failed")
+
+    def teardown():
+        try:
+            stop_sssd()
+        except:
+            pass
+        subprocess.call(["sss_cache", "-E"])
+        for path in os.listdir(config.DB_PATH):
+            os.unlink(config.DB_PATH + "/" + path)
+        for path in os.listdir(config.MCACHE_PATH):
+            os.unlink(config.MCACHE_PATH + "/" + path)
+    request.addfinalizer(teardown)
+
+
+def load_data_to_ldap(request, ldap_conn):
+    ent_list = ldap_ent.List(LDAP_BASE_DN)
+    ent_list.add_user("bwayne", 10001, 20001,
+                      gecos='Bruce Wayne',
+                      shell='/bin/bash',
+                      homedir='/home/gotham')
+
+    ent_list.add_user("ckent", 10002, 20001,
+                      gecos='Clark Joseph Kent',
+                      shell='/bin/sh',
+                      homedir='/home/smallville')
+
+    ent_list.add_user("pparker", 10003, 20001)
+
+    ent_list.add_user("mmccready", 10004, 20001,
+                      gecos='Mindy McCready',
+                      shell='/bin/dash',
+                      homedir='/home/nowhere')
+
+    ent_list.add_group("superheroes", 2001,
+                       ["bwayne", "ckent", "pparker", "mmccready"])
+
+    create_ldap_fixture(request, ldap_conn, ent_list)
+
+
+@pytest.fixture
+def sanity_rfc2307(request, ldap_conn):
+    load_data_to_ldap(request, ldap_conn)
+
+    conf = unindent("""\
+        [sssd]
+        domains             = LDAP
+        services            = nss
+
+        [nss]
+
+        [domain/LDAP]
+        ldap_auth_disable_tls_never_use_in_production = true
+        ldap_schema         = rfc2307
+        id_provider         = ldap
+        auth_provider       = ldap
+        sudo_provider       = ldap
+        ldap_uri            = {ldap_conn.ds_inst.ldap_url}
+        ldap_search_base    = {ldap_conn.ds_inst.base_dn}
+    """).format(**locals())
+    create_conf_fixture(request, conf)
+    create_sssd_fixture(request)
+    return None
+
+
+def check_users_0():
+
+    ent.assert_passwd_by_name(
+        'bwayne',
+        dict(name='bwayne', passwd='*', uid=10001, gid=20001,
+             gecos='Bruce Wayne',
+             shell='/bin/bash',
+             dir='/home/gotham'))
+
+    ent.assert_passwd_by_name(
+        'ckent',
+        dict(name='ckent', passwd='*', uid=10002, gid=20001,
+             gecos='Clark Joseph Kent',
+             shell='/bin/sh',
+             dir='/home/smallville'))
+
+    ent.assert_passwd_by_name(
+        'pparker',
+        dict(name='pparker', passwd='*', uid=10003, gid=20001))
+
+    ent.assert_passwd_by_name(
+        'ckent',
+        dict(name='ckent', passwd='*', uid=10002, gid=20001,
+             gecos='Clark Joseph Kent',
+             shell='/bin/sh',
+             dir='/home/smallville'))
+
+    ent.assert_passwd_by_name(
+        'mmccready',
+        dict(name='mmccready', passwd='*', uid=10004, gid=20001,
+             gecos='Mindy McCready',
+             shell='/bin/dash',
+             dir='/home/nowhere'))
+
+    ent.assert_group_by_name(
+        "superheroes",
+        dict(mem=ent.contains_only("bwayne", "ckent", "pparker", "mmccready")))
+
+
+def check_users_1():
+    # user can be looked up by the overriden name
+    ent.assert_passwd_by_name(
+        'batman',
+        dict(name='batman', passwd='*', uid=10001, gid=20001,
+             gecos='Bruce Wayne',
+             shell='/bin/bash',
+             dir='/home/gotham'))
+
+    # user can be looked up by the original name
+    ent.assert_passwd_by_name(
+        'bwayne',
+        dict(name='batman', passwd='*', uid=10001, gid=20001,
+             gecos='Bruce Wayne',
+             shell='/bin/bash',
+             dir='/home/gotham'))
+
+    # user's attributes gecos, shell and dir are overriden correctly
+    ent.assert_passwd_by_name(
+        'ckent',
+        dict(name='ckent', passwd='*', uid=10002, gid=20001,
+             gecos='Superman',
+             shell='/bin/supershell',
+             dir='/home/metropolis'))
+
+    # check override of user's uid and gid attributes
+    ent.assert_passwd_by_name(
+        'pparker',
+        dict(name='pparker', passwd='*', uid=20000, gid=20000))
+
+    # check override for all attributes
+    ent.assert_passwd_by_name(
+        'mmccready',
+        dict(name='hitgirl', passwd='*',
+             uid=20001,
+             gid=20001,
+             gecos='Hit-Girl',
+             shell='/bin/ksh',
+             dir='/home/everywhere'))
+
+
+def test_local_override_user(ldap_conn, sanity_rfc2307):
+    """ test commands: user-add, user-del, user-import, user export """
+
+    override_filename = "user_overrides_file_1"
+
+    # perform override
+    subprocess.call(["sss_override", "user-add", "bwayne",
+                     "-n", "batman"])
+
+    subprocess.call(["sss_override", "user-add", "ckent",
+                     "-c", "Superman",
+                     "-h", "/home/metropolis",
+                     "-s", "/bin/supershell"])
+
+    subprocess.call(["sss_override", "user-add", "pparker",
+                     "-u", "20000",
+                     "-g", "20000"])
+
+    subprocess.call(["sss_override", "user-add", "mmccready",
+                     "-u", "20001",
+                     "-g", "20001",
+                     "-n", "hitgirl",
+                     "-c", "Hit-Girl",
+                     "-h", "/home/everywhere",
+                     "-s", "/bin/ksh"])
+
+    restart_sssd()
+
+    check_users_1()
+
+    # save overrides
+    subprocess.call(["sss_override", "user-export", override_filename])
+
+    # override name for user with changed uid
+    subprocess.call(["sss_override", "user-add", "pparker", "-n", "spiderman"])
+    restart_sssd()
+
+    # check that only spiderman changed
+    ent.assert_passwd_by_name(
+        'batman',
+        dict(name='batman', passwd='*', uid=10001, gid=20001,
+             gecos='Bruce Wayne',
+             shell='/bin/bash',
+             dir='/home/gotham'))
+
+    ent.assert_passwd_by_name(
+        'bwayne',
+        dict(name='batman', passwd='*', uid=10001, gid=20001,
+             gecos='Bruce Wayne',
+             shell='/bin/bash',
+             dir='/home/gotham'))
+
+    ent.assert_passwd_by_name(
+        'ckent',
+        dict(name='ckent', passwd='*', uid=10002, gid=20001,
+             gecos='Superman',
+             shell='/bin/supershell',
+             dir='/home/metropolis'))
+
+    # previous override for uids/gid got lost by most recent override
+    ent.assert_passwd_by_name(
+        'spiderman',
+        dict(name='spiderman', passwd='*', uid=10003, gid=20001))
+
+    ent.assert_passwd_by_name(
+        'pparker',
+        dict(name='spiderman', passwd='*', uid=10003, gid=20001))
+
+    # delete overrides for pparker
+    subprocess.call(["sss_override", "user-del", "pparker"])
+    restart_sssd()
+
+    # pparker got restored to initial status
+    ent.assert_passwd_by_name(
+        'pparker',
+        dict(name='pparker', passwd='*', uid=10003, gid=20001))
+
+    # pparker's name override to spiderman was removed
+    with pytest.raises(KeyError):
+        pwd.getpwnam('spiderman')
+
+    # by removing override for pparker other users (e.g bwayne) overrides were
+    # not touched
+    ent.assert_passwd_by_name(
+        'batman',
+        dict(name='batman', passwd='*', uid=10001, gid=20001,
+             gecos='Bruce Wayne',
+             shell='/bin/bash',
+             dir='/home/gotham'))
+    ent.assert_passwd_by_name(
+        'bwayne',
+        dict(name='batman', passwd='*', uid=10001, gid=20001,
+             gecos='Bruce Wayne',
+             shell='/bin/bash',
+             dir='/home/gotham'))
+
+    # delete override using overriden name
+    subprocess.call(["sss_override", "user-del", "bwayne"])
+    restart_sssd()
+
+    # bwayne got restored to initial status
+    ent.assert_passwd_by_name(
+        'bwayne',
+        dict(name='bwayne', passwd='*', uid=10001, gid=20001))
+
+    # bwayne's name override to batman was removed
+    with pytest.raises(KeyError):
+        pwd.getpwnam('batman')
+
+    # reload overrides
+    subprocess.call(["sss_override", "user-import", override_filename])
+    restart_sssd()
+
+    check_users_1()
+
+    # clean up - remove override file
+    subprocess.check_call(["rm", override_filename])
+
+
+def test_local_override_user_cached(ldap_conn, sanity_rfc2307):
+
+    # put object to sysdb cache before perfoming tests
+    check_users_0()
+
+    test_local_override_user(ldap_conn, sanity_rfc2307)
-- 
2.4.3

