Raymond Raymond

Java Kerberos Authentication Configuration Sample & SQL Server Connection Practice

event 2016-05-04 visibility 22,655 comment 2 insights toc
more_vert
insights Stats

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. 

[libdefaults]
default_realm = GLOBAL.kontext.tech
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
#default_keytab_name = /app/etl/krb5.keytab
default_keytab_name = C:\ETL\krb5.keytab
[realms] GLOBAL.kontext.tech = { kdc = dc001.global.kontext.tech kdc = domaincontrollerserver001.global.kontext.tech }
  [domain_realm] .global.kontext.tech = GLOBAL.kontext.tech global.kontext.tech = GLOBAL.kontext.tech

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.kontext.tech 

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.kontext.tech

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.kontext.tech. “tangr’ is the LANID in domain “GLOBAL.kontext.tech”. The command line will ask you to input the password for the LANID.

The output is similar to the following:

Password for tangr@GLOBAL.kontext.tech: 
Done! 
Service key for principal tangr@GLOBAL.kontext.tech 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.kontext.tech

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:

/**
* Generate Kerberos authentication ticket.
*
* @param configFilePath
* Path of krb5.conf file.
* @param principalName
* Principal name to use to generate ticket.
* @param javaPath
* Java path
* @throws Exception
*/
public void generateTicket(String configFilePath, String principalName, String javaPath) throws Exception {
     System.setProperty("java.security.krb5.conf", configFilePath);
     String[] envp = { javaPath, "-Djava.security.krb5.conf=" + configFilePath,
     "com.ibm.security.krb5.internal.tools.Kinit", "-k", principalName };
     ProcessBuilder pb = new ProcessBuilder(envp);
     log.logMessage("Command line is: " + envp.toString());
     pb.redirectErrorStream(true);
     Process process = pb.start();
     process.waitFor();
     BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
     String line;
     StringBuilder output = new StringBuilder();
     while ((line = in.readLine()) != null) {
         output.append(line);
     }
     println(line); }

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.kontext.tech. “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.kontext.tech: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.

More from Kontext
comment Comments
hide_source Anonymous #176 access_time 8 years ago more_vert
@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
format_quote

person susan access_time 8 years 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
hide_source Anonymous #114 access_time 8 years ago more_vert
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

Please log in or register to comment.

account_circle Log in person_add Register

Log in with external accounts