Java 7, JAAS and Kerberos Single Sign-on vs. newer Windows Systems

Java Authentication and Authorization Service aka JAAS is a pretty neat way to build a pluggable authentication mechanism for a Java application.

My goal was to build a Single Sign-on (SSO) mechanism targeted on Windows machines (Windows XP SP3, Windows 7) that uses the cached kerberos ticket.

The jaas configuration should be pretty simple:

name_of_the_login_context {
    com.sun.security.auth.module.Krb5LoginModule required
    	debug=true
    	doNotPrompt=true    
    	useTicketCache=true        
    	renewTGT=true
    ;    
};

This means: Require and use the Krb5LoginModule module, do not prompt for a user details and use the windows ticket cache. As it turns out, this works out of the box with Java 6 but does not with Java 7.

Java 7 respects a Windows feature that disables the export of Sessions Key for Ticket-Granting Tickets so the native TGT on Windows (XP with SP2, Vista and 7) has an empty session key.

To enable the export of non empty Session keys add the following registry setting on Vista, 7 and Server:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa\Kerberos\Parameters
Value Name: AllowTgtSessionKey
Value Type: REG_DWORD
Value: 0x01  ( default is 0 )

and this on XP SP2

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa\Kerberos\
Value Name: AllowTgtSessionKey
Value Type: REG_DWORD
Value: 0x01

I expected the configuration to work… But it didn’t. It seems there are problems with User Account Control (UAC) and domain users that are local admins (so is my account on my machine). I tried to disable UAC (not acceptable for either me or the customer), adding the setting above to the KDC server, creating a krb5.ini file and some other attempts but no success. The jaas configuration started to work as soon as i removed my account from the local admins. Funny thing is: I readded it and it still works.

While doing my research i found several other irritating behaviors:

As SSO wasn’t working, it tried the following JAAS config:

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

This should force a login prompt with an adequate javax.security.auth.callback.CallbackHandler. On my Windows 7 machine Java 6 *does* need a krb5.ini file under c:\windows, Java 7 does not.

The exception with Java 6 is: “KrbException: Could not load configuration file C:\Windows\krb5.ini”

So i created one… After that, i had a “KrbException: Message stream modified (41)”, great, thanks. The problem here is the case sensitivity of the realm name. If the domain is FOOBAR and the krb5.ini contains

[realms]
    foobar = {
        kdc = dc.foobar
        admin_server = dc.foobar
        default_domain = foobar
    }

the authentication will fail. If the kdc returns the realm as FOOBAR, the krb5.ini must contain the realm FOOBAR like so

[realms]
    FOOBAR = {
        kdc = dc.foobar
        admin_server = dc.foobar
        default_domain = foobar
    }

Seems to be fun for the whole family… Hopefully this will save someone else some hours of frustration.

tl;dr

  • Java 6 on Windows 7 needs a krb5.ini file when useTicketCache == false
  • The realm name in krb5.ini is case sensitive
  • Kerberos SSO under Windows works only with AllowTgtSessionKey set to 1 under HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa\Kerberos\Parameters
  • Kerberos SSO doesn’t work reliable with Domain Users that are local machine admins due to UAC

Update on the location of the jaas.conf file

I was asked how and where to specifiy the location of the JAAS configuration file. You basically have 3 options (for Java 7).

  • The JRE looks for a default jaas.conf in
    “file:${user.home}/.java.login.config”
  • You can add configuration files to java.security located in “lib/security” in the JRE base directory like so:
    “login.config.url.1=file:C:/config/.java.login.config”
  • Or you can specify the jaas configuration on the command line with:
    “-Djava.security.auth.login.config=path_to_file”

| Comments (4) »

23-Jul-12


VMware Fusion Ctrl+Alt+Del

And again, another quick reminder for myself: How to enter/send Ctrl+Alt+Del with VMware Fusion without using the menubar:

On an external keyboard:

Ctrl+Alt+Del (⌃+⌥+⌦)

On an internal MacBook keyboard:

Fn+Ctrl+Alt+Del (Fn+⌃+⌥+⌦)

| Comments (2) »

23-Jul-12


Take care of net.sf.ehcache.transaction.TransactionTimeoutException

The net.sf.ehcache.transaction.TransactionTimeoutException is one of those unchecked RuntimeExceptions you should take care of if you use ehcache. If this exceptions occurs you must explicitly rollback the ongoing transaction, otherwise all further requests to start an ehcache transaction from within the current thread will fail with another net.sf.ehcache.transaction.TransactionException as the cache is in an inconsistent state.

I do it like so:

final TransactionController transactionController = cacheManager.getTransactionController();
try {
	transactionController.begin();
	// Do stuff
	transactionController.commit();
} catch(TransactionTimeoutException e) {
	// Rollback transaction because cache will be invalid from this point
	transactionController.rollback();
	// Rethrow or handle e in some way
}

| Comments (0) »

15-Feb-12


Get the uptime of your Java VM

You don’t need JConsole or similar for just displaying the approximate uptime of your application respectively your Java Virtual Machine:

import java.lang.management.ManagementFactory;
 
public class Demo {
	public static void main(String... args) {
		final long uptime = ManagementFactory.getRuntimeMXBean().getUptime();
		System.out.println(String.format("Up for %dms", uptime));
	}
}

If you use Joda-Time (and you should if you have anything to do with date/datetime processing), you can format it nicely like so:

import java.lang.management.ManagementFactory;
import java.text.MessageFormat;
 
import org.joda.time.Period;
import org.joda.time.PeriodType;
import org.joda.time.format.PeriodFormatter;
import org.joda.time.format.PeriodFormatterBuilder;
 
public class Demo {
	public static void main(String... args) {
		final Period vmUptime = new Period(ManagementFactory.getRuntimeMXBean().getUptime()).normalizedStandard(PeriodType.yearDayTime());
		final PeriodFormatter pf = new PeriodFormatterBuilder()
				.printZeroAlways()
				.appendDays().appendLiteral(MessageFormat.format("{0,choice,0# days, |1# day, |2# days, }", vmUptime.getDays()))
				.minimumPrintedDigits(2)
				.appendHours().appendLiteral(":").appendMinutes()
				.toFormatter();
		System.out.println(String.format("Up for %s", pf.print(vmUptime)));
	}
}

You also have a nice example of the often unknown MessageFormat.

| Comments (0) »

08-Feb-12


The dangers of Javas ImageIO

Javas ImageIO works… well, most of the time. It contains some unfixed, jpeg related bugs, but it works.

It may contain some dangers when used in a webbased application for generation large images on the fly.

Most problems are related to ImageIOs filed based caching and not flushing buffers when an IOException in an underlying stream occurs.

First, the javax.imageio.ImageReader. It caches some data in files. It is essential to dispose the reader and the underlying ImageInputStream after use if it’s not needed anymore like so:

if(imageReader.getInput() != null && imageReader.getInput() instanceof ImageInputStream)			
  ((ImageInputStream)imageReader.getInput()).close();
imageReader.dispose();

If it isn’t closed and disposed, the temporary cache files are either deleted not at all or maybe at the next garbage collection. I was able to bring down a VM by “java.io.FileNotFoundException: (Too many open files)” several times because i didn’t close a reader in a loop. Even the classloader wasn’t able to load any new classes after the ImageReader going mad on the file handle.

The other side is the javax.imageio.ImageWriter. There is an issue mentioned in the Tomcat Wiki.

I used the ImageWriter to dynamically create large images. I directly passed the javax.servlet.ServletOutputStream to the ImageWriter. If the generation of images takes long enough, there’s a good chance that the client aborts the request and the ServletOutputStream gets flushed right when the ImageWriter is writing to it. I didn’t have the exceptions mentioned in the wiki but my VM crashed. Great. I guess it had something to do with the native org.apache.coyote.ajp.AjpAprProtocol Ajp Apr connector i use, but that’s just guessing.

I solved this problem by using a temporary file and its related outputstream which i then stream like described here. This solution is not only faster but i also can catch any exception related to an aborting client.

Also take care to dispose the write as well like so:

try {
	 imageWriter.setOutput(out);
	 imageWriter.write(null, new IIOImage(image, null, null), iwp);
	 out.flush();
 } catch(IOException e) {                        
	 imageWriter.abort();                    
	 throw e;
 } finally {
	 try {                           
		 out.close();                            
	 } catch(Exception inner) {                              
	 }
	 imageWriter.dispose();
 }

This took me several hours to figure out… I hope someone finds this post useful.

| Comments (7) »

25-Jan-12