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

Introduce a new integration test for local view overrides.

Regression tests for: #2790, #2757 and #2802.

Resolves:
https://fedorahosted.org/sssd/ticket/2732
---
 src/tests/intg/Makefile.am                 |    1 +
 src/tests/intg/ldap_local_override_test.py | 1330 ++++++++++++++++++++++++++++
 2 files changed, 1331 insertions(+)
 create mode 100644 src/tests/intg/ldap_local_override_test.py

diff --git a/src/tests/intg/Makefile.am b/src/tests/intg/Makefile.am
index 6819c2f2cea137c7544e94b0b29391611533b20c..f21880b61bfb07ac1dca65deda70fc50b4943586 100644
--- a/src/tests/intg/Makefile.am
+++ b/src/tests/intg/Makefile.am
@@ -6,6 +6,7 @@ dist_noinst_DATA = \
     ent.py \
     ent_test.py \
     ldap_ent.py \
+    ldap_local_override_test.py \
     ldap_test.py \
     util.py \
     test_memory_cache.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..13d1cc91bfdeedb853725b89c5f632adf1b7599d
--- /dev/null
+++ b/src/tests/intg/ldap_local_override_test.py
@@ -0,0 +1,1330 @@
+#
+# integration test for sss_override tool
+#
+# 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)
+
+
+OVERRIDE_FILENAME = "export_file"
+
+
+def prepare_sssd(request, ldap_conn, use_fully_qualified_names=False):
+    """Prepare SSSD woth defaults"""
+    conf = unindent("""\
+        [sssd]
+        domains             = LDAP
+        services            = nss
+
+        [nss]
+        memcache_timeout = 1
+
+        [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}
+        use_fully_qualified_names = {use_fully_qualified_names}
+    """).format(**locals())
+    create_conf_fixture(request, conf)
+    create_sssd_fixture(request)
+
+    def teardown():
+        # remove user export file
+        try:
+            os.unlink(OVERRIDE_FILENAME)
+        except:
+            pass
+    request.addfinalizer(teardown)
+
+
+#
+# Simple user override
+#
+
+
+@pytest.fixture
+def env_simple_user_override(request, ldap_conn):
+
+    prepare_sssd(request, ldap_conn)
+
+    # Add entries
+    ent_list = ldap_ent.List(LDAP_BASE_DN)
+    ent_list.add_user("user1", 10001, 20001,
+                      gecos='User Number 1',
+                      loginShell='/bin/user1_shell',
+                      homeDirectory='/home/user1')
+
+    ent_list.add_user("user2", 10002, 20001,
+                      gecos='User Number 2',
+                      loginShell='/bin/user2_shell',
+                      homeDirectory='/home/user2')
+
+    ent_list.add_group("group", 2001,
+                       ["user2", "user1"])
+
+    create_ldap_fixture(request, ldap_conn, ent_list)
+
+    # Assert entries are not overriden
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_user1')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_user2')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_user1@LDAP')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_user2@LDAP')
+
+    # Override
+    subprocess.check_call(["sss_override", "user-add", "user1",
+                           "-u", "10010",
+                           "-g", "20010",
+                           "-n", "ov_user1",
+                           "-c", "Overriden User 1",
+                           "-h", "/home/ov/user1",
+                           "-s", "/bin/ov_user1_shell"])
+
+    subprocess.check_call(["sss_override", "user-add", "user2@LDAP",
+                           "-u", "10020",
+                           "-g", "20020",
+                           "-n", "ov_user2",
+                           "-c", "Overriden User 2",
+                           "-h", "/home/ov/user2",
+                           "-s", "/bin/ov_user2_shell"])
+
+    # Restart SSSD so the override might take effect
+    restart_sssd()
+
+    return None
+
+
+def test_simple_user_override(ldap_conn, env_simple_user_override):
+    """Test entries are overriden"""
+
+    ent.assert_passwd_by_name(
+        'ov_user1',
+        dict(name='ov_user1', passwd='*', uid=10010, gid=20010,
+             gecos='Overriden User 1',
+             dir='/home/ov/user1',
+             shell='/bin/ov_user1_shell'))
+
+    ent.assert_passwd_by_name(
+        'user1',
+        dict(name='ov_user1', passwd='*', uid=10010, gid=20010,
+             gecos='Overriden User 1',
+             dir='/home/ov/user1',
+             shell='/bin/ov_user1_shell'))
+
+    ent.assert_passwd_by_name(
+        'ov_user1@LDAP',
+        dict(name='ov_user1', passwd='*', uid=10010, gid=20010,
+             gecos='Overriden User 1',
+             dir='/home/ov/user1',
+             shell='/bin/ov_user1_shell'))
+
+    ent.assert_passwd_by_name(
+        'user1@LDAP',
+        dict(name='ov_user1', passwd='*', uid=10010, gid=20010,
+             gecos='Overriden User 1',
+             dir='/home/ov/user1',
+             shell='/bin/ov_user1_shell'))
+
+    ent.assert_passwd_by_name(
+        'ov_user2@LDAP',
+        dict(name='ov_user2', passwd='*', uid=10020, gid=20020,
+             gecos='Overriden User 2',
+             dir='/home/ov/user2',
+             shell='/bin/ov_user2_shell'))
+
+    ent.assert_passwd_by_name(
+        'user2',
+        dict(name='ov_user2', passwd='*', uid=10020, gid=20020,
+             gecos='Overriden User 2',
+             dir='/home/ov/user2',
+             shell='/bin/ov_user2_shell'))
+
+#
+# Root user override
+#
+
+
+@pytest.fixture
+def env_root_user_override(request, ldap_conn):
+
+    prepare_sssd(request, ldap_conn)
+
+    # Add entries
+    ent_list = ldap_ent.List(LDAP_BASE_DN)
+    ent_list.add_user("user1", 10001, 20001,
+                      gecos='User Number 1',
+                      loginShell='/bin/user1_shell',
+                      homeDirectory='/home/user1')
+    ent_list.add_user("user2", 10002, 20001,
+                      gecos='User Number 2',
+                      loginShell='/bin/user2_shell',
+                      homeDirectory='/home/user2')
+
+    create_ldap_fixture(request, ldap_conn, ent_list)
+
+    # Assert entries are not overriden
+    ent.assert_passwd_by_name(
+        'user1',
+        dict(name='user1', passwd='*', uid=10001, gid=20001,
+             gecos='User Number 1',
+             dir='/home/user1',
+             shell='/bin/user1_shell'))
+
+    ent.assert_passwd_by_name(
+        'user2',
+        dict(name='user2', passwd='*', uid=10002, gid=20001,
+             gecos='User Number 2',
+             dir='/home/user2',
+             shell='/bin/user2_shell'))
+
+    ent.assert_passwd_by_name(
+        'root',
+        dict(name='root', uid=0, gid=0))
+
+    ent.assert_passwd_by_uid(0, dict(name="root"))
+
+    # Override
+    subprocess.check_call(["sss_override", "user-add", "user1",
+                           "-u", "0",
+                           "-g", "0",
+                           "-n", "ov_user1",
+                           "-c", "Overriden User 1",
+                           "-h", "/home/ov/user1",
+                           "-s", "/bin/ov_user1_shell"])
+
+    subprocess.check_call(["sss_override", "user-add", "user2@LDAP",
+                           "-u", "10020",
+                           "-g", "20020",
+                           "-n", "root",
+                           "-c", "Overriden User 2",
+                           "-h", "/home/ov/user2",
+                           "-s", "/bin/ov_user2_shell"])
+
+    # Restart SSSD so the override might take effect
+    restart_sssd()
+
+    return None
+
+
+def test_root_user_override(ldap_conn, env_root_user_override):
+    """Test entries are not overriden to root"""
+
+    # Override does not have to  happen completly, trying to set uid or gid
+    # to 0 is simply ignored.
+    ent.assert_passwd_by_name(
+        'ov_user1',
+        dict(name='ov_user1', passwd='*', uid=10001, gid=20001,
+             gecos='Overriden User 1',
+             dir='/home/ov/user1',
+             shell='/bin/ov_user1_shell'))
+
+    # We can create override with name root.
+    ent.assert_passwd_by_name(
+        'user2',
+        dict(name='root', passwd='*', uid=10020, gid=20020,
+             gecos='Overriden User 2',
+             dir='/home/ov/user2',
+             shell='/bin/ov_user2_shell'))
+
+    ent.assert_passwd_by_uid(0, dict(name="root"))
+
+
+#
+# Override replaces previous override
+#
+
+
+@pytest.fixture
+def env_replace_user_override(request, ldap_conn):
+
+    prepare_sssd(request, ldap_conn)
+
+    # Add entries
+    ent_list = ldap_ent.List(LDAP_BASE_DN)
+    ent_list.add_user("user1", 10001, 20001,
+                      gecos='User Number 1',
+                      loginShell='/bin/user1_shell',
+                      homeDirectory='/home/user1')
+
+    create_ldap_fixture(request, ldap_conn, ent_list)
+
+    # Assert entries are not overriden
+    ent.assert_passwd_by_name(
+        'user1',
+        dict(name='user1', passwd='*', uid=10001, gid=20001,
+             gecos='User Number 1',
+             dir='/home/user1',
+             shell='/bin/user1_shell'))
+
+    # Override
+    subprocess.check_call(["sss_override", "user-add", "user1",
+                           "-u", "10010",
+                           "-g", "20010",
+                           "-n", "ov_user1",
+                           "-c", "Overriden User 1",
+                           "-h", "/home/ov/user1",
+                           "-s", "/bin/ov_user1_shell"])
+
+    # Restart SSSD so the override might take effect
+    restart_sssd()
+
+    # Assert entries are overriden
+    ent.assert_passwd_by_name(
+        'user1',
+        dict(name='ov_user1', passwd='*', uid=10010, gid=20010,
+             gecos='Overriden User 1',
+             dir='/home/ov/user1',
+             shell='/bin/ov_user1_shell'))
+
+    # Override of override
+    subprocess.check_call(["sss_override", "user-add", "user1",
+                           "-u", "10100",
+                           "-g", "20100",
+                           "-n", "ov2_user1",
+                           "-c", "Overriden2 User 1",
+                           "-h", "/home/ov2/user1",
+                           "-s", "/bin/ov2_user1_shell"])
+
+    # Restart SSSD so the override might take effect
+    restart_sssd()
+
+    return None
+
+
+def test_replace_user_override(ldap_conn, env_replace_user_override):
+
+    ent.assert_passwd_by_name(
+        'ov2_user1',
+        dict(name='ov2_user1', passwd='*', uid=10100, gid=20100,
+             gecos='Overriden2 User 1',
+             dir='/home/ov2/user1',
+             shell='/bin/ov2_user1_shell'))
+
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_user1')
+
+
+#
+# Override removal
+#
+
+
+@pytest.fixture
+def env_remove_user_override(request, ldap_conn):
+
+    prepare_sssd(request, ldap_conn)
+
+    # Add entries
+    ent_list = ldap_ent.List(LDAP_BASE_DN)
+    ent_list.add_user("user1", 10001, 20001,
+                      gecos='User Number 1',
+                      loginShell='/bin/user1_shell',
+                      homeDirectory='/home/user1')
+
+    ent_list.add_user("user2", 10002, 20001,
+                      gecos='User Number 2',
+                      loginShell='/bin/user2_shell',
+                      homeDirectory='/home/user2')
+
+    ent_list.add_group("group", 2001,
+                       ["user2", "user1"])
+
+    create_ldap_fixture(request, ldap_conn, ent_list)
+
+    # Assert entries are not overriden
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_user1')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_user2')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_user1@LDAP')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_user2@LDAP')
+
+    # Override
+    subprocess.check_call(["sss_override", "user-add", "user1",
+                           "-u", "10010",
+                           "-g", "20010",
+                           "-n", "ov_user1",
+                           "-c", "Overriden User 1",
+                           "-h", "/home/ov/user1",
+                           "-s", "/bin/ov_user1_shell"])
+
+    subprocess.check_call(["sss_override", "user-add", "user2@LDAP",
+                           "-u", "10020",
+                           "-g", "20020",
+                           "-n", "ov_user2",
+                           "-c", "Overriden User 2",
+                           "-h", "/home/ov/user2",
+                           "-s", "/bin/ov_user2_shell"])
+
+    # Restart SSSD so the override might take effect
+    restart_sssd()
+
+    # Assert entries are overriden
+    ent.assert_passwd_by_name(
+        'ov_user1',
+        dict(name='ov_user1', passwd='*', uid=10010, gid=20010,
+             gecos='Overriden User 1',
+             dir='/home/ov/user1',
+             shell='/bin/ov_user1_shell'))
+
+    ent.assert_passwd_by_name(
+        'user1',
+        dict(name='ov_user1', passwd='*', uid=10010, gid=20010,
+             gecos='Overriden User 1',
+             dir='/home/ov/user1',
+             shell='/bin/ov_user1_shell'))
+
+    ent.assert_passwd_by_name(
+        'ov_user1@LDAP',
+        dict(name='ov_user1', passwd='*', uid=10010, gid=20010,
+             gecos='Overriden User 1',
+             dir='/home/ov/user1',
+             shell='/bin/ov_user1_shell'))
+
+    ent.assert_passwd_by_name(
+        'user1@LDAP',
+        dict(name='ov_user1', passwd='*', uid=10010, gid=20010,
+             gecos='Overriden User 1',
+             dir='/home/ov/user1',
+             shell='/bin/ov_user1_shell'))
+
+    ent.assert_passwd_by_name(
+        'ov_user2@LDAP',
+        dict(name='ov_user2', passwd='*', uid=10020, gid=20020,
+             gecos='Overriden User 2',
+             dir='/home/ov/user2',
+             shell='/bin/ov_user2_shell'))
+
+    ent.assert_passwd_by_name(
+        'user2',
+        dict(name='ov_user2', passwd='*', uid=10020, gid=20020,
+             gecos='Overriden User 2',
+             dir='/home/ov/user2',
+             shell='/bin/ov_user2_shell'))
+
+    # Drop all overrides
+    subprocess.check_call(["sss_override", "user-del", "user1"])
+    subprocess.check_call(["sss_override", "user-del", "user2@LDAP"])
+
+    # Avoid hitting memory cache
+    time.sleep(2)
+
+
+def test_remove_user_override(ldap_conn, env_remove_user_override):
+
+    # Test entries are not overriden
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_user1')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_user2')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_user1@LDAP')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_user2@LDAP')
+
+    ent.assert_passwd_by_name(
+        'user1@LDAP',
+        dict(name='user1', passwd='*', uid=10001, gid=20001,
+             gecos='User Number 1',
+             dir='/home/user1',
+             shell='/bin/user1_shell'))
+
+    ent.assert_passwd_by_name(
+        'user2',
+        dict(name='user2', passwd='*', uid=10002, gid=20001,
+             gecos='User Number 2',
+             dir='/home/user2',
+             shell='/bin/user2_shell'))
+
+
+#
+# Override import/export
+#
+
+
+@pytest.fixture
+def env_imp_exp_user_override(request, ldap_conn):
+
+    prepare_sssd(request, ldap_conn)
+
+    # Add entries
+    ent_list = ldap_ent.List(LDAP_BASE_DN)
+    ent_list.add_user("user1", 10001, 20001,
+                      gecos='User Number 1',
+                      loginShell='/bin/user1_shell',
+                      homeDirectory='/home/user1')
+
+    ent_list.add_user("user2", 10002, 20001,
+                      gecos='User Number 2',
+                      loginShell='/bin/user2_shell',
+                      homeDirectory='/home/user2')
+
+    ent_list.add_group("group", 2001,
+                       ["user2", "user1"])
+
+    create_ldap_fixture(request, ldap_conn, ent_list)
+
+    # Assert entries are not overriden
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_user1')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_user2')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_user1@LDAP')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_user2@LDAP')
+
+    # Override
+    subprocess.check_call(["sss_override", "user-add", "user1",
+                           "-u", "10010",
+                           "-g", "20010",
+                           "-n", "ov_user1",
+                           "-c", "Overriden User 1",
+                           "-h", "/home/ov/user1",
+                           "-s", "/bin/ov_user1_shell"])
+
+    subprocess.check_call(["sss_override", "user-add", "user2@LDAP",
+                           "-u", "10020",
+                           "-g", "20020",
+                           "-n", "ov_user2",
+                           "-c", "Overriden User 2",
+                           "-h", "/home/ov/user2",
+                           "-s", "/bin/ov_user2_shell"])
+
+    # Restart SSSD so the override might take effect
+    restart_sssd()
+
+    # Assert entries are overriden
+    ent.assert_passwd_by_name(
+        'ov_user1',
+        dict(name='ov_user1', passwd='*', uid=10010, gid=20010,
+             gecos='Overriden User 1',
+             dir='/home/ov/user1',
+             shell='/bin/ov_user1_shell'))
+
+    ent.assert_passwd_by_name(
+        'user1',
+        dict(name='ov_user1', passwd='*', uid=10010, gid=20010,
+             gecos='Overriden User 1',
+             dir='/home/ov/user1',
+             shell='/bin/ov_user1_shell'))
+
+    ent.assert_passwd_by_name(
+        'ov_user1@LDAP',
+        dict(name='ov_user1', passwd='*', uid=10010, gid=20010,
+             gecos='Overriden User 1',
+             dir='/home/ov/user1',
+             shell='/bin/ov_user1_shell'))
+
+    ent.assert_passwd_by_name(
+        'user1@LDAP',
+        dict(name='ov_user1', passwd='*', uid=10010, gid=20010,
+             gecos='Overriden User 1',
+             dir='/home/ov/user1',
+             shell='/bin/ov_user1_shell'))
+
+    ent.assert_passwd_by_name(
+        'ov_user2@LDAP',
+        dict(name='ov_user2', passwd='*', uid=10020, gid=20020,
+             gecos='Overriden User 2',
+             dir='/home/ov/user2',
+             shell='/bin/ov_user2_shell'))
+
+    ent.assert_passwd_by_name(
+        'user2',
+        dict(name='ov_user2', passwd='*', uid=10020, gid=20020,
+             gecos='Overriden User 2',
+             dir='/home/ov/user2',
+             shell='/bin/ov_user2_shell'))
+
+    # Export overrides
+    subprocess.check_call(["sss_override", "user-export",
+                           OVERRIDE_FILENAME])
+
+    # Drop all overrides
+    subprocess.check_call(["sss_override", "user-del", "user1"])
+    subprocess.check_call(["sss_override", "user-del", "user2@LDAP"])
+
+    # Avoid hitting memory cache
+    time.sleep(2)
+
+    # Assert entries are not overridden
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_user1')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_user2')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_user1@LDAP')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_user2@LDAP')
+
+    ent.assert_passwd_by_name(
+        'user1@LDAP',
+        dict(name='user1', passwd='*', uid=10001, gid=20001,
+             gecos='User Number 1',
+             dir='/home/user1',
+             shell='/bin/user1_shell'))
+
+    ent.assert_passwd_by_name(
+        'user2',
+        dict(name='user2', passwd='*', uid=10002, gid=20001,
+             gecos='User Number 2',
+             dir='/home/user2',
+             shell='/bin/user2_shell'))
+
+    # Import overrides
+    subprocess.check_call(["sss_override", "user-import",
+                           OVERRIDE_FILENAME])
+    restart_sssd()
+
+
+def test_imp_exp_user_override(ldap_conn, env_imp_exp_user_override):
+
+    # Assert entries are overriden
+    ent.assert_passwd_by_name(
+        'ov_user1',
+        dict(name='ov_user1', passwd='*', uid=10010, gid=20010,
+             gecos='Overriden User 1',
+             dir='/home/ov/user1',
+             shell='/bin/ov_user1_shell'))
+
+    ent.assert_passwd_by_name(
+        'user1',
+        dict(name='ov_user1', passwd='*', uid=10010, gid=20010,
+             gecos='Overriden User 1',
+             dir='/home/ov/user1',
+             shell='/bin/ov_user1_shell'))
+
+    ent.assert_passwd_by_name(
+        'ov_user1@LDAP',
+        dict(name='ov_user1', passwd='*', uid=10010, gid=20010,
+             gecos='Overriden User 1',
+             dir='/home/ov/user1',
+             shell='/bin/ov_user1_shell'))
+
+    ent.assert_passwd_by_name(
+        'user1@LDAP',
+        dict(name='ov_user1', passwd='*', uid=10010, gid=20010,
+             gecos='Overriden User 1',
+             dir='/home/ov/user1',
+             shell='/bin/ov_user1_shell'))
+
+    ent.assert_passwd_by_name(
+        'ov_user2@LDAP',
+        dict(name='ov_user2', passwd='*', uid=10020, gid=20020,
+             gecos='Overriden User 2',
+             dir='/home/ov/user2',
+             shell='/bin/ov_user2_shell'))
+
+    ent.assert_passwd_by_name(
+        'user2',
+        dict(name='ov_user2', passwd='*', uid=10020, gid=20020,
+             gecos='Overriden User 2',
+             dir='/home/ov/user2',
+             shell='/bin/ov_user2_shell'))
+
+
+#
+# Group tests
+#
+#
+# Simple group override
+#
+
+
+@pytest.fixture
+def env_simple_group_override(request, ldap_conn):
+
+    prepare_sssd(request, ldap_conn)
+
+    # Add entries
+    ent_list = ldap_ent.List(LDAP_BASE_DN)
+    ent_list.add_user("user1", 10001, 20001,
+                      gecos='User Number 1',
+                      loginShell='/bin/user1_shell',
+                      homeDirectory='/home/user1')
+
+    ent_list.add_user("user2", 10002, 20001,
+                      gecos='User Number 2',
+                      loginShell='/bin/user2_shell',
+                      homeDirectory='/home/user2')
+
+    ent_list.add_group("group", 2001,
+                       ["user2", "user1"])
+    ent_list.add_group("empty_group", 2002, [])
+
+    create_ldap_fixture(request, ldap_conn, ent_list)
+
+    # Assert entries are not overriden
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_group')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_empty_group')
+
+    # Override
+    subprocess.check_call(["sss_override", "group-add", "group",
+                           "-n", "ov_group",
+                           "-g", "3001"])
+
+    subprocess.check_call(["sss_override", "group-add", "empty_group@LDAP",
+                           "--name", "ov_empty_group",
+                           "--gid", "3002"])
+
+    # Restart SSSD so the override might take effect
+    restart_sssd()
+
+    return None
+
+
+def test_simple_group_override(ldap_conn, env_simple_group_override):
+    """Test entries are overriden"""
+
+    ent.assert_group_by_name(
+        "ov_group", dict(gid=3001, mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "ov_empty_group", dict(gid=3002, mem=ent.contains_only()))
+    ent.assert_group_by_name(
+        "group", dict(gid=3001, mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "empty_group", dict(gid=3002, mem=ent.contains_only()))
+    ent.assert_group_by_name(
+        "ov_group@LDAP", dict(gid=3001,
+                              mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "ov_empty_group@LDAP", dict(gid=3002, mem=ent.contains_only()))
+    ent.assert_group_by_name(
+        "group@LDAP", dict(gid=3001,
+                           mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "empty_group@LDAP", dict(gid=3002, mem=ent.contains_only()))
+
+
+#
+# Root group override
+#
+
+
+@pytest.fixture
+def env_root_group_override(request, ldap_conn):
+
+    prepare_sssd(request, ldap_conn)
+
+    # Add entries
+    ent_list = ldap_ent.List(LDAP_BASE_DN)
+    ent_list.add_user("user1", 10001, 20001,
+                      gecos='User Number 1',
+                      loginShell='/bin/user1_shell',
+                      homeDirectory='/home/user1')
+
+    ent_list.add_user("user2", 10002, 20001,
+                      gecos='User Number 2',
+                      loginShell='/bin/user2_shell',
+                      homeDirectory='/home/user2')
+
+    ent_list.add_group("group", 2001,
+                       ["user2", "user1"])
+    ent_list.add_group("empty_group", 2002, [])
+
+    create_ldap_fixture(request, ldap_conn, ent_list)
+
+    # Assert entries are not overriden
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_group')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_empty_group')
+
+    # Override
+    subprocess.check_call(["sss_override", "group-add", "group",
+                           "-n", "ov_group",
+                           "-g", "0"])
+
+    subprocess.check_call(["sss_override", "group-add", "empty_group@LDAP",
+                           "--name", "ov_empty_group",
+                           "--gid", "0"])
+
+    # Restart SSSD so the override might take effect
+    restart_sssd()
+
+    return None
+
+
+def test_root_group_override(ldap_conn, env_root_group_override):
+    """Test entries are overriden"""
+
+    ent.assert_group_by_name(
+        "ov_group", dict(gid=2001, mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "ov_empty_group", dict(gid=2002, mem=ent.contains_only()))
+    ent.assert_group_by_name(
+        "group", dict(gid=2001, mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "empty_group", dict(gid=2002, mem=ent.contains_only()))
+    ent.assert_group_by_name(
+        "ov_group@LDAP",
+        dict(gid=2001, mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "ov_empty_group@LDAP", dict(gid=2002, mem=ent.contains_only()))
+    ent.assert_group_by_name(
+        "group@LDAP", dict(gid=2001, mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "empty_group@LDAP", dict(gid=2002, mem=ent.contains_only()))
+
+
+#
+# Replace group override
+#
+
+
+@pytest.fixture
+def env_replace_group_override(request, ldap_conn):
+
+    prepare_sssd(request, ldap_conn)
+
+    # Add entries
+    ent_list = ldap_ent.List(LDAP_BASE_DN)
+    ent_list.add_user("user1", 10001, 20001,
+                      gecos='User Number 1',
+                      loginShell='/bin/user1_shell',
+                      homeDirectory='/home/user1')
+
+    ent_list.add_user("user2", 10002, 20001,
+                      gecos='User Number 2',
+                      loginShell='/bin/user2_shell',
+                      homeDirectory='/home/user2')
+
+    ent_list.add_group("group", 2001,
+                       ["user2", "user1"])
+    ent_list.add_group("empty_group", 2002, [])
+
+    create_ldap_fixture(request, ldap_conn, ent_list)
+
+    # Assert entries are not overriden
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_group')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_empty_group')
+
+    # Override
+    subprocess.check_call(["sss_override", "group-add", "group",
+                           "-n", "ov_group",
+                           "-g", "3001"])
+
+    subprocess.check_call(["sss_override", "group-add", "empty_group@LDAP",
+                           "--name", "ov_empty_group",
+                           "--gid", "3002"])
+
+    # Restart SSSD so the override might take effect
+    restart_sssd()
+
+    # Assert entries are overridden
+    ent.assert_group_by_name(
+        "ov_group", dict(gid=3001, mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "ov_empty_group", dict(gid=3002, mem=ent.contains_only()))
+    ent.assert_group_by_name(
+        "group", dict(gid=3001, mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "empty_group", dict(gid=3002, mem=ent.contains_only()))
+    ent.assert_group_by_name(
+        "ov_group@LDAP",
+        dict(gid=3001, mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "ov_empty_group@LDAP", dict(gid=3002, mem=ent.contains_only()))
+    ent.assert_group_by_name(
+        "group@LDAP", dict(gid=3001, mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "empty_group@LDAP", dict(gid=3002, mem=ent.contains_only()))
+
+    # Override of override
+    subprocess.check_call(["sss_override", "group-add", "group",
+                           "-n", "ov2_group",
+                           "-g", "4001"])
+
+    subprocess.check_call(["sss_override", "group-add", "empty_group@LDAP",
+                           "--name", "ov2_empty_group",
+                           "--gid", "4002"])
+
+    # Restart SSSD so the override might take effect
+    restart_sssd()
+
+    return None
+
+
+def test_replace_group_override(ldap_conn, env_replace_group_override):
+
+    # Test overrides are overridden
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_group')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_empty_group')
+
+    ent.assert_group_by_name(
+        "ov2_group", dict(gid=4001, mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "ov2_empty_group", dict(gid=4002, mem=ent.contains_only()))
+    ent.assert_group_by_name(
+        "group", dict(gid=4001, mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "empty_group", dict(gid=4002, mem=ent.contains_only()))
+    ent.assert_group_by_name(
+        "ov2_group@LDAP",
+        dict(gid=4001, mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "ov2_empty_group@LDAP", dict(gid=4002, mem=ent.contains_only()))
+    ent.assert_group_by_name(
+        "group@LDAP",
+        dict(gid=4001, mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "empty_group@LDAP", dict(gid=4002, mem=ent.contains_only()))
+
+
+#
+# Remove override
+#
+
+
+@pytest.fixture
+def env_remove_group_override(request, ldap_conn):
+
+    prepare_sssd(request, ldap_conn)
+
+    # Add entries
+    ent_list = ldap_ent.List(LDAP_BASE_DN)
+    ent_list.add_user("user1", 10001, 20001,
+                      gecos='User Number 1',
+                      loginShell='/bin/user1_shell',
+                      homeDirectory='/home/user1')
+
+    ent_list.add_user("user2", 10002, 20001,
+                      gecos='User Number 2',
+                      loginShell='/bin/user2_shell',
+                      homeDirectory='/home/user2')
+
+    ent_list.add_group("group", 2001,
+                       ["user2", "user1"])
+    ent_list.add_group("empty_group", 2002, [])
+
+    create_ldap_fixture(request, ldap_conn, ent_list)
+
+    # Assert entries are not overriden
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_group')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_empty_group')
+
+    # Override
+    subprocess.check_call(["sss_override", "group-add", "group",
+                           "-n", "ov_group",
+                           "-g", "3001"])
+
+    subprocess.check_call(["sss_override", "group-add", "empty_group@LDAP",
+                           "--name", "ov_empty_group",
+                           "--gid", "3002"])
+
+    # Restart SSSD so the override might take effect
+    restart_sssd()
+
+    # Assert entries are overridden
+    ent.assert_group_by_name(
+        "ov_group", dict(gid=3001, mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "ov_empty_group", dict(gid=3002, mem=ent.contains_only()))
+    ent.assert_group_by_name(
+        "group", dict(gid=3001, mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "empty_group", dict(gid=3002, mem=ent.contains_only()))
+    ent.assert_group_by_name(
+        "ov_group@LDAP",
+        dict(gid=3001, mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "ov_empty_group@LDAP", dict(gid=3002, mem=ent.contains_only()))
+    ent.assert_group_by_name(
+        "group@LDAP", dict(gid=3001, mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "empty_group@LDAP", dict(gid=3002, mem=ent.contains_only()))
+
+    # Drop all overrides
+    subprocess.check_call(["sss_override", "user-del", "user1"])
+    subprocess.check_call(["sss_override", "user-del", "user2@LDAP"])
+
+    # Avoid hitting memory cache
+    time.sleep(2)
+
+    return None
+
+
+def test_remove_group_override(ldap_conn, env_remove_group_override):
+
+    # Test overrides were dropped
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_group')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_empty_group')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_group@LDAP')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_empty_group@LDAP')
+
+    ent.assert_group_by_name(
+        "group", dict(gid=3001, mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "empty_group", dict(gid=3002, mem=ent.contains_only()))
+    ent.assert_group_by_name(
+        "group@LDAP", dict(gid=3001, mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "empty_group@LDAP", dict(gid=3002, mem=ent.contains_only()))
+
+
+#
+# Overridde import/export
+#
+
+
+@pytest.fixture
+def env_imp_exp_group_override(request, ldap_conn):
+
+    prepare_sssd(request, ldap_conn)
+
+    # Add entries
+    ent_list = ldap_ent.List(LDAP_BASE_DN)
+    ent_list.add_user("user1", 10001, 20001,
+                      gecos='User Number 1',
+                      loginShell='/bin/user1_shell',
+                      homeDirectory='/home/user1')
+
+    ent_list.add_user("user2", 10002, 20001,
+                      gecos='User Number 2',
+                      loginShell='/bin/user2_shell',
+                      homeDirectory='/home/user2')
+
+    ent_list.add_group("group", 2001,
+                       ["user2", "user1"])
+    ent_list.add_group("empty_group", 2002, [])
+
+    create_ldap_fixture(request, ldap_conn, ent_list)
+
+    # Assert entries are not overriden
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_group')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_empty_group')
+
+    # Override
+    subprocess.check_call(["sss_override", "group-add", "group",
+                           "-n", "ov_group",
+                           "-g", "3001"])
+
+    subprocess.check_call(["sss_override", "group-add", "empty_group@LDAP",
+                           "--name", "ov_empty_group",
+                           "--gid", "3002"])
+
+    # Restart SSSD so the override might take effect
+    restart_sssd()
+
+    # Assert entries are overridden
+    ent.assert_group_by_name(
+        "ov_group", dict(gid=3001, mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "ov_empty_group", dict(gid=3002, mem=ent.contains_only()))
+    ent.assert_group_by_name(
+        "group", dict(gid=3001, mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "empty_group", dict(gid=3002, mem=ent.contains_only()))
+    ent.assert_group_by_name(
+        "ov_group@LDAP",
+        dict(gid=3001, mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "ov_empty_group@LDAP", dict(gid=3002, mem=ent.contains_only()))
+    ent.assert_group_by_name(
+        "group@LDAP", dict(gid=3001, mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "empty_group@LDAP", dict(gid=3002, mem=ent.contains_only()))
+
+    # Export overrides
+    subprocess.check_call(["sss_override", "group-export",
+                           OVERRIDE_FILENAME])
+
+    # Drop all overrides
+    subprocess.check_call(["sss_override", "group-del", "group"])
+    subprocess.check_call(["sss_override", "group-del", "empty_group@LDAP"])
+
+    # Avoid hitting memory cache
+    time.sleep(2)
+
+    # Assert entries are not overridden
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_group')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_empty_group')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_group@LDAP')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('ov_empty_group@LDAP')
+
+    ent.assert_group_by_name(
+        "group", dict(gid=2001, mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "empty_group", dict(gid=2002, mem=ent.contains_only()))
+    ent.assert_group_by_name(
+        "group@LDAP", dict(gid=2001, mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "empty_group@LDAP", dict(gid=2002, mem=ent.contains_only()))
+
+    # Import overrides
+    subprocess.check_call(["sss_override", "group-import",
+                           OVERRIDE_FILENAME])
+    restart_sssd()
+
+    return None
+
+
+def test_imp_exp_group_override(ldap_conn, env_imp_exp_group_override):
+
+    # Assert entries are overridden
+    ent.assert_group_by_name(
+        "ov_group", dict(gid=3001, mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "ov_empty_group", dict(gid=3002, mem=ent.contains_only()))
+    ent.assert_group_by_name(
+        "group", dict(gid=3001, mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "empty_group", dict(gid=3002, mem=ent.contains_only()))
+    ent.assert_group_by_name(
+        "ov_group@LDAP",
+        dict(gid=3001, mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "ov_empty_group@LDAP", dict(gid=3002, mem=ent.contains_only()))
+    ent.assert_group_by_name(
+        "group@LDAP", dict(gid=3001, mem=ent.contains_only("user1", "user2")))
+    ent.assert_group_by_name(
+        "empty_group@LDAP", dict(gid=3002, mem=ent.contains_only()))
+
+
+# Regression test for bug #2802
+# sss_override segfaults when accidentally adding --help flag to some commands
+
+
+def test_regr_2802_override():
+
+    subprocess.call(["sss_override", "user-del", "--help"])
+
+
+# Regression test for bug #2757
+# sss_override does not work correctly when 'use_fully_qualified_names = True'
+
+
+@pytest.fixture
+def env_regr_2757_override(request, ldap_conn):
+
+    prepare_sssd(request, ldap_conn, use_fully_qualified_names=True)
+
+    # Add entries
+    ent_list = ldap_ent.List(LDAP_BASE_DN)
+    ent_list.add_user("user1", 10001, 20001)
+
+    create_ldap_fixture(request, ldap_conn, ent_list)
+
+    # Assert entries are not overridden
+    ent.assert_passwd_by_name(
+        'user1@LDAP',
+        dict(name='user1@LDAP', passwd='*', uid=10001, gid=20001))
+    with pytest.raises(KeyError):
+        pwd.getpwnam('alias1')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('alias1@LDAP')
+
+    # Override
+    subprocess.check_call(["sss_override", "user-add", "user1@LDAP",
+                           "-n", "alias1"])
+    restart_sssd()
+
+
+def test_regr_2757_override(ldap_conn, env_regr_2757_override):
+
+    # Assert entries are overridden
+    ent.assert_passwd_by_name(
+        'user1@LDAP',
+        dict(name='alias1@LDAP', passwd='*', uid=10001, gid=20001))
+    ent.assert_passwd_by_name(
+        'alias1@LDAP',
+        dict(name='alias1@LDAP', passwd='*', uid=10001, gid=20001))
+
+    with pytest.raises(KeyError):
+        pwd.getpwnam('user1')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('alias1')
+
+
+# Regression test for bug #2790
+# sss_override --name doesn't work with RFC2307 and ghost users
+
+
+@pytest.fixture
+def env_regr_2790_override(request, ldap_conn):
+
+    prepare_sssd(request, ldap_conn)
+
+    # Add entries
+    ent_list = ldap_ent.List(LDAP_BASE_DN)
+    ent_list.add_user("user1", 10001, 20001)
+    ent_list.add_user("user2", 10002, 20002)
+    ent_list.add_group("group1", 2001,
+                       ["user1", "user2"])
+    ent_list.add_group("group2", 2002,
+                       ["user2"])
+
+    create_ldap_fixture(request, ldap_conn, ent_list)
+
+    # Assert entries are not overridden
+    with pytest.raises(KeyError):
+        pwd.getpwnam('alias1')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('alias1@LDAP')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('alias2')
+    with pytest.raises(KeyError):
+        pwd.getpwnam('alias2@LDAP')
+
+    # Override
+    subprocess.check_call(["sss_override", "user-add", "user1",
+                           "-n", "alias1"])
+    subprocess.check_call(["sss_override", "user-add", "user2",
+                           "-n", "alias2"])
+
+    restart_sssd()
+
+
+def test_regr_2790_override(ldap_conn, env_regr_2790_override):
+
+    # Assert entries are overridden
+    (res, errno, grp_list) = sssd_id.get_user_groups("alias1")
+    assert res == sssd_id.NssReturnCode.SUCCESS, \
+        "Could not find groups for user1 %d" % errno
+    assert grp_list == ["group1"]
+
+    (res, errno, grp_list) = sssd_id.get_user_groups("alias2")
+    assert res == sssd_id.NssReturnCode.SUCCESS, \
+        "Could not find groups for user2 %d" % errno
+    assert sorted(grp_list) == sorted(["group1", "group2"])
-- 
2.4.3

