Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enable detailed logging for kerberos in java

I have a Java-based web application that takes the contents of a web form containing a username and password and authenticates using Kerberos to a Windows-based domain.

The KDC address is apparently configured to map to different IP addresses at each lookup and this can be confirmed by using the ping command from the command line.

The call responds immediately for most requests but the response is slow (5-10 seconds or even longer) intermittently. I think this may be due to which domain controller is used.

I've tried to turn on Kerberos logging but the IP address of the domain controller is not shown. How can I turn on more detailed logging to try to identify dodgy domain controllers please?

The code extract sources the kerb.conf and kerb_context.conf from the filesystem.

The kerb.conf is:

[libdefaults]
default_realm = EXAMPLE.COM

[realms]
CYMRU.NHS.UK = {
        kdc = example.com:88
        admin_server = example.com
        kpasswd_server = example.com
}

The kerb_context.conf is:

 primaryLoginContext {
        com.sun.security.auth.module.Krb5LoginModule required
        useTicketCache=false
        refreshKrb5Config=true
        debug=true;
};

The example source is:

static NadexUser executePerformLogin(String username, String password) throws LoginException {
            char[] passwd = password.toCharArray();
            String kerbConf = ERXFileUtilities.pathForResourceNamed("nadex/kerb.conf", "RSCorp", null);
            String kerbContextConf = ERXFileUtilities.pathURLForResourceNamed("nadex/kerb_context.conf", "RSCorp", null).toExternalForm();
            System.setProperty("java.security.krb5.conf", kerbConf);
            System.setProperty("java.security.auth.login.config", kerbContextConf);
            try {
                    LoginContext lc = new LoginContext("primaryLoginContext", new UserNamePasswordCallbackHandler(username, password));
                    lc.login();
                    return new _NadexUser(lc.getSubject());
            }
            catch (javax.security.auth.login.LoginException le) {
                    throw new LoginException("Failed to login : " + le.getLocalizedMessage(), le);
            }
    }
like image 710
Mark Wardle Avatar asked Mar 13 '13 10:03

Mark Wardle


2 Answers

You can enable logging by setting system property sun.security.krb5.debug to true.

See Oracle documentation

like image 115
Ales Dolecek Avatar answered Oct 17 '22 08:10

Ales Dolecek


I did not find a way to turn on such detailed logging, but instead decided to adopt a different approach. The code below is a self-contained application that simply needs a jaas.conf configuration file in the same directory.

An example jaas.conf for use with this short test application is shown:

primaryLoginContext {
        com.sun.security.auth.module.Krb5LoginModule required
        useTicketCache=false
        refreshKrb5Config=true
        debug=false;
};

This code is careful to set the system property sun.net.inetaddr.ttl to avoid java caching the results of the DNS lookup. For my case, the DNS lookup changes at each request. It's a fairly crude piece of code, but will demonstrate any poorly configured or performing KDCs within the network.

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.HashMap;
import java.util.Set;
import java.util.Vector;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginContext;

public class TestNadex {
    private static final String DEFAULT_HOST = "cymru.nhs.uk";

    public static void main(String[] args) {
        System.setProperty("sun.net.inetaddr.ttl", "0");
        String username=null;
        String password=null;
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("Enter username: ");
            username = br.readLine().trim();
            System.out.println("Enter password: ");
            password = br.readLine().trim();
            testHost(DEFAULT_HOST, username, password);
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
    }

    static void testHost(String host, String username, String password) {
        HashMap<String, Vector<Long>> results = new HashMap<String, Vector<Long>>();
        for (int i=0; i<200; i++) {
            InetAddress ia;
            try {
                ia = InetAddress.getByName(host);
                long startTime = System.currentTimeMillis();
                executePerformLogin(ia.getHostAddress(), username, password);
                long endTime = System.currentTimeMillis();
                long duration = endTime - startTime;
                if (results.containsKey(ia.toString()) == false) {
                    Vector<Long> v = new Vector<Long>();
                    v.add(duration);
                    results.put(ia.toString(), v);
                }
                else {
                    Vector<Long> v = results.get(ia.toString());
                    v.add(duration);
                }
                Thread.sleep(1000);
            } catch (UnknownHostException e) {
                System.out.println("Unknown host: "  + host);
                System.exit(1);
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        Set<String> keys = results.keySet();
        for (String key : keys) {
            System.out.println("For address: " + key);
            Vector<Long> times = results.get(key);
            int count = times.size();
            long total = 0;
            for (Long t : times) {
                System.out.println(t + " milliseconds");
                total += t;
            }
            System.out.println("Mean duration: " + new BigDecimal(total).divide(new BigDecimal(count), RoundingMode.HALF_UP));
        }
    }

    static void executePerformLogin(String hostname, String username, String password) throws MalformedURLException {
        System.setProperty("java.security.krb5.realm", "CYMRU.NHS.UK");
        System.setProperty("java.security.krb5.kdc", hostname);
        File jaas = new File("jaas.conf");
        String jaasconf = jaas.toURI().toURL().toExternalForm();
        System.setProperty("java.security.auth.login.config", jaasconf);
        //      System.setProperty("java.security.krb5.realm", "cymru.nhs.uk");
        //      System.setProperty("java.security.krb5.kdc", "cymru.nhs.uk");
        try {
            System.out.println("Performing NADEX login for username: " + username + " at " + new Date() + " to server " + hostname);
            LoginContext lc = new LoginContext("primaryLoginContext", new UserNamePasswordCallbackHandler(username, password));
            lc.login();
            System.out.println("Successful login for " + lc.getSubject().toString() + " at " + new Date());
        }
        catch (javax.security.auth.login.LoginException le) {
            System.err.println("Failed to login: " + le);
        }
    }

    public static class UserNamePasswordCallbackHandler implements CallbackHandler {
        private final String _userName;
        private final String _password;

        public UserNamePasswordCallbackHandler(String userName, String password) {
            _userName = userName;
            _password = password;
        }

        public void handle(Callback[] callbacks) throws IOException,
        UnsupportedCallbackException {
            for (Callback callback : callbacks) {
                if (callback instanceof NameCallback && _userName != null) {
                    ((NameCallback) callback).setName(_userName);
                }
                else if (callback instanceof PasswordCallback && _password != null) {
                    ((PasswordCallback) callback).setPassword(_password.toCharArray());
                }
            }
        }
    }
}
like image 2
Mark Wardle Avatar answered Oct 17 '22 07:10

Mark Wardle