我正在尝试将应用程序从使用java7u51更改为java8u40,但SSO身份验证失败。客户端没有更改,它使用JNA Windows调用(Secur32.INSTANCE.InitializeSecurityContext
),但服务器不再接受票证。服务器代码没有改变,但它使用的标准java库似乎已经改变了。服务器在linux下运行。
服务器代码如下。在我的Windows机器上,我写了一个包含票证的文件,以便我可以运行下面的代码进行测试。我有一个非常高的clockkew设置,以便我可以测试票。我已经使用java7u51编写了客户票,以防万一,但没有帮助。当我在java7中运行以下服务器代码时,相同的票可以正常工作。
失败的位是isEstablished
返回false。没有有用的调试信息。 isEstablished
返回false表示需要更多轮次,但情况并非如此,我认为不应该这样。
有没有人知道java8现在会失败的原因?这不仅仅是更新40的问题,它在早期的Java 8版本中失败了。
感谢
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";
};
更新:如果这有帮助。我认为客户端正在发送SPNEGO票证,因为如果我试图强制上下文只接受Kerberos(1.2.840.113554.1.2.2),我会收到错误failed: No credential found for: 1.3.6.1.5.5.2 usage: Accept
更新2:这不是真正的答案,但如果我改变了Windows客户端创建票证的方式,它就可以运行。因此,如果不是创建SPNEGO包装的票证,而是创建仅限Kerberos的票证,Java8会接受它。因此,在下面将“Negotiate”更改为“Kerberos”可以解决问题。
Secur32.INSTANCE.AcquireCredentialsHandle(
servicePrincipalName,
"Negotiate", // Change to "Kerberos"
new NativeLong(Sspi.SECPKG_CRED_OUTBOUND),
null,
authIdentity.getPointer,
null,
null,
phClientCredential,
ptsClientExpiry)
答案 0 :(得分:1)
Kerberos / SPNEGO是一个废物域..
从我的想法出发,在快速检查清单下面,希望能有所帮助。
您是否需要256位加密? 可以看到打字(键类型18 = AES-256):
%JAVA_HOME%\ bin \ klist -e -f -a -k XX.keytab
如果有,请添加unrestricted policy files local_policy.jar %JAVA_HOME%\ jre \ lib \ security下的 US_export_policy.jar ?确保您获得的列表中的KVNO值相同。理想情况下,您应该只看到一个输出。
您的SPN是否可以ping通?
Kerberos可能很难设置。祝你好运。