Итак, пока есть время, быстренько опишу этот опыт.
Axis, использует системные настройки для осуществления соединения по https, т.е. теоретически можно указать системные свойства
System.setProperty("javax.net.ssl.keyStore", "securirty/cacerts");
System.setProperty("javax.net.ssl.keyStorePassword", "");
System.setProperty("javax.net.ssl.trustStore", "security/cacerts");
и клиент будет их использовать, что вполне допустимо, если нужно соединение только с одним хостом. Но что делать, если нужно коннектиться к нескольким хостам, к каждому с разными сертификатами, причем эти сертификаты находятся в разных хранилищах и имеют разные пароли? Вариантов решения проблемы два: первый - использовать jax-ws для генерации клиента, и дальше идет черная магия с конфигурацией, либо использовать свою SSLConnectionFactory, но завязываться на имя хоста. Какой их этих путей лучше, не знаю, я выбрал решение с созданием SSLConnectionFactory, как более простое. идея и часть кода взята отсюда
Итак, создаем стандартных axis клиентов по wsdl файлам, для каждого хоста получатся свои классы клиента. Далее, перед вызовом методов веб сервиса необходимо установить свойство
AxisProperties.setProperty("axis.socketSecureFactory", "org.yourcompany.packagename.CustomSSLSocketFactory");
Содержимое файла CustomSSLSocketFactory.java примерно следующее:
package org.yourcompany.packagename;
import org.apache.axis.components.net.BooleanHolder;
import org.apache.axis.components.net.JSSESocketFactory;
import org.apache.axis.components.net.SecureSocketFactory;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import java.io.FileInputStream;
import java.net.Socket;
import java.security.KeyStore;
import java.util.Hashtable;
/**
* Custom SSL socket factory to use our integrated keystore.
*
* Based loosely on org.apache.axis.components.net.SunJSSESocketFactory
*/
public class CustomSSLSocketFactory extends JSSESocketFactory implements SecureSocketFactory {
private static final String FILE_SEPARATOR = System.getProperty("file.separator");
private static final String KEYSTORE_PATH = System.getProperty("java.home") + FILE_SEPARATOR
+ "lib" + FILE_SEPARATOR
+ "security" + FILE_SEPARATOR;
public CustomSSLSocketFactory(Hashtable attributes) {
super(attributes);
}
@Override
public Socket create(String host, int port, StringBuffer otherHeaders,
BooleanHolder useFullURL) throws Exception {
sslFactory = createSSlSocketFactory(host);
return super.create(host, port, otherHeaders, useFullURL);
}
private SSLSocketFactory createSSlSocketFactory(String host) throws Exception {
String keystorePass = null;
String keystorePath = null;
if (host.equals("google.com")){
keystorePass = "passforgoogle";
keystorePath = "googlestore.jks";
} else if (host.equals("yandex.com")) {
keystorePass = "passforyandex";
keystorePath = "yandexstore.jks";
} else if (host.equals("yahoo.com")) {
keystorePass = "passforyahoo";
keystorePath = "yahoostore.jks";
}
if (keystorePass == null || keystorePath == null) {
System.out.println("unknown host "+ host +", cannot create socket factory");
return null;
}
char[] keystorepass = keystorePass.toCharArray();
FileInputStream is = new FileInputStream(KEYSTORE_PATH + keystorePath);
// create required keystores and their corresponding manager objects
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(is, keystorepass);
is.close();
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, keystorepass);
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(kmf.getKeyManagers(), null, null);
return sslContext.getSocketFactory();
}
}
Основным недостатком данного метода является то, что нужно каким-то образом задать список хостов и паролей, это может создать трудности при внедрении в системы, требующие безостановочной работы. Как вариант можно запрашивать эти данные из базы или конфигурационного файла.
Следующей на очереди будет описание работы с библиотекой шифрования Signal COM.
Комментариев нет:
Отправить комментарий