Próbuję zmienić aplikację z użycia java7u51 na java8u40, ale uwierzytelnianie SSO nie działa. Klient się nie zmienił, korzysta z wywołań okien JNA (Secur32.INSTANCE.InitializeSecurityContext
), ale serwer nie akceptuje już biletu. Kod serwera nie został zmieniony, ale używa standardowych bibliotek java, które wydają się być zmienione. Serwer działa pod Linuksem.Zmiana uwierzytelnienia serwera Kerberos/SPNEGO w języku Java8
Kod serwera znajduje się poniżej. Na moim komputerze z systemem Windows piszę plik zawierający ten bilet, dzięki czemu mogę uruchomić poniższy kod do testowania. Mam ustawiony bardzo wysoki zegar tak, że mogę przetestować bilet. Napisałem bilet klienta za pomocą java7u51 na wszelki wypadek, ale to nie pomogło. Ten sam bilet działa poprawnie, gdy uruchomię poniższy kod serwera w java7.
Bit, który zawodzi, polega na tym, że isEstablished
zwraca wartość false. Nie ma przydatnych informacji debugowania. isEstablished
Zwrot fałszywego implikuje, że potrzeba więcej rund, ale tak się nie stało i nie sądzę, że tak powinno być.
Czy ktoś wie, dlaczego to się nie powiedzie w java8? To nie jest tylko problem z aktualizacją 40, ale nie działa z wcześniejszymi wersjami java 8.
dzięki
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";
};
Aktualizacja: W przypadku pomaga. Myślę, że klient wysyła bilet SPNEGO, ponieważ jeśli spróbuję zmusić kontekst do zaakceptowania tylko Kerberos (1.2.840.113554.1.2.2) otrzymuję komunikat o błędzie failed: No credential found for: 1.3.6.1.5.5.2 usage: Accept
Aktualizacja 2: To nie jest tak naprawdę odpowiedź , ale jeśli zmienię sposób, w jaki klient systemu Windows tworzy bilet, działa. Jeśli więc zamiast tworzyć bilet zawinięty SPNEGO, utworzysz bilet jedyny Kerberos, zostanie on zaakceptowany przez Javę8. Zatem zmiana "Negocjuj" na "Kerberos" poniżej rozwiązuje problem.
Secur32.INSTANCE.AcquireCredentialsHandle(
servicePrincipalName,
"Negotiate", // Change to "Kerberos"
new NativeLong(Sspi.SECPKG_CRED_OUTBOUND),
null,
authIdentity.getPointer,
null,
null,
phClientCredential,
ptsClientExpiry)
Spróbuj użyć "NTLM" zamiast "Negocjuj" i powiedz mi, czy to działa. Miałem podobny problem. – kukis
Czy java8 może porzucić wsparcie dla 'allow_weak_crypto = true'? –
Java 8 zmieniła domyślną wartość dla allow_weak_crypto na false, więc nie można używać DES, chyba że jest jawnie określone jako prawdziwe: https://docs.oracle.com/javase/8/docs/technotes/guides/security/enhancements-8 .html –