Как включить 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 );

Из документации Salesforce:

Java 7: Включите TLS 1.1 и TLS 1.2, используя системное свойство https.protocols Java для HttpsURLConnection. Чтобы включить TLS 1.1 и TLS 1.2 для соединений, отличных от HttpsURLConnection, установите включенные протоколы для созданных экземпляров SSLSocket и SSLEngine в исходном коде приложения.

Другие вопросы по тегам