summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimo Sorce <simo@redhat.com>2015-06-22 20:57:26 -0400
committerSimo Sorce <simo@redhat.com>2015-06-22 20:57:26 -0400
commit66d6bdf31f897f460bae7b9d919b3f02b48e7ef1 (patch)
tree7f37f82083ccf64e0b1d2e177d375ac553c76180
parenta0cfc1b357998166773d3da36c1fe98ad0ea7d94 (diff)
downloadmod_auth_gssapi-66d6bdf31f897f460bae7b9d919b3f02b48e7ef1.tar.gz
mod_auth_gssapi-66d6bdf31f897f460bae7b9d919b3f02b48e7ef1.tar.xz
mod_auth_gssapi-66d6bdf31f897f460bae7b9d919b3f02b48e7ef1.zip
Add initial test framework
Requires various python packages nd the cwrap project's scoket_wrapper and nss_wrapper tools, as well as the krb5kdc and the httpd server and related modules (like mod_session). Signed-off-by: Simo Sorce <simo@redhat.com>
-rw-r--r--tests/httpd.conf134
-rw-r--r--tests/index.html1
-rwxr-xr-xtests/magtests.py297
-rwxr-xr-xtests/t_spnego.py14
4 files changed, 446 insertions, 0 deletions
diff --git a/tests/httpd.conf b/tests/httpd.conf
new file mode 100644
index 0000000..517203f
--- /dev/null
+++ b/tests/httpd.conf
@@ -0,0 +1,134 @@
+ServerRoot "${HTTPROOT}"
+ServerName "${HTTPNAME}"
+Listen ${HTTPADDR}:${HTTPPORT}
+
+LoadModule access_compat_module modules/mod_access_compat.so
+LoadModule actions_module modules/mod_actions.so
+LoadModule alias_module modules/mod_alias.so
+LoadModule allowmethods_module modules/mod_allowmethods.so
+LoadModule auth_basic_module modules/mod_auth_basic.so
+#LoadModule auth_digest_module modules/mod_auth_digest.so
+LoadModule authn_anon_module modules/mod_authn_anon.so
+LoadModule authn_core_module modules/mod_authn_core.so
+LoadModule authn_dbd_module modules/mod_authn_dbd.so
+LoadModule authn_dbm_module modules/mod_authn_dbm.so
+LoadModule authn_file_module modules/mod_authn_file.so
+LoadModule authn_socache_module modules/mod_authn_socache.so
+LoadModule authz_core_module modules/mod_authz_core.so
+LoadModule authz_dbd_module modules/mod_authz_dbd.so
+LoadModule authz_dbm_module modules/mod_authz_dbm.so
+LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
+LoadModule authz_host_module modules/mod_authz_host.so
+LoadModule authz_owner_module modules/mod_authz_owner.so
+LoadModule authz_user_module modules/mod_authz_user.so
+LoadModule autoindex_module modules/mod_autoindex.so
+LoadModule cache_module modules/mod_cache.so
+LoadModule cache_disk_module modules/mod_cache_disk.so
+LoadModule data_module modules/mod_data.so
+LoadModule dbd_module modules/mod_dbd.so
+LoadModule deflate_module modules/mod_deflate.so
+LoadModule dir_module modules/mod_dir.so
+LoadModule dumpio_module modules/mod_dumpio.so
+LoadModule echo_module modules/mod_echo.so
+LoadModule env_module modules/mod_env.so
+LoadModule expires_module modules/mod_expires.so
+LoadModule ext_filter_module modules/mod_ext_filter.so
+LoadModule filter_module modules/mod_filter.so
+LoadModule headers_module modules/mod_headers.so
+LoadModule include_module modules/mod_include.so
+LoadModule info_module modules/mod_info.so
+LoadModule log_config_module modules/mod_log_config.so
+LoadModule logio_module modules/mod_logio.so
+LoadModule macro_module modules/mod_macro.so
+LoadModule mime_magic_module modules/mod_mime_magic.so
+LoadModule mime_module modules/mod_mime.so
+LoadModule negotiation_module modules/mod_negotiation.so
+LoadModule remoteip_module modules/mod_remoteip.so
+LoadModule reqtimeout_module modules/mod_reqtimeout.so
+LoadModule rewrite_module modules/mod_rewrite.so
+LoadModule session_module modules/mod_session.so
+LoadModule session_cookie_module modules/mod_session_cookie.so
+LoadModule setenvif_module modules/mod_setenvif.so
+LoadModule slotmem_plain_module modules/mod_slotmem_plain.so
+LoadModule slotmem_shm_module modules/mod_slotmem_shm.so
+LoadModule socache_dbm_module modules/mod_socache_dbm.so
+LoadModule socache_memcache_module modules/mod_socache_memcache.so
+LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
+LoadModule status_module modules/mod_status.so
+LoadModule substitute_module modules/mod_substitute.so
+LoadModule suexec_module modules/mod_suexec.so
+LoadModule unique_id_module modules/mod_unique_id.so
+LoadModule unixd_module modules/mod_unixd.so
+LoadModule userdir_module modules/mod_userdir.so
+LoadModule version_module modules/mod_version.so
+LoadModule vhost_alias_module modules/mod_vhost_alias.so
+
+LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
+
+LoadModule auth_gssapi_module mod_auth_gssapi.so
+
+
+<Directory />
+ AllowOverride none
+ Require all denied
+</Directory>
+
+DocumentRoot "${HTTPROOT}/html"
+<Directory "${HTTPROOT}">
+ AllowOverride None
+ # Allow open access:
+ Require all granted
+</Directory>
+<Directory "${HTTPROOT}/html">
+ Options Indexes FollowSymLinks
+ AllowOverride None
+ Require all granted
+</Directory>
+
+<IfModule dir_module>
+ DirectoryIndex index.html
+</IfModule>
+
+<Files ".ht*">
+ Require all denied
+</Files>
+
+PidFile "${HTTPROOT}/logs/httpd.pid"
+
+<IfModule log_config_module>
+LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
+CustomLog "logs/access_log" combined
+</IfModule>
+
+ErrorLog "logs/error_log"
+LogLevel debug
+
+<IfModule mime_module>
+ TypesConfig /etc/mime.types
+ AddType application/x-compress .Z
+ AddType application/x-gzip .gz .tgz
+ AddType text/html .shtml
+ AddOutputFilter INCLUDES .shtml
+</IfModule>
+
+AddDefaultCharset UTF-8
+
+IncludeOptional conf.d/*.conf
+
+CoreDumpDirectory /tmp
+
+<Location /spnego>
+ AuthType GSSAPI
+ AuthName "Login"
+ GssapiSSLonly Off
+ GssapiUseSessions On
+ Session On
+ SessionCookieName gssapi_session path=/spnego;httponly
+ GssapiCredStore ccache:${HTTPROOT}/tmp/httpd_krb5_ccache
+ GssapiCredStore client_keytab:${HTTPROOT}/http.keytab
+ GssapiCredStore keytab:${HTTPROOT}/http.keytab
+ GssapiBasicAuth Off
+ GssapiAllowedMech krb5
+ Require valid-user
+</Location>
+
diff --git a/tests/index.html b/tests/index.html
new file mode 100644
index 0000000..c5ad10e
--- /dev/null
+++ b/tests/index.html
@@ -0,0 +1 @@
+WORKS
diff --git a/tests/magtests.py b/tests/magtests.py
new file mode 100755
index 0000000..4d4cb49
--- /dev/null
+++ b/tests/magtests.py
@@ -0,0 +1,297 @@
+#!/usr/bin/python
+# Copyright (C) 2015 - mod_auth_gssapi contributors, see COPYING for license.
+
+import argparse
+import glob
+import os
+import random
+import shutil
+import signal
+from string import Template
+import subprocess
+import sys
+import time
+
+
+def parse_args():
+ parser = argparse.ArgumentParser(description='Mod Auth GSSAPI Tests Environment')
+ parser.add_argument('--path', default='%s/scratchdir' % os.getcwd(),
+ help="Directory in which tests are run")
+
+ return vars(parser.parse_args())
+
+
+WRAP_HOSTNAME = "kdc.mag.dev"
+WRAP_IPADDR = '127.0.0.9'
+
+def setup_wrappers(base):
+
+ pkgcfg = subprocess.Popen(['pkg-config', '--exists', 'socket_wrapper'])
+ pkgcfg.wait()
+ if pkgcfg.returncode != 0:
+ raise ValueError('Socket Wrappers not available')
+
+ pkgcfg = subprocess.Popen(['pkg-config', '--exists', 'nss_wrapper'])
+ pkgcfg.wait()
+ if pkgcfg.returncode != 0:
+ raise ValueError('Socket Wrappers not available')
+
+ wrapdir = os.path.join(base, 'wrapdir')
+ if not os.path.exists(wrapdir):
+ os.makedirs(wrapdir)
+
+ hosts_file = os.path.join(testdir, 'hosts')
+ with open(hosts_file, 'w+') as f:
+ f.write('%s %s' % (WRAP_IPADDR, WRAP_HOSTNAME))
+
+ wenv = {'LD_PRELOAD': 'libsocket_wrapper.so libnss_wrapper.so',
+ 'SOCKET_WRAPPER_DIR': wrapdir,
+ 'SOCKET_WRAPPER_DEFAULT_IFACE': '9',
+ 'NSS_WRAPPER_HOSTNAME': WRAP_HOSTNAME,
+ 'NSS_WRAPPER_HOSTS': hosts_file}
+
+ return wenv
+
+
+TESTREALM = "MAG.DEV"
+KDC_DBNAME = 'db.file'
+KDC_STASH = 'stash.file'
+KDC_PASSWORD = 'modauthgssapi'
+KRB5_CONF_TEMPLATE = '''
+[libdefaults]
+ default_realm = ${TESTREALM}
+ dns_lookup_realm = false
+ dns_lookup_kdc = false
+ rdns = false
+ ticket_lifetime = 24h
+ forwardable = yes
+ default_ccache_name = FILE://${TESTDIR}/ccaches/krb5_ccache_XXXXXX
+
+[realms]
+ ${TESTREALM} = {
+ kdc =${WRAP_HOSTNAME}
+ }
+
+[domain_realm]
+ .mag.dev = MAG.DEV
+ mag.dev = MAG.DEV
+
+[dbmodules]
+ ${TESTREALM} = {
+ database_name = ${KDCDIR}/${KDC_DBNAME}
+ }
+'''
+KDC_CONF_TEMPLATE = '''
+[kdcdefaults]
+ kdc_ports = 88
+ kdc_tcp_ports = 88
+ restrict_anonymous_to_tgt = true
+
+[realms]
+ ${TESTREALM} = {
+ master_key_type = aes256-cts
+ max_life = 7d
+ max_renewable_life = 14d
+ acl_file = ${KDCDIR}/kadm5.acl
+ dict_file = /usr/share/dict/words
+ default_principal_flags = +preauth
+ admin_keytab = ${TESTREALM}/kadm5.keytab
+ key_stash_file = ${KDCDIR}/${KDC_STASH}
+ }
+[logging]
+ kdc = FILE:${KDCLOG}
+'''
+
+
+def setup_kdc(testdir, wrapenv):
+
+ # setup kerberos environment
+ testlog = os.path.join(testdir, 'kerb.log')
+ krb5conf = os.path.join(testdir, 'krb5.conf')
+ kdcconf = os.path.join(testdir, 'kdc.conf')
+ kdcdir = os.path.join(testdir, 'kdc')
+ kdcstash = os.path.join(kdcdir, KDC_STASH)
+ kdcdb = os.path.join(kdcdir, KDC_DBNAME)
+ if os.path.exists(kdcdir):
+ shutil.rmtree(kdcdir)
+ os.makedirs(kdcdir)
+
+ t = Template(KRB5_CONF_TEMPLATE)
+ text = t.substitute({'TESTREALM': TESTREALM,
+ 'TESTDIR': testdir,
+ 'KDCDIR': kdcdir,
+ 'KDC_DBNAME': KDC_DBNAME,
+ 'WRAP_HOSTNAME': WRAP_HOSTNAME})
+ with open(krb5conf, 'w+') as f:
+ f.write(text)
+
+ t = Template(KDC_CONF_TEMPLATE)
+ text = t.substitute({'TESTREALM': TESTREALM,
+ 'KDCDIR': kdcdir,
+ 'KDCLOG': testlog,
+ 'KDC_STASH': KDC_STASH})
+ with open(kdcconf, 'w+') as f:
+ f.write(text)
+
+ kdcenv = {'PATH': '/sbin:/bin:/usr/sbin:/usr/bin',
+ 'KRB5_CONFIG': krb5conf,
+ 'KRB5_KDC_PROFILE': kdcconf}
+ kdcenv.update(wrapenv)
+
+ with (open(testlog, 'a')) as logfile:
+ ksetup = subprocess.Popen(["kdb5_util", "create", "-s",
+ "-r", TESTREALM, "-P", KDC_PASSWORD],
+ stdout=logfile, stderr=logfile,
+ env=kdcenv, preexec_fn=os.setsid)
+ ksetup.wait()
+ if ksetup.returncode != 0:
+ raise ValueError('KDC Setup failed')
+
+ with (open(testlog, 'a')) as logfile:
+ kdcproc = subprocess.Popen(['krb5kdc', '-n'],
+ stdout=logfile, stderr=logfile,
+ env=kdcenv, preexec_fn=os.setsid)
+
+ return kdcproc, kdcenv
+
+
+def kadmin_local(cmd, env, logfile):
+ ksetup = subprocess.Popen(["kadmin.local", "-q", cmd],
+ stdout=logfile, stderr=logfile,
+ env=env, preexec_fn=os.setsid)
+ ksetup.wait()
+ if ksetup.returncode != 0:
+ raise ValueError('Kadmin local [%s] failed' % cmd)
+
+
+USR_NAME = "maguser"
+USR_PWD = "magpwd"
+SVC_KTNAME = "httpd/http.keytab"
+KEY_TYPE = "aes256-cts-hmac-sha1-96:normal"
+
+
+def setup_keys(tesdir, env):
+
+ testlog = os.path.join(testdir, 'kerb.log')
+
+ svc_name = "HTTP/%s" % WRAP_HOSTNAME
+ svc_keytab = os.path.join(testdir, SVC_KTNAME)
+ cmd = "addprinc -randkey -e %s %s" % (KEY_TYPE, svc_name)
+ with (open(testlog, 'a')) as logfile:
+ kadmin_local(cmd, env, logfile)
+ cmd = "ktadd -k %s -e %s %s" % (svc_keytab, KEY_TYPE, svc_name)
+ with (open(testlog, 'a')) as logfile:
+ kadmin_local(cmd, env, logfile)
+
+ cmd = "addprinc -pw %s -e %s %s" % (USR_PWD, KEY_TYPE, USR_NAME)
+ with (open(testlog, 'a')) as logfile:
+ kadmin_local(cmd, env, logfile)
+
+ keys_env = { "KRB5_KTNAME": svc_keytab }
+ keys_env.update(env)
+
+ return keys_env
+
+
+def setup_http(testdir, wrapenv):
+
+ httpdir = os.path.join(testdir, 'httpd')
+ if os.path.exists(httpdir):
+ shutil.rmtree(httpdir)
+ os.makedirs(httpdir)
+ os.mkdir(os.path.join(httpdir, 'conf.d'))
+ os.mkdir(os.path.join(httpdir, 'html'))
+ os.mkdir(os.path.join(httpdir, 'logs'))
+ os.symlink('/etc/httpd/modules', os.path.join(httpdir, 'modules'))
+
+ shutil.copy('src/.libs/mod_auth_gssapi.so', httpdir)
+
+ with open('tests/httpd.conf') as f:
+ t = Template(f.read())
+ text = t.substitute({'HTTPROOT': httpdir,
+ 'HTTPNAME': WRAP_HOSTNAME,
+ 'HTTPADDR': WRAP_IPADDR,
+ 'HTTPPORT': '80'})
+ config = os.path.join(httpdir, 'httpd.conf')
+ with open(config, 'w+') as f:
+ f.write(text)
+
+ httpenv = {'PATH': '/sbin:/bin:/usr/sbin:/usr/bin',
+ 'MALLOC_CHECK_': '3',
+ 'MALLOC_PERTURB_': str(random.randint(0, 32767) % 255 + 1)}
+ httpenv.update(wrapenv)
+
+ httpproc = subprocess.Popen(['httpd', '-DFOREGROUND', '-f', config],
+ env=httpenv, preexec_fn=os.setsid)
+
+ return httpproc
+
+
+def kinit_user(testdir, kdcenv):
+ testlog = os.path.join(testdir, 'kinit.log')
+ ccache = os.path.join(testdir, 'k5ccache')
+ testenv = {'KRB5CCNAME': ccache}
+ testenv.update(kdcenv)
+
+ with (open(testlog, 'a')) as logfile:
+ kinit = subprocess.Popen(["kinit", USR_NAME],
+ stdin=subprocess.PIPE,
+ stdout=logfile, stderr=logfile,
+ env=testenv, preexec_fn=os.setsid)
+ kinit.communicate('%s\n' % USR_PWD)
+ kinit.wait()
+ if kinit.returncode != 0:
+ raise ValueError('kinit failed')
+
+ return testenv
+
+
+def test_spnego_auth(testdir, testenv, testlog):
+
+ spnegodir = os.path.join(testdir, 'httpd', 'html', 'spnego')
+ os.mkdir(spnegodir)
+ shutil.copy('tests/index.html', spnegodir)
+
+ with (open(testlog, 'a')) as logfile:
+ spnego = subprocess.Popen(["tests/t_spnego.py"],
+ stdout=logfile, stderr=logfile,
+ env=testenv, preexec_fn=os.setsid)
+ spnego.wait()
+ if spnego.returncode != 0:
+ sys.stderr.write('SPNEGO: FAILED\n')
+ else:
+ sys.stderr.write('SPNEGO: SUCCESS\n')
+
+
+if __name__ == '__main__':
+
+ args = parse_args()
+
+ testdir = args['path']
+ if os.path.exists(testdir):
+ shutil.rmtree(testdir)
+ os.makedirs(testdir)
+
+ processes = dict()
+
+ testlog = os.path.join(testdir, 'tests.log')
+
+ try:
+ wrapenv = setup_wrappers(testdir)
+
+ kdcproc, kdcenv = setup_kdc(testdir, wrapenv)
+ processes['KDC(%d)' % kdcproc.pid] = kdcproc
+
+ httpproc = setup_http(testdir, wrapenv)
+ processes['HTTPD(%d)' % httpproc.pid] = httpproc
+
+ keysenv = setup_keys(testdir, kdcenv)
+ testenv = kinit_user(testdir, kdcenv)
+
+ test_spnego_auth(testdir, testenv, testlog)
+
+ finally:
+ with (open(testlog, 'a')) as logfile:
+ for name in processes:
+ logfile.write("Killing %s\n" % name)
+ os.killpg(processes[name].pid, signal.SIGTERM)
diff --git a/tests/t_spnego.py b/tests/t_spnego.py
new file mode 100755
index 0000000..83a9586
--- /dev/null
+++ b/tests/t_spnego.py
@@ -0,0 +1,14 @@
+#!/usr/bin/python
+# Copyright (C) 2015 - mod_auth_gssapi contributors, see COPYING for license.
+
+import os
+import requests
+from requests_kerberos import HTTPKerberosAuth, OPTIONAL
+
+
+if __name__ == '__main__':
+ sess = requests.Session()
+ url = 'http://%s/spnego/' % os.environ['NSS_WRAPPER_HOSTNAME']
+ r = sess.get(url, auth=HTTPKerberosAuth())
+ if r.status_code != 200:
+ raise ValueError('Spnego failed')