Integrating Java, JDBC and Kerberos

This notes are to help integrating Java applications into Kerberos environments (most likely Active Directory-based). It’s not a cookbook but gives few pointers that I find useful.


Background


I have integrated Windows Kerberos environment with alien platforms before. See, for example, my notes on Configuring Apache on Linux for Kerberos Authentication. So when I faced the need to configure Java environment to use Kerberos for Microsoft SQL Server authentication, I was excited. As it turns out, Java is as bad as Linux – if not worse [;)]


Problem


There’s a Windows-based Java environment and a Microsoft SQL Server database. The task is to configure Java to connect to SQL Server database using Kerberos authentication in the current user security context – that is, without specifying the account name or keytab file. Not changing Kerberos encryption types for the account in Active Directory highly desired.


Solution


For this particular solution I was using DataDirect JDBC driver for Microsoft SQL Server. Other options are OEM versions of the same (that are cut-down, with the cut including some authentication features), and Microsoft SQL Server JDBC driver (that does support integrated authentication but only on Microsoft Windows operating systems – I naturally want to go multiplatform). DataDirect provides two testing tools – WATest for basic Kerberos functionality testing and ConnTestWA for JDBC specifically , as well as testforjdbc utility included with the driver distribution set.


The steps of the solution include: installation of Java Virtual Machine, configuration of Kerberos, and configuration of login parameters for particular connection. On Windows you can choose not to use keytab files; on UNIX/Linux you have to.


The success criteria was successful run of testforjdbc, with Kerberos ticket for SQL Server service added to the local ticket cache. You can check the cache using Kerbtray GUI or klist.exe command line utility, from Windows Resource Kit utilities and support tools respectively. On UNIX and Linux, you have to run klist. If the connection works and uses Kerberos, a service ticket is added to the cache.


Caveat


Don’t take for granted that Kerberos authentication is available on the server, even if it comes from Microsoft and is using Windows integrated authentication. In case of SQL Server, you need to refer to Q319723 – How to use Kerberos authentication in SQL Server. Note that you need to use service account, and there are some specifics when you use cluster; also note that delegation settings are only required if there is an intermediary point in the communication (like IIS in the KB article scenario). IIS configuration for Kerberos has similar caveat(s).


Installing the JVM


Remember Wirite Once, Run Anywhere capability (see INDEPENDENT TESTS DEMONSTRATE WRITE ONCE RUN ANYWHERE CAPBILITIES OF JAVA)? Well, that doesn’t quite work any more. For that reason you have different constraints with each version of JVM. Pure Java (that is, without using native platform calls and only JVM in-built features) Kerberos failed for me using Sun’s JVM 1.4. With JVM 1.5, Windows default encryption types for Kerberos (namely, RC4-HMAC) are not yet supported, so you have to use DES encryption types for Kerberos (using AD Users and Computers GUI in the service acccount properties – and see  833708 for issue with Windows 2003 domain controllers). Only Java 1.6 comes with RC4-HMAC support. Use the latest version if you can.


Configuring Kerberos in Java


Just like in UNIX/Linux, java is using krb5.conf file and exactly same format. On Windows, the file is renamed to c:\winnt\krb5.ini (if c:\winnt\ directory doesn’t exist, you have to create it). Details about the location of the configuration file and search order please find here. here’s my configuration file:


[libdefaults]
 default_realm = EXAMPLE.COM
 default_tkt_enctypes = aes128-cts des3-cbc-sha1 rc4-hmac arcfour-hmac-md5 des-cbc-md5 des-cbc-crc
 default_tgs_enctypes = aes128-cts des3-cbc-sha1 rc4-hmac arcfour-hmac-md5 des-cbc-md5 des-cbc-crc
 permitted_enctypes = rc4-hmac arcfour-hmac-md5


[realms] 
 EXAMPLE.COM = {
  kdc = DC.EXAMPLE.COM
 }


Important: RC4-HMAC is not enabled by default, so it needs to be on the list.


Configuring login parameters


Kerberos requires configuration file for every connection using Kerberos login. The one for DataDirect JDBC driver is by default named JDBCDriveLogin.conf (akternative configuration file can be specified by changing java.security.auth.login.config Java environment variable), and should look like this:

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

Explanations: debug=true is self-explanatory, and it’s essential during the configuration. The “useTicketCache=true doNotPrompt=true” pair chieves using Windows ticket cache (as opposed to useKeyTab, which is another option); it’s addressing a potential “No CallbackHandler available to garner authentication information from the user” error.


The rest


…is well documented in DataDirect KB article Setup of pure Java approach for Windows Authentication with DataDirect Connect for JDBC.


Point solutions


You can as well avoid the hassles of pure Java just by using Type 2 (Windows native) integration for DataDirect driver. All that ise required is connection string like jdbc:datadirect:sqlserver://yoursqlserver.example.com:1433;AuthenticationMethod=Type2 or jdbc:datadirect:sqlserver://yoursqlserver.example.com:1433;AuthenticationMethod=auto (as opposed to jdbc:datadirect:sqlserver://yoursqlserver.example.com:1433;AuthenticationMethod=Type4 or jdbc:datadirect:sqlserver://yoursqlserver.example.com:1433;AuthenticationMethod=Kerberos required for pure Java Kerberos authentication). Make sure that java.library.path includes path to DDJDBCAuth04.dll supplied with the driver. Or you can use Microsoft JDBC driver. Both will integrate with Windows.


Troubleshooting


1. Verify SPN in question. In AD, use ADSIedit to check the SPN. The LDAP attribure you are looking for is “servicePrincipalName”;
2. Enable Kerberos logging on the DCs (http://support.microsoft.com/kb/262177/) and look for relevant information in the logs;
3. Capture traffic on the client requesting Kerberos ticket and see Kerberos communications and error codes in the capture;
4. Review Q326985 (http://support.microsoft.com/kb/326985) -it’s about troubleshooting Kerberos with IIS but gives good idea about other services.
5. Did I mention enabling Java debugging where possible?
6. And if you use Java security policy, there’s a whole new world for stuff-ups.


Good luck with the integration, and don’t hesitate to post your own experiences on the Internet. Scenarios are plentiful, documentation scarce, and every piece of information helps.

3 thoughts on “Integrating Java, JDBC and Kerberos”

  1. Hello and thanks for your helpful blog post. This is the only useful piece of information I have been able to find on this subject.

    I am running WebLogic 8.1.6 on Win2003 server, and using the Datadirect Driver for my connection pool. I have set up Kerberos authentication as described and am trying to get a connection (and execute a stored procedure) as a logged in user, but when I do Datasource#getConnection (in Security.runAs(subject, new PrivilegedExceptionAction() {….) I get the following error:

    Debug is true storeKey false useTicketCache true useKeyTab false doNotPrompt true ticketCache is null KeyTab is null refreshKrb5Config is false princ
    ipal is null tryFirstPass is false useFirstPass is false storePass is false clearPass is false
    Principal is host/XXXXX@FORMUE.LOCAL
    Commit Succeeded

    applicationlogger 2007-10-31 12:01:54,202 ERROR java.sql.SQLException: Pool connect failed : java.lang.SecurityException: [Security:090398]Invalid Sub
    ject: xxxxx
    <[ServletContext(id=28475974,name=web,context-path=)] Servlet failed with Exception
    java.lang.RuntimeException: java.sql.SQLException: Pool connect failed : java.lang.SecurityException: [Security:090398]Invalid Subject: xxxxx
    at no.formue.util.database.DBMgr$1.run(DBMgr.java:308)
    at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:363)
    at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:147)
    at weblogic.security.Security.runAs(Security.java:61)
    at no.formue.util.database.DBMgr.getConnection(DBMgr.java:294)
    at no.formue.util.database.DBMgr.getDefaultConnection(DBMgr.java:262)
    at no.formue.login.servlet.ADLoginServlet.doGet(ADLoginServlet.java:45)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:740)

    The subject is authenticated and valid at this point as far as I can tell. Any ideas what might cause this?

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>