logo_kerberos.gif

Manual Testing

From K5Wiki
Jump to: navigation, search

This page describes manual testing procedures. There are two reasons these exist:

  1. Manual testing is sometimes simpler than running an automated test and instrumenting it.
  2. In some cases we have a manual testing procedure for part of the code, but not an automated test.

We do have an automated Test suite.

Basic Test KDC Setup

Test KDCs are a crucial building block of testing. You can set one up easily by running "make testrealm" in the top level of a build tree, or you can follow these steps to set one up by hand:

1. Pick a name for your test KDC; this example will assume EXAMPLE.COM.

2. Do a build and install of the krb5 sources into some prefix; this example will assume /usr/local, but anywhere is fine. Put the prefix's bin and sbin directories in your path, or use full pathnames for the commands below.

3. Pick two port numbers, for the KDC and admin server. This example will assume 50000 and 50001.

4. Set up a krb5.conf file somewhere; this example will assume /usr/local/etc/krb5.conf. Make it look something like:

 [libdefaults]
   default_realm = EXAMPLE.COM
   # Depending on what you are testing, you may want something like:
   # default_keytab_name = FILE:/usr/local/var/keytab
 [realms]
   EXAMPLE.COM = {
     admin_server = 127.0.0.1:50001
     kdc = 127.0.0.1:50000
     database_module = DB2
     kdc_ports = 50000
     kadmind_port = 50001
   }
 [dbmodules]
   DB2 = {
     db_library = db2
   }
 [logging]
   # Use any pathnames you want here.
   kdc = FILE:/usr/local/var/krb5kdc/kdc.log
   admin_server = FILE:/usr/local/var/krb5kdc/kadmin.log
 # Depending on what you are testing, you may want:
 # [domain_realm]
 #   your.domain = EXAMPLE.COM

Set the environment variable KRB5_CONFIG to the pathname of this krb5.conf file. Set the environment variable KRB5_KDC_PROFILE to /dev/null.

5. Run:

 kdb5_util create -s

Enter a master password; it can be something insecure like "master". The DB will be created in /usr/local/var/krb5kdc/principal and a few other similarly-named files. The master key stash will be created in /usr/local/var/krb5kdc/.k5.EXAMPLE.COM.

6. Run:

 kadmin.local
 addprinc user
 quit

Enter a user password; it can be something insecure like "user".

7. Start the KDC by running:

 krb5kdc

Check the log file specified in krb5.conf if the KDC has any trouble starting. You should be able to "kinit user" at this point.

8. If you need kadmind, add another principle user/admin (using kadmin.local as described above), and create the file /usr/local/var/krb5kdc/kadm5.acl containing:

 user/admin *

Then start the kadmind server with:

 kadmind

If it has trouble starting, check the log file specified in krb5.conf.

LDAP test KDB setup

These instructions will create a minimal LDAP KDC on a Debian or Ubuntu system.

Install the packages slapd, ldap-utils, and libldap2-dev. You can run "dpkg-reconfigure slapd" to choose the domain suffix for the LDAP database. You may wish to edit /etc/default/slapd and ensure that SLAPD_SERVICES is set to "ldapi:///" to allow only local access.

Use "ldapadd -Y EXTERNAL -H ldapi:/// -f /path/to/src/plugins/kdb/ldap/libkdb_ldap/kerberos.openldap.ldif" to add the Kerberos schema.

Configure the source tree with "--with-ldap" and do a build and install. Set up a krb5.conf similar to the one in the previous section, but with:

   [realms]
       EXAMPLE.COM = {
           database_module = LDAP
       }
   [dbmodules]
       LDAP = {
           db_library = kldap
           ldap_kerberos_container_dn = cn=krbContainer,dc=example,dc=com
           ldap_kdc_dn = cn=admin,dc=example,dc=com
           ldap_kadmind_dn = cn=admin,dc=example,dc=com
           ldap_service_password_file = /usr/local/var/krb5kdc/admin.stash
           ldap_servers = ldapi:///
       }

Replace "dc=example,dc=com" with the domain suffix for the server.

Stash the LDAP admin password with "kdb5_ldap_util stashsrvpw cn=admin,dc=example,dc=com".

Create the database with "kdb5_ldap_util create -s". Destroy it with "kdb5_ldap_util destroy -f".

Valgrind

Many of the automated tests are configured to optionally be run under valgrind, a memory checking tool. However, some tests will fail if there is extra output on stdout or stderr, such as that written by valgrind's summary report. Manually running the test suite under valgrind can be done with

   make VALGRIND='${VALGRIND1}' check

The VALGRIND1 variable is set automatically by the build system to run with the memory checker, a log file at BUILDTOP/vg.[pid] and a list of known warnings to suppress. It is a make variable, not a shell/environment variable, so it must be quoted on the command line.

In order to get more useful stack traces from valgrind, it may be useful to add RTLD_NODELETE to the flags passed to dlopen() in src/util/support/plugins.c (if your platform supports that flag). Compiling with debugging symbols is also useful.

Services4User testing

A test for Services4User can be found in tests/gssapi/t_s4u.c. You will need a W2K3 or higher AD domain to test this. Notes follow:

  • Create a computer account FOO$ using Active Directory Users & Computers (ADUC)
  • Set the UPN to host/foo.domain (no suffix); this is necessary to be able to send an AS-REQ as this principal, otherwise you would need to use the canonical name (FOO$), which will cause principal comparison errors in gss_accept_sec_context() (note: apparently only W2K8 supports suffix-less UPNs; you should use the domain as a suffix for earlier versions). There is an attribute editor in the W2K8 ADUC that lets you do this, otherwise you will need to use LDP.exe or a generic LDAP client.
  • Add a SPN of host/foo.domain. (Again, you can use ADUC in W2K8, or LDP.exe/generic client.)
  • Configure the computer account to support constrained delegation with protocol transition (Trust this computer for delegation to specified services only / Use any authentication protocol)
  • Add host/foo.domain to the keytab (possibly easiest to do this manually with ktadd)

For S4U2Proxy to work the TGT must be forwardable too.

kinit -k -t test.keytab -f 'host/test.win.mit.edu@WIN.MIT.EDU'
./t_s4u delegtest@WIN.MIT.EDU HOST/winhost.win.mit.edu@WIN.MIT.EDU test.keytab

In the above example delegtest@WIN.MIT.EDU is the principal on whose behalf credentials are acquired using S4U2Self; HOST/winhost.win.mit.edu is the host to which we wish to delegate using S4U2Proxy; and test.keytab contains the long term key for test.win.mit.edu.

To test S4U2Self with the MIT KDC, set the ok_to_auth_as_delegate attribute on the service principal using kadmin.

GSS-API Naming Extensions testing

Note: the S4U test also tests the GSS-API naming extensions, but there also is a specific test in tests/gssapi/t_namingexts.c. This tests the following APIs:

  • gss_import_name() with composite names
  • gss_inquire_name()
  • gss_get_name_attribute()
  • gss_set_name_attribute()
  • gss_delete_name_attribute()
  • gss_export_name_composite()
  • gss_map_name_to_any
  • gss_release_any_name_mapping

Note: gss_display_name_ext() is not tested because we don't yet have a concrete implementation of it.

The usage of this test is:

t_namingexts [--spnego] [principal] [keytab]

where the optional --spnego argument uses the SPNEGO (as opposed to the krb5) mechanism; principal is the service principal to test with, and keytab is a path to the keytab containing the key for the service principal. (The client and service principal are identical in the test. To test with another client principal, use the S4U test.)

You likely want to test this against a Windows KDC, in order to validate PAC introspection; however, you can also test with the greet_client (and greet_server) plugins that are included in plugins/authdata/greet_{client,server}.

Principal lockout testing

There are now some automated lockout tests, but these procedures are still helpful for examining some edge cases.

Testing for lockout is identical for the LDAP and DB2 backends, although if you wish to test the replication functionality, you'll need to use a DB2 backend. No changes are required for configuring kprop/iprop; it's business as usual (the only difference being that lockout-related attributes will not be replicated, so as part of testing you should verify on each KDC that this is the case).

First, you need to create a password policy that specifies a lockout policy. Do this with kadmin. Here we create a policy where a maximum failure count of 3, a failure count reset interval of 180 seconds, and a lockout duration of 60 seconds.

kadmin: addpol -maxfailure 3 -failurecountinterval 180 -lockoutduration 60 lockout_test

Then, you need to associate a principal with the lockout policy. Note also that the pre-authentication required attribute must be set on the principal; principals without this attribute set are not subject to the lockout policy (as they are not required to prove knowledge of their long-term key to the KDC).

kadmin:  modprinc -policy lockout_test +requires_preauth lukeh
Principal "lukeh@MIT.DE.PADL.COM" modified.

Now, perform a successful authentication with kinit. You should see the last successful authentication timestamp updated in the information returned by kadmin:

kadmin: getprinc lukeh
...
Last successful authentication: Wed Oct 07 14:07:08 CEST 2009

Perform an unsuccessful authentication (ie. kinit with an incorrect password) and you should see the failed authentication timestamp and count updated:

kadmin: getprinc lukeh
...
Last failed authentication: Wed Oct 07 14:07:58 CEST 2009
Failed password attempts: 1
Account locked time: [never]

Another two authentication failures (recall, the maximum failure count above is 3) and you should see that the principal is locked out:

kadmin: getprinc lukeh
...
Last failed authentication: Wed Oct 07 14:08:37 CEST 2009
Failed password attempts: 3
Account locked time: Wed Oct 07 14:08:37 CEST 2009

You can try to unlock the account explicitly with modprinc -unlock, or you can wait the lockout duration (here, 60 seconds) and you should be able to authenticate again.

KDC worker processes

There is a very basic automated test of parallel KDC worker processes, but it doesn't ensure that all worker processes can receive packets. To test that, make the following temporary code modifications:

  • In plugins/kdb/db2/kdb_db2.c:krb5_db2_get_principal(), add this code near the beginning:
   if (searchfor->length >= 1 &&
       data_eq_string(searchfor->data[0], "slowuser"))
       sleep(60);
  • In lib/krb5/os/sendto_kdc.c, change MAX_PASS from 3 to 1, and in krb5_sendto_kdc() change all assignments of socktype2 to 0. This ensures that kinit will only send one request.
  • In util/k5test.py, change the default arguments for the start_kdc() realm method like so:
   def start_kdc(self, args=['-w', '3']):

Build the sources and run "make testrealm". You should be able to run "kinit slowuser" three times before the KDC becomes unresponsive to "kinit user".

SAM-2 preauth client code

The securid_sam2 preauth module isn't built by default and ordinarily only compiles successfully in the presence of the RSA ACE library. But it can be built with alternate flags to use a test method which can help exercise the client SAM-2 preauth code in send-encrypted-sad mode.

  • First, build the securid_sam2 module with the test method instead of the securid method:
   cd plugins/preauth/securid_sam2
   make DEFINES='-DGRAIL_PREAUTH' ACELIB=
   cd ../../..
  • Start with a basic test realm:
   make testrealm
  • Edit testdir/krb5.conf and add the following to register the module. Make sure to specify the correct absolute path to the module shared object, which will depend on where your build directory is located.
   [plugins]
       kdcpreauth = {
           module = securid_sam2:/path/to/plugins/preauth/securid_sam2/securid_sam2.so
       }
  • Do the following in kadmin.local:
   addprinc -randkey user/GRAIL
   modprinc +requires_hwauth user
  • Restart the KDC (find the pid of the running krb5kdc process, kill it, and then run "krb5kdc").
  • Run "kinit user". If you enter the correct password for user and correctly echo the challenge, you should get tickets. If you enter either one wrong, you should get an error.
  • Remember to kill your krb5kdc process after exiting the test realm; the test realm code won't clean up the one you started by hand.

FAST option handling

We do not currently have the necessary tools in our automated test suite to construct KDC requests with arbitrary FAST options or to examine KDC replies for the plaintext client name, so FAST option handling must be tested manually, by temporarily modifying the code.

To modify the FAST options in all kdc-reqs, look for the assignment to fast_req.fast_options in lib/krb5/krb/fast.c and assign the desired value. To ensure that we are recognizing the correct ASN.1 encodings of flags, it is best to use constants for KDCOptions, which have had more interoperability testing than FAST options. Some relevant constants are:

  • KDC_OPT_FORWARDABLE(1) corresponds to hide-client-names(1).
  • KDC_OPT_FORWARDED(2) and KDC_OPT_CANONICALIZE(15) correspond to the limits of the other critical FAST option bits.
  • KDC_OPT_REQUEST_ANONYMOUS(16) is the first non-critical FAST option bit.
  • KDC_OPT_RENEW(30) is a FAST option bit which was erroneously treated as critical before [krbdev.mit.edu #7701] was fixed.

To examine KDC-REP or KRB-ERROR fields before FAST processing replaces the client name, run the client program in a debugger and break on decode_krb5_as_rep, decode_krb5_tgs_rep, or decode_krb5_error as appropriate. Let the function finish (e.g. with the "fin" command in gdb) and then look at the values in the structure it yields.

A reasonably comprehensive series of tests is:

  1. Run "make testrealm" with unmodified code.
  2. Run "kinit -T testdir/ccache" in a debugger and check that the AS-REP has client user@KRBTEST.COM.
  3. Run "kinit -T testdir/ccache notfound" and check that the KRB-ERROR has client notfound@KRBTEST.COM.
  4. Run "kvno user" in a debugger and check that the TGS-REP contains client principal user@KRBTEST.COM.
  5. Run "kvno notfound" in a debugger and check that the KRB-ERROR has client user@KRBTEST.COM.
  6. Modify fast.c to set fast_options to KDC_OPT_FORWARDABLE (corresponding to hide-client-names) and rebuild.
  7. Perform steps #2-#5 and check that the client name is WELLKNOWN/ANONYMOUS@WELLKNOWN:ANONYMOUS in all four cases. Also check that the operations continue to work as they do without the hide-client-names option.
  8. Modify fast.c to set fast_options to KDC_OPT_FORWARDED (corresponding to flag bit 2) and rebuild.
  9. Verify that "kinit -T testdir/ccache" and "kvno notfound" yield the error "An unsupported critical FAST option was requested."
  10. Repeat steps #8-#9 with KDC_OPT_CANONICALIZE (corresponding to flag bit 15).
  11. Modify fast.c to set fast_options to KDC_OPT_REQUEST_ANONYMOUS (corresponding to flag bit 16) and rebuild.
  12. Verify that "kinit -T testdir/ccache" gives a password prompt and that "kvno notfound" yields a "not found in Kerberos database" error.
  13. Repeat steps #11-12 with KDC_OPT_RENEW (corresponding to flag bit 30).

KCM cache type

Since we only implement the client side of the KCM cache type at this time, we cannot test it automatically. Even if the host system has a kcm daemon program installed, Heimdal's kcm does not implement the --socket-path option, so we can't spawn a private daemon to test against.

To manually test the KCM cache type, these steps will exercise most of the code:

  1. Build and install Heimdal to some prefix.
  2. In a separate root shell, run /path/to/heimdal/libexec/kcm. By default, it does not fork.
  3. Run "make testrealm".
  4. Run "export KRB5CCNAME=KCM:".
  5. Run "kinit user" and enter the user password.
  6. Run "kvno host/this.host.name".
  7. Run "kinit user/admin" and enter the admin password.
  8. Run "klist -A" and verify that both caches are displayed.
  9. Run "kdestroy -A".
  10. Run "klist" and verify that no cache is displayed.

Unlocked kdb5_util dump

An automated test for this would be subject to race conditions or long run times.

make testrealm
awk 'BEGIN { for (i = 0; i < 1024 * 1024; i++) { printf("ank -randkey a%07d\n", i) } }' /dev/null | kadmin.local > /dev/null 2>&1
(time kdb5_util dump > /dev/null)& sleep 1; kadmin.local -q 'ank -randkey test1'
(time kdb5_util -x unlockiter dump > /dev/null)& sleep 1; kadmin.local -q 'ank -randkey test2'

The kadmin.local driven by the awk script could take a long time to complete.

The creation of "test1" should hang until the (normal, locked) dump completes. The creation of "test2" should complete immediately (after the sleep 1), but the unlocked dump could take about twice as long to execute.

Add the [dbmodules] setting "unlockiter = true" and then run:

(time kdb5_util dump > /dev/null)& sleep 1; kadmin.local -q 'ank -randkey test3'
(time kdb5_util -x lockiter dump > /dev/null)& sleep 1; kadmin.local -q 'ank -randkey test4'

Creation of test3 should happen immediately (after the sleep 1) but the creation of test4 should hang until the dump completes.

Add the appropriate [realms] entry for "iprop_enable = true", set an iprop_logfile appropriately, then:

slave/kproplog -R
(time kdb5_util dump -i > /dev/null)& sleep 1; kadmin.local -q 'ank -randkey test5'
(time kdb5_util -x lockiter dump -i > /dev/null)& sleep 1; kadmin.local -q 'ank -randkey test6'

There should be similar results as above.