javakerberosjtdsapache-commons-dbcpintegrated-security

Kerberos and Integrated Security using jTDS Driver


Up till now we were using MS JDBC Driver 4.0 to connect to SQL Server 2008 using Integrated Security and Java Kerberos and everything was working fine.

Here is the code:

Spring Context:

<!-- ***** Data Source Configuration ***** -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close">
    <property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
    <property name="url"
        value="jdbc:jtds:sqlserver://<serverName>:<port>;databaseName=<DBName>;integratedSecurity=true;authenticationScheme=JavaKerberos; />
    <property name="initialSize" value="5" />
    <property name="maxActive" value="2" />
    <property name="defaultAutoCommit" value="false" />
</bean>

<!-- ***** Transaction Manager ***** -->
<bean id="txManager"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="txManager" />

<!-- ***** JDBC Configuration ***** -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <constructor-arg type="javax.sql.DataSource" ref="dataSource" />
</bean>

login.conf File:

com.sun.security.jgss.krb5.initiate {
   com.sun.security.auth.module.Krb5LoginModule required
   useTicketCache=false
   doNotPrompt=true
   useKeyTab=true
   keyTab="C:/myKeyTABFile"
   principal="me@org.foo.com"
   storeKey=true
   debug=true
};

krb5.conf File:

[libdefaults]
    default_realm = org.foo.com
    dns_lookup_realm = false
    dns_lookup_kdc = true
    ticket_lifetime = 1s
    forwardable = yes
    #udp_preference_limit = 1

[realms]
    org.foo.com = {
      kdc = org.foo.com
      default_domain = org.foo.com
    }

[domain_realm]
    .org.foo.com = org.foo.com

[login]
    krb4_convert = true
    krb4_get_tickets = false

We were passing following arguments while running the Project:

-Djava.security.krb5.debug=true 
-Djava.security.auth.login.config="C:\login.conf" 
-Djava.security.krb5.conf="C:\krb5.conf

Now, we decided to use jTDS instead of MS JDBC Driver and I made following changes in the above configuration:

  1. Changed Driver class from com.microsoft.sqlserver.jdbc.SQLServerDriver to net.sourceforge.jtds.jdbc.Driver
  2. Changed Connection String from jdbc:sqlserver://... to jdbc:jtds:sqlserver://...
  3. Added jTDS JAR and NTLM Authentication DLL File(s) to the Classpath

But it is giving me the following error:

Exception in thread "main" org.apache.commons.dbcp.SQLNestedException: Cannot create PoolableConnectionFactory (I/O Error: GSS Failed: No valid credentials provided (Mechanism level: Failed to find any Kerberos tgt)) at org.apache.commons.dbcp.BasicDataSource.createPoolableConnectionFactory(BasicDataSource.java:1549) at org.apache.commons.dbcp.BasicDataSource.createDataSource(BasicDataSource.java:1388) at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044) at org.foo.utils.Foo.main(Foo.java:51) Caused by: java.sql.SQLException: I/O Error: GSS Failed: No valid credentials provided (Mechanism level: Failed to find any Kerberos tgt) at net.sourceforge.jtds.jdbc.TdsCore.login(TdsCore.java:654) at net.sourceforge.jtds.jdbc.JtdsConnection.(JtdsConnection.java:371) at net.sourceforge.jtds.jdbc.Driver.connect(Driver.java:184) at org.apache.commons.dbcp.DriverConnectionFactory.createConnection(DriverConnectionFactory.java:38) at org.apache.commons.dbcp.PoolableConnectionFactory.makeObject(PoolableConnectionFactory.java:582) at org.apache.commons.dbcp.BasicDataSource.validateConnectionFactory(BasicDataSource.java:1556) at org.apache.commons.dbcp.BasicDataSource.createPoolableConnectionFactory(BasicDataSource.java:1545) ... 3 more Caused by: java.io.IOException: GSS Failed: No valid credentials provided (Mechanism level: Failed to find any Kerberos tgt) at net.sourceforge.jtds.jdbc.TdsCore.sendMSLoginPkt(TdsCore.java:1976) at net.sourceforge.jtds.jdbc.TdsCore.login(TdsCore.java:617) ... 9 more

Things I have already tried:

  1. Tried appending useKerberos=true; and useNTLMv2=true; to the Connection String
  2. Tried appending domain=org.foo.com to the Connection String

But it does not seems to be working. I tried searching on internet but could not find any solution.

Would appreciate if someone could help me out.


Solution

  • After searching and trying different combinations and looking at the source code of jTDS this is what finally worked for me.

    1. Use property useKerberos=true in the Connection String

      Source: https://sourceforge.net/p/jtds/patches/101/

    2. Pass VM Argument -Djavax.security.auth.useSubjectCredsOnly=false

    So, finally after applying the above changes my Connection String looked like below:

    jdbc:jtds:sqlserver://<serverName>:<port>;databaseName=<DBName>;useKerberos=true;
    

    Arguments List:

    -Djava.security.krb5.debug=true 
    -Djava.security.auth.login.config="C:\login.conf" 
    -Djava.security.krb5.conf="C:\krb5.conf
    -Djavax.security.auth.useSubjectCredsOnly=false