我正在编写用于使用服务进行 Windows Kerberos 身份验证的客户端代码(省略日志记录代码):
System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");
// System.setProperty("sun.security.krb5.debug", "true");
Package thisPkg = AuthHelper.class.getPackage();
String configPath = Util.getConfigPath(thisPkg, "jaas.conf");
System.setProperty("java.security.auth.login.config", "=" + configPath);
GSSManager manager = GSSManager.getInstance();
GSSName peerName = manager.createName(spn, GSSName.NT_HOSTBASED_SERVICE);
GSSContext context = manager.createContext(peerName, null, null,
GSSContext.DEFAULT_LIFETIME);
context.requestMutualAuth(true); // required
context.requestCredDeleg(true); // required for publish
byte[] serverTokenBytes = new byte[0];
while (!context.isEstablished()) {
byte[] clientTokenBytes = context.initSecContext(serverTokenBytes, 0,
serverTokenBytes.length);
if (clientTokenBytes != null)
socket.send(createClientMessage(clientTokenBytes));
if (context.isEstablished()) break;
Message message = socket.receive();
String serverToken = message.getFirst("SERVERTOKEN").toString();
serverTokenBytes = Base64.decodeBase64(serverToken);
}
其中 jaas.conf
仅包含:
sp {
com.sun.security.auth.module.Krb5LoginModule required debug=true;
};
我还根据需要设置了 allowtgtsessionkey
注册表项,并安装了 JCE Unlimited Strength Jurisdiction Policy Files 7 .
该代码有时可以工作(即建立相互身份验证);然而,有时它会在第一次调用 GSSContext.initSecContext 时卡住一段时间,大约一分钟后抛出异常:
Exception in thread "main" GSSException: No valid credentials provided (Mechanism level: Receive timed out)
...
Caused by: java.net.SocketTimeoutException: Receive timed out
...
当我启用 Kerberos 调试输出(通过取消上面第二行的注释)时,我可以看到协议(protocol)有时会卡在以下行:
getKDCFromDNS using UDP
A Java Kerberos troubleshooting website表明这是 Kerberos 身份验证服务器的问题,但我知道服务器已启动并正在运行,因为我们有用 C#(使用 .NET 库)编写的类似代码,永远不会卡住。
最佳答案
Kerberos 身份验证服务器的 DNS 解析似乎正在经历一些间接的过程,这是不可靠的。如果您明确指定服务器(在代码开头的某个位置),它将绕过该重定向:
System.setProperty("java.security.krb5.realm", "<YOUR_KRB_REALM>");
System.setProperty("java.security.krb5.kdc", "<YOUR_KRB_SERVER_ADDR_OR_IP>");
编辑:事实证明,由于使用 UDP 协议(protocol),与 Kerberos 服务器的通信本质上是不可靠的,因此对于距离相对较远的服务器来说,它很有可能失败。 Windows 8默认使用TCP;在以前的版本上强制使用 TCP:
- XP/2000:在
HKLM\System\CurrentControlSet\Control\Lsa\Kerberos
中,将 DWORDMaxPacketSize
设置为1
。 - 2003/Vista/7:在
HKLM\System\CurrentControlSet\Control\Lsa\Kerberos\Parameters
中,将 DWORDMaxPacketSize
设置为1
。
(请注意,同一注册表目录还需要将 DWORD AllowTGTSessionKey
设置为 1
才能使 Kerberos 正常工作。)
关于java - 调用 GSSContext.initSecContext 间歇性失败 : Receive timed out,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15501633/