Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java + Kerberos - disable reverse DNS lookup

Tags:

java

kerberos

We are using the Apache HttpClient library in order to connect to a Kerberos-secured REST endpoint which is behind a load balancer that serves multiple applications, so there is a mismatch between the forward and reverse DNS lookup results.

While we can successfully establish an authenticated session using cURL by setting rdns=false in the krb5.conf file, the same does not seem possible in Java - it is simply ignoring this setting and always performs the reverse DNS lookup, which of course fails the handshake due to the mismatch.

I haven't found too much information regarding this issue, but I did find this open Jira item, which explains the behavior we're seeing.. but does not provide any workaround: https://bugs.openjdk.java.net/browse/JDK-8189361

The only viable workaround I've found so far is to use a custom nameservice provider to "hijack" the reverse DNS lookups and return the desired hostname.
There is also very scarce information on this, but I found this blogpost from almost 12 years ago that still seems to work (although it feels like a pretty dirty hack):
http://rkuzmik.blogspot.co.il/2006/08/local-managed-dns-java_11.html

However it feels like I may be missing something here as it seems unlikely that there is so little information about this problem..

Has anyone else faced an issue with disabling reverse DNS lookups when doing Kerberos, in Java? If so, how did you resolve this.

like image 772
Dan Markhasin Avatar asked Jan 10 '18 17:01

Dan Markhasin


People also ask

How to disable reverse DNS lookup in Kerberos authentication?

I know one can disable the reverse DNS lookup made by individual client applications when calculating SPN of the called server during Kerberos authentication. There are various ways, e. g.: In Java: Java + Kerberos - disable reverse DNS lookup. When using the MIT Kerberos implementation: Principal names and DNS - search for rdns = false.

What is the default DNS lookup for SSH authentication requests?

By default, ssh server performs a reverse DNS lookup for authentication requests. This can be so annoying as you wait ten’s of seconds for the lookup to finish.

What's the problem with reverse lookup?

The problem is that the reverse lookups not only break the usage of server aliases (CNAMES), but their optional-ity can cause really unexpected and unstable behavior when different programs on the same machine decide to handle it differently. Like for example when Fiddler makes Kerberos authentication work.

Is the Kerberos protocol too complicated?

At its base, Kerberos isn't an overly complicated protocol. I have also already successfully configured a server to accept Kerberos authentications via SPNEGO HTTP headers. I'm new in this area though, so maybe I have just overlooked something...


Video Answer


3 Answers

I experienced the same error last week when I was using a VIP but the reverse dns gave back to me the FQDN of the physical server. Unfortunately I'm not using directly HttpClient-4.5.1 library but a software which is using it behind the scenes; for that reason I was looking for a solution without touching the source code of that software. I did really a huge amount of tentatives (jvm spi.dns, jvm gss native, dnsjava.jar, ...) unfortunately without any success. At the end, the "dirty solution" has been for me to rebuild the HttpClient jar changing the class "org.apache.http.impl.auth.GGSSchemeBase" on its method "String resolveCanonicalHostname(final String host)".

For a possible "good solution", I saw that this class is receiving the parameter "boolean useCanonicalHostname" directly in its constructor so, if you can work directly with HttpClient library, there might be a way to set this parameter to false somewhere and propagate it down to this class where the kerberos service ticket is generated (if the parameter is false, the rdns check is not done and the Host string is used instead).

I hope that this hint can help you.

BR

Samuele

like image 98
Samuele Avatar answered Oct 13 '22 15:10

Samuele


For anyone who runs into the same issue using the Apache HttpClient library, the following code works - the important bit is the constructor of SPNegoSchemeFactory which is:

public SPNegoSchemeFactory(final boolean stripPort, final boolean useCanonicalHostname)

Below is the Scala code that I am using right now:

  private val registry = RegistryBuilder
    .create()
    .register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory(true,false))
    .build()
    .asInstanceOf[Lookup[AuthSchemeProvider]]

  private val credentialsProvider = new BasicCredentialsProvider

  private val useJaasCreds = new Credentials()
  {
    def getPassword: String = null

    def getUserPrincipal: Principal = null
  }

  credentialsProvider.setCredentials(new AuthScope(null, -1, null), useJaasCreds)

  private val httpClient = HttpClientBuilder
    .create()
    .setDefaultAuthSchemeRegistry(registry)
      .setDefaultCredentialsProvider(credentialsProvider)
    .build()
like image 33
Dan Markhasin Avatar answered Oct 13 '22 16:10

Dan Markhasin


I have faced the same issue and after doing the investigation found that none of existing Java HTTP/Kerberos clients gives you full control over generation of SPNs. So I've started working on a standalone library which allows generation and validation of Authorization: Negotiate XXX / WWW-Authenticate: Negotiate XXX HTTP headers.

It's called Kerb4J.

Consider you have a domain cname.provider.acme.com which is a CNAME (AKA alias) for domain a.provider.acme.com whose canonical DNS name (i.e. which is resolved after reverse DNS lookup) is ptr.provider.acme.com

You want to make a request to cname.provider.acme.com using your favorite HTTP client but do not want it to make any additional manipulations to DNS during SPN calculation.

URL url = new URL("http://cname.provider.acme.com/api/operation1");
SpnegoContext context = spnegoClient.createContext("http://cname.provider.acme.com"); // Will result in HTTP/cname.provider.acme.com SPN
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestProperty("Authorization", context.createTokenAsAuthroizationHeader());

With Kerb4J you can even make SPNEGO-protected requests using an arbitrary SPN (useful say when testing code on local machine):

URL url = new URL("http://localhost:8080/api/operation1");
SpnegoContext context = spnegoClient.createContext("http://cname.provider.acme.com"); // Will result in HTTP/cname.provider.acme.com SPN
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestProperty("Authorization", context.createTokenAsAuthroizationHeader());

There's a released version available in Maven Central.

Disclaimer: I'm the author of Kerb4J.

like image 1
bedrin Avatar answered Oct 13 '22 16:10

bedrin