Как включить TLS1.1 в Java7 для клиента веб-сервиса Axis1
Описание: Salesforce.com недавно отключил TLSv1 для своих экземпляров песочницы (test.salesforce.com) и может поддерживать TLSv1.1 и выше только для интеграции API как для входящих, так и для исходящих запросов.
Я использую клиентский код Java Axis1.0 с JDK 7.0 для подключения (через мыло веб-сервиса) к salesforce.com. Я получаю исключение "UNSUPPORTED_CLIENT: TLS 1.0 был отключен в этой организации. Пожалуйста, используйте TLS 1.1 или выше при подключении к Salesforce с использованием https".With Java7.0
Supported Protocols:SSLv2Hello, SSLv3, TLSv1, TLSv1.1, TLSv1.2
Enabled Protocols: TLSv1
`С Java8.0, когда я пытаюсь подключиться к salesforce.com с клиентом java8, соединение успешно.
Поддерживаемые протоколы: SSLv2Hello, SSLv3, TLSv1, TLSv1.1, TLSv1.2 Включенные протоколы: TLSv1, TLSv1.1, TLSv1.2`
Я должен использовать Java 7, потому что наше приложение использует его. Я попытался установить vm args: -Dhttps.protocols=TLSv1.1,TLSv1.2 -Ddeployment.security.SSLv2Hello=false -Ddeployment.security.SSLv3=false -Ddeployment.security.TLSv1=false -Ddeployment.security.TLSv1.1=true -Ddeployment.security.TLSv1.2=true", но безуспешно.
Можете ли вы помочь мне узнать настройки в Java7 для включения TLSv1.1?
3 ответа
Нашел решение:
Мне пришлось написать пользовательские настройки JSSESocketFactory (потому что я использую клиент Axis1.0 веб-службы Java) и настройки AxisProperties.
Что-то вроде,
public class TLSSocketSecureFactory extends JSSESocketFactory {
private final String TLS_VERSION_1_1 = "TLSv1.1";
private final String TLS_VERSION_1_2 = "TLSv1.2";
public TLSSocketSecureFactory(@SuppressWarnings("rawtypes") Hashtable attributes) {
super(attributes);
}
@Override
protected void initFactory() throws IOException {
SSLContext context;
try {
context = SSLContext.getInstance(TLS_VERSION_1_1);
context.init(null, null, null);
sslFactory = context.getSocketFactory();
} catch (NoSuchAlgorithmException | KeyManagementException e) {
//printstacktrace or throw IOException
}
}
@Override
public Socket create(String host, int port, StringBuffer otherHeaders, BooleanHolder useFullURL) throws Exception {
if (sslFactory == null) {
initFactory();
}
Socket s = super.create(host, port, otherHeaders, useFullURL);
((SSLSocket) s).setEnabledProtocols(new String[] {TLS_VERSION_1_1, TLS_VERSION_1_2 });
return s;
}
}
AxisProperties.setProperty ("axis.socketSecureFactory", TLSSocketSecureFactory.class.getCanonicalName ());
Это требуется только для JDK7. при переносе приложения на JDK8 этот класс не требуется. В Java8 TLSv1.1 и TLS1.2 включены по умолчанию.
Примечание. Настройка конфигурации VM на сервере здесь не поможет для Java-клиента Axis.
Приведенное выше решение хорошо работает, когда транспорт Axis является HTTPSender по умолчанию. Также полезно знать, что новую фабрику сокетов можно заменить не только AxisProperties, но и системным свойством, которое можно передать в командной строке следующим образом:
-Dorg.apache.axis.components.net.SecureSocketFactory=your.package.TLSv12JSSESocketFactory
Вот код для моей TLSv12JSSESocketFactory:
package your.package;
import java.util.Hashtable;
import java.io.IOException;
import java.net.Socket;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import org.apache.axis.components.net.JSSESocketFactory;
import org.apache.axis.components.net.BooleanHolder;
public class TLSv12JSSESocketFactory extends JSSESocketFactory {
private final String TLS_VERSION_1_2 = "TLSv1.2";
public TLSv12JSSESocketFactory( @SuppressWarnings("rawtypes") Hashtable attributes ) {
super(attributes);
}
@Override
protected void initFactory() throws IOException {
SSLContext context;
try {
context = SSLContext.getInstance( TLS_VERSION_1_2 );
context.init( null, null, null );
sslFactory = context.getSocketFactory();
} catch ( Exception e ) {
throw new IOException( "Could not init SSL factory with TLS context: " + TLS_VERSION_1_2, e );
}
}
@Override
public Socket create( String host, int port, StringBuffer otherHeaders, BooleanHolder useFullURL ) throws Exception {
Socket s = super.create( host, port, otherHeaders, useFullURL );
((SSLSocket) s).setEnabledProtocols( new String[] { TLS_VERSION_1_2 } );
return s;
}
}
В моем случае мне пришлось изменить Axis 1.4 с использованием Apache Commons HttpClient в качестве транспорта. Это включало создание класса, реализующего интерфейс SecureProtocolSocketFactory. Вот мой код:
package your.package;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import javax.net.ssl.SSLSocket;
import org.apache.commons.httpclient.params.HttpConnectionParams;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory;
public class TLSv12HttpsSocketFactory implements SecureProtocolSocketFactory
{
private static final String TLS_VERSION_1_2 = "TLSv1.2";
private final SecureProtocolSocketFactory base;
public TLSv12HttpsSocketFactory( ProtocolSocketFactory base )
{
if ( base == null || !(base instanceof SecureProtocolSocketFactory) ) throw new IllegalArgumentException();
this.base = (SecureProtocolSocketFactory) base;
}
private Socket acceptOnlyTLS12( Socket socket )
{
if ( socket != null && (socket instanceof SSLSocket) ) {
((SSLSocket) socket).setEnabledProtocols( new String[] { TLS_VERSION_1_2 } );
}
return socket;
}
@Override
public Socket createSocket( String host, int port ) throws IOException
{
return acceptOnlyTLS12( base.createSocket(host, port) );
}
@Override
public Socket createSocket( String host, int port, InetAddress localAddress, int localPort ) throws IOException
{
return acceptOnlyTLS12( base.createSocket(host, port, localAddress, localPort) );
}
@Override
public Socket createSocket( String host, int port, InetAddress localAddress, int localPort, HttpConnectionParams params ) throws IOException
{
return acceptOnlyTLS12( base.createSocket(host, port, localAddress, localPort, params) );
}
@Override
public Socket createSocket( Socket socket, String host, int port, boolean autoClose ) throws IOException
{
return acceptOnlyTLS12( base.createSocket(socket, host, port, autoClose) );
}
}
Но мне также пришлось изменить класс org.apache.axis.transport.http.CommonsHTTPSender (генерирует несколько файлов классов при компиляции) следующим образом:
// import the new socket factory
import your.package.TLSv12HttpsSocketFactory;
...
// add this at the end of the initialize() method
// setup to our custom TLSv1.2 socket factory
String scheme = "https";
Protocol baseHttps = Protocol.getProtocol( scheme );
int defaultPort = baseHttps.getDefaultPort();
ProtocolSocketFactory baseFactory = baseHttps.getSocketFactory();
ProtocolSocketFactory customFactory = new TLSv12HttpsSocketFactory( baseFactory );
Protocol customHttps = new Protocol( scheme, customFactory, defaultPort );
Protocol.registerProtocol( scheme, customHttps );
Java 7: Включите TLS 1.1 и TLS 1.2, используя системное свойство https.protocols Java для HttpsURLConnection. Чтобы включить TLS 1.1 и TLS 1.2 для соединений, отличных от HttpsURLConnection, установите включенные протоколы для созданных экземпляров SSLSocket и SSLEngine в исходном коде приложения.