Spark/Openfire SSO setup questions

My organization is in the process of deploying Kerberos SSO. The KDCs are Active Directory. We have things working nicely across Windows XP, MacOS X, and Red Hat Linux. Functional apps include ssh, WinSCP, ldapsearch, curl, FireFox, IE (of course), Safari, IE, and Apache. All in the way of establishing background :sunglasses:

However, this is my first exposure to the Java Kerberos implementation.

So Iā€™'m very excited to see the SSO feature in Spark. I followed the instructions at http://wiki.igniterealtime.org/display/WILDFIRE/Configuring+Openfire+for+Kerbero s and was able to get a test box hosted on Linux working in about 20 minutes, with Spark 2.5.4ā€¦ Whee!

Then I tried to get it working in a broader scope, and things broke down:

Issue 1: Getting Spark 2.5.4 (java 1.6.0_01 and 1.5.0_09) on Linux to use SSO with my test server. Note, Spark on Windows works with this server so we know the server config is good. On Linux Spark will connect using SASL PLAIN, but when I try to enable SSO the tab says ā€œSpark is unable to find the principal to use for Single Sign-Onā€¦ā€.

I definitely have a TGT, and can get tickets for services (Web servers, sshd, etc.). So Kerberos is definitely functional on this client. KRB5CCNAME is set in the environment. The krb5.conf is in the standard /etc/krb5.conf location and is world readable. So itā€™ā€˜s not clear to me why it isnā€™'t able to get the credential.

If I turn on debugging I get the following in output.log:

Debug is true storeKey false useTicketCache true useKeyTab false doNotPrompt tr

ue ticketCache is null isInitiator true KeyTab is null refreshKrb5Config is fals

e principal is null tryFirstPass is false useFirstPass is false storePass is fal

se clearPass is false

Acquire TGT from Cache

Principal is null

null credentials from Ticket Cache

authentication failed

Unable to obtain Princpal Name for authentication

which pretty much says what I already know. How to solve?

Issue 2:

Trying to enable our production server. We do use SRV records, however I have been configuring my client to connect specifically to the underlying hostname rather than using automatic discovery, and the keytab on the server is for the SPN xmpp/hostname@REALM (and that SPN is specified in the principal= part of the gss.conf). I believe this should work around the known issues with SRV records since the client-side Kerberos code should just look up the target host, do a reverse lookup, and get the right hostname, but tell me if Iā€™'m just mistaken.

But it doesnā€™ā€˜t work. The underlying host definitely does have a working Keberos config - I can use Kerberized sshd to log on and I can do kinit to get a TGT using the xmpp serviceā€™'s keytab.

When running my test server I start the server using openfire.sh, and I get useful Kerberos debug info in my console. Since this is production with ~1000 users I really donā€™ā€˜t want to run it that way, but the relevant log lines(snippet from the test system below) donā€™ā€˜t seem to show up in the openfire log files. How do I get this server to log the data somewhere useful so I can see what it is doing? And while weā€™'re at it, is there any way to get the server to reload this config without shutting it down?

Example of what Iā€™'d like to see (for working test system):

added Krb5Principal xmpp/host@REALM to Subject

Added serverā€™'s keyKerberos Principal xmpp/host@REALMKey Version 2key EncryptionKey: keyType=3 keyBytes (hex dump)=

0000: AE 62 1C FB 54 1C D6 25

Even the Windows Spark doesnā€™ā€˜t work, although it does seem to get a ticket and do a SASL GSSAPI exchange. How can I tell exactly which service principal name Spark is trying to use? Even when it is working with the test box a ticket never shows up in the credential cache (either the LSA or the GSSAPI cache used by MITā€™ā€˜s Kerberos for Windows), so klist isnā€™'t useful. I assume this is because Java is using its own credential cache (hence the need to extract the TGT from the LSA). But it makes it almighty difficult to debug this sort of thing.

Thanks for any help you can provide.

  • Ken

khamer wrote:

If I turn on debugging I get the following in output.log:

Debug is true storeKey false useTicketCache true useKeyTab false doNotPrompt tr

ue ticketCache is null isInitiator true KeyTab is null refreshKrb5Config is fals

e principal is null tryFirstPass is false useFirstPass is false storePass is fal

se clearPass is false

Acquire TGT from Cache

Principal is null

null credentials from Ticket Cache

authentication failed

Unable to obtain Princpal Name for authentication

Answering part of my own post :sunglasses:

Perhaps the issue is that ticketCache is null and Java isnā€™ā€˜t defaulting to use $KRB5CCNAME? Canā€™ā€˜t test since Iā€™ā€˜m at home now, but Iā€™'ll give it a look tomorrow. That would be unfortunate, since $KRB5CCNAME varies from user to user.

Your KRB5CCNAME might be the issue. I think that Java dosnt actually look for this, and just assumes $TMP/krb5cc_$UID . Which is unfortunate since moderen implementations add randomness to this for security reasons. But there is hope- Java 1.6 supposedly has the ability to use Native libraries which should be able to resolve this problem. Ive not had the chance to play with them yet, so bear with me on this one.

Modify the Spark script so you add this to the final java command:

-Dsun.security.jgss.native=true

It should figure out which library to use, but if it needs help add

-Dsun.security.jgss.lib=libgss.so

(see http://java.sun.com/developer/technicalArticles/J2SE/security/#3 for details here, since Ive never actually tried this). Note that this only works for Linux and Solaris.

For your second issueā€¦ SRV records do work fine, but add complexity to the process. Spark knows how to ask for the right principal, but Openfire needs help knowing who itself is- so make sure you have the property xmpp.fqdn set to the correct name (that will end up being used in the service principal). Ive been using my own startup scripts for openfire for a while now, that log STDOUT and STDERR to seperate files, so the debugging information gets logged somewhere. I think some of the official scripts do this too, but Ive not looked at them in a while. There isnt a good way to flick the kerberos debugging on and off at this point, but maybe that property should get moved out of the XML properties and into the regular ones (that would allow dynamic switching easier).

To see what principal is actually getting passed around, grab the GSSAPI token (packet capture if SSL isnt used, or with the right debugging enabled in Spark, or use Gaim with the debug window, if needed). The token the client sends to the server is base64 encoded, just decode that to a file and run strings on it- it should be pretty obvious. With MIT kerberos you can just watch the KDC logs too, if someone knows of a windows equivilant here, please speak up- it would be great to know of that option.

slushpupie wrote:

Your KRB5CCNAME might be the issue. I think that Java dosnt actually look for this, and just assumes $TMP/krb5cc_$UID . Which is unfortunate since moderen implementations add randomness to this for security reasons. But there is hope- Java 1.6 supposedly has the ability to use Native libraries which should be able to resolve this problem. Ive not had the chance to play with them yet, so bear with me on this one.

Modify the Spark script so you add this to the final java command:

> -Dsun.security.jgss.native=true

Thanks - I also noted that in Sunā€™'s docs last night.

That yields a slightly different failure:

Debug is true storeKey false useTicketCache true useKeyTab false doNotPrompt tr

ue ticketCache is null isInitiator true KeyTab is null refreshKrb5Config is fals

e principal is null tryFirstPass is false useFirstPass is false storePass is fal

se clearPass is false

Acquire TGT from Cache

KinitOptions cache name is /tmp/krb5cc_58915

Principal is null

null credentials from Ticket Cache

authentication failed

Unable to obtain Princpal Name for authentication

This is informative because it does tell me that the credential cache it is trying to use is wrong; at this point $KRB5CCNAME is /tmp/krb5cc_58915_WW6104; as you noted there is randomness added to the end.

So, I guess I need to explicitly specify the location of the cache. Iā€™'ve tried a number of things, none of which work:

  1. Specify the location of the cache in a login config file, i.e.

com.sun.security.jgss.initiate {

com.sun.security.auth.module.Krb5LoginModule required

ticketCache=/tmp/krb5cc_58915_vwmskp

useTicketCache=true

doNotPrompt=true

debug=true;

};

and then tell java to load it by adding -Djava.security.auth.login.config=/path/to/file to the command line. No joy. Same for putting it in ~/.java.login.config where the JRE is supposed to look for it.

  1. Specify native Kerberos and specify the location of the gssapi library. No joy. Java still wants to find the credential cache at /tmp/krb5_$uid no matter what I do.

What does work is to copy my credential cache to the filename java is looking for 8-). So this is clearly not a Kerberos or Spark issue as such, itā€™ā€˜s simply a matter of configuring JAAS to play nice with the Kerberos on RHEL3. Yay. Any other suggestions are welcome, but Iā€™ā€˜m going to take this to some java forums. Iā€™'ll follow up if I come up with an answer.

Iā€™'m going to call this answered for nowā€¦

Message was edited by: khamer

And using xmpp.fqdn solved the server problem. So I have SSO working in production with Spark 2.5.4 (Windows and Linux) and OpenFire 3.2.1 (Linux) with an SRV record. To re-cap for others:

  1. Follow the instructions at http://wiki.igniterealtime.org/display/WILDFIRE/ConfiguringOpenfirefor+Kerberos.

  2. If the server hostname is not the same as the domain part of your JIDs, set the property xmpp.fqdn to the actual hostname of the server. This should be the same hostname you use in the service principal name (SPN) for your keytab (xmpp/hostname@REALM)[1]. Since we actually have a failover pair of servers weā€™ā€˜re writing our failover scripts to update the database and config files as needed depending on which host is live. Presumably youā€™'d also need to deal with this if you use connection managers.

  3. Profit.

On Linux, do a lot of screwing around to get java to import your existing TGT. I can make this work but do not yet have a maintainable or user-ready solution.

On Windows XP SP2, do remember to set the AllowTGTSessionKey registry value so that Java can get the TGT from the LSA.

Actually, itā€™ā€˜s a little more complicated that but in most cases that should be correct. The name to use is whatever Kerberos is going to get when it looks up the IP of the name by which your clients access the serviceand then does a reverse lookup on that IP. And if itā€™ā€˜s a SRV record weā€™ā€˜re talking about the names the SRV record points to, not the SRV recordā€™'s name.

Message was edited by: khamer

The only caveat is that you if you want to use SSO, your Kerberos username has to be the same as the first part of your JID (until SlushPupieā€™'s patches make it into Openfire).

Thatā€™'s the only stumbling block for me at the moment

Yep - we happen to have decided that all email addresses, usernames, etc. will be lower case. So itā€™'s not an issue.

As a side note, I did get Spark working on Linux (RHEL3) with SSO and native Kerberos:

  1. Use JRE 1.6.0+

  2. Add -Dsun.security.jgss.native=true and -Dsun.security.jgss.lib=/usr/kerberos/lib/libgssapi_krb5.so to the Spark shell script that you use to start the app.

  3. Profit.

The issue was that java expects the native library to be libgssapi.so on Linux, so you have to override that. Sadly, this probably wonā€™'t help on MacOS X (my next mountain to climb) since there is native Kerberos support only on Solaris and Linux.

Interestingly, the output.log from Spark still looks like it is bombing out, but it definitely works and the XML stream shows a successful GSSAPI authentication.

Also (and tremendously useful for debugging this is), the ticket for the xmpp service actually shows up in the normal native credential cache and can be viewed with klist, etc. So you can easily see which principal the client is requesting and be sure thatā€™'s the primsipal you have on the server.

  • Ken

Thats good info on the native libs. For OSX it should ā€œjust workā€ unless you installed some version of Kerberos besides what it comes with.

Yes, once I straightened out the krb5.conf (/Library/Preferences/edu.mit.Kerberos) it works fine. The issue was that be defauly I wasnā€™ā€˜t getting the tight encryption types - I needed to explicitly specify them and the default Mac config didnā€™'t do that. So I grabbed the same file I successfully used on the Linux box and voila!

Niceā€¦ Now if I can just sort out Vista. It looks like you hay have to be running in an elevated privilege context to let Java get the TGT from the system.

Same problem.

Linux

Java-1.6.0_02

Heimdal Kerberos implementation.

Trying to use native libs screws SSO completely (integrity check failed).

The only thing that works is to provide /tmp/krb5cc_ file.

I have not used heimdal before-I wonder if its gssapi lib dosnt use the same api (I bet it dosnt).