This is an automated email from the git hooks/post-receive script.
firstyear pushed a change to branch master in repository 389-ds-base.
from debe278 Issue #35 - dsconf automember support new 87609c0 Ticket 49474 - Improve GSSAPI testing capability
The 1 revisions listed above as "new" are entirely new to this repository and will be described in separate emails. The revisions listed as "adds" were already present in the repository and have only been added to this reference.
Summary of changes: dirsrvtests/{ => tests/suites/gssapi}/__init__.py | 0 .../tests/suites/gssapi/simple_gssapi_test.py | 147 +++++++++++++++++++++ src/lib389/lib389/__init__.py | 64 +++------ src/lib389/lib389/idm/account.py | 31 +++++ src/lib389/lib389/mit_krb5.py | 19 +-- src/lib389/lib389/properties.py | 1 - src/lib389/lib389/saslmap.py | 54 ++++++++ src/lib389/lib389/tests/krb5_create_test.py | 147 --------------------- src/lib389/lib389/tools.py | 2 +- src/lib389/lib389/topologies.py | 76 ++++++++++- 10 files changed, 332 insertions(+), 209 deletions(-) copy dirsrvtests/{ => tests/suites/gssapi}/__init__.py (100%) create mode 100644 dirsrvtests/tests/suites/gssapi/simple_gssapi_test.py create mode 100644 src/lib389/lib389/saslmap.py delete mode 100644 src/lib389/lib389/tests/krb5_create_test.py
This is an automated email from the git hooks/post-receive script.
firstyear pushed a commit to branch master in repository 389-ds-base.
commit 87609c0a150cbf5db404aa57e8e7ad63e4d222fa Author: William Brown firstyear@redhat.com Date: Wed Nov 29 15:55:12 2017 +0100
Ticket 49474 - Improve GSSAPI testing capability
Bug Description: GSSAPI is difficult to test correctly. Having support for it as a topology in lib389 will mak ethis easier.
Note that these tests require specific dns and hosts settings.
Fix Description: Improve the ability to integrate accounts with principles, bind them with GSSAPI, oru ability to return valid uris with krb realms, our saslmap capabilities and create a single master gssapi topology.
https://pagure.io/389-ds-base/issue/49474
Author: wibrown
Review by: spichugi (Thank you!) --- dirsrvtests/tests/suites/gssapi/__init__.py | 0 .../tests/suites/gssapi/simple_gssapi_test.py | 147 +++++++++++++++++++++ src/lib389/lib389/__init__.py | 64 +++------ src/lib389/lib389/idm/account.py | 31 +++++ src/lib389/lib389/mit_krb5.py | 19 +-- src/lib389/lib389/properties.py | 1 - src/lib389/lib389/saslmap.py | 54 ++++++++ src/lib389/lib389/tests/krb5_create_test.py | 147 --------------------- src/lib389/lib389/tools.py | 2 +- src/lib389/lib389/topologies.py | 76 ++++++++++- 10 files changed, 332 insertions(+), 209 deletions(-)
diff --git a/dirsrvtests/tests/suites/gssapi/__init__.py b/dirsrvtests/tests/suites/gssapi/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dirsrvtests/tests/suites/gssapi/simple_gssapi_test.py b/dirsrvtests/tests/suites/gssapi/simple_gssapi_test.py new file mode 100644 index 0000000..9a881cb --- /dev/null +++ b/dirsrvtests/tests/suites/gssapi/simple_gssapi_test.py @@ -0,0 +1,147 @@ +# --- BEGIN COPYRIGHT BLOCK --- +# Copyright (C) 2017 Red Hat, Inc. +# All rights reserved. +# +# License: GPL (version 3 or any later version). +# See LICENSE for details. +# --- END COPYRIGHT BLOCK --- + +from lib389.topologies import topology_st_gssapi, gssapi_ack +from lib389.idm.user import UserAccounts + +from lib389.saslmap import SaslMappings + +from lib389._constants import DEFAULT_SUFFIX + +import ldap +import subprocess +import os +import pytest + + + +@pytest.fixture(scope='module') +def testuser(topology_st_gssapi): + # Create a user + users = UserAccounts(topology_st_gssapi.standalone, DEFAULT_SUFFIX) + user = users.create(properties={ + 'uid': 'testuser', + 'cn' : 'testuser', + 'sn' : 'user', + 'uidNumber' : '1000', + 'gidNumber' : '2000', + 'homeDirectory' : '/home/testuser' + }) + # Give them a krb princ + user.create_keytab() + return user + +@gssapi_ack +def test_gssapi_bind(topology_st_gssapi, testuser): + """Test that we can bind with GSSAPI + + :id: 894a4c27-3d4c-4ba3-aa33-2910032e3783 + + :setup: standalone gssapi instance + + :steps: + 1. Bind with sasl/gssapi + :expectedresults: + 1. Bind succeeds + + """ + conn = testuser.bind_gssapi() + assert(conn.whoami_s() == "dn: %s" % testuser.dn.lower()) + +@gssapi_ack +def test_invalid_sasl_map(topology_st_gssapi, testuser): + """Test that auth fails when we can not map a user. + + :id: dd4218eb-9237-4611-ba2f-1781391cadd1 + + :setup: standalone gssapi instance + + :steps: + 1. Invalidate a sasl map + 2. Attempt to bind + :expectedresults: + 1. The sasl map is invalid. + 2. The bind fails. + """ + saslmaps = SaslMappings(topology_st_gssapi.standalone) + saslmap = saslmaps.get('suffix map') + saslmap.set('nsSaslMapFilterTemplate', '(invalidattr=\1)') + + with pytest.raises(ldap.INVALID_CREDENTIALS): + conn = testuser.bind_gssapi() + + saslmap.set('nsSaslMapFilterTemplate', '(uid=\1)') + +@gssapi_ack +def test_missing_user(topology_st_gssapi): + """Test that binding with no user does not work. + + :id: 109b5ab8-6556-4222-92d6-398476a50d30 + + :setup: standalone gssapi instance + + :steps: + 1. Create a principal with a name that is not mappable + 2. Attempt to bind + :expectedresults: + 1. The principal is created + 2. The bind fails. + """ + # Make a principal and bind with no user. + st = topology_st_gssapi.standalone + st.realm.create_principal("doesnotexist") + st.realm.create_keytab("doesnotexist", "/tmp/doesnotexist.keytab") + # Now try to bind. + subprocess.call(['/usr/bin/kdestroy', '-A']) + os.environ["KRB5_CLIENT_KTNAME"] = "/tmp/doesnotexist.keytab" + + conn = ldap.initialize(st.toLDAPURL()) + sasltok = ldap.sasl.gssapi() + + with pytest.raises(ldap.INVALID_CREDENTIALS): + conn.sasl_interactive_bind_s('', sasltok) + +@gssapi_ack +def test_support_mech(topology_st_gssapi, testuser): + """Test allowed sasl mechs works when GSSAPI is allowed + + :id: 6ec80aca-00c4-4141-b96b-3ae8837fc751 + + :setup: standalone gssapi instance + + :steps: + 1. Add GSSAPI to allowed sasl mechanisms. + 2. Attempt to bind + :expectedresults: + 1. The allowed mechs are changed. + 2. The bind succeeds. + """ + topology_st_gssapi.standalone.config.set('nsslapd-allowed-sasl-mechanisms', 'GSSAPI EXTERNAL ANONYMOUS') + conn = testuser.bind_gssapi() + assert(conn.whoami_s() == "dn: %s" % testuser.dn.lower()) + +@gssapi_ack +def test_rejected_mech(topology_st_gssapi, testuser): + """Test allowed sasl mechs fail when GSSAPI is not allowed. + + :id: 7896c756-6f65-4390-a844-12e2eec19675 + + :setup: standalone gssapi instance + + :steps: + 1. Add GSSAPI to allowed sasl mechanisms. + 2. Attempt to bind + :expectedresults: + 1. The allowed mechs are changed. + 2. The bind fails. + """ + topology_st_gssapi.standalone.config.set('nsslapd-allowed-sasl-mechanisms', 'EXTERNAL ANONYMOUS') + with pytest.raises(ldap.STRONG_AUTH_NOT_SUPPORTED): + conn = testuser.bind_gssapi() + topology_st_gssapi.standalone.config.set('nsslapd-allowed-sasl-mechanisms', 'GSSAPI EXTERNAL ANONYMOUS') + diff --git a/src/lib389/lib389/__init__.py b/src/lib389/lib389/__init__.py index 6961d1f..fab1ed1 100644 --- a/src/lib389/lib389/__init__.py +++ b/src/lib389/lib389/__init__.py @@ -50,6 +50,8 @@ import subprocess import collections import signal import errno +import pwd +import grp from shutil import copy2 try: # There are too many issues with this on EL7 @@ -390,7 +392,6 @@ class DirSrv(SimpleLDAPObject, object): args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX args_instance[SER_USER_ID] = None args_instance[SER_GROUP_ID] = None - args_instance[SER_REALM] = None args_instance[SER_INST_SCRIPTS_ENABLED] = None
# We allocate a "default" prefix here which allows an un-allocate or @@ -522,7 +523,7 @@ class DirSrv(SimpleLDAPObject, object): self.ldapuri = args.get(SER_LDAP_URL, None) self.log.debug("Allocate %s with %s" % (self.__class__, self.ldapuri)) # Still needed in setup, even if ldapuri over writes. - self.host = args.get(SER_HOST, LOCALHOST) + self.host = args.get(SER_HOST, socket.gethostname()) self.port = args.get(SER_PORT, DEFAULT_PORT) self.sslport = args.get(SER_SECURE_PORT)
@@ -564,9 +565,8 @@ class DirSrv(SimpleLDAPObject, object): # Allocate from the args, or use our env, or use / if args.get(SER_DEPLOYED_DIR, self.prefix) is not None: self.prefix = args.get(SER_DEPLOYED_DIR, self.prefix) - self.realm = args.get(SER_REALM, None) - if self.realm is not None: - self.krb5_realm = MitKrb5(realm=self.realm, debug=self.verbose) + # This will be externally populated in topologies. + self.realm = None
# Those variables needs to be revisited (sroot for 64 bits) # self.sroot = os.path.join(self.prefix, "lib/dirsrv") @@ -596,6 +596,7 @@ class DirSrv(SimpleLDAPObject, object): args_instance[SER_LDAP_URL] = self.ldapuri args_instance[SER_HOST] = self.host args_instance[SER_PORT] = self.port + args_instance[SER_LDAP_URL] = self.ldapuri args_instance[SER_SECURE_PORT] = self.sslport args_instance[SER_SERVERID_PROP] = self.serverid args_standalone = args_instance.copy() @@ -863,7 +864,6 @@ class DirSrv(SimpleLDAPObject, object): SER_GROUP_ID (groupid) SER_DEPLOYED_DIR (prefix) SER_BACKUP_INST_DIR (backupdir) - SER_REALM (krb5_realm)
@return None
@@ -901,17 +901,6 @@ class DirSrv(SimpleLDAPObject, object): prefix=self.prefix) if result != 0: raise Exception('Failed to run setup-ds.pl') - if self.realm is not None: - # This may conflict in some tests, we may need to use /etc/host - # aliases or we may need to use server id - self.krb5_realm.create_principal(principal='ldap/%s' % self.host) - ktab = '%s/ldap.keytab' % (self.ds_paths.config_dir) - self.krb5_realm.create_keytab(principal='ldap/%s' % self.host, keytab=ktab) - with open('%s/dirsrv-%s' % (self.ds_paths.initconfig_dir, self.serverid), 'a') as sfile: - sfile.write("\nKRB5_KTNAME=%s/etc/dirsrv/slapd-%s/" - "ldap.keytab\nexport KRB5_KTNAME\n" % - (self.prefix, self.serverid)) - self.restart()
def _createPythonDirsrv(self, version): """ @@ -953,17 +942,7 @@ class DirSrv(SimpleLDAPObject, object):
# Go! sds.create_from_args(general, slapd, backends, None) - if self.realm is not None: - # This may conflict in some tests, we may need to use /etc/host - # aliases or we may need to use server id - self.krb5_realm.create_principal(principal='ldap/%s' % self.host) - ktab = '%s/ldap.keytab' % (self.ds_paths.config_dir) - self.krb5_realm.create_keytab(principal='ldap/%s' % self.host, keytab=ktab) - with open('%s/dirsrv-%s' % (self.ds_paths.initconfig_dir, self.serverid), 'a') as sfile: - sfile.write("\nKRB5_KTNAME=%s/etc/dirsrv/slapd-%s/" - "ldap.keytab\nexport KRB5_KTNAME\n" % - (self.prefix, self.serverid)) - self.restart() +
def create(self, pyinstall=False, version=INSTALL_LATEST_CONFIG): """ @@ -1144,28 +1123,20 @@ class DirSrv(SimpleLDAPObject, object): if starttls and not uri.startswith('ldaps'): self.start_tls_s()
- if saslmethod and saslmethod.lower() == 'gssapi': + if saslmethod and sasltoken is not None: + # Just pass the sasltoken in! + self.sasl_interactive_bind_s("", sasltoken) + elif saslmethod and saslmethod.lower() == 'gssapi': """ Perform kerberos/gssapi authentication """ - try: - sasl_auth = ldap.sasl.gssapi("") - self.sasl_interactive_bind_s("", sasl_auth) - except ldap.LOCAL_ERROR as e: - # No Ticket - ultimately invalid credentials - self.log.debug("Error: No Ticket (%s)" % str(e)) - raise ldap.INVALID_CREDENTIALS - except ldap.LDAPError as e: - self.log.debug("SASL/GSSAPI Bind Failed: %s" % str(e)) - raise e + sasl_auth = ldap.sasl.gssapi("") + self.sasl_interactive_bind_s("", sasl_auth)
elif saslmethod == 'EXTERNAL': # Do nothing. sasl_auth = ldap.sasl.external() self.sasl_interactive_bind_s("", sasl_auth) - elif saslmethod and sasltoken is not None: - # Just pass the sasltoken in! - self.sasl_interactive_bind_s("", sasltoken) elif saslmethod: # Unknown or unsupported method self.log.debug('Unsupported SASL method: %s' % saslmethod) @@ -1651,7 +1622,8 @@ class DirSrv(SimpleLDAPObject, object): return self.ldapuri elif self.ldapi_enabled == 'on' and self.ldapi_socket is not None: return "ldapi://%s" % (ldapurl.ldapUrlEscape(ensure_str(ldapi_socket))) - elif self.sslport: + elif self.sslport and not self.realm: + # Gssapi can't use SSL so we have to nuke it here. return "ldaps://%s:%d/" % (ensure_str(self.host), self.sslport) else: return "ldap://%s:%d/" % (ensure_str(self.host), self.port) @@ -1772,6 +1744,12 @@ class DirSrv(SimpleLDAPObject, object): def get_ldapi_path(self): return self.ds_paths.ldapi
+ def get_user_uid(self): + return pwd.getpwnam(self.ds_paths.user).pw_uid + + def get_group_gid(self): + return grp.getgrnam(self.ds_paths.group).gr_gid + def has_asan(self): return self.ds_paths.asan_enabled
diff --git a/src/lib389/lib389/idm/account.py b/src/lib389/lib389/idm/account.py index 02c2954..92038bf 100644 --- a/src/lib389/lib389/idm/account.py +++ b/src/lib389/lib389/idm/account.py @@ -9,6 +9,8 @@ from lib389._mapped_object import DSLdapObject, DSLdapObjects, _gen_or, _gen_filter, _term_gen from lib389._constants import SER_ROOT_DN, SER_ROOT_PW
+import os +import subprocess
class Account(DSLdapObject): """A single instance of Account entry @@ -62,6 +64,35 @@ class Account(DSLdapObject): inst_clone.open(*args, **kwargs) return inst_clone
+ def create_keytab(self): + """ + Create a keytab for this account valid to bind with. + """ + assert self._instance.realm is not None + + myuid = self.get_attr_val_utf8('uid') + self._instance.realm.create_principal(myuid) + self._instance.realm.create_keytab(myuid, "/tmp/%s.keytab" % myuid) + + self._keytab = "/tmp/%s.keytab" % myuid + + def bind_gssapi(self): + """ + Bind this account with gssapi credntials (if available) + """ + assert self._instance.realm is not None + # Kill any local ccache. + subprocess.call(['/usr/bin/kdestroy', '-A']) + + # This uses an in memory once off ccache. + os.environ["KRB5_CLIENT_KTNAME"] = self._keytab + + # Because of the way that GSSAPI works, we can't + # use the normal dirsrv open method. + inst_clone = self._instance.clone() + inst_clone.open(saslmethod='gssapi') + return inst_clone + class Accounts(DSLdapObjects): """DSLdapObjects that represents Account entry
diff --git a/src/lib389/lib389/mit_krb5.py b/src/lib389/lib389/mit_krb5.py index 64ca24d..fe37387 100644 --- a/src/lib389/lib389/mit_krb5.py +++ b/src/lib389/lib389/mit_krb5.py @@ -108,6 +108,9 @@ class MitKrb5(object): realm = self.realm lrealm = self.realm.lower() cfile.write(""" +[libdefaults] + default_realm = {REALM} + [realms] {REALM} = {{ kdc = {HOST} @@ -130,12 +133,11 @@ class MitKrb5(object):
[realms] {REALM} = {{ - #master_key_type = aes256-cts acl_file = {PREFIX}/var/kerberos/krb5kdc/kadm5.acl dict_file = /usr/share/dict/words admin_keytab = {PREFIX}/var/kerberos/krb5kdc/kadm5.keytab # Just use strong enctypes - supported_enctypes = aes256-cts:normal aes128-cts:normal + # supported_enctypes = aes256-cts:normal aes128-cts:normal }}
""".format(REALM=self.realm, PREFIX=self.krb_prefix)) @@ -170,7 +172,7 @@ class MitKrb5(object):
p = Popen([self.kdb5_util, 'destroy', '-r', self.realm], env=self.krb_env, stdin=PIPE) - p.communicate("yes\n") + p.communicate(b"yes\n") p.wait() assert(p.returncode == 0) # Should we clean up the configurations we made too? @@ -213,14 +215,3 @@ class MitKrb5(object): (keytab, principal, self.realm)]) assert(p.wait() == 0)
- -class KrbClient(object): - def __init__(self, principal, keytab, ccache=None): - self.krb_prefix = "" - self.kdestroy = "/usr/bin/kdestroy" - if ccache is not None: - os.environ["KRB5CCNAME"] = ccache - # Destroy the previous cache if any. - subprocess.call(self.kdestroy) - # Gssapi has magic that automatically creates things by env vars - os.environ["KRB5_CLIENT_KTNAME"] = keytab diff --git a/src/lib389/lib389/properties.py b/src/lib389/lib389/properties.py index 2a9e174..e986aea 100644 --- a/src/lib389/lib389/properties.py +++ b/src/lib389/lib389/properties.py @@ -44,7 +44,6 @@ SER_PROPNAME_TO_ATTRNAME = {SER_HOST: 'nsslapd-localhost', # # Those WITHOUT related attribute name # -SER_REALM = 'krb5_realm' SER_SERVERID_PROP = 'server-id' SER_GROUP_ID = 'group-id' SER_DEPLOYED_DIR = 'deployed-dir' diff --git a/src/lib389/lib389/saslmap.py b/src/lib389/lib389/saslmap.py new file mode 100644 index 0000000..3105f2e --- /dev/null +++ b/src/lib389/lib389/saslmap.py @@ -0,0 +1,54 @@ +# --- BEGIN COPYRIGHT BLOCK --- +# Copyright (C) 2016 Red Hat, Inc. +# All rights reserved. +# +# License: GPL (version 3 or any later version). +# See LICENSE for details. +# --- END COPYRIGHT BLOCK --- + +from lib389._mapped_object import DSLdapObject, DSLdapObjects + +class SaslMapping(DSLdapObject): + """A sasl map providing a link from a sasl user and realm + to a valid directory server entry. + + :param instance: An instance + :type instance: lib389.DirSrv + :param dn: Entry DN + :type dn: str + """ + + def __init__(self, instance, dn=None): + super(SaslMapping, self).__init__(instance, dn) + self._rdn_attribute = 'cn' + self._must_attributes = [ + 'cn', + 'nsSaslMapRegexString', + 'nsSaslMapBaseDNTemplate', + 'nsSaslMapFilterTemplate', + ] + self._create_objectclasses = [ + 'top', + 'nsSaslMapping', + ] + self._protected = False + +class SaslMappings(DSLdapObjects): + """DSLdapObjects that represents SaslMappings in the server. + + :param instance: An instance + :type instance: lib389.DirSrv + :param basedn: Base DN for all group entries below + :type basedn: str + """ + + def __init__(self, instance): + super(SaslMappings, self).__init__(instance) + self._objectclasses = [ + 'nsSaslMapping', + ] + self._filterattrs = ['cn'] + self._childobject = SaslMapping + self._basedn = 'cn=mapping,cn=sasl,cn=config' + + diff --git a/src/lib389/lib389/tests/krb5_create_test.py b/src/lib389/lib389/tests/krb5_create_test.py deleted file mode 100644 index 182d51f..0000000 --- a/src/lib389/lib389/tests/krb5_create_test.py +++ /dev/null @@ -1,147 +0,0 @@ - -# --- BEGIN COPYRIGHT BLOCK --- -# Copyright (C) 2015 Red Hat, Inc. -# All rights reserved. -# -# License: GPL (version 3 or any later version). -# See LICENSE for details. -# --- END COPYRIGHT BLOCK --- -# -from lib389._constants import * -from lib389.mit_krb5 import MitKrb5, KrbClient -from lib389 import DirSrv, Entry -import pytest -import logging -import socket -import subprocess - -import ldap -import ldap.sasl - -logging.getLogger(__name__).setLevel(logging.DEBUG) -log = logging.getLogger(__name__) - -INSTANCE_PORT = 54321 -INSTANCE_SERVERID = 'standalone' -REALM = "EXAMPLE.COM" -TEST_USER = 'uid=test,%s' % DEFAULT_SUFFIX - -KEYTAB = "/tmp/test.keytab" -CCACHE = "FILE:/tmp/test.ccache" - - -class TopologyInstance(object): - def __init__(self, instance): - instance.open() - self.instance = instance - - -@pytest.fixture(scope="module") -def topology(request): - # Create the realm - krb = MitKrb5(realm=REALM) - instance = DirSrv(verbose=False) - instance.log.debug("Instance allocated") - # WARNING: If this test fails it's like a hostname issue!!! - args = {SER_HOST: socket.gethostname(), - SER_PORT: INSTANCE_PORT, - SER_REALM: REALM, - SER_SERVERID_PROP: INSTANCE_SERVERID} - instance.allocate(args) - if instance.exists(): - instance.delete() - # Its likely our realm exists too - # Remove the old keytab - if os.path.exists(KEYTAB): - os.remove(KEYTAB) - if krb.check_realm(): - krb.destroy_realm() - # This will automatically create the krb entries - krb.create_realm() - instance.create() - instance.open() - - def fin(): - if instance.exists(): - instance.delete() - if krb.check_realm(): - krb.destroy_realm() - if os.path.exists(KEYTAB): - os.remove(KEYTAB) - if os.path.exists(CCACHE): - os.remove(CCACHE) - request.addfinalizer(fin) - - return TopologyInstance(instance) - - -@pytest.fixture(scope="module") -def add_user(topology): - """ - Create a user entry - """ - - log.info('Create a user entry: %s' % TEST_USER) - uentry = Entry(TEST_USER) - uentry.setValues('objectclass', 'top', 'extensibleobject') - uentry.setValues('uid', 'test') - topology.instance.add_s(uentry) - # This doesn't matter that we re-open the realm - krb = MitKrb5(realm=REALM) - krb.create_principal("test") - # We extract the kt so we can kinit from it - krb.create_keytab("test", "/tmp/test.keytab") - - -def test_gssapi(topology, add_user): - """ - Check that our bind completese with ldapwhoami correctly mapped from - the principal to our test user object. - """ - # Init our local ccache - kclient = KrbClient("test@%s" % REALM, KEYTAB, CCACHE) - # Probably need to change this to NOT be raw python ldap - # conn = ldap.initialize("ldap://%s:%s" % (LOCALHOST, INSTANCE_PORT)) - conn = ldap.initialize("ldap://%s:%s" % (socket.gethostname(), INSTANCE_PORT)) - sasl = ldap.sasl.gssapi("test@%s" % REALM) - try: - conn.sasl_interactive_bind_s('', sasl) - except Exception as e: - try: - print("%s" % subprocess.check_output(['klist'])) - except Exception as ex: - print("%s" % ex) - print("%s" % os.environ) - print("IF THIS TEST FAILS ITS LIKELY A HOSTNAME ISSUE") - raise e - assert(conn.whoami_s() == "dn: uid=test,dc=example,dc=com") - - print("Error case 1. Broken Kerberos uid mapping") - uidmapping = 'cn=Kerberos uid mapping,cn=mapping,cn=sasl,cn=config' - topology.instance.modify_s(uidmapping, [(ldap.MOD_REPLACE, 'nsSaslMapFilterTemplate', '(cn=\1)')]) - conn0 = ldap.initialize("ldap://%s:%s" % (socket.gethostname(), INSTANCE_PORT)) - try: - conn0.sasl_interactive_bind_s('', sasl) - except Exception as e: - print("Exception (expected): %s" % type(e).__name__) - print('Desc ' + str(e['desc'])) - assert isinstance(e, ldap.INVALID_CREDENTIALS) - - # undo - topology.instance.modify_s(uidmapping, [(ldap.MOD_REPLACE, 'nsSaslMapFilterTemplate', '(uid=\1)')]) - - print("Error case 2. Delete %s from DS" % TEST_USER) - topology.instance.delete_s(TEST_USER) - try: - conn0.sasl_interactive_bind_s('', sasl) - except Exception as e: - print("Exception (expected): %s" % type(e).__name__) - print('Desc ' + str(e['desc'])) - assert isinstance(e, ldap.INVALID_CREDENTIALS) - - print("SUCCESS") - - -if __name__ == "__main__": - CURRENT_FILE = os.path.realpath(__file__) - pytest.main("-s -v %s" % CURRENT_FILE) diff --git a/src/lib389/lib389/tools.py b/src/lib389/lib389/tools.py index edb95b1..f0f4b1c 100644 --- a/src/lib389/lib389/tools.py +++ b/src/lib389/lib389/tools.py @@ -857,7 +857,7 @@ class DirSrvTools(object): for line in hostfp.readlines(): if ipPattern is None: words = line.split() - if words[1] == expectedHost: + if len(words) >= 2 and words[1] == expectedHost: return True else: if line.find(ipPattern) >= 0: diff --git a/src/lib389/lib389/topologies.py b/src/lib389/lib389/topologies.py index 068a24a..ae64828 100644 --- a/src/lib389/lib389/topologies.py +++ b/src/lib389/lib389/topologies.py @@ -10,13 +10,19 @@ import os import logging import time
+# For hostname detection for GSSAPI tests +import socket + import pytest
from lib389 import DirSrv from lib389.nss_ssl import NssSsl from lib389.utils import generate_ds_params from lib389.replica import Replicas -from lib389._constants import (args_instance, SER_HOST, SER_PORT, SER_SERVERID_PROP, SER_CREATION_SUFFIX, +from lib389.mit_krb5 import MitKrb5 +from lib389.saslmap import SaslMappings + +from lib389._constants import (SER_HOST, SER_PORT, SER_SERVERID_PROP, SER_CREATION_SUFFIX, SER_SECURE_PORT, ReplicaRole, DEFAULT_SUFFIX, REPLICA_ID, SER_LDAP_URL)
@@ -61,7 +67,8 @@ def create_topology(topo_dict): # Also, we need to keep in mind that the function returns # SER_SECURE_PORT and REPLICA_ID that are not used in # the instance creation here. - args_instance[SER_HOST] = instance_data[SER_HOST] + # args_instance[SER_HOST] = instance_data[SER_HOST] + args_instance = {} args_instance[SER_PORT] = instance_data[SER_PORT] args_instance[SER_SECURE_PORT] = instance_data[SER_SECURE_PORT] args_instance[SER_SERVERID_PROP] = instance_data[SER_SERVERID_PROP] @@ -198,6 +205,68 @@ def topology_st(request):
return topology
+gssapi_ack = pytest.mark.skipif(not os.environ.get('GSSAPI_ACK', False), reason="GSSAPI tests may damage system configuration.") + +@pytest.fixture(scope="module") +def topology_st_gssapi(request): + """Create a DS standalone instance with GSSAPI enabled. + + This will alter the instance to remove the secure port, to allow + GSSAPI to function. + """ + hostname = socket.gethostname().split('.', 1) + + # Assert we have a domain setup in some kind. + assert len(hostname) == 2 + + REALM = hostname[1].upper() + + topology = create_topology({ReplicaRole.STANDALONE: 1}) + + # Fix the hostname. + topology.standalone.host = socket.gethostname() + + krb = MitKrb5(realm=REALM, debug=DEBUGGING) + + # Destroy existing realm. + if krb.check_realm(): + krb.destroy_realm() + krb.create_realm() + + # Now add krb to our instance. + krb.create_principal(principal='ldap/%s' % topology.standalone.host) + krb.create_keytab(principal='ldap/%s' % topology.standalone.host, keytab='/etc/krb5.keytab') + os.chown('/etc/krb5.keytab', topology.standalone.get_user_uid(), topology.standalone.get_group_gid()) + + # Add sasl mappings + saslmappings = SaslMappings(topology.standalone) + saslmappings.create(properties={ + 'cn': 'suffix map', + # Don't add the realm due to a SASL bug + # 'nsSaslMapRegexString': '\(.*\)@%s' % self.realm, + 'nsSaslMapRegexString': '\(.*\)', + 'nsSaslMapBaseDNTemplate': topology.standalone.creation_suffix, + 'nsSaslMapFilterTemplate': '(uid=\1)' + }) + topology.standalone.realm = krb + + topology.standalone.config.set('nsslapd-localhost', topology.standalone.host) + + topology.standalone.sslport = None + + topology.standalone.restart() + + def fin(): + if DEBUGGING: + topology.standalone.stop() + else: + topology.standalone.delete() + krb.destroy_realm() + + request.addfinalizer(fin) + + return topology +
@pytest.fixture(scope="module") def topology_i2(request): @@ -338,7 +407,8 @@ def topology_m1h1c1(request): instance = DirSrv(verbose=True) else: instance = DirSrv(verbose=False) - args_instance[SER_HOST] = instance_data[SER_HOST] + args_instance = {} + # args_instance[SER_HOST] = instance_data[SER_HOST] args_instance[SER_PORT] = instance_data[SER_PORT] args_instance[SER_SECURE_PORT] = instance_data[SER_SECURE_PORT] args_instance[SER_SERVERID_PROP] = instance_data[SER_SERVERID_PROP]
389-commits@lists.fedoraproject.org