While you can just use the automated travis-ci build to test out your changes it is also nice to be able to run the tests locally before pushing them. Unfortunately due to the nature of Kerberos it can be hard to have an environment on hand to test this out. Please note that any scripts or commands run are not indicative of a properly secured and hardened Kerberos environment and should not be used to set up a real Kerberos environment used in a non testing context.
The script .travis.sh is the script used in the automated travis-ci build and
can be run locally. You can take parts of this script to install a Kerberos
KDC and Apache site secured with Kerberos and run the tests using py.test.
Otherwise you can run the tests on a host already connected to your own domain
and modify the values in tests/test_kerberos.py
which is valid for your
environment. See an explanation for each option below;
# The username without the realm to validate
username = os.environ.get('KERBEROS_USERNAME', 'administrator')
# The password for the username
password = os.environ.get('KERBEROS_PASSWORD', 'Password01')
# The realm/domain of your environment in lowercase
realm = os.environ.get('KERBEROS_REALM', 'example.com')
# The FQDN of the host
hostname = os.environ.get('KERBEROS_HOSTNAME', 'hostname.example.com')
# The port the Apache site is listening to
port = os.environ.get('KERBEROS_PORT', '80')
You can use the package mod_auth_gssapi to secure your Apache site with Kerberos authentication. For you to do this you can install the package by running;
# for Debian/Ubuntu:
sudo apt-get install libapache2-mod-auth-gssapi
# for RHEL/CentOS:
sudo yum install mod_auth_gssapi
In your site configuration an example setup of the config would look something like this
<VirtualHost *:80>
ServerName hostname.example.com
ServerAlias hostname.example.com
DocumentRoot /var/www/example.com/public_html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
<Directory "/var/www/example.com/public_html">
AuthType GSSAPI
AuthName "GSSAPI Single Sign On Login"
Require user [email protected]
GssapiCredStore keytab:/etc/krb5.keytab
</Directory>
</VirtualHost>
Your keytab file needs to have the SPN added for the site, this can be done by running on your KDC
kadmin.local -q "addprinc -randkey HTTP/hostname.example.com"
kadmin.local -q "ktadd -k /etc/krb5.keytab HTTP/hostname.example.com"
Take note to change the hostname used with the actual hostname of your host.
There are currently 4 test cases in this library
- basic
- service
- gssapi
- server
This test performs a basic authentication test with the specified username / password. This does not require any credentials to be cached.
Does what a Kerberized service needs to do. It attempts to read the service
keytab from /etc/krb5.keytab
. Before running this test you need to ensure
/etc/krb5.keytab
contains the keytab HTTP/[email protected]
where the hostname and realm suite your environment. You can verify this by
running
[administrator@HOSTNAME ]$ klist -k /etc/krb5.keytab
Keytab name: FILE:/etc/krb5.keytab
KVNO Principal
---- --------------------------------------------------------------------------
1 HTTP/[email protected]
2 host/[email protected]
2 host/[email protected]
2 host/[email protected]
2 host/[email protected]
2 host/[email protected]
2 host/[email protected]
2 host/[email protected]
2 host/[email protected]
2 host/[email protected]
2 host/[email protected]
2 [email protected]
2 [email protected]
2 [email protected]
2 [email protected]
2 [email protected]
Your keytab can contain other entries it just needs to contain the one mentioned above.
Requires user tgt and service keytab access (hence root), this test will obtain the service ticker for the specified user
userfoo@domain-controller:~/PyKerberos$ sudo kinit userfoo
Password for [email protected]:
userfoo@domain-controller:~/PyKerberos$ sudo klist
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: [email protected]
Valid starting Expires Service principal
06/03/16 05:08:53 06/03/16 15:08:53 krbtgt/[email protected]
renew until 06/04/16 05:08:52
userfoo@domain-controller:~/PyKerberos$ sudo py.test
userfoo@domain-controller:~/PyKerberos$ sudo klist
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: [email protected]
Valid starting Expires Service principal
06/03/16 05:08:53 06/03/16 15:08:53 krbtgt/[email protected]
renew until 06/04/16 05:08:52
06/03/16 05:08:59 06/03/16 15:08:53 HTTP/[email protected]
renew until 06/04/16 05:08:52
This test will validate Kerberos authentication against a HTTP endpoint
protected by Kerberos authentication. It requires a HTTP website set up and
running, details on this can be found in the sections above and in the
.travis-ci.sh
script.
Use curl to cross-check the kerberized http service
userfoo@domain-controller:~/PyKerberos$ kdestroy
userfoo@domain-controller:~/PyKerberos$ curl --negotiate -u userfoo server.example.org/test
Enter host password for user 'userfoo':
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>401 Authorization Required</title>
</head><body>
<h1>Authorization Required</h1>
<p>This server could not verify that you
are authorized to access the document
requested. Either you supplied the wrong
credentials (e.g., bad password), or your
browser doesn't understand how to supply
the credentials required.</p>
<hr>
<address>Apache/2.2.16 (Debian) Server at server.example.org Port 80</address>
</body></html>
userfoo@domain-controller:~/PyKerberos$ klist
klist: No credentials cache found (ticket cache FILE:/tmp/krb5cc_1001)
userfoo@domain-controller:~/PyKerberos$ kinit
Password for [email protected]:
userfoo@domain-controller:~/PyKerberos$ klist
Ticket cache: FILE:/tmp/krb5cc_1001
Default principal: [email protected]
Valid starting Expires Service principal
06/03/16 03:12:43 06/03/16 13:12:43 krbtgt/[email protected]
renew until 06/04/16 03:12:42
userfoo@domain-controller:~/PyKerberos$ curl --negotiate -u userfoo server.example.org/test
Enter host password for user 'userfoo':
it works! :)
userfoo@domain-controller:~/PyKerberos$ klist
Ticket cache: FILE:/tmp/krb5cc_1001
Default principal: [email protected]
Valid starting Expires Service principal
06/03/16 03:12:43 06/03/16 13:12:43 krbtgt/[email protected]
renew until 06/04/16 03:12:42
06/03/16 03:12:49 06/03/16 13:12:43 HTTP/[email protected]
renew until 06/04/16 03:12:42
hold httplib in your hands to help discover that you were passing the wrong cli option to test.py for 'port', causing it to try to connect to 8008, which was refused!
>>> import httplib
>>> http = httplib.HTTPConnection('domain-controller', 80)
>>> http
<httplib.HTTPConnection instance at 0x7f9ed9c680e0>
>>>
>>> http.request("GET", "http://domain-controller", "", {})
>>> response = http.getresponse()
>>> response
<httplib.HTTPResponse instance at 0x7f9ed9c68638>
>>> response.status
200
>>> import httplib
>>> http = httplib.HTTPConnection('domain-controller', 80)
>>> http.request("GET", "http://domain-controller/test", "", {})
>>> response = http.getresponse()
>>> response.status
401