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)
allow_weak_crypto=true
? – Morbilli