如果 Tomcat 服务器(在 Linux 上)以 client-authentication=on (org.jboss.web.connector.ssl.client-auth=true) 运行,那么客户端 (OSX 1.7.3) 可以下载 JNLP(在浏览器中),但是 java-webstart 不能下载任何东西,甚至 JNLP 也不能,只显示一个空的证书选择对话框。
证书是自签名的。CA 和客户端证书被导入 OSX 的 KeyChain (ca->system, client+key->login)
调试问题似乎是苹果的 JNLP Java 接口试图以错误的方式到达 OSX 的 KeyChain 密钥库,没有密码(*参见下面的示例)
我基于调试JNLP下载(在OSX上)上的运行代码制作了一个小程序。
import java.security.Key;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.X509KeyManager;
public class OSXKeyChainTest {
/**
* Demonstrating issue in OSX-JNLP-Java interface, the keys from the
* KeyChain are not accessed during JNLP downloading phase. But if it would
* use any password it would work (see the FIXME line). This small test
* program is based on the debugging works on OSX 1.7.3.
*/
public static void main(String[] args) throws Exception {
KeyStore ks = KeyStore.getInstance("KeyChainStore", "Apple");
ks.load(null, new char[0]);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509", "SunJSSE");
// FIXME !!!! try it with ANY password, and it will work, eg. = new char[] {'x'};
char[] password = new char[] {};
// as AppleX509DeployKeyManager.getBrowserKeyManager() does
keyManagerFactory.init(ks, password);
X509KeyManager localX509KeyManager = null;
KeyManager[] arrayOfKeyManager = keyManagerFactory.getKeyManagers();
int i = 0;
while (i < arrayOfKeyManager.length) {
if ((arrayOfKeyManager[i] instanceof X509KeyManager)) {
localX509KeyManager = (X509KeyManager) arrayOfKeyManager[i];
break;
}
i++;
}
for (Enumeration<String> t = ks.aliases(); t.hasMoreElements();) {
String alias = t.nextElement();
System.out.println("@Alias: " + alias);
if (ks.isKeyEntry(alias)) {
System.out.println("It's a key entry");
for (Certificate c : ks.getCertificateChain(alias)) {
X509Certificate x509 = (X509Certificate) c;
System.out.println(x509.getSubjectDN().toString());
System.out.println("SN: " + x509.getSerialNumber());
}
// as SunX509KeyManagerImpl does
Key localKey = ks.getKey(alias, password);
System.out.println("Localkey: " + localKey);
}
}
System.out.println("--------------------------------");
System.out.println("It should be not null!: " + localX509KeyManager.getPrivateKey("client"));
}
}