【发布时间】:2014-05-31 03:30:11
【问题描述】:
我有一个程序,该程序有两个可运行文件,一个称为 ServerImpl,另一个称为 ClientImpl。我的目标是能够让 ClientImpl 使用带有 SSL 的 RMI 连接到 ServerImpl 并调用一个方法。服务器还应该能够使用 RMI 和 SSL 通过回调调用客户端上的方法。我可以让客户端使用 SSL 连接到服务器并调用该服务器上的方法,但是我无法让服务器使用带有 SSL 的 RMI 连接回客户端。
该程序还有两个目录,其中包含两组不同的证书、密钥库、信任库文件:
resources/client/
client_cert.cer
client_keystore.jks
client_truststore.jks
resources/server/
server_cert.cer
server_keystore.jks
server_truststore.jks
ServerImpl.java 文件:
public class ServerImpl implements ServerInt {
private ClientInt client;
public static void main(String[] args) {
ServerImpl server = new ServerImpl();
server.bind();
}
public void bind() {
System.setProperty("java.rmi.server.hostname", "192.168.0.32");
System.setProperty("javax.net.ssl.keyStore", "./resources/server/server_keystore.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "password");
RMIClientSocketFactory rmiClientSocketFactory = new SslRMIClientSocketFactory();
RMIServerSocketFactory rmiServerSocketFactory = new SslRMIServerSocketFactory();
try {
ServerInt si = (ServerInt) UnicastRemoteObject.exportObject(this, 0, rmiClientSocketFactory, rmiServerSocketFactory);
Registry reg = LocateRegistry.createRegistry(1099);
reg.rebind("server", si);
System.out.println("RMIServer is bound in registry");
} catch (RemoteException ex) {
Logger.getLogger(ServerImpl.class.getName()).log(Level.SEVERE, null, ex);
}
}
@Override
public void connect(ClientInt ci) throws RemoteException {
System.out.println("client connected");
}
}
ClientImpl.java 文件:
public class ClientImpl implements ClientInt {
private ServerInt server;
public static void main(String[] args) {
ClientImpl client = new ClientImpl();
client.bind();
client.initConnection();
client.connectToServer();
}
public void initConnection() {
System.setProperty("javax.net.ssl.trustStore", "./resources/client/client_truststore.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "password");
try {
Registry reg = LocateRegistry.getRegistry("192.168.0.32", 1099);
server = (ServerInt) reg.lookup("server");
} catch (RemoteException ex) {
Logger.getLogger(ClientImpl.class.getName()).log(Level.SEVERE, null, ex);
} catch (NotBoundException ex) {
Logger.getLogger(ClientImpl.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void bind() {
System.setProperty("java.rmi.server.hostname", "192.168.0.32");
System.setProperty("javax.net.ssl.keyStore", "./resources/client/client_keystore.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "password");
RMIClientSocketFactory rmiClientSocketFactory = new SslRMIClientSocketFactory();
RMIServerSocketFactory rmiServerSockeyFactory = new SslRMIServerSocketFactory();
try {
ClientInt ci = (ClientInt) UnicastRemoteObject.exportObject(this, 0, rmiClientSocketFactory, rmiServerSockeyFactory);
Registry reg = LocateRegistry.createRegistry(5001);
reg.rebind("client", ci);
System.out.println("RMIClient is bound in registry");
} catch (RemoteException ex) {
Logger.getLogger(ClientImpl.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void connectToServer() {
try {
server.connect(this);
} catch (RemoteException ex) {
Logger.getLogger(ClientImpl.class.getName()).log(Level.SEVERE, null, ex);
}
}
@Override
public void sayHelloToClient(String helloText) throws RemoteException {
System.out.println(helloText);
}
}
然后我运行 ServerImpl.java 文件,它运行正常没有问题。然后我运行 ClientImpl.java 文件,调用 connectToServer 方法时出现错误:
java.rmi.ConnectIOException: error during JRMP connection establishment; nested exception is:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
任何人都可以阐明这里的问题以及我可以如何解决它吗?如果做不到这一点,任何人都可以向我指出一个关于让两个 RMI 实体使用 SSL 相互通信的好教程吗?谢谢。
【问题讨论】: