URL: https://github.com/SSSD/sssd/pull/102 Author: mzidek-rh Title: #102: Sssctl no case sensitive searches Action: synchronized
To pull the PR as Git branch: git remote add ghsssd https://github.com/SSSD/sssd git fetch ghsssd pull/102/head:pr102 git checkout pr102
From 20596900fca35c3039a22679f8eb4c7d1ba2be2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzi...@redhat.com> Date: Thu, 1 Dec 2016 15:56:39 +0100 Subject: [PATCH 1/4] common: Fix domain case sensitivity init Fix initialization of domain case sensitivity. Resolves: https://fedorahosted.org/sssd/ticket/3235 --- src/confdb/confdb.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c index f0e3942..cfe765c 100644 --- a/src/confdb/confdb.c +++ b/src/confdb/confdb.c @@ -1292,7 +1292,7 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb, } tmp = ldb_msg_find_attr_as_string(res->msgs[0], - CONFDB_DOMAIN_CASE_SENSITIVE, "true"); + CONFDB_DOMAIN_CASE_SENSITIVE, NULL); if (tmp != NULL) { if (strcasecmp(tmp, "true") == 0) { domain->case_sensitive = true; @@ -1310,9 +1310,15 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb, } } else { /* default */ - domain->case_sensitive = true; - domain->case_preserve = true; + if (strcasecmp(domain->provider, "ad") == 0) { + domain->case_sensitive = false; + domain->case_sensitive = false; + } else { + domain->case_sensitive = true; + domain->case_preserve = true; + } } + if (domain->case_sensitive == false && strcasecmp(domain->provider, "local") == 0) { DEBUG(SSSDBG_FATAL_FAILURE, From 89d31727c8292aefb333e11899635dbeaa223993 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzi...@redhat.com> Date: Thu, 1 Dec 2016 14:51:37 +0100 Subject: [PATCH 2/4] sssctl: Users and groups search by alias Also search by alias when using sssctl user/group-show command. Resolves: https://fedorahosted.org/sssd/ticket/3235 --- src/tools/sssctl/sssctl_cache.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/tools/sssctl/sssctl_cache.c b/src/tools/sssctl/sssctl_cache.c index b1a7cc9..93601b9 100644 --- a/src/tools/sssctl/sssctl_cache.c +++ b/src/tools/sssctl/sssctl_cache.c @@ -295,10 +295,12 @@ static const char *sssctl_create_filter(TALLOC_CTX *mem_ctx, const char *filter; char *filter_value; bool qualify_attr = false; + bool use_alias = false; if (strcmp(attr_name, SYSDB_NAME) == 0) { if (obj_type == CACHED_USER || obj_type == CACHED_GROUP) { qualify_attr = true; + use_alias = true; } } @@ -327,8 +329,15 @@ static const char *sssctl_create_filter(TALLOC_CTX *mem_ctx, return NULL; } - filter = talloc_asprintf(mem_ctx, "(&(objectClass=%s)(%s=%s))", - class, attr_name, filter_value); + if (use_alias) { + filter = talloc_asprintf(mem_ctx, "(&(objectClass=%s)(|(%s=%s)(%s=%s)))", + class, attr_name, filter_value, + SYSDB_NAME_ALIAS, filter_value); + } else { + filter = talloc_asprintf(mem_ctx, "(&(objectClass=%s)(%s=%s))", + class, attr_name, filter_value); + } + talloc_free(filter_value); return filter; From 04e8d5a5d2d85734cb3edd7b8097a7dc2c08f3d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzi...@redhat.com> Date: Thu, 1 Dec 2016 15:22:42 +0100 Subject: [PATCH 3/4] sssctl: Case insensitive filters Lowercase the filter in case insensitive domains. Resolves: https://fedorahosted.org/sssd/ticket/3235 --- src/tools/sssctl/sssctl_cache.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/tools/sssctl/sssctl_cache.c b/src/tools/sssctl/sssctl_cache.c index 93601b9..a8d703d 100644 --- a/src/tools/sssctl/sssctl_cache.c +++ b/src/tools/sssctl/sssctl_cache.c @@ -329,6 +329,14 @@ static const char *sssctl_create_filter(TALLOC_CTX *mem_ctx, return NULL; } + if (dom->case_sensitive == false) { + char *filter_value_old; + + filter_value_old = filter_value; + filter_value = sss_tc_utf8_str_tolower(mem_ctx, filter_value_old); + talloc_free(filter_value_old); + } + if (use_alias) { filter = talloc_asprintf(mem_ctx, "(&(objectClass=%s)(|(%s=%s)(%s=%s)))", class, attr_name, filter_value, From 0aa18539c8bdc93e1fcac9d1d559682c07c60848 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzi...@redhat.com> Date: Fri, 2 Dec 2016 13:21:47 +0100 Subject: [PATCH 4/4] tests: sssctl user/group-show basic tests Add basic tests for sssctl user/group-show commands. This includes regression test for ticket #3235. Resolves: https://fedorahosted.org/sssd/ticket/3235 --- src/tests/intg/Makefile.am | 1 + src/tests/intg/test_sssctl.py | 364 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 365 insertions(+) create mode 100644 src/tests/intg/test_sssctl.py diff --git a/src/tests/intg/Makefile.am b/src/tests/intg/Makefile.am index 1e08ead..e81e5ee 100644 --- a/src/tests/intg/Makefile.am +++ b/src/tests/intg/Makefile.am @@ -18,6 +18,7 @@ dist_noinst_DATA = \ test_netgroup.py \ secrets.py \ test_secrets.py \ + test_sssctl.py \ $(NULL) config.py: config.py.m4 diff --git a/src/tests/intg/test_sssctl.py b/src/tests/intg/test_sssctl.py new file mode 100644 index 0000000..f75a95e --- /dev/null +++ b/src/tests/intg/test_sssctl.py @@ -0,0 +1,364 @@ +# +# sssctl tool integration test +# +# Copyright (c) 2016 Red Hat, Inc. +# Author: Michal Zidek <mzi...@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 ent +import grp +import pwd +import subprocess +import pytest +import stat +import time +import signal +import ds_openldap +import ldap_ent +import config +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 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 + 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) + + +@pytest.fixture +def portable_LC_ALL(request): + os.environ["LC_ALL"] = "C" + return None + + +def load_data_to_ldap(request, ldap_conn): + ent_list = ldap_ent.List(ldap_conn.ds_inst.base_dn) + ent_list.add_user("user1", 1001, 2001) + ent_list.add_user("CamelCaseUser1", 1002, 2002) + + ent_list.add_group("group1", 2001, ["user1"]) + ent_list.add_group("CamelCaseGroup1", 2002, ["CamelCaseUser1"]) + + 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 + + +@pytest.fixture +def fqname_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} + use_fully_qualified_names = true + """).format(**locals()) + create_conf_fixture(request, conf) + create_sssd_fixture(request) + return None + + +@pytest.fixture +def fqname_case_insensitive_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} + use_fully_qualified_names = true + case_sensitive = false + """).format(**locals()) + create_conf_fixture(request, conf) + create_sssd_fixture(request) + return None + + +def test_user_show_basic_sanity(ldap_conn, sanity_rfc2307, portable_LC_ALL): + # Fill the cache first + ent.assert_passwd_by_name( + 'user1', + dict(name='user1', passwd='*', uid=1001, gid=2001, + gecos='1001', shell='/bin/bash')) + ent.assert_passwd_by_name( + 'CamelCaseUser1', + dict(name='CamelCaseUser1', passwd='*', uid=1002, gid=2002, + gecos='1002', shell='/bin/bash')) + + output = subprocess.check_output(["sssctl", "user-show", "user1"]) + assert output.find("Name: user1") != -1 + assert output.find("Initgroups expiration time: Initgroups were not yet " + "performed") != -1 + assert output.find("Cached in InfoPipe: No") != -1 + + output = subprocess.check_output(["sssctl", "user-show", + "CamelCaseUser1"]) + assert output.find("Name: CamelCaseUser1") != -1 + assert output.find("Initgroups expiration time: Initgroups were not yet " + "performed") != -1 + assert output.find("Cached in InfoPipe: No") != -1 + + output = subprocess.check_output(["sssctl", "user-show", "camelcaseuser1"]) + assert output.find("User camelcaseuser1 is not present in cache.") != -1 + + +def test_user_show_basic_fqname(ldap_conn, fqname_rfc2307, portable_LC_ALL): + # Fill the cache first + ent.assert_passwd_by_name( + 'user1@LDAP', + dict(name='user1@LDAP', passwd='*', uid=1001, gid=2001, + gecos='1001', shell='/bin/bash')) + ent.assert_passwd_by_name( + 'CamelCaseUser1@LDAP', + dict(name='CamelCaseUser1@LDAP', passwd='*', uid=1002, gid=2002, + gecos='1002', shell='/bin/bash')) + + output = subprocess.check_output(["sssctl", "user-show", "user1@LDAP"]) + assert output.find("Name: user1@LDAP") != -1 + assert output.find("Initgroups expiration time: Initgroups were not yet " + "performed") != -1 + assert output.find("Cached in InfoPipe: No") != -1 + + output = subprocess.check_output(["sssctl", "user-show", + "CamelCaseUser1@LDAP"]) + assert output.find("Name: CamelCaseUser1@LDAP") != -1 + assert output.find("Initgroups expiration time: Initgroups were not yet " + "performed") != -1 + assert output.find("Cached in InfoPipe: No") != -1 + + output = subprocess.check_output(["sssctl", "user-show", + "camelcaseuser1@LDAP"]) + assert output.find("User camelcaseuser1 is not present in cache.") != -1 + + +def test_user_show_basic_fqname_insensitive(ldap_conn, + fqname_case_insensitive_rfc2307, + portable_LC_ALL): + # Fill the cache first + ent.assert_passwd_by_name( + 'user1@LDAP', + dict(name='user1@LDAP', passwd='*', uid=1001, gid=2001, + gecos='1001', shell='/bin/bash')) + ent.assert_passwd_by_name( + 'CamelCaseUser1@LDAP', + dict(name='camelcaseuser1@LDAP', passwd='*', uid=1002, gid=2002, + gecos='1002', shell='/bin/bash')) + + output = subprocess.check_output(["sssctl", "user-show", "user1@LDAP"]) + assert output.find("Name: user1@LDAP") != -1 + assert output.find("Initgroups expiration time: Initgroups were not yet " + "performed") != -1 + assert output.find("Cached in InfoPipe: No") != -1 + + output = subprocess.check_output(["sssctl", "user-show", + "CamelCaseUser1@LDAP"]) + assert output.find("Name: camelcaseuser1@LDAP") != -1 + assert output.find("Initgroups expiration time: Initgroups were not yet " + "performed") != -1 + assert output.find("Cached in InfoPipe: No") != -1 + + output = subprocess.check_output(["sssctl", "user-show", + "camelcaseuser1@LDAP"]) + assert output.find("Name: camelcaseuser1@LDAP") != -1 + assert output.find("Initgroups expiration time: Initgroups were not yet " + "performed") != -1 + assert output.find("Cached in InfoPipe: No") != -1 + + +def test_group_show_basic_sanity(ldap_conn, sanity_rfc2307, portable_LC_ALL): + # Fill the cache first + ent.assert_group_by_name( + "group1", + dict(mem=ent.contains_only("user1"))) + ent.assert_group_by_name( + "CamelCaseGroup1", + dict(mem=ent.contains_only("CamelCaseUser1"))) + + output = subprocess.check_output(["sssctl", "group-show", "group1"]) + assert output.find("Name: group1") != -1 + assert output.find("Cached in InfoPipe: No") != -1 + + output = subprocess.check_output(["sssctl", "group-show", + "CamelCaseGroup1"]) + assert output.find("Name: CamelCaseGroup1") != -1 + assert output.find("Cached in InfoPipe: No") != -1 + + output = subprocess.check_output(["sssctl", "group-show", + "camelcasegroup1"]) + assert output.find("Group camelcasegroup1 is not present in cache.") != -1 + + +def test_group_show_basic_fqname(ldap_conn, fqname_rfc2307, portable_LC_ALL): + # Fill the cache first + ent.assert_group_by_name( + "group1@LDAP", + dict(mem=ent.contains_only("user1@LDAP"))) + ent.assert_group_by_name( + "CamelCaseGroup1@LDAP", + dict(mem=ent.contains_only("CamelCaseUser1@LDAP"))) + + output = subprocess.check_output(["sssctl", "group-show", "group1@LDAP"]) + assert output.find("Name: group1@LDAP") != -1 + assert output.find("Cached in InfoPipe: No") != -1 + + output = subprocess.check_output(["sssctl", "group-show", + "CamelCaseGroup1@LDAP"]) + assert output.find("Name: CamelCaseGroup1@LDAP") != -1 + assert output.find("Cached in InfoPipe: No") != -1 + + output = subprocess.check_output(["sssctl", "group-show", + "camelcasegroup1@LDAP"]) + assert output.find("Group camelcasegroup1 is not present in cache.") != -1 + + +def test_group_show_basic_fqname_insensitive(ldap_conn, + fqname_case_insensitive_rfc2307, + portable_LC_ALL): + # Fill the cache first + ent.assert_group_by_name( + "group1@LDAP", + dict(mem=ent.contains_only("user1@LDAP"))) + ent.assert_group_by_name( + "camelcasegroup1@LDAP", + dict(mem=ent.contains_only("camelcaseuser1@LDAP"))) + + output = subprocess.check_output(["sssctl", "group-show", "group1@LDAP"]) + assert output.find("Name: group1@LDAP") != -1 + assert output.find("Cached in InfoPipe: No") != -1 + + output = subprocess.check_output(["sssctl", "group-show", + "CamelCaseGroup1@LDAP"]) + assert output.find("Name: camelcasegroup1@LDAP") != -1 + assert output.find("Cached in InfoPipe: No") != -1 + + output = subprocess.check_output(["sssctl", "group-show", + "camelcasegroup1@LDAP"]) + assert output.find("Name: camelcasegroup1@LDAP") != -1 + assert output.find("Cached in InfoPipe: No") != -1
_______________________________________________ sssd-devel mailing list -- sssd-devel@lists.fedorahosted.org To unsubscribe send an email to sssd-devel-le...@lists.fedorahosted.org