Kerberos/SPNEGO server side auth change in Java8
Asked Answered
F

1

9

I'm trying to change an application from using java7u51 to java8u40 but the SSO authentication is failing. The client hasn't changed, it uses JNA windows calls (Secur32.INSTANCE.InitializeSecurityContext) but the server is no longer accepting the ticket. The server code hasn't changed but it is using the standard java libraries which seem to have changed. The server runs under linux.

The server code is below. On my windows machine I write a file containing the ticket so that I can run the code below for testing. I have a very high clockskew set so that I can test against the ticket. I have written the client ticket using java7u51 just in case but that hasn't helped. The same ticket works fine when I run the below server code in java7.

The bit that fails is that isEstablished returns false. There is no helpful debug info. isEstablished returning false implies that there are more rounds needed but that used not be the case, and I don't think it should be.

Does anyone know of a reason that this would now fail in java8? It's not just an update 40 issue, it fails with earlier java 8 versions.

thanks

Properties.setProp("sun.security.krb5.debug", "true")
Properties.setProp("java.security.krb5.realm", "xxxx")
Properties.setProp("java.security.krb5.kdc", "xxxx")
Properties.setProp("java.security.krb5.conf", url(getClass, "/krb5.conf.auth").toExternalForm)
Properties.setProp("java.security.auth.login.config", url(getClass, "/jaas.conf.auth").toExternalForm)
Properties.setProp("javax.security.auth.useSubjectCredsOnly", "true")

val loginCtx: LoginContext = new LoginContext("Server", new LoginCallbackHandler(password))
loginCtx.login()
val subject = loginCtx.getSubject
val ticket = StringIO.readStringFromFile(new File("/tmp/ticket"))
val decoder: BASE64Decoder = new BASE64Decoder
val serviceTicket = decoder.decodeBuffer(ticket)

val user = Subject.doAs(subject, new PrivilegedAction[Option[String]]() {
  def run = {
    try {
      val manager = GSSManager.getInstance
      val context: GSSContext = manager.createContext(null: GSSCredential)
      val arrayOfBytes = context.acceptSecContext(serviceTicket, 0, serviceTicket.length)
      // we ignore arrayOfBytes
      assert(context.isEstablished, "Failed to establish context: " + context)
      val username = context.getSrcName.toString
      Some(username)
    } catch {
      case e: Exception =>
        println("failed: " + e.getMessage)
        None
    }
  }
})

krb5.conf.auth
[libdefaults]
default_realm = XXX
allow_weak_crypto=true
default_tkt_enctypes = rc4-hmac des-cbc-md5 des-cbc-crc des3-cbc-sha1
default_tgs_enctypes = rc4-hmac des-cbc-md5 des-cbc-crc des3-cbc-sha1
permitted_enctypes = rc4-hmac des-cbc-md5 des-cbc-crc des3-cbc-sha1
default_checksum = rsa-md5
kdc_timesync = 0
kdc_default_options = 0x40000010
clockskew = 30000
check_delegate = 0
ccache_type = 3
kdc_timeout = 60000
forwardable = true
dns_lookup_realm = true
dns_lookup_kdc = true
ticket_lifetime = 24h

#excluding realms and domain_realm

jaas.conf.auth (server section)

Server {
   com.sun.security.auth.module.Krb5LoginModule required
     useKeyTab=false
     debug=true
     isInitiator=false
     storeKey=true
     useTicketCache=false
     principal="XXX";
};

Update: In case this helps. I think the client is sending a SPNEGO ticket, because if I try to force the context to accept only Kerberos(1.2.840.113554.1.2.2) I get the error failed: No credential found for: 1.3.6.1.5.5.2 usage: Accept

Update 2: This isn't really the answer, but if I change the way the windows client creates the ticket it works. So if instead of creating a SPNEGO wrapped ticket you create a Kerberos only ticket it is accepted by Java8. So changing "Negotiate" to "Kerberos" below fixes the problem.

Secur32.INSTANCE.AcquireCredentialsHandle(
      servicePrincipalName,
      "Negotiate", // Change to "Kerberos"
      new NativeLong(Sspi.SECPKG_CRED_OUTBOUND),
      null,
      authIdentity.getPointer,
      null,
      null,
      phClientCredential,
      ptsClientExpiry)
Fontes answered 6/3, 2015 at 12:0 Comment(3)
Try to use "NTLM" instead of "Negotiate" and tell me whether it works. I had similar problem.Whereat
Did java8 maybe drop support for allow_weak_crypto=true?Morbilli
Java 8 changed the default for allow_weak_crypto to false, so you can't use DES unless it's explicitly specified as true: docs.oracle.com/javase/8/docs/technotes/guides/security/…Quag
A
1

Kerberos/SPNEGO is a waste domain..

From what comes to my mind, below a quick check list that hopefully will be of any help.

  1. Have you regenerate your keytab? with the same JDK that you are using on the server side ?
  2. Is your server running under the right user (as defined in your key tab) ?
  3. Have you generate them selecting "never expire" option?
  4. Do you requiert 256 bits encryption ? Can be seen typing (key type 18 = AES-256):

    %JAVA_HOME%\bin\klist -e -f -a -k XX.keytab

    %JAVA_HOME%\bin\klist -e -f -a -k XX.keytab]

    If so, have you add the unrestricted policy files local_policy.jar US_export_policy.jar under %JAVA_HOME%\jre\lib\security ? Ensure the KVNO value is the same in the list you get. Ideally, you should see only one output.

  5. Is your SPN pingable ?

  6. Is your KDC server list correct ?
  7. Pay attention to the krb5.conf. Got problem with. Seems to be case sensitive even in Windows environment.

Kerberos can be difficult to setup. So Good luck.

Autrey answered 6/10, 2015 at 12:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.