Java Kerberos Authentication Configuration Sample & SQL Server Connection Practice

2974 views 2 comments posted at about 2 years ago Raymond

Overview

Recently, I have been working on an ETL framework to load various source data (i.e. files, SQL Server, Oracle and Teradata) into Teradata. Due to some limitations, Java was chosen as the implementation language though IBM Infosphere DataStage is available to use. DataStage has provided built-in ODBC drivers (from DataDirect) while JDBC drivers are available for almost all the databases. For example, Teradata provides JDBC sample codes about how to connect to Teradata using FASTLOAD, FASTLOADCSV and etc.

The whole development process using Java is smooth even I didn’t have any experience before. As a .NET engineer, it is pretty easy to start coding with Java. Only recently we met one issue about Kerberos authentication. Our framework needs to support Windows authentication for SQL Server. It is easy to implement in Windows client as we can use sqljdbc_auth.dll but we need to make it work in UNIX (IBM AIX) where our framework will reside in. So we choose pure Java Kerberos authentication. As I am not familiar with Kerberos authentication, it took about one day to read through all the posts and related documentations in the internet. To save your time, I am summarizing the steps required.

Prerequisites

If you are not familiar with Kerberos authentication or its usage in SQL Server/Windows, I suggest you read through the following articles:

· MIT Kerberos Documentation: http://web.mit.edu/kerberos/krb5-1.13/doc/admin/conf_files/krb5_conf.html#libdefaults

· Java Kerberos Requirements: https://docs.oracle.com/javase/8/docs/technotes/guides/security/jgss/tutorials/KerberosReq.html#SetProps

· Using Kerberos Integrated Authentication to Connect to SQL Server: https://msdn.microsoft.com/en-us/library/gg558122(v=sql.110).aspx

As we are using Java Kerberos, some Java related executables are used to create configurations.

· Kinit or com.ibm.security.krb5.internal.tools.Kinit: http://docs.oracle.com/javase/7/docs/technotes/tools/windows/kinit.html

· Ktab or com.ibm.security.krb5.internal.tools.Ktab: http://docs.oracle.com/javase/7/docs/technotes/tools/windows/ktab.html or https://www.ibm.com/support/knowledgecenter/SSYGQH_4.5.0/admin/secure/t_install_kerb_create_service_account.html

We will use ktab to create principle and kinit to create ticket.

As we are using Java, all the configuration, tools or code will work in all the supported platforms, i.e. Windows, UNIX and Linux.

Create krb5.conf

The follow is one sample configuration file. If you need to understand the configuration items, please read through the MIT documentation.

   1:  [libdefaults]
   2:   
   3:  default_realm = GLOBAL.KOSMISCH.NET
   4:   
   5:  default_tkt_enctypes = rc4-hmac des3-cbc-sha1 arcfour-hmac des-cbc-md5 des-cbc-crc
   6:   
   7:  default_tgs_enctypes = rc4-hmac des3-cbc-sha1 arcfour-hmac des-cbc-md5 des-cbc-crc
   8:   
   9:  #default_keytab_name = /app/etl/krb5.keytab
  10:   
  11:  default_keytab_name = C:\ETL\krb5.keytab
  12:   
  13:  [realms]
  14:   
  15:  GLOBAL.KOSMISCH.NET = {
  16:   
  17:  kdc = dc001.global.kosmisch.net
  18:   
  19:  kdc = domaincontrollerserver001.global.kosmisch.net 
  20:   
  21:  }
  22:   
  23:  [domain_realm]
  24:   
  25:  .global.kosmisch.net = GLOBAL.KOSMISCH.NET
  26:   
  27:  global.kosmisch.net = GLOBAL.KOSMISCH.NET
  28:   

In the above example, I am using keytab file to generate ticket. The kdc server name is normally the domain controller server name.

Find KDC in your Active Directory

If you don’t know your KDC server name in your domain, you can use the following command lines to find it out.

nltest /dsgetdc:global.kosmisch.net

Change the domain address to your own ones. In the output, DC is the domain controller which is also normally your KDC (Kerberos Distribution Centre) host name.

The command below will also give you a list of hostnames which you can configure.

nslookup -type=any _kerberos._tcp

Generate keytab file

As I am changing the default location of Java krb5.conf file, I need to specify Java system property “java.security.krb5.conf” to the location of configuration file.

   1:  java -Djava.security.krb5.conf=C:\ETL\krb5.conf com.ibm.security.krb5.internal.tools.Ktab -a tangr@ GLOBAL.KOSMISCH.NET

If you have access to any of the default file locations (documented in Java Kerberos documentation), you can directly use ktab command line to create the file.

In the above example, I am using IBM tool to create a principle named tangr@GLOBAL.KOSMISCH.NET. “tangr’ is the LANID in domain “GLOBAL.KOSMISCH.NET”. The command line will ask you to input the password for the LANID.

The output is similar to the following:

Password for tangr@GLOBAL.KOSMISCH.NET:

Done!

Service key for principal tangr@GLOBAL.KOSMISCH.NET saved

Keytab file “C:\ETL\krb5.keytab” will be created based on my configuration if it is not configured previously.

Initialize Ticket

Since we have keytab file created, we can now initialize ticket cache by using the following command:

   1:  java -Djava.security.krb5.conf=C:\ETL\krb5.conf com.ibm.security.krb5.internal.tools.Kinit -k tangr@ GLOBAL.KOSMISCH.NET

Similar to the ktab example, I am using IBM Kinit tool to generate. As we are using keytab, you don’t need to specify the password for your LANID again.

Done!

New ticket is stored in cache file C:\Users\tangr\krb5cc_tangr

The cached ticket is stored in user folder with name krb5cc_$username by default.

Connect to SQL Server in Java from Windows or UNIX/Linux

Once all the items are configured, you can initialize the ticket through Java code as well before creating SQL Server connection:

   1:  /**
   2:  
   3:  * Generate Kerberos authentication ticket.
   4:  
   5:  * 
   6:  
   7:  * @param configFilePath
   8:  
   9:  * Path of krb5.conf file.
  10:  
  11:  * @param principalName
  12:  
  13:  * Principal name to use to generate ticket.
  14:  
  15:  * @param javaPath
  16:  
  17:  * Java path
  18:  
  19:  * @throws Exception
  20:  
  21:  */
  22:   
  23:  public void generateTicket(String configFilePath, String principalName, String javaPath) throws Exception {
  24:   
  25:  System.setProperty("java.security.krb5.conf", configFilePath);
  26:   
  27:  String[] envp = { javaPath, "-Djava.security.krb5.conf=" + configFilePath,
  28:   
  29:  "com.ibm.security.krb5.internal.tools.Kinit", "-k", principalName };
  30:   
  31:  ProcessBuilder pb = new ProcessBuilder(envp);
  32:   
  33:  log.logMessage("Command line is: " + envp.toString());
  34:   
  35:  pb.redirectErrorStream(true);
  36:   
  37:  Process process = pb.start();
  38:   
  39:  process.waitFor();
  40:   
  41:  BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
  42:   
  43:  String line;
  44:   
  45:  StringBuilder output = new StringBuilder();
  46:   
  47:  while ((line = in.readLine()) != null) {
  48:   
  49:  output.append(line);
  50:   
  51:  }
  52:   
  53:  println(line);
  54:   
  55:  }
  56:   

In the above code, “principalName” is the one which you initialized ticket for, which is also the account that will be used to connect to your database. In my example, principleName is tangr@ GLOBAL.KOSMISCH.NET. “javaPath” can be specified as full path of java.exe or java based on your environment and system path settings. You don’t need to specify username or password for creating connection when using Kerberos.

conn = DriverManager.getConnection(jdbcString, null, null);

The following is one example of JDBC connection string when using Kerberos authentication:

   1:  jdbc:sqlserver://servername.global.kosmisch.net:54555;integratedSecurity=true;databaseName=myDatabase;authenticationScheme=JavaKerberos;

‘54555’ is the SQL Server service port number. JDBC will automatically build the principle name based on connection string for you. In SQL Server JDBC 4.2 or later version (requires Java version 52.0/1.8), you can specify the principle name as well in connection string.

Fix Some Issues

Unable to obtain Princpal Name for authentication

If you got the above exception, it means you didn’t generate cached ticket for the principle.

com.microsoft.sqlserver.jdbc.SQLServerException: Integrated authentication failed.

Caused by: javax.security.auth.login.LoginException: Unable to obtain Princpal Name for authentication

at com.sun.security.auth.module.Krb5LoginModule.promptForName(Krb5LoginModule.java:796)

at com.sun.security.auth.module.Krb5LoginModule.attemptAuthentication(Krb5LoginModule.java:667)

at com.sun.security.auth.module.Krb5LoginModule.login(Krb5LoginModule.java:580)

at sun.reflect.GeneratedMethodAccessor2.invoke(Unknown Source)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

at java.lang.reflect.Method.invoke(Method.java:601)

at javax.security.auth.login.LoginContext.invoke(LoginContext.java:784)

at javax.security.auth.login.LoginContext.access$000(LoginContext.java:203)

at javax.security.auth.login.LoginContext$4.run(LoginContext.java:698)

at javax.security.auth.login.LoginContext$4.run(LoginContext.java:696)

at java.security.AccessController.doPrivileged(Native Method)

at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:695)

at javax.security.auth.login.LoginContext.login(LoginContext.java:594)

at com.microsoft.sqlserver.jdbc.KerbAuthentication.intAuthInit(KerbAuthentication.java:132)

Illegal key size or default parameters

If you got this exception, that means your krb5.conf is not correctly configured for encryption method.

default_tkt_enctypes = rc4-hmac des3-cbc-sha1 arcfour-hmac des-cbc-md5 des-cbc-crc

default_tgs_enctypes = rc4-hmac des3-cbc-sha1 arcfour-hmac des-cbc-md5 des-cbc-crc

I got this issue when our AD was configured not to avoid AES256 while I previously added it into the above configuration. Once I remove that algorithm from the list, the problem is resolved.

Add comment

Comments (2)

Raymond about 9 months ago Re:Java Kerberos Authentication Configuration Sample & SQL Server Connection Practice

@susan Hi please refer to the KTab and KInit links in the page to generate principle: As we are using Java Kerberos, some Java related executables are used to create configurations. · Kinit or com.ibm.security.krb5.internal.tools.Kinit: http://docs.oracle.com/javase/7/docs/technotes/tools/windows/kinit.html · Ktab or com.ibm.security.krb5.internal.tools.Ktab: http://docs.oracle.com/javase/7/docs/technotes/tools/windows/ktab.html or https://www.ibm.com/support/knowledgecenter/SSYGQH_4.5.0/admin/secure/t_install_kerb_create_service_account.html

susan about 9 months ago

can you provide the detail steps on fix the Unable to obtain Principal Name for authentication. I have been search this one. Your posting identified the issue

susan about 9 months ago Re:Java Kerberos Authentication Configuration Sample & SQL Server Connection Practice

can you provide the detail steps on fix the Unable to obtain Principal Name for authentication. I have been search this one. Your posting identified the issue
In this Page