Как использовать UnboundID SDK для подключения к серверу LDAP с сертификатом сервера SSL?

У меня в руках сертификат сервера SSL LDAP. Я хочу использовать его для подключения к серверу LDAP с помощью UnboundID SDK.

Я не хочу использовать com.unboundid.util.ssl.TrustAllTrustManager, как показано здесь: Использование UnboundID SDK с файлом сертификата SSL для подключения к серверу LDAP в приложении Android

Следующие TrustManager не соответствуют нашим требованиям к продукту:

com.unboundid.util.ssl.PromptTrustManager
com.unboundid.util.ssl.HostNameTrustManager
com.unboundid.util.ssl.ValidityDateTrustManager

Я не хочу никакого взаимодействия с пользователем и того, чего мне не хватает в списке выше TrustManager, который проверяет эмитентов сертификатов.

Кроме того, я не хочу вставлять сертификат сервера LDAP в любое хранилище ключей, поэтому я не могу использовать следующие TrustManagers:

com.unboundid.util.ssl.WrapperKeyManager
com.unboundid.util.ssl.PKCS11KeyManager
com.unboundid.util.ssl.KeyStoreKeyManager

Я хочу сделать что-то вроде кода ниже:

CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate cert = cf.generateCertificate(byteArrayInputStream);
SSLUtil sslUtil = new SSLUtil(new CertificateTrustManager(cert));
SSLSocketFactory socketFactory = sslUtil.createSSLSocketFactory();
LDAPConnection connection = new LDAPConnection(socketFactory,
     "server.example.com", 636);

Обратите внимание, что CertificateTrustManager не существует в UnboundID SDK. Как это возможно сделать?


person Michael    schedule 15.07.2013    source источник


Ответы (3)


Я нашел решение, используя Использование UnboundID SDK с файлом сертификата SSL для подключения к серверу LDAP в приложении Android и Как импортировать сертификат .cer в хранилище ключей Java? (ответ Патрика М).

Теперь я могу взять сертификат из UI и подключиться к LDAP через SSL :)

import com.unboundid.ldap.sdk.LDAPConnection;
import com.unboundid.util.ssl.SSLUtil;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import java.io.ByteArrayInputStream;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;

String base64EncodedCertificateString = "...";
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(base64EncodedCertificateString.getBytes());
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
int i = 0;
while (byteArrayInputStream.available() > 0) {
    Certificate cert = cf.generateCertificate(byteArrayInputStream);
    trustStore.setCertificateEntry("cert " + i++, cert);
}

TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
tmf.init(trustStore);
TrustManager[] trustManagers = tmf.getTrustManagers();
SSLUtil sslUtil = new SSLUtil(trustManagers);
SSLSocketFactory socketFactory = sslUtil.createSSLSocketFactory();
LDAPConnection connection = new LDAPConnection(socketFactory);
connection.connect("place.myserver.com", 636);
person Michael    schedule 16.07.2013

Если есть определенный сертификат или набор сертификатов, которым вы хотите доверять, вы можете просто создать свои собственные реализации javax.net.ssl.X509TrustManager, которые исследуют представленную цепочку сертификатов и определяют, представляет ли она один из ожидаемых сертификатов. Вы можете жестко закодировать информацию об этих сертификатах в своем коде (или, что еще лучше, поместить ее в файл конфигурации, чтобы вы могли изменить ее без изменения кода) и сделать что-то вроде сравнения отпечатков сертификатов, чтобы получить соответствующую степень уверенности в том, что они фактически законный сертификат.

Если вы не знаете, какими будут отдельные сертификаты, но знаете, что у всех них есть общий эмитент, и вы доверяете этому эмитенту только хорошие сертификаты, вы можете включить информацию о доверии для этого эмитента.

Если вы хотите разрешить ряд неизвестных сертификатов, возможно, от ненадежных эмитентов (и вы не знаете, какими могут быть эти эмитенты заранее), и вы не хотите спрашивать пользователя о том, доверять ли им (что вы потенциально может кешировать, поэтому вам нужно спросить только один раз), тогда я не уверен, что вы могли бы сделать. Если вы не сможете найти какой-либо способ отличить сертификаты хороших серверов от сертификатов плохих серверов, ваше приложение рискует либо доверять плохим сертификатам, либо не доверять хорошим.

person Neil Wilson    schedule 15.07.2013
comment
Спасибо за ответ (+1)! Я нашел решение. Буду рад вашим комментариям. - person Michael; 16.07.2013

Хотя это не рекомендуется из соображений безопасности, иногда может быть полезно, по крайней мере, для тестовых ситуаций, использовать TrustAllTrustManager следующим образом:

TrustAllTrustManager tm = new TrustAllTrustManager();
TrustManager[] trustManagers = new TrustManager[] {tm};
SSLUtil sslUtil = new SSLUtil(trustManagers);
SSLSocketFactory socketFactory = sslUtil.createSSLSocketFactory();
LDAPConnection connection = new LDAPConnection(socketFactory);

Это НЕ должно использоваться для производственных сред!

person diadyne    schedule 18.02.2015